diff --git a/circuits/encoding.go b/circuits/encoder_base.go similarity index 90% rename from circuits/encoding.go rename to circuits/encoder_base.go index 52d06cbb..0e7545ee 100644 --- a/circuits/encoding.go +++ b/circuits/encoder_base.go @@ -1,7 +1,6 @@ package circuits import ( - //"github.com/tuneinsight/lattigo/v4/bgv" "github.com/tuneinsight/lattigo/v4/ring" "github.com/tuneinsight/lattigo/v4/rlwe" "github.com/tuneinsight/lattigo/v4/rlwe/ringqp" diff --git a/circuits/float/float_test.go b/circuits/float/float_test.go index d18185e4..e2a36c43 100644 --- a/circuits/float/float_test.go +++ b/circuits/float/float_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/tuneinsight/lattigo/v4/circuits" "github.com/tuneinsight/lattigo/v4/ckks" "github.com/tuneinsight/lattigo/v4/ring" "github.com/tuneinsight/lattigo/v4/rlwe" @@ -48,7 +47,7 @@ type ckksTestContext struct { evaluator *ckks.Evaluator } -func TestCKKS(t *testing.T) { +func TestFloat(t *testing.T) { var err error @@ -408,7 +407,7 @@ func testEvaluatePolynomial(tc *ckksTestContext, t *testing.T) { valuesWant[j] = poly.Evaluate(values[j]) } - polyVector, err := circuits.NewPolynomialVector([]circuits.Polynomial{circuits.NewPolynomial(poly)}, slotIndex) + polyVector, err := NewPolynomialVector([]bignum.Polynomial{poly}, slotIndex) require.NoError(t, err) if ciphertext, err = polyEval.Polynomial(ciphertext, polyVector, ciphertext.Scale); err != nil { diff --git a/circuits/float/polynomial.go b/circuits/float/polynomial.go new file mode 100644 index 00000000..af68944a --- /dev/null +++ b/circuits/float/polynomial.go @@ -0,0 +1,19 @@ +package float + +import ( + "github.com/tuneinsight/lattigo/v4/circuits" + "github.com/tuneinsight/lattigo/v4/utils/bignum" +) + +type Polynomial circuits.Polynomial + +func NewPolynomial(poly bignum.Polynomial) Polynomial { + return Polynomial(circuits.NewPolynomial(poly)) +} + +type PolynomialVector circuits.PolynomialVector + +func NewPolynomialVector(polys []bignum.Polynomial, mapping map[int][]int) (PolynomialVector, error) { + p, err := circuits.NewPolynomialVector(polys, mapping) + return PolynomialVector(p), err +} diff --git a/circuits/float/polynomial_evaluation.go b/circuits/float/polynomial_evaluation.go index 6451137b..361c18cc 100644 --- a/circuits/float/polynomial_evaluation.go +++ b/circuits/float/polynomial_evaluation.go @@ -15,11 +15,11 @@ type PolynomialEvaluator struct { Parameters ckks.Parameters } -// NewFloatPowerBasis is a wrapper of NewPolynomialBasis. +// NewPowerBasis is a wrapper of NewPolynomialBasis. // This function creates a new powerBasis from the input ciphertext. // The input ciphertext is treated as the base monomial X used to // generate the other powers X^{n}. -func NewFloatPowerBasis(ct *rlwe.Ciphertext, basis bignum.Basis) circuits.PowerBasis { +func NewPowerBasis(ct *rlwe.Ciphertext, basis bignum.Basis) circuits.PowerBasis { return circuits.NewPowerBasis(ct, basis) } @@ -40,8 +40,20 @@ func NewPolynomialEvaluator(params ckks.Parameters, eval circuits.EvaluatorForPo // targetScale: the desired output scale. This value shouldn't differ too much from the original ciphertext scale. It can // for example be used to correct small deviations in the ciphertext scale and reset it to the default scale. func (eval PolynomialEvaluator) Polynomial(input interface{}, p interface{}, targetScale rlwe.Scale) (opOut *rlwe.Ciphertext, err error) { + + var pcircuits interface{} + switch p := p.(type) { + case Polynomial: + pcircuits = circuits.Polynomial(p) + case PolynomialVector: + pcircuits = circuits.PolynomialVector(p) + default: + pcircuits = p + } + levelsConsummedPerRescaling := eval.Parameters.LevelsConsummedPerRescaling() - return circuits.EvaluatePolynomial(eval.PolynomialEvaluator, eval, input, p, targetScale, levelsConsummedPerRescaling, &simEvaluator{eval.Parameters, levelsConsummedPerRescaling}) + + return circuits.EvaluatePolynomial(eval.PolynomialEvaluator, eval, input, pcircuits, targetScale, levelsConsummedPerRescaling, &simEvaluator{eval.Parameters, levelsConsummedPerRescaling}) } func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLevel int, pol circuits.PolynomialVector, pb circuits.PowerBasis, targetScale rlwe.Scale) (res *rlwe.Ciphertext, err error) { @@ -54,7 +66,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev slots := 1 << logSlots.Cols params := eval.Parameters - slotsIndex := pol.SlotsIndex + mapping := pol.Mapping even := pol.IsEven() odd := pol.IsOdd() @@ -75,7 +87,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev } // If an index slot is given (either multiply polynomials or masking) - if slotsIndex != nil { + if mapping != nil { var toEncode bool @@ -95,7 +107,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev for i, p := range pol.Value { if !isZero(p.Coeffs[0]) { toEncode = true - for _, j := range slotsIndex[i] { + for _, j := range mapping[i] { values[j] = p.Coeffs[0] } } @@ -125,7 +137,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev for i, p := range pol.Value { if !isZero(p.Coeffs[0]) { toEncode = true - for _, j := range slotsIndex[i] { + for _, j := range mapping[i] { values[j] = p.Coeffs[0] } } @@ -171,7 +183,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev // Copies the coefficient on the temporary array // according to the slot map index - for _, j := range slotsIndex[i] { + for _, j := range mapping[i] { values[j] = p.Coeffs[key] } } diff --git a/circuits/integer/circuits_bfv_test.go b/circuits/integer/circuits_bfv_test.go index 7c9a3b34..e6805058 100644 --- a/circuits/integer/circuits_bfv_test.go +++ b/circuits/integer/circuits_bfv_test.go @@ -12,7 +12,6 @@ import ( "github.com/stretchr/testify/require" "github.com/tuneinsight/lattigo/v4/bfv" "github.com/tuneinsight/lattigo/v4/bgv" - "github.com/tuneinsight/lattigo/v4/circuits" "github.com/tuneinsight/lattigo/v4/ring" "github.com/tuneinsight/lattigo/v4/rlwe" "github.com/tuneinsight/lattigo/v4/utils" @@ -280,9 +279,9 @@ func testLinearTransformation(tc *testContext, t *testing.T) { slotIndex[0] = idx0 slotIndex[1] = idx1 - polyVector, err := circuits.NewPolynomialVector([]circuits.Polynomial{ - NewIntegerPolynomial(coeffs0), - NewIntegerPolynomial(coeffs1), + polyVector, err := NewPolynomialVector([][]uint64{ + coeffs0, + coeffs1, }, slotIndex) require.NoError(t, err) diff --git a/circuits/integer/integer_test.go b/circuits/integer/integer_test.go index 6a14488a..44897f39 100644 --- a/circuits/integer/integer_test.go +++ b/circuits/integer/integer_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/tuneinsight/lattigo/v4/bgv" - "github.com/tuneinsight/lattigo/v4/circuits" "github.com/tuneinsight/lattigo/v4/ring" "github.com/tuneinsight/lattigo/v4/rlwe" "github.com/tuneinsight/lattigo/v4/utils" @@ -365,7 +364,7 @@ func testBGVLinearTransformation(tc *bgvTestContext, t *testing.T) { slots := values.N() - slotIndex := make(map[int][]int) + mapping := make(map[int][]int) idx0 := make([]int, slots>>1) idx1 := make([]int, slots>>1) for i := 0; i < slots>>1; i++ { @@ -373,17 +372,17 @@ func testBGVLinearTransformation(tc *bgvTestContext, t *testing.T) { idx1[i] = 2*i + 1 } - slotIndex[0] = idx0 - slotIndex[1] = idx1 + mapping[0] = idx0 + mapping[1] = idx1 - polyVector, err := circuits.NewPolynomialVector([]circuits.Polynomial{ - NewIntegerPolynomial(coeffs0), - NewIntegerPolynomial(coeffs1), - }, slotIndex) + polyVector, err := NewPolynomialVector([][]uint64{ + coeffs0, + coeffs1, + }, mapping) require.NoError(t, err) TInt := new(big.Int).SetUint64(tc.params.PlaintextModulus()) - for pol, idx := range slotIndex { + for pol, idx := range mapping { for _, i := range idx { values.Coeffs[0][i] = polyVector.Value[pol].EvaluateModP(new(big.Int).SetUint64(values.Coeffs[0][i]), TInt).Uint64() } diff --git a/circuits/integer/polynomial.go b/circuits/integer/polynomial.go new file mode 100644 index 00000000..0bbc9824 --- /dev/null +++ b/circuits/integer/polynomial.go @@ -0,0 +1,26 @@ +package integer + +import ( + "github.com/tuneinsight/lattigo/v4/circuits" + "github.com/tuneinsight/lattigo/v4/utils/bignum" +) + +type Polynomial circuits.Polynomial + +func NewPolynomial[T Integer](coeffs []T) Polynomial { + return Polynomial(circuits.NewPolynomial(bignum.NewPolynomial(bignum.Monomial, coeffs, nil))) +} + +type PolynomialVector circuits.PolynomialVector + +func NewPolynomialVector[T Integer](polys [][]T, mapping map[int][]int) (PolynomialVector, error) { + + ps := make([]bignum.Polynomial, len(polys)) + + for i := range ps { + ps[i] = bignum.NewPolynomial(bignum.Monomial, polys[i], nil) + } + + p, err := circuits.NewPolynomialVector(ps, mapping) + return PolynomialVector(p), err +} diff --git a/circuits/integer/polynomial_evaluation.go b/circuits/integer/polynomial_evaluation.go index d3e462cc..c3729e52 100644 --- a/circuits/integer/polynomial_evaluation.go +++ b/circuits/integer/polynomial_evaluation.go @@ -14,21 +14,14 @@ type PolynomialEvaluator struct { InvariantTensoring bool } -// NewIntegerPowerBasis is a wrapper of NewPolynomialBasis. +// NewPowerBasis is a wrapper of NewPolynomialBasis. // This function creates a new powerBasis from the input ciphertext. // The input ciphertext is treated as the base monomial X used to // generate the other powers X^{n}. -func NewIntegerPowerBasis(ct *rlwe.Ciphertext) circuits.PowerBasis { +func NewPowerBasis(ct *rlwe.Ciphertext) circuits.PowerBasis { return circuits.NewPowerBasis(ct, bignum.Monomial) } -// NewIntegerPolynomial is a wrapper of NewPolynomial. -// This function creates a new polynomial from the input coefficients. -// This polynomial can be evaluated on a ciphertext. -func NewIntegerPolynomial[T Integer](coeffs []T) circuits.Polynomial { - return circuits.NewPolynomial(bignum.NewPolynomial(bignum.Monomial, coeffs, nil)) -} - func NewPolynomialEvaluator(params bgv.Parameters, eval *bgv.Evaluator, InvariantTensoring bool) *PolynomialEvaluator { e := new(PolynomialEvaluator) @@ -44,7 +37,18 @@ func NewPolynomialEvaluator(params bgv.Parameters, eval *bgv.Evaluator, Invarian } func (eval PolynomialEvaluator) Polynomial(input interface{}, p interface{}, targetScale rlwe.Scale) (opOut *rlwe.Ciphertext, err error) { - return circuits.EvaluatePolynomial(eval.PolynomialEvaluator, eval, input, p, targetScale, 1, &simIntegerPolynomialEvaluator{eval.Parameters, eval.InvariantTensoring}) + + var pcircuits interface{} + switch p := p.(type) { + case Polynomial: + pcircuits = circuits.Polynomial(p) + case PolynomialVector: + pcircuits = circuits.PolynomialVector(p) + default: + pcircuits = p + } + + return circuits.EvaluatePolynomial(eval.PolynomialEvaluator, eval, input, pcircuits, targetScale, 1, &simIntegerPolynomialEvaluator{eval.Parameters, eval.InvariantTensoring}) } type scaleInvariantEvaluator struct { @@ -76,7 +80,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev X := pb.Value params := eval.Parameters - slotsIndex := pol.SlotsIndex + mapping := pol.Mapping slots := params.RingT().N() even := pol.IsEven() odd := pol.IsOdd() @@ -97,7 +101,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev } // If an index slot is given (either multiply polynomials or masking) - if slotsIndex != nil { + if mapping != nil { var toEncode bool @@ -115,7 +119,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev for i, p := range pol.Value { if c := p.Coeffs[0].Uint64(); c != 0 { toEncode = true - for _, j := range slotsIndex[i] { + for _, j := range mapping[i] { values[j] = c } } @@ -146,7 +150,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev for i, p := range pol.Value { if c := p.Coeffs[0].Uint64(); c != 0 { toEncode = true - for _, j := range slotsIndex[i] { + for _, j := range mapping[i] { values[j] = c } } @@ -188,7 +192,7 @@ func (eval PolynomialEvaluator) EvaluatePolynomialVectorFromPowerBasis(targetLev // Copies the coefficient on the temporary array // according to the slot map index - for _, j := range slotsIndex[i] { + for _, j := range mapping[i] { values[j] = c } } diff --git a/circuits/poly_eval.go b/circuits/poly_eval.go index b5519279..d4740784 100644 --- a/circuits/poly_eval.go +++ b/circuits/poly_eval.go @@ -104,8 +104,8 @@ func (eval PolynomialEvaluator) EvaluatePatersonStockmeyerPolynomialVector(pvEva for i := range tmp { polyVec := PolynomialVector{ - Value: make([]Polynomial, nbPoly), - SlotsIndex: poly.SlotsIndex, + Value: make([]Polynomial, nbPoly), + Mapping: poly.Mapping, } // Transposes the polynomial matrix diff --git a/circuits/polynomial.go b/circuits/polynomial.go index b74b1c3c..07b8e3cd 100644 --- a/circuits/polynomial.go +++ b/circuits/polynomial.go @@ -134,11 +134,11 @@ func recursePS(params rlwe.ParameterProvider, logSplit, targetLevel int, p Polyn } type PolynomialVector struct { - Value []Polynomial - SlotsIndex map[int][]int + Value []Polynomial + Mapping map[int][]int } -func NewPolynomialVector(polys []Polynomial, slotsIndex map[int][]int) (PolynomialVector, error) { +func NewPolynomialVector(polys []bignum.Polynomial, mapping map[int][]int) (PolynomialVector, error) { var maxDeg int var basis bignum.Basis for i := range polys { @@ -158,11 +158,13 @@ func NewPolynomialVector(polys []Polynomial, slotsIndex map[int][]int) (Polynomi polyvec := make([]Polynomial, len(polys)) - copy(polyvec, polys) + for i := range polyvec { + polyvec[i] = NewPolynomial(polys[i]) + } return PolynomialVector{ - Value: polyvec, - SlotsIndex: slotsIndex, + Value: polyvec, + Mapping: mapping, }, nil } @@ -191,12 +193,12 @@ func (p PolynomialVector) Factorize(n int) (polyq, polyr PolynomialVector) { coeffsq[i], coeffsr[i] = p.Factorize(n) } - return PolynomialVector{Value: coeffsq, SlotsIndex: p.SlotsIndex}, PolynomialVector{Value: coeffsr, SlotsIndex: p.SlotsIndex} + return PolynomialVector{Value: coeffsq, Mapping: p.Mapping}, PolynomialVector{Value: coeffsr, Mapping: p.Mapping} } type PatersonStockmeyerPolynomialVector struct { - Value []PatersonStockmeyerPolynomial - SlotsIndex map[int][]int + Value []PatersonStockmeyerPolynomial + Mapping map[int][]int } // GetPatersonStockmeyerPolynomial returns @@ -207,7 +209,7 @@ func (p PolynomialVector) GetPatersonStockmeyerPolynomial(params rlwe.Parameters } return PatersonStockmeyerPolynomialVector{ - Value: Value, - SlotsIndex: p.SlotsIndex, + Value: Value, + Mapping: p.Mapping, } } diff --git a/examples/ckks/polyeval/main.go b/examples/ckks/polyeval/main.go index f492eaf5..81919ea4 100644 --- a/examples/ckks/polyeval/main.go +++ b/examples/ckks/polyeval/main.go @@ -5,7 +5,6 @@ import ( "math" "math/big" - "github.com/tuneinsight/lattigo/v4/circuits" "github.com/tuneinsight/lattigo/v4/circuits/float" "github.com/tuneinsight/lattigo/v4/ckks" "github.com/tuneinsight/lattigo/v4/rlwe" @@ -96,7 +95,7 @@ func chebyshevinterpolation() { approxG := bignum.ChebyshevApproximation(g, interval) // Map storing which polynomial has to be applied to which slot. - slotsIndex := make(map[int][]int) + mapping := make(map[int][]int) idxF := make([]int, slots>>1) idxG := make([]int, slots>>1) @@ -105,8 +104,8 @@ func chebyshevinterpolation() { idxG[i] = i*2 + 1 // Index with all odd slots } - slotsIndex[0] = idxF // Assigns index of all even slots to poly[0] = f(x) - slotsIndex[1] = idxG // Assigns index of all odd slots to poly[1] = g(x) + mapping[0] = idxF // Assigns index of all even slots to poly[0] = f(x) + mapping[1] = idxG // Assigns index of all odd slots to poly[1] = g(x) // Change of variable if err := evaluator.Mul(ciphertext, 2/(b-a), ciphertext); err != nil { @@ -121,7 +120,7 @@ func chebyshevinterpolation() { panic(err) } - polyVec, err := circuits.NewPolynomialVector([]circuits.Polynomial{circuits.NewPolynomial(approxF), circuits.NewPolynomial(approxG)}, slotsIndex) + polyVec, err := float.NewPolynomialVector([]bignum.Polynomial{approxF, approxG}, mapping) if err != nil { panic(err) }