diff --git a/core/rlwe/encryptor.go b/core/rlwe/encryptor.go index fa59990b..8421189d 100644 --- a/core/rlwe/encryptor.go +++ b/core/rlwe/encryptor.go @@ -99,6 +99,29 @@ func newEncryptor(params Parameters) *Encryptor { } } +// NewTestEncryptorWithPRNG creates a new [Encryptor] that uses the provided prng for randomness. +// CAUTION: THIS FUNCTION SHOULD BE USED FOR TESTING PURPOSES ONLY. +func NewTestEncryptorWithPRNG(params ParameterProvider, key EncryptionKey, prng sampling.PRNG) *Encryptor { + p := *params.GetRLWEParameters() + + enc := NewEncryptor(params, key) + xeSampler, err := ring.NewSampler(prng, p.RingQ(), p.Xe(), false) + if err != nil { + panic(fmt.Errorf("NewEncryptorWithPRNG: cannot create xeSampler %w", err)) + } + xsSampler, err := ring.NewSampler(prng, p.RingQ(), p.Xs(), false) + if err != nil { + panic(fmt.Errorf("NewEncryptorWithPRNG: cannot create xsSampler %w", err)) + } + uniformSampler := ringqp.NewUniformSampler(prng, *p.RingQP()) + enc.prng = prng + enc.xeSampler = xeSampler + enc.xsSampler = xsSampler + enc.uniformSampler = uniformSampler + + return enc +} + type encryptorBuffers struct { buffQP [3]ringqp.Poly } diff --git a/core/rlwe/rlwe_test.go b/core/rlwe/rlwe_test.go index 43546a6a..9b4794af 100644 --- a/core/rlwe/rlwe_test.go +++ b/core/rlwe/rlwe_test.go @@ -1,6 +1,7 @@ package rlwe import ( + "encoding/base64" "encoding/json" "flag" "fmt" @@ -8,6 +9,8 @@ import ( "runtime" "testing" + "golang.org/x/crypto/blake2b" + "github.com/stretchr/testify/require" "github.com/tuneinsight/lattigo/v6/ring" @@ -31,6 +34,86 @@ func testString(params Parameters, levelQ, levelP, bpw2 int, opname string) stri params.RingType()) } +// TestRLWEConstSerialization test detects (fails) if the serialization of +// [PublicKey], [SecretKey], [Ciphertext], [GaloisKey], [MemEvaluationKeySet] has changed. +// If such a modification is intended, this test must be updated and users notified s.t. +// old serialized objects can be converted to the new format. +func TestRLWEConstSerialization(t *testing.T) { + // Note: changing nbIteration will change the expected value + const nbIteration = 10 + const expected = "XRdlwx5vEX9qdGY3CeeAxzGHa0gbXghzpLhV0eIgVk8=" + var err error + defaultParamsLiteral := testInsecure + seedKeyGen := []byte{'l', 'a', 't'} + seedEnc := []byte{'t', 'i', 'g', 'o'} + hash, err := blake2b.New(32, nil) + require.Nil(t, err) + + for _, paramsLit := range defaultParamsLiteral[:] { + + for _, NTTFlag := range []bool{true, false}[:] { + + for _, RingType := range []ring.Type{ring.Standard, ring.ConjugateInvariant}[:] { + + paramsLit.NTTFlag = NTTFlag + paramsLit.RingType = RingType + + var params Parameters + if params, err = NewParametersFromLiteral(paramsLit.ParametersLiteral); err != nil { + t.Fatal(err) + } + + detTC, err := NewDeterministicTestContext(params, seedKeyGen, seedEnc) + require.Nil(t, err) + for i := 0; i < nbIteration; i++ { + // Add marshalled (sk, pk) to the hash input + sk, pk := detTC.kgen.GenKeyPairNew() + skBytes, err := sk.MarshalBinary() + hash.Write(skBytes) + require.Nil(t, err) + + pkBytes, err := pk.MarshalBinary() + require.Nil(t, err) + hash.Write(pkBytes) + + // Add marshalled GaloisKey to the hash input + galEl := params.GaloisElement(-1) + galEl2 := params.GaloisElement(3) + galKey := detTC.kgen.GenGaloisKeysNew([]uint64{galEl, galEl2}, sk) + galKeyBytes, err := galKey[0].MarshalBinary() + require.Nil(t, err) + hash.Write(galKeyBytes) + + // Add marshalled MemEvaluationKeySet to the hash input + relinKey := detTC.kgen.GenRelinearizationKeyNew(sk) + evk := NewMemEvaluationKeySet(relinKey, galKey...) + evkBytes, err := evk.MarshalBinary() + require.Nil(t, err) + hash.Write(evkBytes) + + // Add marshalled MemEvaluationKeySet to the hash input + ct := NewCiphertext(params, 1, params.MaxLevel()) + pt := genPlaintext(params, params.MaxLevel(), (1<