mirror of
https://github.com/luxfi/lattice.git
synced 2026-09-24 00:25:44 +00:00
545 lines
17 KiB
Go
545 lines
17 KiB
Go
package bfv
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"math"
|
|
"runtime"
|
|
"testing"
|
|
|
|
"github.com/luxdefi/lattice/v5/core/rlwe"
|
|
"github.com/luxdefi/lattice/v5/ring"
|
|
"github.com/luxdefi/lattice/v5/utils"
|
|
"github.com/luxdefi/lattice/v5/utils/sampling"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var flagPrintNoise = flag.Bool("print-noise", false, "print the residual noise")
|
|
var flagParamString = flag.String("params", "", "specify the test cryptographic parameters as a JSON string. Overrides -short.")
|
|
|
|
func GetTestName(opname string, p Parameters, lvl int) string {
|
|
return fmt.Sprintf("%s/LogN=%d/logQ=%d/logP=%d/logT=%d/Qi=%d/Pi=%d/lvl=%d",
|
|
opname,
|
|
p.LogN(),
|
|
int(math.Round(p.LogQ())),
|
|
int(math.Round(p.LogP())),
|
|
int(math.Round(p.LogT())),
|
|
p.QCount(),
|
|
p.PCount(),
|
|
lvl)
|
|
}
|
|
|
|
func TestBFV(t *testing.T) {
|
|
|
|
var err error
|
|
|
|
paramsLiterals := testParams
|
|
|
|
if *flagParamString != "" {
|
|
var jsonParams ParametersLiteral
|
|
if err = json.Unmarshal([]byte(*flagParamString), &jsonParams); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
paramsLiterals = []ParametersLiteral{jsonParams} // the custom test suite reads the parameters from the -params flag
|
|
}
|
|
|
|
for _, p := range paramsLiterals[:] {
|
|
|
|
for _, plaintextModulus := range testPlaintextModulus[:] {
|
|
|
|
p.PlaintextModulus = plaintextModulus
|
|
|
|
params, err := NewParametersFromLiteral(p)
|
|
require.NoError(t, err)
|
|
|
|
tc, err := genTestParams(params)
|
|
require.NoError(t, err)
|
|
|
|
for _, testSet := range []func(tc *testContext, t *testing.T){
|
|
testParameters,
|
|
testEncoder,
|
|
testEvaluator,
|
|
} {
|
|
testSet(tc, t)
|
|
runtime.GC()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type testContext struct {
|
|
params Parameters
|
|
ringQ *ring.Ring
|
|
ringT *ring.Ring
|
|
prng sampling.PRNG
|
|
uSampler *ring.UniformSampler
|
|
encoder *Encoder
|
|
kgen *rlwe.KeyGenerator
|
|
sk *rlwe.SecretKey
|
|
pk *rlwe.PublicKey
|
|
encryptorPk *rlwe.Encryptor
|
|
encryptorSk *rlwe.Encryptor
|
|
decryptor *rlwe.Decryptor
|
|
evaluator *Evaluator
|
|
testLevel []int
|
|
}
|
|
|
|
func genTestParams(params Parameters) (tc *testContext, err error) {
|
|
|
|
tc = new(testContext)
|
|
tc.params = params
|
|
|
|
if tc.prng, err = sampling.NewPRNG(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tc.ringQ = params.RingQ()
|
|
tc.ringT = params.RingT()
|
|
|
|
tc.uSampler = ring.NewUniformSampler(tc.prng, tc.ringT)
|
|
tc.kgen = NewKeyGenerator(tc.params)
|
|
tc.sk, tc.pk = tc.kgen.GenKeyPairNew()
|
|
tc.encoder = NewEncoder(tc.params)
|
|
|
|
tc.encryptorPk = NewEncryptor(tc.params, tc.pk)
|
|
tc.encryptorSk = NewEncryptor(tc.params, tc.sk)
|
|
tc.decryptor = NewDecryptor(tc.params, tc.sk)
|
|
tc.evaluator = NewEvaluator(tc.params, rlwe.NewMemEvaluationKeySet(tc.kgen.GenRelinearizationKeyNew(tc.sk)))
|
|
|
|
tc.testLevel = []int{0, params.MaxLevel()}
|
|
|
|
return
|
|
}
|
|
|
|
func newTestVectorsLvl(level int, scale rlwe.Scale, tc *testContext, encryptor *rlwe.Encryptor) (coeffs ring.Poly, plaintext *rlwe.Plaintext, ciphertext *rlwe.Ciphertext) {
|
|
coeffs = tc.uSampler.ReadNew()
|
|
for i := range coeffs.Coeffs[0] {
|
|
coeffs.Coeffs[0][i] = uint64(i)
|
|
}
|
|
plaintext = NewPlaintext(tc.params, level)
|
|
plaintext.Scale = scale
|
|
tc.encoder.Encode(coeffs.Coeffs[0], plaintext)
|
|
if encryptor != nil {
|
|
var err error
|
|
ciphertext, err = encryptor.EncryptNew(plaintext)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
return coeffs, plaintext, ciphertext
|
|
}
|
|
|
|
func verifyTestVectors(tc *testContext, decryptor *rlwe.Decryptor, coeffs ring.Poly, element rlwe.ElementInterface[ring.Poly], t *testing.T) {
|
|
|
|
coeffsTest := make([]uint64, tc.params.MaxSlots())
|
|
|
|
switch el := element.(type) {
|
|
case *rlwe.Plaintext:
|
|
require.NoError(t, tc.encoder.Decode(el, coeffsTest))
|
|
case *rlwe.Ciphertext:
|
|
|
|
pt := decryptor.DecryptNew(el)
|
|
|
|
require.NoError(t, tc.encoder.Decode(pt, coeffsTest))
|
|
|
|
if *flagPrintNoise {
|
|
require.NoError(t, tc.encoder.Encode(coeffsTest, pt))
|
|
ct, err := tc.evaluator.SubNew(el, pt)
|
|
require.NoError(t, err)
|
|
vartmp, _, _ := rlwe.Norm(ct, decryptor)
|
|
t.Logf("STD(noise): %f\n", vartmp)
|
|
}
|
|
|
|
default:
|
|
t.Fatal("invalid test object to verify")
|
|
}
|
|
|
|
require.True(t, utils.EqualSlice(coeffs.Coeffs[0], coeffsTest))
|
|
}
|
|
|
|
func testParameters(tc *testContext, t *testing.T) {
|
|
t.Run(GetTestName("Parameters/Marshaller/Binary", tc.params, 0), func(t *testing.T) {
|
|
|
|
bytes, err := tc.params.MarshalBinary()
|
|
require.Nil(t, err)
|
|
var p Parameters
|
|
require.Nil(t, p.UnmarshalBinary(bytes))
|
|
require.True(t, tc.params.Equal(&p))
|
|
})
|
|
|
|
t.Run(GetTestName("Parameters/Marshaller/JSON", tc.params, 0), func(t *testing.T) {
|
|
// checks that parameters can be marshalled without error
|
|
data, err := json.Marshal(tc.params)
|
|
require.Nil(t, err)
|
|
require.NotNil(t, data)
|
|
|
|
// checks that the Parameters can be unmarshalled without error
|
|
var paramsRec Parameters
|
|
err = json.Unmarshal(data, ¶msRec)
|
|
require.Nil(t, err)
|
|
require.True(t, tc.params.Equal(¶msRec))
|
|
|
|
// checks that the Parameters can be unmarshalled with log-moduli definition without error
|
|
dataWithLogModuli := []byte(fmt.Sprintf(`{"LogN":%d,"LogQ":[50,50],"LogP":[60], "PlaintextModulus":65537}`, tc.params.LogN()))
|
|
var paramsWithLogModuli Parameters
|
|
err = json.Unmarshal(dataWithLogModuli, ¶msWithLogModuli)
|
|
require.Nil(t, err)
|
|
require.Equal(t, 2, paramsWithLogModuli.QCount())
|
|
require.Equal(t, 1, paramsWithLogModuli.PCount())
|
|
require.Equal(t, rlwe.DefaultXe, paramsWithLogModuli.Xe()) // Omitting Xe should result in Default being used
|
|
require.Equal(t, rlwe.DefaultXs, paramsWithLogModuli.Xs()) // Omitting Xe should result in Default being used
|
|
|
|
// checks that one can provide custom parameters for the secret-key and error distributions
|
|
dataWithCustomSecrets := []byte(fmt.Sprintf(`{"LogN":%d,"LogQ":[50,50],"LogP":[60], "PlaintextModulus":65537, "Xs": {"Type": "Ternary", "H": 192}, "Xe": {"Type": "DiscreteGaussian", "Sigma": 6.6, "Bound": 39.6}}`, tc.params.LogN()))
|
|
var paramsWithCustomSecrets Parameters
|
|
err = json.Unmarshal(dataWithCustomSecrets, ¶msWithCustomSecrets)
|
|
require.Nil(t, err)
|
|
require.Equal(t, ring.DiscreteGaussian{Sigma: 6.6, Bound: 39.6}, paramsWithCustomSecrets.Xe())
|
|
require.Equal(t, ring.Ternary{H: 192}, paramsWithCustomSecrets.Xs())
|
|
})
|
|
}
|
|
|
|
func testEncoder(tc *testContext, t *testing.T) {
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Encoder/Uint", tc.params, lvl), func(t *testing.T) {
|
|
values, plaintext, _ := newTestVectorsLvl(lvl, tc.params.DefaultScale(), tc, nil)
|
|
verifyTestVectors(tc, nil, values, plaintext, t)
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Encoder/Int", tc.params, lvl), func(t *testing.T) {
|
|
|
|
T := tc.params.PlaintextModulus()
|
|
THalf := T >> 1
|
|
coeffs := tc.uSampler.ReadNew()
|
|
coeffsInt := make([]int64, len(coeffs.Coeffs[0]))
|
|
for i, c := range coeffs.Coeffs[0] {
|
|
c %= T
|
|
if c >= THalf {
|
|
coeffsInt[i] = -int64(T - c)
|
|
} else {
|
|
coeffsInt[i] = int64(c)
|
|
}
|
|
}
|
|
|
|
plaintext := NewPlaintext(tc.params, lvl)
|
|
tc.encoder.Encode(coeffsInt, plaintext)
|
|
have := make([]int64, tc.params.MaxSlots())
|
|
tc.encoder.Decode(plaintext, have)
|
|
require.True(t, utils.EqualSlice(coeffsInt, have))
|
|
})
|
|
}
|
|
}
|
|
|
|
func testEvaluator(tc *testContext, t *testing.T) {
|
|
|
|
t.Run("Evaluator", func(t *testing.T) {
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Add/Ct/Ct/New", tc.params, lvl), func(t *testing.T) {
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
|
|
ciphertext2, err := tc.evaluator.AddNew(ciphertext0, ciphertext1)
|
|
require.NoError(t, err)
|
|
tc.ringT.Add(values0, values1, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext2, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Add/Ct/Ct/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.Add(ciphertext0, ciphertext1, ciphertext0))
|
|
tc.ringT.Add(values0, values1, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext0, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Add/Ct/Pt/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, plaintext, _ := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(plaintext.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.Add(ciphertext0, plaintext, ciphertext0))
|
|
tc.ringT.Add(values0, values1, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext0, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Add/Ct/Scalar/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
values, _, ciphertext := newTestVectorsLvl(lvl, tc.params.DefaultScale(), tc, tc.encryptorSk)
|
|
|
|
scalar := tc.params.PlaintextModulus() >> 1
|
|
|
|
require.NoError(t, tc.evaluator.Add(ciphertext, scalar, ciphertext))
|
|
tc.ringT.AddScalar(values, scalar, values)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values, ciphertext, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Sub/Ct/Ct/New", tc.params, lvl), func(t *testing.T) {
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
|
|
ciphertext0, err := tc.evaluator.SubNew(ciphertext0, ciphertext1)
|
|
require.NoError(t, err)
|
|
tc.ringT.Sub(values0, values1, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext0, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Sub/Ct/Ct/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.Sub(ciphertext0, ciphertext1, ciphertext0))
|
|
tc.ringT.Sub(values0, values1, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext0, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Sub/Ct/Pt/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, plaintext, _ := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(plaintext.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.Sub(ciphertext0, plaintext, ciphertext0))
|
|
tc.ringT.Sub(values0, values1, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext0, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Mul/Ct/Ct/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.Mul(ciphertext0, ciphertext1, ciphertext0))
|
|
tc.ringT.MulCoeffsBarrett(values0, values1, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext0, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Mul/Ct/Pt/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, plaintext, _ := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(plaintext.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.Mul(ciphertext0, plaintext, ciphertext0))
|
|
tc.ringT.MulCoeffsBarrett(values0, values1, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext0, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Mul/Ct/Scalar/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values, _, ciphertext := newTestVectorsLvl(lvl, tc.params.DefaultScale(), tc, tc.encryptorSk)
|
|
|
|
scalar := tc.params.PlaintextModulus() >> 1
|
|
|
|
tc.evaluator.Mul(ciphertext, scalar, ciphertext)
|
|
tc.ringT.MulScalar(values, scalar, values)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values, ciphertext, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("Square/Ct/Ct/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
|
|
require.NoError(t, tc.evaluator.Mul(ciphertext0, ciphertext0, ciphertext0))
|
|
tc.ringT.MulCoeffsBarrett(values0, values0, values0)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, ciphertext0, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("MulRelin/Ct/Ct/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
tc.ringT.MulCoeffsBarrett(values0, values1, values0)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
|
|
receiver := NewCiphertext(tc.params, 1, lvl)
|
|
|
|
require.NoError(t, tc.evaluator.MulRelin(ciphertext0, ciphertext1, receiver))
|
|
|
|
require.NoError(t, tc.evaluator.Rescale(receiver, receiver))
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values0, receiver, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("MulThenAdd/Ct/Ct/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.DefaultScale(), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, rlwe.NewScale(2), tc, tc.encryptorSk)
|
|
values2, _, ciphertext2 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext2.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.MulThenAdd(ciphertext0, ciphertext1, ciphertext2))
|
|
tc.ringT.MulCoeffsBarrettThenAdd(values0, values1, values2)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values2, ciphertext2, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("MulThenAdd/Ct/Pt/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.DefaultScale(), tc, tc.encryptorSk)
|
|
values1, plaintext1, _ := newTestVectorsLvl(lvl, rlwe.NewScale(2), tc, tc.encryptorSk)
|
|
values2, _, ciphertext2 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(plaintext1.Scale) != 0)
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext2.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.MulThenAdd(ciphertext0, plaintext1, ciphertext2))
|
|
tc.ringT.MulCoeffsBarrettThenAdd(values0, values1, values2)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values2, ciphertext2, t)
|
|
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("MulThenAdd/Ct/Scalar/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, tc.params.NewScale(3), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
|
|
scalar := tc.params.PlaintextModulus() >> 1
|
|
|
|
require.NoError(t, tc.evaluator.MulThenAdd(ciphertext0, scalar, ciphertext1))
|
|
tc.ringT.MulScalarThenAdd(values0, scalar, values1)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values1, ciphertext1, t)
|
|
})
|
|
}
|
|
|
|
for _, lvl := range tc.testLevel {
|
|
t.Run(GetTestName("MulRelinThenAdd/Ct/Ct/Inplace", tc.params, lvl), func(t *testing.T) {
|
|
|
|
if lvl == 0 {
|
|
t.Skip("Level = 0")
|
|
}
|
|
|
|
values0, _, ciphertext0 := newTestVectorsLvl(lvl, tc.params.DefaultScale(), tc, tc.encryptorSk)
|
|
values1, _, ciphertext1 := newTestVectorsLvl(lvl, rlwe.NewScale(2), tc, tc.encryptorSk)
|
|
values2, _, ciphertext2 := newTestVectorsLvl(lvl, tc.params.NewScale(7), tc, tc.encryptorSk)
|
|
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext1.Scale) != 0)
|
|
require.True(t, ciphertext0.Scale.Cmp(ciphertext2.Scale) != 0)
|
|
|
|
require.NoError(t, tc.evaluator.MulRelinThenAdd(ciphertext0, ciphertext1, ciphertext2))
|
|
tc.ringT.MulCoeffsBarrettThenAdd(values0, values1, values2)
|
|
|
|
verifyTestVectors(tc, tc.decryptor, values2, ciphertext2, t)
|
|
|
|
})
|
|
}
|
|
})
|
|
}
|