diff --git a/bfv/params.go b/bfv/params.go index 95b2727d..4b2b43d4 100644 --- a/bfv/params.go +++ b/bfv/params.go @@ -259,7 +259,7 @@ func (p Parameters) MarshalBinary() ([]byte, error) { // len(rlweBytes) : RLWE parameters // 8 byte : T var tBytes [8]byte - binary.BigEndian.PutUint64(tBytes[:], p.T()) + binary.LittleEndian.PutUint64(tBytes[:], p.T()) data := append(rlweBytes, tBytes[:]...) return data, nil } @@ -275,7 +275,7 @@ func (p *Parameters) UnmarshalBinary(data []byte) (err error) { return err } - t := binary.BigEndian.Uint64(data[len(data)-8:]) + t := binary.LittleEndian.Uint64(data[len(data)-8:]) if p.ringT, err = ring.NewRing(p.N(), []uint64{t}); err != nil { return err diff --git a/bgv/params.go b/bgv/params.go index 1d002c8d..e75cc71b 100644 --- a/bgv/params.go +++ b/bgv/params.go @@ -244,7 +244,7 @@ func (p Parameters) MarshalBinary() ([]byte, error) { // len(rlweBytes) : RLWE parameters // 8 byte : T var tBytes [8]byte - binary.BigEndian.PutUint64(tBytes[:], p.T()) + binary.LittleEndian.PutUint64(tBytes[:], p.T()) data := append(rlweBytes, tBytes[:]...) return data, nil } @@ -256,7 +256,7 @@ func (p *Parameters) UnmarshalBinary(data []byte) (err error) { return err } - t := binary.BigEndian.Uint64(data[len(data)-8:]) + t := binary.LittleEndian.Uint64(data[len(data)-8:]) if p.ringT, err = ring.NewRing(p.N(), []uint64{t}); err != nil { return err diff --git a/ring/poly.go b/ring/poly.go index 01c06e5b..5174888d 100644 --- a/ring/poly.go +++ b/ring/poly.go @@ -4,7 +4,7 @@ import ( "encoding/binary" "fmt" - "github.com/tuneinsight/lattigo/v4/utils" + "github.com/tuneinsight/lattigo/v4/utils/buffer" ) // Poly is the structure that contains the coefficients of a polynomial. @@ -114,42 +114,42 @@ func (pol *Poly) Equals(other *Poly) bool { } // MarshalBinarySize returns the size in bytes that the object once marshalled into a binary form. -func MarshalBinarySize(N, Level int) (cnt int) { +func MarshalBinarySize(N, Level int) (size int) { return 5 + N*(Level+1)<<3 } // MarshalBinarySize returns the size in bytes that the object once marshalled into a binary form. // Assumes that each coefficient takes 8 bytes. -func (pol *Poly) MarshalBinarySize() (cnt int) { +func (pol *Poly) MarshalBinarySize() (size int) { return MarshalBinarySize(pol.N(), pol.Level()) } // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (pol *Poly) MarshalBinary() (p []byte, err error) { p = make([]byte, pol.MarshalBinarySize()) - _, err = pol.Write(p) + _, err = pol.Read(p) return } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (pol *Poly) UnmarshalBinary(p []byte) (err error) { - N := int(binary.BigEndian.Uint32(p)) + N := int(binary.LittleEndian.Uint32(p)) Level := int(p[4]) if size := MarshalBinarySize(N, Level); len(p) != size { return fmt.Errorf("cannot UnmarshalBinary: len(p)=%d != %d", len(p), size) } - if _, err = pol.Read(p); err != nil { - return err + if _, err = pol.Write(p); err != nil { + return } return nil } -func (pol *Poly) WriteTo(w *utils.Writer) (n int, err error) { +func (pol *Poly) WriteTo(w *buffer.Writer) (n int, err error) { var inc int if inc, err = w.WriteUint32(uint32(pol.N())); err != nil { @@ -173,7 +173,7 @@ func (pol *Poly) WriteTo(w *utils.Writer) (n int, err error) { return n, nil } -func (pol *Poly) ReadFrom(r *utils.Reader) (n int, err error) { +func (pol *Poly) ReadFrom(r *buffer.Reader) (n int, err error) { var inc int var NU32 uint32 @@ -232,27 +232,29 @@ func (pol *Poly) Read(p []byte) (n int, err error) { return n, fmt.Errorf("cannot Read: len(p)=%d < %d", len(p), pol.MarshalBinarySize()) } - binary.BigEndian.PutUint32(p, uint32(N)) + binary.LittleEndian.PutUint32(p[n:], uint32(N)) + n += 4 - p[4] = uint8(Level) + p[n] = uint8(Level) + n++ coeffs := pol.Buff NCoeffs := len(coeffs) - n = 5 - for i, j := 0, n; i < NCoeffs; i, j = i+1, j+8 { - binary.BigEndian.PutUint64(p[j:], coeffs[i]) + binary.LittleEndian.PutUint64(p[j:], coeffs[i]) } + n += N * (Level + 1) << 3 + return } // Write decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. +// Read on the object and returns the number of bytes read. func (pol *Poly) Write(p []byte) (n int, err error) { - N := int(binary.BigEndian.Uint32(p)) + N := int(binary.LittleEndian.Uint32(p)) Level := int(p[4]) n = 5 @@ -269,14 +271,16 @@ func (pol *Poly) Write(p []byte) (n int, err error) { NBuff := len(coeffs) for i, j := 0, n; i < NBuff; i, j = i+1, j+8 { - coeffs[i] = binary.BigEndian.Uint64(p[j:]) + coeffs[i] = binary.LittleEndian.Uint64(p[j:]) } + n += N * (Level + 1) << 3 + // Reslice pol.Coeffs = make([][]uint64, Level+1) for i := 0; i < Level+1; i++ { pol.Coeffs[i] = pol.Buff[i*N : (i+1)*N] } - return n, nil + return } diff --git a/ring/ring_sampler_uniform.go b/ring/ring_sampler_uniform.go index 0568c817..5c080fa3 100644 --- a/ring/ring_sampler_uniform.go +++ b/ring/ring_sampler_uniform.go @@ -3,7 +3,7 @@ package ring import ( "encoding/binary" - "github.com/tuneinsight/lattigo/v4/utils" + "github.com/tuneinsight/lattigo/v4/utils/sampling" ) // UniformSampler wraps a util.PRNG and represents the state of a sampler of uniform polynomials. @@ -13,7 +13,7 @@ type UniformSampler struct { } // NewUniformSampler creates a new instance of UniformSampler from a PRNG and ring definition. -func NewUniformSampler(prng utils.PRNG, baseRing *Ring) *UniformSampler { +func NewUniformSampler(prng sampling.PRNG, baseRing *Ring) *UniformSampler { uniformSampler := new(UniformSampler) uniformSampler.baseRing = baseRing uniformSampler.prng = prng @@ -64,7 +64,7 @@ func (u *UniformSampler) Read(pol *Poly) { } // Reads bytes from the buff - randomUint = binary.BigEndian.Uint64(buffer[ptr:ptr+8]) & mask + randomUint = binary.LittleEndian.Uint64(buffer[ptr:ptr+8]) & mask ptr += 8 // If the integer is between [0, qi-1], breaks the loop @@ -86,13 +86,13 @@ func (u *UniformSampler) ReadNew() (Pol *Poly) { return } -func (u *UniformSampler) WithPRNG(prng utils.PRNG) *UniformSampler { +func (u *UniformSampler) WithPRNG(prng sampling.PRNG) *UniformSampler { return &UniformSampler{baseSampler: baseSampler{prng: prng, baseRing: u.baseRing}, randomBufferN: u.randomBufferN} } // RandUniform samples a uniform randomInt variable in the range [0, mask] until randomInt is in the range [0, v-1]. // mask needs to be of the form 2^n -1. -func RandUniform(prng utils.PRNG, v uint64, mask uint64) (randomInt uint64) { +func RandUniform(prng sampling.PRNG, v uint64, mask uint64) (randomInt uint64) { for { randomInt = randInt64(prng, mask) if randomInt < v { @@ -102,28 +102,28 @@ func RandUniform(prng utils.PRNG, v uint64, mask uint64) (randomInt uint64) { } // randInt32 samples a uniform variable in the range [0, mask], where mask is of the form 2^n-1, with n in [0, 32]. -func randInt32(prng utils.PRNG, mask uint64) uint64 { +func randInt32(prng sampling.PRNG, mask uint64) uint64 { // generate random 4 bytes randomBytes := make([]byte, 4) prng.Read(randomBytes) // convert 4 bytes to a uint32 - randomUint32 := uint64(binary.BigEndian.Uint32(randomBytes)) + randomUint32 := uint64(binary.LittleEndian.Uint32(randomBytes)) // return required bits return mask & randomUint32 } // randInt64 samples a uniform variable in the range [0, mask], where mask is of the form 2^n-1, with n in [0, 64]. -func randInt64(prng utils.PRNG, mask uint64) uint64 { +func randInt64(prng sampling.PRNG, mask uint64) uint64 { // generate random 8 bytes randomBytes := make([]byte, 8) prng.Read(randomBytes) // convert 8 bytes to a uint64 - randomUint64 := binary.BigEndian.Uint64(randomBytes) + randomUint64 := binary.LittleEndian.Uint64(randomBytes) // return required bits return mask & randomUint64 diff --git a/ring/ring_test.go b/ring/ring_test.go index 928a9128..5524f2f2 100644 --- a/ring/ring_test.go +++ b/ring/ring_test.go @@ -6,7 +6,7 @@ import ( "math/big" "testing" - "github.com/tuneinsight/lattigo/v4/utils" + "github.com/tuneinsight/lattigo/v4/utils/sampling" "github.com/stretchr/testify/require" ) @@ -24,7 +24,7 @@ func testString(opname string, ringQ *Ring) string { type testParams struct { ringQ *Ring ringP *Ring - prng utils.PRNG + prng sampling.PRNG uniformSamplerQ *UniformSampler uniformSamplerP *UniformSampler } @@ -39,7 +39,7 @@ func genTestParams(defaultParams Parameters) (tc *testParams, err error) { if tc.ringP, err = NewRing(1< degree { - ct.Value = ct.Value[:degree] + if len(ct.Value) > degree+1 { + ct.Value = ct.Value[:degree+1] } else { - ct.Value = append(ct.Value, make([]*ring.Poly, degree-len(ct.Value))...) + ct.Value = append(ct.Value, make([]*ring.Poly, degree+1-len(ct.Value))...) } } n++ @@ -293,7 +293,7 @@ func (ct *Ciphertext) UnmarshalBinaryInPlace(p []byte) (n int, err error) { ct.Value[i] = new(ring.Poly) } - if inc, err = ct.Value[i].Decode64(p[n:]); err != nil { + if inc, err = ct.Value[i].Write(p[n:]); err != nil { return } diff --git a/rlwe/ciphertextQP.go b/rlwe/ciphertextQP.go index b11bed06..381846f8 100644 --- a/rlwe/ciphertextQP.go +++ b/rlwe/ciphertextQP.go @@ -52,37 +52,37 @@ func (ct *CiphertextQP) CopyNew() *CiphertextQP { // MarshalBinarySize returns the size in bytes that the object once marshalled into a binary form. func (ct *CiphertextQP) MarshalBinarySize() int { - return ct.MetaData.MarshalBinarySize() + ct.Value[0].MarshalBinarySize64() + ct.Value[1].MarshalBinarySize64() + return ct.MetaData.MarshalBinarySize() + ct.Value[0].MarshalBinarySize() + ct.Value[1].MarshalBinarySize() } // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (ct *CiphertextQP) MarshalBinary() (data []byte, err error) { data = make([]byte, ct.MarshalBinarySize()) - _, err = ct.MarshalBinaryInPlace(data) + _, err = ct.Read(data) return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (ct *CiphertextQP) MarshalBinaryInPlace(data []byte) (ptr int, err error) { +func (ct *CiphertextQP) Read(data []byte) (ptr int, err error) { if len(data) < ct.MarshalBinarySize() { return 0, fmt.Errorf("cannote write: len(data) is too small") } - if ptr, err = ct.MetaData.MarshalBinaryInPlace(data); err != nil { + if ptr, err = ct.MetaData.Read(data); err != nil { return } var inc int - if inc, err = ct.Value[0].Encode64(data[ptr:]); err != nil { + if inc, err = ct.Value[0].Read(data[ptr:]); err != nil { return } ptr += inc - if inc, err = ct.Value[1].Encode64(data[ptr:]); err != nil { + if inc, err = ct.Value[1].Read(data[ptr:]); err != nil { return } @@ -94,27 +94,27 @@ func (ct *CiphertextQP) MarshalBinaryInPlace(data []byte) (ptr int, err error) { // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary // or MarshalBinaryInPlace on the object. func (ct *CiphertextQP) UnmarshalBinary(data []byte) (err error) { - _, err = ct.UnmarshalBinaryInPlace(data) + _, err = ct.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or +// Write decodes a slice of bytes generated by MarshalBinary or // MarshalBinaryInPlace on the object and returns the number of bytes read. -func (ct *CiphertextQP) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { +func (ct *CiphertextQP) Write(data []byte) (ptr int, err error) { - if ptr, err = ct.MetaData.UnmarshalBinaryInPlace(data); err != nil { + if ptr, err = ct.MetaData.Write(data); err != nil { return } var inc int - if inc, err = ct.Value[0].Decode64(data[ptr:]); err != nil { + if inc, err = ct.Value[0].Write(data[ptr:]); err != nil { return } ptr += inc - if inc, err = ct.Value[1].Decode64(data[ptr:]); err != nil { + if inc, err = ct.Value[1].Write(data[ptr:]); err != nil { return } diff --git a/rlwe/encryptor.go b/rlwe/encryptor.go index 2bf8d2cf..3afaec63 100644 --- a/rlwe/encryptor.go +++ b/rlwe/encryptor.go @@ -7,6 +7,7 @@ import ( "github.com/tuneinsight/lattigo/v4/ring" "github.com/tuneinsight/lattigo/v4/rlwe/ringqp" "github.com/tuneinsight/lattigo/v4/utils" + "github.com/tuneinsight/lattigo/v4/utils/sampling" ) // Encryptor a generic RLWE encryption interface. @@ -26,14 +27,14 @@ type Encryptor interface { // interface. type PRNGEncryptor interface { Encryptor - WithPRNG(prng utils.PRNG) PRNGEncryptor + WithPRNG(prng sampling.PRNG) PRNGEncryptor } type encryptorBase struct { params Parameters *encryptorBuffers - prng utils.PRNG + prng sampling.PRNG gaussianSampler *ring.GaussianSampler ternarySampler *ring.TernarySampler basisextender *ring.BasisExtender @@ -72,7 +73,7 @@ func NewPRNGEncryptor(params Parameters, key *SecretKey) PRNGEncryptor { func newEncryptorBase(params Parameters) *encryptorBase { - prng, err := utils.NewPRNG() + prng, err := sampling.NewPRNG() if err != nil { panic(err) } @@ -453,7 +454,7 @@ func (enc *skEncryptor) ShallowCopy() Encryptor { // WithPRNG returns this encryptor with prng as its source of randomness for the uniform // element c1. -func (enc skEncryptor) WithPRNG(prng utils.PRNG) PRNGEncryptor { +func (enc skEncryptor) WithPRNG(prng sampling.PRNG) PRNGEncryptor { encBase := enc.encryptorBase encBase.uniformSampler = ringqp.NewUniformSampler(prng, *enc.params.RingQP()) return &skEncryptor{encBase, enc.sk} diff --git a/rlwe/evaluationkey.go b/rlwe/evaluationkey.go index 88206648..8d4507bf 100644 --- a/rlwe/evaluationkey.go +++ b/rlwe/evaluationkey.go @@ -46,25 +46,25 @@ func (evk *EvaluationKey) MarshalBinarySize() (dataLen int) { // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (evk *EvaluationKey) MarshalBinary() (data []byte, err error) { data = make([]byte, evk.MarshalBinarySize()) - _, err = evk.MarshalBinaryInPlace(data) + _, err = evk.Read(data) return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (evk *EvaluationKey) MarshalBinaryInPlace(data []byte) (ptr int, err error) { - return evk.GadgetCiphertext.MarshalBinaryInPlace(data) +func (evk *EvaluationKey) Read(data []byte) (ptr int, err error) { + return evk.GadgetCiphertext.Read(data) } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (evk *EvaluationKey) UnmarshalBinary(data []byte) (err error) { - _, err = evk.UnmarshalBinaryInPlace(data) + _, err = evk.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (evk *EvaluationKey) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { - return evk.GadgetCiphertext.UnmarshalBinaryInPlace(data) +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (evk *EvaluationKey) Write(data []byte) (ptr int, err error) { + return evk.GadgetCiphertext.Write(data) } diff --git a/rlwe/gadgetciphertext.go b/rlwe/gadgetciphertext.go index e3b70f04..79dddd15 100644 --- a/rlwe/gadgetciphertext.go +++ b/rlwe/gadgetciphertext.go @@ -104,13 +104,13 @@ func (ct *GadgetCiphertext) MarshalBinarySize() (dataLen int) { // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (ct *GadgetCiphertext) MarshalBinary() (data []byte, err error) { data = make([]byte, ct.MarshalBinarySize()) - _, err = ct.MarshalBinaryInPlace(data) + _, err = ct.Read(data) return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (ct *GadgetCiphertext) MarshalBinaryInPlace(data []byte) (ptr int, err error) { +func (ct *GadgetCiphertext) Read(data []byte) (ptr int, err error) { var inc int @@ -122,7 +122,7 @@ func (ct *GadgetCiphertext) MarshalBinaryInPlace(data []byte) (ptr int, err erro for i := range ct.Value { for _, el := range ct.Value[i] { - if inc, err = el.MarshalBinaryInPlace(data[ptr:]); err != nil { + if inc, err = el.Read(data[ptr:]); err != nil { return ptr, err } ptr += inc @@ -133,15 +133,15 @@ func (ct *GadgetCiphertext) MarshalBinaryInPlace(data []byte) (ptr int, err erro } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (ct *GadgetCiphertext) UnmarshalBinary(data []byte) (err error) { - _, err = ct.UnmarshalBinaryInPlace(data) + _, err = ct.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (ct *GadgetCiphertext) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (ct *GadgetCiphertext) Write(data []byte) (ptr int, err error) { decompRNS := int(data[0]) decompBIT := int(data[1]) @@ -162,7 +162,7 @@ func (ct *GadgetCiphertext) UnmarshalBinaryInPlace(data []byte) (ptr int, err er for j := range ct.Value[i] { - if inc, err = ct.Value[i][j].UnmarshalBinaryInPlace(data[ptr:]); err != nil { + if inc, err = ct.Value[i][j].Write(data[ptr:]); err != nil { return } ptr += inc diff --git a/rlwe/galoiskey.go b/rlwe/galoiskey.go index 11047f49..3ad6aca8 100644 --- a/rlwe/galoiskey.go +++ b/rlwe/galoiskey.go @@ -49,13 +49,13 @@ func (gk *GaloisKey) MarshalBinarySize() (dataLen int) { // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (gk *GaloisKey) MarshalBinary() (data []byte, err error) { data = make([]byte, gk.MarshalBinarySize()) - _, err = gk.MarshalBinaryInPlace(data) + _, err = gk.Read(data) return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (gk *GaloisKey) MarshalBinaryInPlace(data []byte) (ptr int, err error) { +func (gk *GaloisKey) Read(data []byte) (ptr int, err error) { if len(data) < 16 { return ptr, fmt.Errorf("cannot write: len(data) < 16") @@ -68,7 +68,7 @@ func (gk *GaloisKey) MarshalBinaryInPlace(data []byte) (ptr int, err error) { ptr += 8 var inc int - if inc, err = gk.EvaluationKey.MarshalBinaryInPlace(data[ptr:]); err != nil { + if inc, err = gk.EvaluationKey.Read(data[ptr:]); err != nil { return } @@ -79,15 +79,15 @@ func (gk *GaloisKey) MarshalBinaryInPlace(data []byte) (ptr int, err error) { } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (gk *GaloisKey) UnmarshalBinary(data []byte) (err error) { - _, err = gk.UnmarshalBinaryInPlace(data) + _, err = gk.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (gk *GaloisKey) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (gk *GaloisKey) Write(data []byte) (ptr int, err error) { if len(data) < 16 { return ptr, fmt.Errorf("cannot read: len(data) < 16") @@ -100,7 +100,7 @@ func (gk *GaloisKey) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { ptr += 8 var inc int - if inc, err = gk.EvaluationKey.UnmarshalBinaryInPlace(data[ptr:]); err != nil { + if inc, err = gk.EvaluationKey.Write(data[ptr:]); err != nil { return } diff --git a/rlwe/metadata.go b/rlwe/metadata.go index a8a3be6a..b7349b2e 100644 --- a/rlwe/metadata.go +++ b/rlwe/metadata.go @@ -27,26 +27,26 @@ func (m *MetaData) MarshalBinarySize() int { // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (m *MetaData) MarshalBinary() (data []byte, err error) { data = make([]byte, m.MarshalBinarySize()) - _, err = m.MarshalBinaryInPlace(data) + _, err = m.Read(data) return } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (m *MetaData) UnmarshalBinary(data []byte) (err error) { - _, err = m.UnmarshalBinaryInPlace(data) + _, err = m.Write(data) return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (m *MetaData) MarshalBinaryInPlace(data []byte) (ptr int, err error) { +func (m *MetaData) Read(data []byte) (ptr int, err error) { if len(data) < m.MarshalBinarySize() { return 0, fmt.Errorf("cannot write: len(data) is too small") } - if ptr, err = m.Scale.MarshalBinaryInPlace(data[ptr:]); err != nil { + if ptr, err = m.Scale.Read(data[ptr:]); err != nil { return 0, err } @@ -65,15 +65,15 @@ func (m *MetaData) MarshalBinaryInPlace(data []byte) (ptr int, err error) { return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (m *MetaData) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (m *MetaData) Write(data []byte) (ptr int, err error) { if len(data) < m.MarshalBinarySize() { return 0, fmt.Errorf("canoot read: len(data) is too small") } - if ptr, err = m.Scale.UnmarshalBinaryInPlace(data[ptr:]); err != nil { + if ptr, err = m.Scale.Write(data[ptr:]); err != nil { return } diff --git a/rlwe/params.go b/rlwe/params.go index 054a89fd..4ffe144b 100644 --- a/rlwe/params.go +++ b/rlwe/params.go @@ -11,6 +11,7 @@ import ( "github.com/tuneinsight/lattigo/v4/ring" "github.com/tuneinsight/lattigo/v4/rlwe/ringqp" "github.com/tuneinsight/lattigo/v4/utils" + "github.com/tuneinsight/lattigo/v4/utils/buffer" ) // MaxLogN is the log2 of the largest supported polynomial modulus degree. @@ -670,7 +671,7 @@ func (p Parameters) MarshalBinary() ([]byte, error) { // 48 bytes: defaultScale // 8 * (#Q) : Q // 8 * (#P) : P - b := utils.NewBuffer(make([]byte, 0, p.MarshalBinarySize())) + b := buffer.NewBuffer(make([]byte, 0, p.MarshalBinarySize())) b.WriteUint8(uint8(p.logN)) b.WriteUint8(uint8(len(p.qi))) b.WriteUint8(uint8(len(p.pi))) @@ -686,7 +687,7 @@ func (p Parameters) MarshalBinary() ([]byte, error) { data := make([]byte, p.defaultScale.MarshalBinarySize()) - if _, err := p.defaultScale.MarshalBinaryInPlace(data); err != nil { + if _, err := p.defaultScale.Read(data); err != nil { return nil, err } @@ -705,7 +706,7 @@ func (p *Parameters) UnmarshalBinary(data []byte) (err error) { if len(data) < 11 { return fmt.Errorf("invalid rlwe.Parameter serialization") } - b := utils.NewBuffer(data) + b := buffer.NewBuffer(data) logN := int(b.ReadUint8()) lenQ := int(b.ReadUint8()) lenP := int(b.ReadUint8()) @@ -721,7 +722,7 @@ func (p *Parameters) UnmarshalBinary(data []byte) (err error) { var defaultScale Scale dataScale := make([]uint8, defaultScale.MarshalBinarySize()) b.ReadUint8Slice(dataScale) - if _, err = defaultScale.UnmarshalBinaryInPlace(dataScale); err != nil { + if _, err = defaultScale.Write(dataScale); err != nil { return } diff --git a/rlwe/plaintext.go b/rlwe/plaintext.go index 88087e52..50c7ee24 100644 --- a/rlwe/plaintext.go +++ b/rlwe/plaintext.go @@ -67,30 +67,30 @@ func (pt *Plaintext) Copy(other *Plaintext) { // MarshalBinarySize returns the size in bytes that the object once marshalled into a binary form. func (pt *Plaintext) MarshalBinarySize() (dataLen int) { - return pt.MetaData.MarshalBinarySize() + pt.Value.MarshalBinarySize64() + return pt.MetaData.MarshalBinarySize() + pt.Value.MarshalBinarySize() } // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (pt *Plaintext) MarshalBinary() (data []byte, err error) { data = make([]byte, pt.MarshalBinarySize()) - _, err = pt.MarshalBinaryInPlace(data) + _, err = pt.Read(data) return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (pt *Plaintext) MarshalBinaryInPlace(data []byte) (ptr int, err error) { +func (pt *Plaintext) Read(data []byte) (ptr int, err error) { if len(data) < pt.MarshalBinarySize() { return 0, fmt.Errorf("cannot write: len(data) is too small") } - if ptr, err = pt.MetaData.MarshalBinaryInPlace(data); err != nil { + if ptr, err = pt.MetaData.Read(data); err != nil { return } var inc int - if inc, err = pt.Value.Encode64(data[ptr:]); err != nil { + if inc, err = pt.Value.Read(data[ptr:]); err != nil { return } @@ -100,17 +100,17 @@ func (pt *Plaintext) MarshalBinaryInPlace(data []byte) (ptr int, err error) { } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (pt *Plaintext) UnmarshalBinary(data []byte) (err error) { - _, err = pt.UnmarshalBinaryInPlace(data) + _, err = pt.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (pt *Plaintext) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (pt *Plaintext) Write(data []byte) (ptr int, err error) { - if ptr, err = pt.MetaData.UnmarshalBinaryInPlace(data); err != nil { + if ptr, err = pt.MetaData.Write(data); err != nil { return } @@ -119,7 +119,7 @@ func (pt *Plaintext) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { } var inc int - if inc, err = pt.Value.Decode64(data[ptr:]); err != nil { + if inc, err = pt.Value.Write(data[ptr:]); err != nil { return } diff --git a/rlwe/publickey.go b/rlwe/publickey.go index 65ae13d8..837e6ed6 100644 --- a/rlwe/publickey.go +++ b/rlwe/publickey.go @@ -46,33 +46,33 @@ func (pk *PublicKey) CopyNew() *PublicKey { // MarshalBinarySize returns the size in bytes that the object once marshalled into a binary form. func (pk *PublicKey) MarshalBinarySize() (dataLen int) { - return pk.Value[0].MarshalBinarySize64() + pk.Value[1].MarshalBinarySize64() + pk.MetaData.MarshalBinarySize() + return pk.CiphertextQP.MarshalBinarySize() } // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (pk *PublicKey) MarshalBinary() (data []byte, err error) { data = make([]byte, pk.MarshalBinarySize()) - if _, err = pk.MarshalBinaryInPlace(data); err != nil { + if _, err = pk.Read(data); err != nil { return nil, err } return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (pk *PublicKey) MarshalBinaryInPlace(data []byte) (ptr int, err error) { - return pk.CiphertextQP.MarshalBinaryInPlace(data) +func (pk *PublicKey) Read(data []byte) (ptr int, err error) { + return pk.CiphertextQP.Read(data) } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (pk *PublicKey) UnmarshalBinary(data []byte) (err error) { - _, err = pk.UnmarshalBinaryInPlace(data) + _, err = pk.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (pk *PublicKey) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { - return pk.CiphertextQP.UnmarshalBinaryInPlace(data) +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (pk *PublicKey) Write(data []byte) (ptr int, err error) { + return pk.CiphertextQP.Write(data) } diff --git a/rlwe/relinearizationkey.go b/rlwe/relinearizationkey.go index 0327c88b..207ef754 100644 --- a/rlwe/relinearizationkey.go +++ b/rlwe/relinearizationkey.go @@ -33,21 +33,21 @@ func (rlk *RelinearizationKey) MarshalBinary() (data []byte, err error) { return rlk.EvaluationKey.MarshalBinary() } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (rlk *RelinearizationKey) MarshalBinaryInPlace(data []byte) (ptr int, err error) { - return rlk.EvaluationKey.MarshalBinaryInPlace(data) +func (rlk *RelinearizationKey) Read(data []byte) (ptr int, err error) { + return rlk.EvaluationKey.Read(data) } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (rlk *RelinearizationKey) UnmarshalBinary(data []byte) (err error) { - _, err = rlk.UnmarshalBinaryInPlace(data) + _, err = rlk.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (rlk *RelinearizationKey) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { - return rlk.EvaluationKey.UnmarshalBinaryInPlace(data) +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (rlk *RelinearizationKey) Write(data []byte) (ptr int, err error) { + return rlk.EvaluationKey.Write(data) } diff --git a/rlwe/ringqp/ringqp.go b/rlwe/ringqp/ringqp.go index b2deb925..cfb200da 100644 --- a/rlwe/ringqp/ringqp.go +++ b/rlwe/ringqp/ringqp.go @@ -3,7 +3,7 @@ package ringqp import ( "github.com/tuneinsight/lattigo/v4/ring" - "github.com/tuneinsight/lattigo/v4/utils" + "github.com/tuneinsight/lattigo/v4/utils/sampling" ) // Poly represents a polynomial in the ring of polynomial modulo Q*P. @@ -502,25 +502,25 @@ func (r *Ring) ExtendBasisSmallNormAndCenter(polyInQ *ring.Poly, levelP int, pol } } -// MarshalBinarySize64 returns the length in byte of the target Poly. -// Assumes that each coefficient uses 8 bytes. -func (p *Poly) MarshalBinarySize64() (dataLen int) { +// MarshalBinarySize returns the size in bytes that the object once marshalled into a binary form. +// Assumes that each coefficient takes 8 bytes. +func (p *Poly) MarshalBinarySize() (dataLen int) { dataLen = 2 if p.Q != nil { - dataLen += p.Q.MarshalBinarySize64() + dataLen += p.Q.MarshalBinarySize() } if p.P != nil { - dataLen += p.P.MarshalBinarySize64() + dataLen += p.P.MarshalBinarySize() } return } -// Encode64 writes a Poly on the input data. -// Encodes each coefficient on 8 bytes. -func (p *Poly) Encode64(data []byte) (pt int, err error) { +// Read encodes the object into a binary form on a preallocated slice of bytes +// and returns the number of bytes written. +func (p *Poly) Read(data []byte) (n int, err error) { var inc int if p.Q != nil { @@ -531,32 +531,31 @@ func (p *Poly) Encode64(data []byte) (pt int, err error) { data[1] = 1 } - pt = 2 + n = 2 if data[0] == 1 { - if inc, err = p.Q.Encode64(data[pt:]); err != nil { + if inc, err = p.Q.Read(data[n:]); err != nil { return } - pt += inc + n += inc } if data[1] == 1 { - if inc, err = p.P.Encode64(data[pt:]); err != nil { + if inc, err = p.P.Read(data[n:]); err != nil { return } - pt += inc + n += inc } return } -// Decode64 decodes the input bytes on the target Poly. -// Writes on pre-allocated coefficients. -// Assumes that each coefficient is encoded on 8 bytes. -func (p *Poly) Decode64(data []byte) (pt int, err error) { +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (p *Poly) Write(data []byte) (n int, err error) { var inc int - pt = 2 + n = 2 if data[0] == 1 { @@ -564,10 +563,10 @@ func (p *Poly) Decode64(data []byte) (pt int, err error) { p.Q = new(ring.Poly) } - if inc, err = p.Q.Decode64(data[pt:]); err != nil { + if inc, err = p.Q.Write(data[n:]); err != nil { return } - pt += inc + n += inc } if data[1] == 1 { @@ -576,23 +575,26 @@ func (p *Poly) Decode64(data []byte) (pt int, err error) { p.P = new(ring.Poly) } - if inc, err = p.P.Decode64(data[pt:]); err != nil { + if inc, err = p.P.Write(data[n:]); err != nil { return } - pt += inc + n += inc } return } -func (p *Poly) MarshalBinary() ([]byte, error) { - b := make([]byte, p.MarshalBinarySize64()) - _, err := p.Encode64(b) - return b, err +// MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. +func (p *Poly) MarshalBinary() (data []byte, err error) { + data = make([]byte, p.MarshalBinarySize()) + _, err = p.Read(data) + return } -func (p *Poly) UnmarshalBinary(b []byte) error { - _, err := p.Decode64(b) +// UnmarshalBinary decodes a slice of bytes generated by MarshalBinary +// or Read on the object. +func (p *Poly) UnmarshalBinary(data []byte) (err error) { + _, err = p.Write(data) return err } @@ -602,7 +604,7 @@ type UniformSampler struct { } // NewUniformSampler instantiates a new UniformSampler from a given PRNG. -func NewUniformSampler(prng utils.PRNG, r Ring) (s UniformSampler) { +func NewUniformSampler(prng sampling.PRNG, r Ring) (s UniformSampler) { if r.RingQ != nil { s.samplerQ = ring.NewUniformSampler(prng, r.RingQ) } @@ -644,7 +646,7 @@ func (s UniformSampler) Read(p Poly) { } } -func (s UniformSampler) WithPRNG(prng utils.PRNG) UniformSampler { +func (s UniformSampler) WithPRNG(prng sampling.PRNG) UniformSampler { sp := UniformSampler{samplerQ: s.samplerQ.WithPRNG(prng)} if s.samplerP != nil { sp.samplerP = s.samplerP.WithPRNG(prng) diff --git a/rlwe/rlwe_test.go b/rlwe/rlwe_test.go index 047075fb..1d739856 100644 --- a/rlwe/rlwe_test.go +++ b/rlwe/rlwe_test.go @@ -14,7 +14,7 @@ import ( "github.com/tuneinsight/lattigo/v4/rlwe/ringqp" "github.com/tuneinsight/lattigo/v4/ring" - "github.com/tuneinsight/lattigo/v4/utils" + "github.com/tuneinsight/lattigo/v4/utils/sampling" ) var flagParamString = flag.String("params", "", "specify the test cryptographic parameters as a JSON string. Overrides -short and -long.") @@ -309,8 +309,8 @@ func testEncryptor(tc *TestContext, level int, t *testing.T) { enc := NewPRNGEncryptor(params, sk) ct := NewCiphertext(params, 1, level) - prng1, _ := utils.NewKeyedPRNG([]byte{'a', 'b', 'c'}) - prng2, _ := utils.NewKeyedPRNG([]byte{'a', 'b', 'c'}) + prng1, _ := sampling.NewKeyedPRNG([]byte{'a', 'b', 'c'}) + prng2, _ := sampling.NewKeyedPRNG([]byte{'a', 'b', 'c'}) enc.WithPRNG(prng1).Encrypt(pt, ct) @@ -475,7 +475,7 @@ func testGadgetProduct(tc *TestContext, level int, t *testing.T) { ringQ := params.RingQ().AtLevel(level) - prng, _ := utils.NewKeyedPRNG([]byte{'a', 'b', 'c'}) + prng, _ := sampling.NewKeyedPRNG([]byte{'a', 'b', 'c'}) sampler := ring.NewUniformSampler(prng, ringQ) @@ -956,7 +956,7 @@ func testMarshaller(tc *TestContext, t *testing.T) { t.Run(testString(params, params.MaxLevel(), "Marshaller/Plaintext"), func(t *testing.T) { - prng, _ := utils.NewPRNG() + prng, _ := sampling.NewPRNG() plaintextWant := NewPlaintext(params, params.MaxLevel()) ring.NewUniformSampler(prng, params.RingQ()).Read(plaintextWant.Value) @@ -973,7 +973,7 @@ func testMarshaller(tc *TestContext, t *testing.T) { t.Run(testString(params, params.MaxLevel(), "Marshaller/Ciphertext"), func(t *testing.T) { - prng, _ := utils.NewPRNG() + prng, _ := sampling.NewPRNG() for degree := 0; degree < 4; degree++ { t.Run(fmt.Sprintf("degree=%d", degree), func(t *testing.T) { @@ -997,7 +997,7 @@ func testMarshaller(tc *TestContext, t *testing.T) { t.Run(testString(params, params.MaxLevel(), "Marshaller/CiphertextQP"), func(t *testing.T) { - prng, _ := utils.NewPRNG() + prng, _ := sampling.NewPRNG() sampler := ringqp.NewUniformSampler(prng, *params.RingQP()) @@ -1020,7 +1020,7 @@ func testMarshaller(tc *TestContext, t *testing.T) { t.Run(testString(params, params.MaxLevel(), "Marshaller/GadgetCiphertext"), func(t *testing.T) { - prng, _ := utils.NewPRNG() + prng, _ := sampling.NewPRNG() sampler := ringqp.NewUniformSampler(prng, *params.RingQP()) diff --git a/rlwe/scale.go b/rlwe/scale.go index 266c2d7f..829ec9a0 100644 --- a/rlwe/scale.go +++ b/rlwe/scale.go @@ -137,13 +137,13 @@ func (s Scale) MarshalBinarySize() int { // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (s Scale) MarshalBinary() (data []byte, err error) { data = make([]byte, s.MarshalBinarySize()) - _, err = s.MarshalBinaryInPlace(data) + _, err = s.Read(data) return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (s Scale) MarshalBinaryInPlace(data []byte) (ptr int, err error) { +func (s Scale) Read(data []byte) (ptr int, err error) { var sBytes []byte if sBytes, err = s.Value.MarshalText(); err != nil { return @@ -167,15 +167,15 @@ func (s Scale) MarshalBinaryInPlace(data []byte) (ptr int, err error) { } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (s Scale) UnmarshalBinary(data []byte) (err error) { - _, err = s.UnmarshalBinaryInPlace(data) + _, err = s.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (s *Scale) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (s *Scale) Write(data []byte) (ptr int, err error) { if dLen := s.MarshalBinarySize(); len(data) < dLen { return 0, fmt.Errorf("cannot read: len(data) < %d", dLen) diff --git a/rlwe/secretkey.go b/rlwe/secretkey.go index 3f74d916..3f8cb33a 100644 --- a/rlwe/secretkey.go +++ b/rlwe/secretkey.go @@ -38,33 +38,33 @@ func (sk *SecretKey) CopyNew() *SecretKey { // MarshalBinarySize returns the size in bytes that the object once marshalled into a binary form. func (sk *SecretKey) MarshalBinarySize() (dataLen int) { - return sk.Value.MarshalBinarySize64() + return sk.Value.MarshalBinarySize() } // MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes. func (sk *SecretKey) MarshalBinary() (data []byte, err error) { data = make([]byte, sk.MarshalBinarySize()) - if _, err = sk.MarshalBinaryInPlace(data); err != nil { + if _, err = sk.Read(data); err != nil { return nil, err } return } -// MarshalBinaryInPlace encodes the object into a binary form on a preallocated slice of bytes +// Read encodes the object into a binary form on a preallocated slice of bytes // and returns the number of bytes written. -func (sk *SecretKey) MarshalBinaryInPlace(data []byte) (ptr int, err error) { - return sk.Value.Encode64(data) +func (sk *SecretKey) Read(data []byte) (ptr int, err error) { + return sk.Value.Read(data) } // UnmarshalBinary decodes a slice of bytes generated by MarshalBinary -// or MarshalBinaryInPlace on the object. +// or Read on the object. func (sk *SecretKey) UnmarshalBinary(data []byte) (err error) { - _, err = sk.UnmarshalBinaryInPlace(data) + _, err = sk.Write(data) return } -// UnmarshalBinaryInPlace decodes a slice of bytes generated by MarshalBinary or -// MarshalBinaryInPlace on the object and returns the number of bytes read. -func (sk *SecretKey) UnmarshalBinaryInPlace(data []byte) (ptr int, err error) { - return sk.Value.Decode64(data) +// Write decodes a slice of bytes generated by MarshalBinary or +// Read on the object and returns the number of bytes read. +func (sk *SecretKey) Write(data []byte) (ptr int, err error) { + return sk.Value.Write(data) } diff --git a/utils/buffer.go b/utils/buffer/buffer.go similarity index 94% rename from utils/buffer.go rename to utils/buffer/buffer.go index 9d26e037..5d7fccee 100644 --- a/utils/buffer.go +++ b/utils/buffer/buffer.go @@ -1,5 +1,5 @@ -// Package utils contains helper structures and function -package utils +// Package buffer implements interfaces and structs for buffered read and write. +package buffer // Buffer is a simple wrapper around a []byte to facilitate efficient marshalling of lattigo's objects type Buffer struct { diff --git a/utils/buffer_test.go b/utils/buffer/buffer_test.go similarity index 68% rename from utils/buffer_test.go rename to utils/buffer/buffer_test.go index bc099988..ea5a746c 100644 --- a/utils/buffer_test.go +++ b/utils/buffer/buffer_test.go @@ -1,20 +1,20 @@ -// Package containing helper structures and function -package utils +package buffer_test import ( "testing" "github.com/stretchr/testify/assert" + "github.com/tuneinsight/lattigo/v4/utils/buffer" ) func TestNewBuffer(t *testing.T) { - assert.Equal(t, []byte(nil), NewBuffer(nil).Bytes()) - assert.Equal(t, []byte{}, NewBuffer([]byte{}).Bytes()) - assert.Equal(t, []byte{1, 2, 3}, NewBuffer([]byte{1, 2, 3}).Bytes()) + assert.Equal(t, []byte(nil), buffer.NewBuffer(nil).Bytes()) + assert.Equal(t, []byte{}, buffer.NewBuffer([]byte{}).Bytes()) + assert.Equal(t, []byte{1, 2, 3}, buffer.NewBuffer([]byte{1, 2, 3}).Bytes()) } func TestBuffer_WriteReadUint8(t *testing.T) { - b := NewBuffer(make([]byte, 0, 1)) + b := buffer.NewBuffer(make([]byte, 0, 1)) b.WriteUint8(0xff) assert.Equal(t, []byte{0xff}, b.Bytes()) assert.Equal(t, byte(0xff), b.ReadUint8()) @@ -22,7 +22,7 @@ func TestBuffer_WriteReadUint8(t *testing.T) { } func TestBuffer_WriteReadUint64(t *testing.T) { - b := NewBuffer(make([]byte, 0, 8)) + b := buffer.NewBuffer(make([]byte, 0, 8)) b.WriteUint64(0x1122334455667788) assert.Equal(t, []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, b.Bytes()) assert.Equal(t, uint64(0x1122334455667788), b.ReadUint64()) @@ -30,7 +30,7 @@ func TestBuffer_WriteReadUint64(t *testing.T) { } func TestBuffer_WriteReadUint64Slice(t *testing.T) { - b := NewBuffer(make([]byte, 0, 8)) + b := buffer.NewBuffer(make([]byte, 0, 8)) b.WriteUint64Slice([]uint64{0x1122334455667788}) assert.Equal(t, []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, b.Bytes()) s := make([]uint64, 1) diff --git a/utils/marshaling.go b/utils/buffer/interface.go similarity index 99% rename from utils/marshaling.go rename to utils/buffer/interface.go index 5e0ae919..25ccc6c1 100644 --- a/utils/marshaling.go +++ b/utils/buffer/interface.go @@ -1,4 +1,4 @@ -package utils +package buffer // BinaryMarshaler is an interface implemented by an object that can marshal itself into a binary form. type BinaryMarshaler interface { diff --git a/utils/reader.go b/utils/buffer/reader.go similarity index 99% rename from utils/reader.go rename to utils/buffer/reader.go index be8c5ba5..602bec17 100644 --- a/utils/reader.go +++ b/utils/buffer/reader.go @@ -1,4 +1,4 @@ -package utils +package buffer import ( "encoding/binary" diff --git a/utils/writer.go b/utils/buffer/writer.go similarity index 54% rename from utils/writer.go rename to utils/buffer/writer.go index 1a686ec2..3f3e7f1e 100644 --- a/utils/writer.go +++ b/utils/buffer/writer.go @@ -1,4 +1,4 @@ -package utils +package buffer import ( "encoding/binary" @@ -6,22 +6,74 @@ import ( "io" ) +const ( + DefaultWriterBufferSize = 1024 +) + +// Writer implements buffering for an io.Writer object. +// If an error occurs writing to a Writer, no more data will be accepted and all subsequent writes, and Flush, will return the error. +// After all data has been written, the client should call the Flush method to guarantee all data has been forwarded to the underlying io.Writer. type Writer struct { io.Writer buff []byte n int + err error } +// NewWriter returns a new Writer whose buffer has the default size DefaultWriterBufferSize. +// If the argument io.Writer is already a Writer with large enough buffer size, it returns the underlying Writer. func NewWriter(w io.Writer) *Writer { + return NewWriterSize(w, DefaultWriterBufferSize) +} + +// NewWriterSize returns a new Writer whose buffer has the specified size. +func NewWriterSize(w io.Writer, size int) *Writer { + + switch w := w.(type) { + case *Writer: + if w.Size() >= size { + return w + } + } + return &Writer{ Writer: w, - buff: make([]byte, 1<<10), //1KB of buffer + buff: make([]byte, size), n: 0, } } +// Available returns how many bytes are unused in the buffer. +func (w *Writer) Available() int { + return len(w.buff[w.n:]) +} + +// AvailableBuffer returns an empty buffer with b.Available() capacity. +// This buffer is intended to be appended to and passed to an immediately succeeding Write call. +// The buffer is only valid until the next write operation on b. +func (w *Writer) AvailableBuffer() []byte { + return make([]byte, w.Available()) +} + +// Size returns the size of the underlying buffer in bytes. +func (w *Writer) Size() int { + return len(w.buff) +} + +// Buffered returns the number of bytes that have been written into the current buffer. +func (w *Writer) Buffered() int { + return w.n +} + +// Flush writes any buffered data to the underlying io.Writer. func (w *Writer) Flush() (err error) { + + if w.err != nil { + return fmt.Errorf("cannot flush: previous error: %w", w.err) + } + if _, err = w.Writer.Write(w.buff[:w.n]); err != nil { + w.err = err return fmt.Errorf("cannot flush: %w", err) } @@ -30,20 +82,44 @@ func (w *Writer) Flush() (err error) { return } +// Reset discards any unflushed buffered data, clears any error, and resets b to write its output to w. +// Calling Reset on the zero value of Writer initializes the internal buffer to the default size. +func (w *Writer) Reset() { + w.err = nil + buff := w.buff + for i := range buff { + buff[i] = 0 + } + w.n = 0 +} + +// Write flushes the internal buffer on the io.Writer and writes p directly on the underlying io.Writer. +// It returns the number of bytes written. func (w *Writer) Write(p []byte) (n int, err error) { + if w.err != nil { + return n, fmt.Errorf("cannot Write: previous error: %w", w.err) + } + // First we flush because we bypass the internal buffer if err = w.Flush(); err != nil { + w.err = err return } return w.Writer.Write(p) } +// WriteUint8 writes a single uint8. func (w *Writer) WriteUint8(c uint8) (n int, err error) { + if w.err != nil { + return n, fmt.Errorf("cannot WriteUint8: previous error: %w", w.err) + } + if len(w.buff[w.n:]) < 1 { if err = w.Flush(); err != nil { + w.err = err return n, fmt.Errorf("cannot WriteUint8: %w", err) } } @@ -55,14 +131,26 @@ func (w *Writer) WriteUint8(c uint8) (n int, err error) { return 1, nil } +// WriteUint8Slice writes a slice of uint8. func (w *Writer) WriteUint8Slice(c []uint8) (n int, err error) { + + if w.err != nil { + return n, fmt.Errorf("cannot WriteUint8Slice: previous error: %w", w.err) + } + return w.Write(c) } +// WriteUint16 writes a single uint16. func (w *Writer) WriteUint16(c uint16) (n int, err error) { + if w.err != nil { + return n, fmt.Errorf("cannot WriteUint16: previous error: %w", w.err) + } + if len(w.buff[w.n:]) < 2 { if err = w.Flush(); err != nil { + w.err = err return n, fmt.Errorf("cannot WriteUint16: %w", err) } } @@ -74,8 +162,13 @@ func (w *Writer) WriteUint16(c uint16) (n int, err error) { return 2, nil } +// WriteUint16Slice writes a slice of uint16. func (w *Writer) WriteUint16Slice(c []uint16) (n int, err error) { + if w.err != nil { + return n, fmt.Errorf("cannot WriteUint16Slice: previous error: %w", w.err) + } + buff := w.buff[w.n:] // Remaining available space in the internal buffer @@ -111,16 +204,23 @@ func (w *Writer) WriteUint16Slice(c []uint16) (n int, err error) { // Then recurses on itself with the remaining slice var inc int if inc, err = w.WriteUint16Slice(c[available:]); err != nil { + w.err = err return n + inc, err } return n + inc, nil } +// WriteUint32 writes a single uint32. func (w *Writer) WriteUint32(c uint32) (n int, err error) { + if w.err != nil { + return n, fmt.Errorf("cannot WriteUint32: previous error: %w", w.err) + } + if len(w.buff[w.n:]) < 4 { if err = w.Flush(); err != nil { + w.err = err return n, fmt.Errorf("cannot WriteUint32: %w", err) } } @@ -132,8 +232,13 @@ func (w *Writer) WriteUint32(c uint32) (n int, err error) { return 4, nil } +// WriteUint32Slice writes a slice of uint32. func (w *Writer) WriteUint32Slice(c []uint32) (n int, err error) { + if w.err != nil { + return n, fmt.Errorf("cannot WriteUint32Slice: previous error: %w", w.err) + } + buff := w.buff[w.n:] // Remaining available space in the internal buffer @@ -169,16 +274,23 @@ func (w *Writer) WriteUint32Slice(c []uint32) (n int, err error) { // Then recurses on itself with the remaining slice var inc int if inc, err = w.WriteUint32Slice(c[available:]); err != nil { + w.err = err return n + inc, err } return n + inc, nil } +// WriteUint64 writes a single uint64. func (w *Writer) WriteUint64(c uint64) (n int, err error) { + if w.err != nil { + return n, fmt.Errorf("cannot WriteUint64: previous error: %w", w.err) + } + if len(w.buff[w.n:]) < 8 { if err = w.Flush(); err != nil { + w.err = err return n, fmt.Errorf("cannot WriteUint64: %w", err) } } @@ -190,8 +302,13 @@ func (w *Writer) WriteUint64(c uint64) (n int, err error) { return 8, nil } +// WriteUint64Slice writes a slice of uint64. func (w *Writer) WriteUint64Slice(c []uint64) (n int, err error) { + if w.err != nil { + return n, fmt.Errorf("cannot WriteUint64Slice: previous error: %w", w.err) + } + buff := w.buff[w.n:] // Remaining available space in the internal buffer @@ -227,6 +344,7 @@ func (w *Writer) WriteUint64Slice(c []uint64) (n int, err error) { // Then recurses on itself with the remaining slice var inc int if inc, err = w.WriteUint64Slice(c[available:]); err != nil { + w.err = err return n + inc, err } diff --git a/utils/factorization.go b/utils/factorization/factorization.go similarity index 99% rename from utils/factorization.go rename to utils/factorization/factorization.go index 555b1532..14631900 100644 --- a/utils/factorization.go +++ b/utils/factorization/factorization.go @@ -1,4 +1,4 @@ -package utils +package factorization import ( "math" diff --git a/utils/factorization/factorization_test.go b/utils/factorization/factorization_test.go new file mode 100644 index 00000000..464c3840 --- /dev/null +++ b/utils/factorization/factorization_test.go @@ -0,0 +1,30 @@ +package factorization_test + +import ( + "math/big" + "testing" + + "github.com/tuneinsight/lattigo/v4/utils/factorization" +) + +func TestGetFactors(t *testing.T) { + + m := new(big.Int).SetUint64(35184372088631) + + t.Run("ECM", func(t *testing.T) { + + factor := factorization.GetFactorECM(m) + + if factor.Cmp(new(big.Int).SetUint64(6292343)) != 0 && factor.Cmp(new(big.Int).SetUint64(5591617)) != 0 { + t.Fail() + } + }) + + t.Run("PollardRho", func(t *testing.T) { + factor := factorization.GetFactorPollardRho(m) + + if factor.Cmp(new(big.Int).SetUint64(6292343)) != 0 && factor.Cmp(new(big.Int).SetUint64(5591617)) != 0 { + t.Fail() + } + }) +} diff --git a/utils/weierstrass.go b/utils/factorization/weierstrass.go similarity index 94% rename from utils/weierstrass.go rename to utils/factorization/weierstrass.go index 3ded8a56..b6d91e17 100644 --- a/utils/weierstrass.go +++ b/utils/factorization/weierstrass.go @@ -1,7 +1,9 @@ -package utils +package factorization import ( "math/big" + + "github.com/tuneinsight/lattigo/v4/utils/sampling" ) // Weierstrass is an elliptic curve y^2 = x^3 + ax + b mod N. @@ -92,9 +94,9 @@ func NewRandomWeierstrassCurve(N *big.Int) (Weierstrass, Point) { for { // Select random values for A, xG and yG - A = RandInt(N) - xG = RandInt(N) - yG = RandInt(N) + A = sampling.RandInt(N) + xG = sampling.RandInt(N) + yG = sampling.RandInt(N) // Deduces B from Y^2 = X^3 + A * X + B evaluated at point (xG, yG) yGpow2 := new(big.Int).Mul(yG, yG) diff --git a/utils/prng.go b/utils/sampling/prng.go similarity index 99% rename from utils/prng.go rename to utils/sampling/prng.go index 8585926b..87f4f9ca 100644 --- a/utils/prng.go +++ b/utils/sampling/prng.go @@ -1,4 +1,4 @@ -package utils +package sampling import ( "crypto/rand" diff --git a/utils/prng_test.go b/utils/sampling/prng_test.go similarity index 78% rename from utils/prng_test.go rename to utils/sampling/prng_test.go index aa914d31..35b7bfd1 100644 --- a/utils/prng_test.go +++ b/utils/sampling/prng_test.go @@ -1,9 +1,10 @@ -package utils +package sampling_test import ( "testing" "github.com/stretchr/testify/require" + "github.com/tuneinsight/lattigo/v4/utils/sampling" ) func Test_PRNG(t *testing.T) { @@ -13,8 +14,8 @@ func Test_PRNG(t *testing.T) { key := []byte{0x49, 0x0a, 0x42, 0x3d, 0x97, 0x9d, 0xc1, 0x07, 0xa1, 0xd7, 0xe9, 0x7b, 0x3b, 0xce, 0xa1, 0xdb, 0x42, 0xf3, 0xa6, 0xd5, 0x75, 0xd2, 0x0c, 0x92, 0xb7, 0x35, 0xce, 0x0c, 0xee, 0x09, 0x7c, 0x98} - Ha, _ := NewKeyedPRNG(key) - Hb, _ := NewKeyedPRNG(key) + Ha, _ := sampling.NewKeyedPRNG(key) + Hb, _ := sampling.NewKeyedPRNG(key) sum0 := make([]byte, 512) sum1 := make([]byte, 512) diff --git a/utils/sampling/sampling.go b/utils/sampling/sampling.go new file mode 100644 index 00000000..028ed8c3 --- /dev/null +++ b/utils/sampling/sampling.go @@ -0,0 +1,40 @@ +package sampling + +import ( + "crypto/rand" + "encoding/binary" + "math/big" +) + +// RandUint64 return a random value between 0 and 0xFFFFFFFFFFFFFFFF. +func RandUint64() uint64 { + b := []byte{0, 0, 0, 0, 0, 0, 0, 0} + if _, err := rand.Read(b); err != nil { + panic(err) + } + return binary.LittleEndian.Uint64(b) +} + +// RandFloat64 returns a random float between min and max. +func RandFloat64(min, max float64) float64 { + b := []byte{0, 0, 0, 0, 0, 0, 0, 0} + if _, err := rand.Read(b); err != nil { + panic(err) + } + f := float64(binary.LittleEndian.Uint64(b)) / 1.8446744073709552e+19 + return min + f*(max-min) +} + +// RandComplex128 returns a random complex with the real and imaginary part between min and max. +func RandComplex128(min, max float64) complex128 { + return complex(RandFloat64(min, max), RandFloat64(min, max)) +} + +// RandInt generates a random Int in [0, max-1]. +func RandInt(max *big.Int) (n *big.Int) { + var err error + if n, err = rand.Int(rand.Reader, max); err != nil { + panic(err) + } + return +} diff --git a/utils/utils.go b/utils/utils.go index 2d658b6c..ca93d493 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,45 +1,9 @@ package utils import ( - "crypto/rand" - "encoding/binary" - "math/big" "math/bits" ) -// RandUint64 return a random value between 0 and 0xFFFFFFFFFFFFFFFF. -func RandUint64() uint64 { - b := []byte{0, 0, 0, 0, 0, 0, 0, 0} - if _, err := rand.Read(b); err != nil { - panic(err) - } - return binary.BigEndian.Uint64(b) -} - -// RandFloat64 returns a random float between min and max. -func RandFloat64(min, max float64) float64 { - b := []byte{0, 0, 0, 0, 0, 0, 0, 0} - if _, err := rand.Read(b); err != nil { - panic(err) - } - f := float64(binary.BigEndian.Uint64(b)) / 1.8446744073709552e+19 - return min + f*(max-min) -} - -// RandComplex128 returns a random complex with the real and imaginary part between min and max. -func RandComplex128(min, max float64) complex128 { - return complex(RandFloat64(min, max), RandFloat64(min, max)) -} - -// RandInt generates a random Int in [0, max-1]. -func RandInt(max *big.Int) (n *big.Int) { - var err error - if n, err = rand.Int(rand.Reader, max); err != nil { - panic(err) - } - return -} - // EqualSliceUint64 checks the equality between two uint64 slices. func EqualSliceUint64(a, b []uint64) (v bool) { v = true diff --git a/utils/utils_test.go b/utils/utils_test.go index ea5d8eba..53618cb9 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -1,7 +1,6 @@ package utils import ( - "math/big" "testing" "github.com/stretchr/testify/require" @@ -44,25 +43,3 @@ func TestRotateUint64(t *testing.T) { RotateUint64SliceAllocFree(s, -2, s) require.Equal(t, []uint64{7, 0, 1, 2, 3, 4, 5, 6}, s) } - -func TestGetFactors(t *testing.T) { - - m := new(big.Int).SetUint64(35184372088631) - - t.Run("ECM", func(t *testing.T) { - - factor := GetFactorECM(m) - - if factor.Cmp(new(big.Int).SetUint64(6292343)) != 0 && factor.Cmp(new(big.Int).SetUint64(5591617)) != 0 { - t.Fail() - } - }) - - t.Run("PollardRho", func(t *testing.T) { - factor := GetFactorPollardRho(m) - - if factor.Cmp(new(big.Int).SetUint64(6292343)) != 0 && factor.Cmp(new(big.Int).SetUint64(5591617)) != 0 { - t.Fail() - } - }) -}