mirror of
https://github.com/tuneinsight/lattigo.git
synced 2025-09-13 03:27:14 +00:00
Merge branch 'main' into 510-bgv-wrong-result-from-innersum
This commit is contained in:
@@ -279,12 +279,13 @@ func (kgen KeyGenerator) genEvaluationKey(skIn ring.Poly, skOut ringqp.Poly, evk
|
||||
// For a compressed evaluation key, a seed is created and stored in the EvaluationKey struct
|
||||
// struct while an uncompressed key uses an ephemeral seed.
|
||||
if evk.IsCompressed() {
|
||||
evk.Seed = make([]byte, 32)
|
||||
if n, err := kgen.prng.Read(evk.Seed); n != 32 || err != nil {
|
||||
var seed [32]byte
|
||||
if n, err := kgen.prng.Read(seed[:]); n != 32 || err != nil {
|
||||
panic(fmt.Errorf("unable to sample evaluation key seed"))
|
||||
}
|
||||
evk.Seed = &seed
|
||||
|
||||
sampler, err := sampling.NewKeyedPRNG(evk.Seed)
|
||||
sampler, err := sampling.NewKeyedPRNG(seed[:])
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("sampling.NewKeyedPRNG: %w", err))
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ func (p *PublicKey) isEncryptionKey() {}
|
||||
// is used to bring it back to its original key.
|
||||
type EvaluationKey struct {
|
||||
GadgetCiphertext
|
||||
Seed []byte
|
||||
Seed *[32]byte // Must be != nil iff EvaluationKey.IsCompressed() = true
|
||||
}
|
||||
|
||||
type EvaluationKeyParameters struct {
|
||||
@@ -362,7 +362,11 @@ func (evk EvaluationKey) Expand(params ParameterProvider, buffer *GadgetCipherte
|
||||
return fmt.Errorf("evaluation key is not compressed")
|
||||
}
|
||||
|
||||
prng, err := sampling.NewKeyedPRNG(evk.Seed)
|
||||
if evk.Seed == nil {
|
||||
return fmt.Errorf("seed is missing")
|
||||
}
|
||||
|
||||
prng, err := sampling.NewKeyedPRNG((*evk.Seed)[:])
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("sampling.NewKeyedPRNG: %s", err))
|
||||
}
|
||||
@@ -417,6 +421,115 @@ func (evk EvaluationKey) Expand(params ParameterProvider, buffer *GadgetCipherte
|
||||
return nil
|
||||
}
|
||||
|
||||
// BinarySize returns the serialized size of the object in bytes.
|
||||
func (evk EvaluationKey) BinarySize() (size int) {
|
||||
if evk.Seed != nil {
|
||||
return evk.GadgetCiphertext.BinarySize() + len(*evk.Seed)
|
||||
}
|
||||
return evk.GadgetCiphertext.BinarySize()
|
||||
}
|
||||
|
||||
// WriteTo writes the object on an [io.Writer]. It implements the [io.WriterTo]
|
||||
// interface, and will write exactly object.BinarySize() bytes on w.
|
||||
//
|
||||
// Unless w implements the [buffer.Writer] interface (see lattigo/utils/buffer/writer.go),
|
||||
// it will be wrapped into a [bufio.Writer]. Since this requires allocations, it
|
||||
// is preferable to pass a [buffer.Writer] directly:
|
||||
//
|
||||
// - When writing multiple times to a [io.Writer], it is preferable to first wrap the
|
||||
// io.Writer in a pre-allocated [bufio.Writer].
|
||||
// - When writing to a pre-allocated var b []byte, it is preferable to pass
|
||||
// buffer.NewBuffer(b) as w (see lattigo/utils/buffer/buffer.go).
|
||||
func (evk EvaluationKey) WriteTo(w io.Writer) (n int64, err error) {
|
||||
switch w := w.(type) {
|
||||
case buffer.Writer:
|
||||
|
||||
var inc int64
|
||||
|
||||
if inc, err = evk.GadgetCiphertext.WriteTo(w); err != nil {
|
||||
return n + inc, err
|
||||
}
|
||||
|
||||
n += inc
|
||||
|
||||
if evk.IsCompressed() {
|
||||
|
||||
// Sanity check, should not happen unless evk has been manually modified
|
||||
if evk.Seed == nil {
|
||||
return n + inc, fmt.Errorf("writing compressed evaluation key: the seed is nil")
|
||||
}
|
||||
|
||||
if inc, err = buffer.Write(w, (*evk.Seed)[:]); err != nil {
|
||||
return n + inc, err
|
||||
}
|
||||
|
||||
n += inc
|
||||
}
|
||||
|
||||
if err = w.Flush(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
return
|
||||
|
||||
default:
|
||||
return evk.WriteTo(bufio.NewWriter(w))
|
||||
}
|
||||
}
|
||||
|
||||
// ReadFrom reads on the object from an [io.Writer]. It implements the
|
||||
// [io.ReaderFrom] interface.
|
||||
//
|
||||
// Unless r implements the [buffer.Reader] interface (see see lattigo/utils/buffer/reader.go),
|
||||
// it will be wrapped into a [bufio.Reader]. Since this requires allocation, it
|
||||
// is preferable to pass a [buffer.Reader] directly:
|
||||
//
|
||||
// - When reading multiple values from a [io.Reader], it is preferable to first
|
||||
// first wrap io.Reader in a pre-allocated [bufio.Reader].
|
||||
// - When reading from a var b []byte, it is preferable to pass a buffer.NewBuffer(b)
|
||||
// as w (see lattigo/utils/buffer/buffer.go).
|
||||
func (evk *EvaluationKey) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
switch r := r.(type) {
|
||||
case buffer.Reader:
|
||||
|
||||
var inc int64
|
||||
|
||||
if inc, err = evk.GadgetCiphertext.ReadFrom(r); err != nil {
|
||||
return n + inc, err
|
||||
}
|
||||
|
||||
n += inc
|
||||
|
||||
if evk.IsCompressed() {
|
||||
var seed [32]byte
|
||||
if inc, err = buffer.Read(r, seed[:]); err != nil {
|
||||
return n + inc, err
|
||||
}
|
||||
|
||||
evk.Seed = &seed
|
||||
|
||||
n += inc
|
||||
}
|
||||
|
||||
return
|
||||
default:
|
||||
return evk.ReadFrom(bufio.NewReader(r))
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes.
|
||||
func (evk EvaluationKey) MarshalBinary() (p []byte, err error) {
|
||||
buf := buffer.NewBufferSize(evk.BinarySize())
|
||||
_, err = evk.WriteTo(buf)
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
// UnmarshalBinary decodes a slice of bytes generated by
|
||||
// [EvaluationKey.MarshalBinary] or [EvaluationKey.WriteTo] on the object.
|
||||
func (evk *EvaluationKey) UnmarshalBinary(p []byte) (err error) {
|
||||
_, err = evk.ReadFrom(buffer.NewBuffer(p))
|
||||
return
|
||||
}
|
||||
|
||||
// CopyNew creates a deep copy of the target [EvaluationKey] and returns it.
|
||||
func (evk EvaluationKey) CopyNew() *EvaluationKey {
|
||||
return &EvaluationKey{GadgetCiphertext: *evk.GadgetCiphertext.CopyNew()}
|
||||
|
||||
@@ -41,7 +41,7 @@ func testString(params Parameters, levelQ, levelP, bpw2 int, opname string) stri
|
||||
func TestRLWEConstSerialization(t *testing.T) {
|
||||
// Note: changing nbIteration will change the expected value
|
||||
const nbIteration = 10
|
||||
const expected = "XRdlwx5vEX9qdGY3CeeAxzGHa0gbXghzpLhV0eIgVk8="
|
||||
const expected = "/mTt2kB+03NdOMoI1msW+glCZmrF1sxEGQkFsC6P1SA="
|
||||
var err error
|
||||
defaultParamsLiteral := testInsecure
|
||||
seedKeyGen := []byte{'l', 'a', 't'}
|
||||
@@ -77,16 +77,20 @@ func TestRLWEConstSerialization(t *testing.T) {
|
||||
hash.Write(pkBytes)
|
||||
|
||||
// Add marshalled GaloisKey to the hash input
|
||||
galEl := params.GaloisElement(-1)
|
||||
galEl1 := params.GaloisElement(-1)
|
||||
galEl2 := params.GaloisElement(3)
|
||||
galKey := detTC.kgen.GenGaloisKeysNew([]uint64{galEl, galEl2}, sk)
|
||||
galKeyBytes, err := galKey[0].MarshalBinary()
|
||||
galKey1 := detTC.kgen.GenGaloisKeyNew(galEl1, sk)
|
||||
galKey2 := detTC.kgen.GenGaloisKeyNew(galEl2, sk, EvaluationKeyParameters{Compressed: true})
|
||||
galKeyBytes, err := galKey1.MarshalBinary()
|
||||
require.Nil(t, err)
|
||||
hash.Write(galKeyBytes)
|
||||
galKeyBytes, err = galKey2.MarshalBinary()
|
||||
require.Nil(t, err)
|
||||
hash.Write(galKeyBytes)
|
||||
|
||||
// Add marshalled MemEvaluationKeySet to the hash input
|
||||
relinKey := detTC.kgen.GenRelinearizationKeyNew(sk)
|
||||
evk := NewMemEvaluationKeySet(relinKey, galKey...)
|
||||
evk := NewMemEvaluationKeySet(relinKey, galKey1, galKey2)
|
||||
evkBytes, err := evk.MarshalBinary()
|
||||
require.Nil(t, err)
|
||||
hash.Write(evkBytes)
|
||||
@@ -1239,6 +1243,10 @@ func testWriteAndRead(tc *TestContext, bpw2 int, t *testing.T) {
|
||||
buffer.RequireSerializerCorrect(t, tc.kgen.GenEvaluationKeyNew(sk, sk))
|
||||
})
|
||||
|
||||
t.Run(testString(params, levelQ, levelP, bpw2, "WriteAndRead/EvaluationKey/Compressed=True"), func(t *testing.T) {
|
||||
buffer.RequireSerializerCorrect(t, tc.kgen.GenEvaluationKeyNew(sk, sk, EvaluationKeyParameters{Compressed: true}))
|
||||
})
|
||||
|
||||
t.Run(testString(params, levelQ, levelP, bpw2, "WriteAndRead/RelinearizationKey"), func(t *testing.T) {
|
||||
buffer.RequireSerializerCorrect(t, tc.kgen.GenRelinearizationKeyNew(tc.sk))
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user