[utils]: added subpacakges and updated Write/Read API

This commit is contained in:
Jean-Philippe Bossuat
2023-03-21 10:43:54 +01:00
parent ae9a5a3bcb
commit cb20936495
37 changed files with 451 additions and 310 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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<<defaultParams.logN, defaultParams.pi); err != nil {
return nil, err
}
if tc.prng, err = utils.NewPRNG(); err != nil {
if tc.prng, err = sampling.NewPRNG(); err != nil {
return nil, err
}
tc.uniformSamplerQ = NewUniformSampler(tc.prng, tc.ringQ)
@@ -176,14 +176,14 @@ func testPRNG(tc *testParams, t *testing.T) {
var err error
var prng1, prng2 utils.PRNG
var prng1, prng2 sampling.PRNG
if prng1, err = utils.NewKeyedPRNG(nil); err != nil {
t.Error(err)
if prng1, err = sampling.NewKeyedPRNG(nil); err != nil {
t.Fatal(err)
}
if prng2, err = utils.NewKeyedPRNG(nil); err != nil {
t.Error(err)
if prng2, err = sampling.NewKeyedPRNG(nil); err != nil {
t.Fatal(err)
}
crsGenerator1 := NewUniformSampler(prng1, tc.ringQ)
@@ -307,12 +307,12 @@ func testMarshalBinary(tc *testParams, t *testing.T) {
var data []byte
if data, err = tc.ringQ.MarshalBinary(); err != nil {
t.Error(err)
t.Fatal(err)
}
ringQTest := new(Ring)
if err = ringQTest.UnmarshalBinary(data); err != nil {
t.Error(err)
t.Fatal(err)
}
require.Equal(t, ringQTest, tc.ringQ)
@@ -326,12 +326,12 @@ func testMarshalBinary(tc *testParams, t *testing.T) {
var data []byte
if data, err = p.MarshalBinary(); err != nil {
t.Error(err)
t.Fatal(err)
}
pTest := new(Poly)
if err = pTest.UnmarshalBinary(data); err != nil {
t.Error(err)
t.Fatal(err)
}
for i := range tc.ringQ.SubRings {
@@ -392,7 +392,7 @@ func testTernarySampler(tc *testParams, t *testing.T) {
for _, p := range []float64{.5, 1. / 3., 128. / 65536.} {
t.Run(testString(fmt.Sprintf("TernarySampler/p=%1.2f", p), tc.ringQ), func(t *testing.T) {
prng, err := utils.NewPRNG()
prng, err := sampling.NewPRNG()
if err != nil {
panic(err)
}
@@ -411,7 +411,7 @@ func testTernarySampler(tc *testParams, t *testing.T) {
for _, p := range []int{0, 64, 96, 128, 256} {
t.Run(testString(fmt.Sprintf("TernarySampler/hw=%d", p), tc.ringQ), func(t *testing.T) {
prng, err := utils.NewPRNG()
prng, err := sampling.NewPRNG()
if err != nil {
panic(err)
}

View File

@@ -1,13 +1,13 @@
package ring
import (
"github.com/tuneinsight/lattigo/v4/utils"
"github.com/tuneinsight/lattigo/v4/utils/sampling"
)
const precision = uint64(56)
type baseSampler struct {
prng utils.PRNG
prng sampling.PRNG
baseRing *Ring
}

View File

@@ -4,7 +4,7 @@ import (
"encoding/binary"
"math"
"github.com/tuneinsight/lattigo/v4/utils"
"github.com/tuneinsight/lattigo/v4/utils/sampling"
)
// GaussianSampler keeps the state of a truncated Gaussian polynomial sampler.
@@ -19,7 +19,7 @@ type GaussianSampler struct {
// NewGaussianSampler creates a new instance of GaussianSampler from a PRNG, a ring definition and the truncated
// Gaussian distribution parameters. Sigma is the desired standard deviation and bound is the maximum coefficient norm in absolute
// value.
func NewGaussianSampler(prng utils.PRNG, baseRing *Ring, sigma float64, bound int) (g *GaussianSampler) {
func NewGaussianSampler(prng sampling.PRNG, baseRing *Ring, sigma float64, bound int) (g *GaussianSampler) {
g = new(GaussianSampler)
g.prng = prng
g.randomBufferN = make([]byte, 1024)
@@ -122,7 +122,7 @@ func (g *GaussianSampler) read(pol *Poly, r *Ring, sigma float64, bound int) {
// randFloat64 returns a uniform float64 value between 0 and 1.
func randFloat64(randomBytes []byte) float64 {
return float64(binary.BigEndian.Uint64(randomBytes)&0x1fffffffffffff) / float64(0x1fffffffffffff)
return float64(binary.LittleEndian.Uint64(randomBytes)&0x1fffffffffffff) / float64(0x1fffffffffffff)
}
// NormFloat64 returns a normally distributed float64 in
@@ -144,7 +144,7 @@ func (g *GaussianSampler) normFloat64() (float64, uint64) {
g.ptr = 0
}
juint32 := binary.BigEndian.Uint32(g.randomBufferN[g.ptr : g.ptr+4])
juint32 := binary.LittleEndian.Uint32(g.randomBufferN[g.ptr : g.ptr+4])
g.ptr += 8
j := int32(juint32 & 0x7fffffff)

View File

@@ -4,7 +4,7 @@ import (
"math"
"math/bits"
"github.com/tuneinsight/lattigo/v4/utils"
"github.com/tuneinsight/lattigo/v4/utils/sampling"
)
// TernarySampler keeps the state of a polynomial sampler in the ternary distribution.
@@ -20,7 +20,7 @@ type TernarySampler struct {
// NewTernarySampler creates a new instance of TernarySampler from a PRNG, the ring definition and the distribution
// parameters: p is the probability of a coefficient being 0, (1-p)/2 is the probability of 1 and -1. If "montgomery"
// is set to true, polynomials read from this sampler are in Montgomery form.
func NewTernarySampler(prng utils.PRNG, baseRing *Ring, p float64, montgomery bool) *TernarySampler {
func NewTernarySampler(prng sampling.PRNG, baseRing *Ring, p float64, montgomery bool) *TernarySampler {
ternarySampler := new(TernarySampler)
ternarySampler.baseRing = baseRing
ternarySampler.prng = prng
@@ -52,7 +52,7 @@ func (ts *TernarySampler) AtLevel(level int) Sampler {
// NewTernarySamplerWithHammingWeight creates a new instance of a fixed-hamming-weight TernarySampler from a PRNG, the ring definition and the desired
// hamming weight for the output polynomials. If "montgomery" is set to true, polynomials read from this sampler
// are in Montgomery form.
func NewTernarySamplerWithHammingWeight(prng utils.PRNG, baseRing *Ring, hw int, montgomery bool) *TernarySampler {
func NewTernarySamplerWithHammingWeight(prng sampling.PRNG, baseRing *Ring, hw int, montgomery bool) *TernarySampler {
ternarySampler := new(TernarySampler)
ternarySampler.baseRing = baseRing
ternarySampler.prng = prng
@@ -238,7 +238,7 @@ func (ts *TernarySampler) sampleSparse(pol *Poly) {
}
// kysampling uses the binary expansion and random bytes matrix to sample a discrete Gaussian value and its sign.
func (ts *TernarySampler) kysampling(prng utils.PRNG, randomBytes []byte, pointer uint8, bytePointer, byteLength int) (uint64, uint64, []byte, uint8, int) {
func (ts *TernarySampler) kysampling(prng sampling.PRNG, randomBytes []byte, pointer uint8, bytePointer, byteLength int) (uint64, uint64, []byte, uint8, int) {
var sign uint8

View File

@@ -7,6 +7,7 @@ import (
"math/bits"
"github.com/tuneinsight/lattigo/v4/utils"
"github.com/tuneinsight/lattigo/v4/utils/factorization"
)
// SubRing is a struct storing precomputation
@@ -162,7 +163,7 @@ func PrimitiveRoot(q uint64, factors []uint64) (uint64, []uint64, error) {
}
} else {
factorsBig := utils.GetFactors(new(big.Int).SetUint64(q - 1)) //Factor q-1, might be slow
factorsBig := factorization.GetFactors(new(big.Int).SetUint64(q - 1)) //Factor q-1, might be slow
factors = make([]uint64, len(factorsBig))
for i := range factors {

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"github.com/tuneinsight/lattigo/v4/ring"
"github.com/tuneinsight/lattigo/v4/utils"
"github.com/tuneinsight/lattigo/v4/utils/sampling"
)
// Ciphertext is a generic type for RLWE ciphertexts.
@@ -40,7 +40,7 @@ func NewCiphertextAtLevelFromPoly(level int, poly []*ring.Poly) (ct *Ciphertext)
}
// NewCiphertextRandom generates a new uniformly distributed Ciphertext of degree, level.
func NewCiphertextRandom(prng utils.PRNG, params Parameters, degree, level int) (ciphertext *Ciphertext) {
func NewCiphertextRandom(prng sampling.PRNG, params Parameters, degree, level int) (ciphertext *Ciphertext) {
ciphertext = NewCiphertext(params, degree, level)
PopulateElementRandom(prng, params, ciphertext)
return
@@ -201,7 +201,7 @@ func GetSmallestLargest(el0, el1 *Ciphertext) (smallest, largest *Ciphertext, sa
}
// PopulateElementRandom creates a new rlwe.Element with random coefficients.
func PopulateElementRandom(prng utils.PRNG, params Parameters, ct *Ciphertext) {
func PopulateElementRandom(prng sampling.PRNG, params Parameters, ct *Ciphertext) {
sampler := ring.NewUniformSampler(prng, params.RingQ()).AtLevel(ct.Level())
for i := range ct.Value {
sampler.Read(ct.Value[i])
@@ -215,7 +215,7 @@ func (ct *Ciphertext) MarshalBinarySize() (dataLen int) {
dataLen++
for _, ct := range ct.Value {
dataLen += ct.MarshalBinarySize64()
dataLen += ct.MarshalBinarySize()
}
dataLen += ct.MetaData.MarshalBinarySize()
@@ -226,29 +226,29 @@ func (ct *Ciphertext) MarshalBinarySize() (dataLen int) {
// MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes.
func (ct *Ciphertext) 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 *Ciphertext) MarshalBinaryInPlace(p []byte) (n int, err error) {
func (ct *Ciphertext) Read(p []byte) (n int, err error) {
if len(p) < ct.MarshalBinarySize() {
return 0, fmt.Errorf("cannot write: len(p) is too small")
}
if n, err = ct.MetaData.MarshalBinaryInPlace(p); err != nil {
if n, err = ct.MetaData.Read(p); err != nil {
return
}
p[n] = uint8(ct.Degree() + 1)
p[n] = uint8(ct.Degree())
n++
var inc int
for _, pol := range ct.Value {
if inc, err = pol.Encode64(p[n:]); err != nil {
if inc, err = pol.Read(p[n:]); err != nil {
return
}
@@ -261,27 +261,27 @@ func (ct *Ciphertext) MarshalBinaryInPlace(p []byte) (n int, err error) {
// UnmarshalBinary decodes a slice of bytes generated by MarshalBinary
// or MarshalBinaryInPlace on the object.
func (ct *Ciphertext) UnmarshalBinary(data []byte) (err error) {
_, err = ct.UnmarshalBinaryInPlace(data)
_, err = ct.Write(data)
return
}
// UnmarshalBinaryInPlace decodes a slice of bytes generated by Read on the object and returns
// Write decodes a slice of bytes generated by Read on the object and returns
// the number of bytes decoded (0<=len(p)<=n), as well as any error encountered
// that caused the write to stop early. Unlike io.Writer, the method will not
// return an error if n < len(p) as it is intended to be used this way.
func (ct *Ciphertext) UnmarshalBinaryInPlace(p []byte) (n int, err error) {
func (ct *Ciphertext) Write(p []byte) (n int, err error) {
if n, err = ct.MetaData.UnmarshalBinaryInPlace(p); err != nil {
if n, err = ct.MetaData.Write(p); err != nil {
return
}
if degree := int(p[n]); ct.Value == nil {
ct.Value = make([]*ring.Poly, degree)
ct.Value = make([]*ring.Poly, degree+1)
} else {
if len(ct.Value) > 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
}

View File

@@ -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
}

View File

@@ -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}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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())

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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 {

View File

@@ -1,4 +1,4 @@
package utils
package buffer
import (
"encoding/binary"

View File

@@ -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
}

View File

@@ -1,4 +1,4 @@
package utils
package factorization
import (
"math"

View File

@@ -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()
}
})
}

View File

@@ -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)

View File

@@ -1,4 +1,4 @@
package utils
package sampling
import (
"crypto/rand"

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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()
}
})
}