From 1ea7f3af5c05fa664b340cdc7059caaf13e2fea1 Mon Sep 17 00:00:00 2001 From: Andrea Caforio Date: Fri, 5 Jul 2024 11:34:56 +0200 Subject: [PATCH] he collapse --- circuits/bootstrapping/evaluator.go | 7 +- circuits/bootstrapping/parameters_literal.go | 7 +- circuits/dft/dft.go | 6 +- circuits/inverse/inverse.go | 4 +- circuits/inverse/inverse_test.go | 4 +- .../ltfloat/linear_transformation.go | 9 +- {he/hefloat => circuits/minimax}/README.md | 2 +- .../polyint/polynomial_evaluator.go | 3 +- examples/README.md | 12 +- examples/example_test.go | 28 +- examples/multi_party/int_pir/main.go | 42 +- examples/multi_party/int_psi/main.go | 32 +- examples/params.go | 104 ++-- .../applications/int_ride_hailing/main.go | 15 +- .../reals_bootstrapping/basics/main.go | 6 +- .../high_precision/main.go | 10 +- .../reals_bootstrapping/slim/main.go | 2 +- .../reals_sigmoid_chebyshev/main.go | 23 +- .../main.go | 25 +- examples/single_party/templates/int/main.go | 14 +- examples/single_party/templates/reals/main.go | 16 +- examples/single_party/tutorials/reals/main.go | 85 ++-- he/bootstrapper.go | 34 -- he/he.go | 30 -- he/hebin/README.md | 3 - he/hebin/blindrotation.go | 39 -- he/hebin/blindrotation_benchmark_test.go | 72 --- he/hebin/evaluator.go | 298 ----------- he/hebin/utils.go | 53 -- he/hefloat/bootstrapping/README.md | 11 - he/hefloat/bootstrapping/bootstrapper_test.go | 374 -------------- he/hefloat/bootstrapping/default_parameter.go | 195 -------- he/hefloat/bootstrapping/evaluator.go | 223 --------- .../bootstrapping/evaluator_bench_test.go | 79 --- he/hefloat/bootstrapping/evaluator_test.go | 319 ------------ he/hefloat/comparisons.go | 196 -------- he/hefloat/comparisons_test.go | 154 ------ he/hefloat/cosine/cosine_approx.go | 377 -------------- he/hefloat/hefloat.go | 112 ----- he/hefloat/hefloat_benchmark_test.go | 438 ---------------- he/hefloat/inverse_test.go | 162 ------ he/hefloat/mod1_parameters.go | 245 --------- he/hefloat/mod1_test.go | 204 -------- he/hefloat/polynomial_evaluator_sim.go | 82 --- he/hefloat/test_parameters_test.go | 26 - he/heint/heint.go | 94 ---- he/heint/heint_benchmark_test.go | 453 ----------------- he/heint/heint_test.go | 466 ------------------ he/heint/parameters_test.go | 19 - he/heint/polynomial_evaluator_sim.go | 98 ---- he/polynomial_evaluator_sim.go | 40 -- he/power_basis_test.go | 39 -- he/ring_packing_keys.go | 181 ------- mhe/README.md | 8 +- mhe/mhefloat/mhe_test.go | 54 +- mhe/mhefloat/mhefloat_benchmark_test.go | 19 +- mhe/mhefloat/refresh.go | 4 +- mhe/mhefloat/sharing.go | 19 +- mhe/mhefloat/test_params.go | 10 +- mhe/mhefloat/transform.go | 22 +- mhe/mheint/mheint.go | 4 +- mhe/mheint/mheint_benchmark_test.go | 15 +- mhe/mheint/mheint_test.go | 35 +- mhe/mheint/refresh.go | 7 +- mhe/mheint/sharing.go | 22 +- mhe/mheint/test_parameters.go | 8 +- mhe/mheint/transform.go | 9 +- 67 files changed, 341 insertions(+), 5467 deletions(-) rename {he/hefloat => circuits/minimax}/README.md (86%) delete mode 100644 he/bootstrapper.go delete mode 100644 he/he.go delete mode 100644 he/hebin/README.md delete mode 100644 he/hebin/blindrotation.go delete mode 100644 he/hebin/blindrotation_benchmark_test.go delete mode 100644 he/hebin/evaluator.go delete mode 100644 he/hebin/utils.go delete mode 100644 he/hefloat/bootstrapping/README.md delete mode 100644 he/hefloat/bootstrapping/bootstrapper_test.go delete mode 100644 he/hefloat/bootstrapping/default_parameter.go delete mode 100644 he/hefloat/bootstrapping/evaluator.go delete mode 100644 he/hefloat/bootstrapping/evaluator_bench_test.go delete mode 100644 he/hefloat/bootstrapping/evaluator_test.go delete mode 100644 he/hefloat/comparisons.go delete mode 100644 he/hefloat/comparisons_test.go delete mode 100644 he/hefloat/cosine/cosine_approx.go delete mode 100644 he/hefloat/hefloat.go delete mode 100644 he/hefloat/hefloat_benchmark_test.go delete mode 100644 he/hefloat/inverse_test.go delete mode 100644 he/hefloat/mod1_parameters.go delete mode 100644 he/hefloat/mod1_test.go delete mode 100644 he/hefloat/polynomial_evaluator_sim.go delete mode 100644 he/hefloat/test_parameters_test.go delete mode 100644 he/heint/heint.go delete mode 100644 he/heint/heint_benchmark_test.go delete mode 100644 he/heint/heint_test.go delete mode 100644 he/heint/parameters_test.go delete mode 100644 he/heint/polynomial_evaluator_sim.go delete mode 100644 he/polynomial_evaluator_sim.go delete mode 100644 he/power_basis_test.go delete mode 100644 he/ring_packing_keys.go diff --git a/circuits/bootstrapping/evaluator.go b/circuits/bootstrapping/evaluator.go index 448e9fbc..04d1757e 100644 --- a/circuits/bootstrapping/evaluator.go +++ b/circuits/bootstrapping/evaluator.go @@ -10,7 +10,6 @@ import ( "github.com/tuneinsight/lattigo/v5/circuits/mod1" "github.com/tuneinsight/lattigo/v5/circuits/polynomial/polyfloat" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he" "github.com/tuneinsight/lattigo/v5/ring" "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/utils" @@ -73,9 +72,9 @@ func NewEvaluator(btpParams Parameters, evk *EvaluationKeys) (eval *Evaluator, e eval.Parameters = btpParams if paramsN1.N() != paramsN2.N() { - eval.xPow2N1 = he.GenXPow2NTT(paramsN1.RingQ().AtLevel(0), paramsN2.LogN(), false) - eval.xPow2N2 = he.GenXPow2NTT(paramsN2.RingQ().AtLevel(0), paramsN2.LogN(), false) - eval.xPow2InvN2 = he.GenXPow2NTT(paramsN2.RingQ(), paramsN2.LogN(), true) + eval.xPow2N1 = rlwe.GenXPow2NTT(paramsN1.RingQ().AtLevel(0), paramsN2.LogN(), false) + eval.xPow2N2 = rlwe.GenXPow2NTT(paramsN2.RingQ().AtLevel(0), paramsN2.LogN(), false) + eval.xPow2InvN2 = rlwe.GenXPow2NTT(paramsN2.RingQ(), paramsN2.LogN(), true) } if btpParams.Mod1ParametersLiteral.Mod1Type == mod1.SinContinuous && btpParams.Mod1ParametersLiteral.DoubleAngle != 0 { diff --git a/circuits/bootstrapping/parameters_literal.go b/circuits/bootstrapping/parameters_literal.go index 767b52ce..2645298b 100644 --- a/circuits/bootstrapping/parameters_literal.go +++ b/circuits/bootstrapping/parameters_literal.go @@ -8,7 +8,6 @@ import ( "github.com/tuneinsight/lattigo/v5/circuits/mod1" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" "github.com/tuneinsight/lattigo/v5/ring" "github.com/tuneinsight/lattigo/v5/utils" ) @@ -112,7 +111,7 @@ import ( // When using a small ratio (i.e. 2^4), for example if ct.PlaintextScale is close to Q[0] is small or if |m| is large, the Mod1InvDegree can be set to // a non zero value (i.e. 5 or 7). This will greatly improve the precision of the bootstrapping, at the expense of slightly increasing its depth. // -// Mod1Type: the type of approximation for the modular reduction polynomial. By default set to hefloat.CosDiscrete. +// Mod1Type: the type of approximation for the modular reduction polynomial. By default set to mod1.CosDiscrete. // // K: the range of the approximation interval, by default set to 16. // @@ -132,7 +131,7 @@ type ParametersLiteral struct { EvalModLogScale *int // Default: 60 EphemeralSecretWeight *int // Default: 32 IterationsParameters *IterationsParameters // Default: nil (default starting level of 0 and 1 iteration) - Mod1Type mod1.Mod1Type // Default: hefloat.CosDiscrete + Mod1Type mod1.Mod1Type // Default: mod1.CosDiscrete LogMessageRatio *int // Default: 8 K *int // Default: 16 Mod1Degree *int // Default: 30 @@ -166,7 +165,7 @@ const ( // DefaultIterations is the default number of bootstrapping iterations. DefaultIterations = 1 // DefaultMod1Type is the default function and approximation technique for the homomorphic modular reduction polynomial. - DefaultMod1Type = hefloat.CosDiscrete + DefaultMod1Type = mod1.CosDiscrete // DefaultLogMessageRatio is the default ratio between Q[0] and |m|. DefaultLogMessageRatio = 8 // DefaultK is the default interval [-K+1, K-1] for the polynomial approximation of the homomorphic modular reduction. diff --git a/circuits/dft/dft.go b/circuits/dft/dft.go index 6ea98bd1..473a51ef 100644 --- a/circuits/dft/dft.go +++ b/circuits/dft/dft.go @@ -7,9 +7,9 @@ import ( "math/big" "slices" + "github.com/tuneinsight/lattigo/v5/circuits/linear_transformation" "github.com/tuneinsight/lattigo/v5/circuits/linear_transformation/ltfloat" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he" "github.com/tuneinsight/lattigo/v5/ring" "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/utils" @@ -118,7 +118,7 @@ func (d DFTMatrixLiteral) GaloisElements(params ckks.Parameters) (galEls []uint6 // Coeffs to Slots rotations for i, pVec := range indexCtS { - N1 := he.FindBestBSGSRatio(utils.GetKeys(pVec), dslots, d.LogBSGSRatio) + N1 := linear_transformation.FindBestBSGSRatio(utils.GetKeys(pVec), dslots, d.LogBSGSRatio) rotations = addMatrixRotToList(pVec, rotations, N1, slots, d.Type == HomomorphicDecode && logSlots < logN-1 && i == 0 && imgRepack) } @@ -200,7 +200,7 @@ func NewDFTMatrixFromLiteral(params ckks.Parameters, d DFTMatrixLiteral, encoder mat := ltfloat.NewLinearTransformation(params, ltparams) - if err := ltfloat.EncodeLinearTransformation[*bignum.Complex](encoder, pVecDFT[idx], mat); err != nil { + if err := ltfloat.EncodeLinearTransformation(encoder, pVecDFT[idx], mat); err != nil { return DFTMatrix{}, fmt.Errorf("cannot NewDFTMatrixFromLiteral: %w", err) } diff --git a/circuits/inverse/inverse.go b/circuits/inverse/inverse.go index 8975f684..96b8f6bd 100644 --- a/circuits/inverse/inverse.go +++ b/circuits/inverse/inverse.go @@ -4,10 +4,10 @@ import ( "fmt" "math" + "github.com/tuneinsight/lattigo/v5/circuits/bootstrapping" "github.com/tuneinsight/lattigo/v5/circuits/comparison" "github.com/tuneinsight/lattigo/v5/circuits/minimax" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he" "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/utils" ) @@ -310,7 +310,7 @@ func (eval InverseEvaluator) GoldschmidtDivisionNew(ct *rlwe.Ciphertext, log2min // The normalization factor is independant to each slot: // - values smaller than 1 will have a normalization factor that tends to 1 // - values greater than 1 will have a normalization factor that tends to 1/x -func (eval InverseEvaluator) IntervalNormalization(ct *rlwe.Ciphertext, log2Max float64, btp he.Bootstrapper[rlwe.Ciphertext]) (ctNorm, ctNormFac *rlwe.Ciphertext, err error) { +func (eval InverseEvaluator) IntervalNormalization(ct *rlwe.Ciphertext, log2Max float64, btp bootstrapping.Bootstrapper) (ctNorm, ctNormFac *rlwe.Ciphertext, err error) { ctNorm = ct.CopyNew() diff --git a/circuits/inverse/inverse_test.go b/circuits/inverse/inverse_test.go index df41813e..5035f6dc 100644 --- a/circuits/inverse/inverse_test.go +++ b/circuits/inverse/inverse_test.go @@ -10,9 +10,9 @@ import ( "github.com/stretchr/testify/require" "github.com/tuneinsight/lattigo/v5/circuits/bootstrapping" + "github.com/tuneinsight/lattigo/v5/circuits/comparison" "github.com/tuneinsight/lattigo/v5/circuits/minimax" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" "github.com/tuneinsight/lattigo/v5/ring" "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/utils/bignum" @@ -141,7 +141,7 @@ func TestInverse(t *testing.T) { invEval := NewInverseEvaluator(tc.Params, minEvl) - cInv, err := invEval.EvaluateFullDomainNew(ct, logmin, logmax, minimax.NewMinimaxCompositePolynomial(hefloat.DefaultMinimaxCompositePolynomialForSign)) + cInv, err := invEval.EvaluateFullDomainNew(ct, logmin, logmax, minimax.NewMinimaxCompositePolynomial(comparison.DefaultMinimaxCompositePolynomialForSign)) require.NoError(t, err) have := make([]*big.Float, tc.Params.MaxSlots()) diff --git a/circuits/linear_transformation/ltfloat/linear_transformation.go b/circuits/linear_transformation/ltfloat/linear_transformation.go index f5f258ff..dc358962 100644 --- a/circuits/linear_transformation/ltfloat/linear_transformation.go +++ b/circuits/linear_transformation/ltfloat/linear_transformation.go @@ -3,7 +3,6 @@ package ltfloat import ( "github.com/tuneinsight/lattigo/v5/circuits/linear_transformation" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he" "github.com/tuneinsight/lattigo/v5/schemes" "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/utils" @@ -11,12 +10,12 @@ import ( // Diagonals is a wrapper of [he.Diagonals]. // See [he.Diagonals] for the documentation. -type Diagonals[T ckks.Float] he.Diagonals[T] +type Diagonals[T ckks.Float] linear_transformation.Diagonals[T] // DiagonalsIndexList returns the list of the non-zero diagonals of the square matrix. // A non zero diagonals is a diagonal with a least one non-zero element. func (m Diagonals[T]) DiagonalsIndexList() (indexes []int) { - return he.Diagonals[T](m).DiagonalsIndexList() + return linear_transformation.Diagonals[T](m).DiagonalsIndexList() } // Evaluate evaluates the linear transformation on the provided vector. @@ -28,9 +27,9 @@ func (m Diagonals[T]) Evaluate(vector []T, newVec func(size int) []T, add func(a keys := utils.GetKeys(m) - N1 := he.FindBestBSGSRatio(keys, slots, 1) + N1 := linear_transformation.FindBestBSGSRatio(keys, slots, 1) - index, _, _ := he.BSGSIndex(keys, slots, N1) + index, _, _ := linear_transformation.BSGSIndex(keys, slots, N1) res = newVec(slots) diff --git a/he/hefloat/README.md b/circuits/minimax/README.md similarity index 86% rename from he/hefloat/README.md rename to circuits/minimax/README.md index 356925ca..5f6b42ce 100644 --- a/he/hefloat/README.md +++ b/circuits/minimax/README.md @@ -1,3 +1,3 @@ ## References -1. Minimax Approximation of Sign Function by Composite Polynomial for Homomorphic Comparison () \ No newline at end of file +1. Minimax Approximation of Sign Function by Composite Polynomial for Homomorphic Comparison () diff --git a/circuits/polynomial/polyint/polynomial_evaluator.go b/circuits/polynomial/polyint/polynomial_evaluator.go index b89a13ed..d7985655 100644 --- a/circuits/polynomial/polyint/polynomial_evaluator.go +++ b/circuits/polynomial/polyint/polynomial_evaluator.go @@ -5,7 +5,6 @@ import ( "github.com/tuneinsight/lattigo/v5/circuits/polynomial" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he" "github.com/tuneinsight/lattigo/v5/schemes" "github.com/tuneinsight/lattigo/v5/schemes/bfv" "github.com/tuneinsight/lattigo/v5/schemes/bgv" @@ -78,7 +77,7 @@ func (eval PolynomialEvaluator) Evaluate(ct *rlwe.Ciphertext, p interface{}, tar // EvaluateFromPowerBasis evaluates a polynomial using the provided PowerBasis, holding pre-computed powers of X. // This method is the same as Evaluate except that the encrypted input is a PowerBasis. // See Evaluate for additional information. -func (eval PolynomialEvaluator) EvaluateFromPowerBasis(pb he.PowerBasis, p interface{}, targetScale rlwe.Scale) (opOut *rlwe.Ciphertext, err error) { +func (eval PolynomialEvaluator) EvaluateFromPowerBasis(pb polynomial.PowerBasis, p interface{}, targetScale rlwe.Scale) (opOut *rlwe.Ciphertext, err error) { var phe interface{} switch p := p.(type) { diff --git a/examples/README.md b/examples/README.md index f3e308b9..03bc6a16 100644 --- a/examples/README.md +++ b/examples/README.md @@ -20,7 +20,7 @@ Application examples are examples showcasing specific capabilities of the librar - `high_precision`: an example showcasing high-precision bootstrapping. - `slim`: an example showcasing slim bootstrapping, i.e. re-ordering the steps of the bootstrapping. -- `reals_scheme_switching`: an example showcasing scheme switching between `hefloat` and `hebin` to complement fixed-point arithmetic with lookup tables. +- `reals_scheme_switching`: an example showcasing scheme switching between `ckks` and `rgsw` to complement fixed-point arithmetic with lookup tables. - `reals_sigmoid_chebyshev`: an example showcasing polynomial evaluation of a Chebyshev approximation of the sigmoid. - `reals_sigmoid_minimax`: an example showcasing polynomial evaluation of a minimax approximation of the sigmoid. - `reals_vectorized_polynomial_evaluation`: an example showcasing vectorized polynomial evaluation, i.e. evaluating different polynomials in parallel on specific slots. @@ -29,14 +29,14 @@ Application examples are examples showcasing specific capabilities of the librar Templates are files containing the basic instantiation, i.e. parameters, key-generation, encoding, encryption and decryption. -- `reals`: a template for `hefloat`. -- `int`: a template for `heint`. +- `reals`: a template for `ckks`. +- `int`: a template for `bgv`. ## Tutorials Tutorials are examples showcasing the basic capabilities of the library. -- `reals`: a tutorial on all the basic capabilities of the package `hefloat`. +- `reals`: a tutorial on all the basic capabilities of the package `ckks`. # Multi Party Examples @@ -46,8 +46,8 @@ Tutorials are examples showcasing the basic capabilities of the library. ## Parameters -The `params.go` file contains several sets of example parameters for both `heint` and `hefloat`. +The `params.go` file contains several sets of example parameters for both `bgv` and `ckks`. These parameter are chosen to represent several degrees of homomorphic capacity for a fixed 128-bit security (according to the standard estimates at the time of writing). They do not represent a set of default parameters to be used in real HE applications. Rather, they are meant to facilitate quick tests and experimentation -with the library. \ No newline at end of file +with the library. diff --git a/examples/example_test.go b/examples/example_test.go index 2e909871..2cdcec81 100644 --- a/examples/example_test.go +++ b/examples/example_test.go @@ -3,44 +3,44 @@ package examples import ( "testing" - "github.com/tuneinsight/lattigo/v5/he/hefloat" - "github.com/tuneinsight/lattigo/v5/he/heint" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" + "github.com/tuneinsight/lattigo/v5/schemes/ckks" ) func TestExampleParams(t *testing.T) { - for _, pl := range HEIntParams { - p, err := heint.NewParametersFromLiteral(pl) + for _, pl := range BGVParams { + p, err := bgv.NewParametersFromLiteral(pl) if err != nil { t.Fatal(err) } p.RingQ() - t.Logf("HEIntParams: LogN: %d - LogQP: %12.7f - LogSlots: %d", p.LogN(), p.LogQP(), p.LogMaxSlots()) + t.Logf("BGVParams: LogN: %d - LogQP: %12.7f - LogSlots: %d", p.LogN(), p.LogQP(), p.LogMaxSlots()) } - for _, pl := range HEIntScaleInvariantParams { - p, err := heint.NewParametersFromLiteral(pl) + for _, pl := range BGVScaleInvariantParams { + p, err := bgv.NewParametersFromLiteral(pl) if err != nil { t.Fatal(err) } p.RingQ() - t.Logf("HEIntScaleInvariantParams: LogN: %d - LogQP: %12.7f - LogSlots: %d", p.LogN(), p.LogQP(), p.LogMaxSlots()) + t.Logf("BGVScaleInvariantParams: LogN: %d - LogQP: %12.7f - LogSlots: %d", p.LogN(), p.LogQP(), p.LogMaxSlots()) } - for _, pl := range HEFloatComplexParams { - p, err := hefloat.NewParametersFromLiteral(pl) + for _, pl := range CKKSComplexParams { + p, err := ckks.NewParametersFromLiteral(pl) if err != nil { t.Fatal(err) } p.RingQ() - t.Logf("HEFloatComplex: LogN: %d - LogQP: %12.7f - LogSlots: %d", p.LogN(), p.LogQP(), p.LogMaxSlots()) + t.Logf("CKKSComplex: LogN: %d - LogQP: %12.7f - LogSlots: %d", p.LogN(), p.LogQP(), p.LogMaxSlots()) } - for _, pl := range HEFloatRealParams { - p, err := hefloat.NewParametersFromLiteral(pl) + for _, pl := range CKKSRealParams { + p, err := ckks.NewParametersFromLiteral(pl) if err != nil { t.Fatal(err) } p.RingQ() - t.Logf("HEFloatReal: LogN: %d - LogQP: %12.7f - LogSlots: %d", p.LogN(), p.LogQP(), p.LogMaxSlots()) + t.Logf("CKKSReal: LogN: %d - LogQP: %12.7f - LogSlots: %d", p.LogN(), p.LogQP(), p.LogMaxSlots()) } } diff --git a/examples/multi_party/int_pir/main.go b/examples/multi_party/int_pir/main.go index 93d9cc86..0f415809 100644 --- a/examples/multi_party/int_pir/main.go +++ b/examples/multi_party/int_pir/main.go @@ -8,9 +8,9 @@ import ( "time" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/heint" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" "github.com/tuneinsight/lattigo/v5/utils/sampling" ) @@ -102,7 +102,7 @@ func main() { // Creating encryption parameters // LogN = 13 & LogQP = 218 - params, err := heint.NewParametersFromLiteral(heint.ParametersLiteral{ + params, err := bgv.NewParametersFromLiteral(bgv.ParametersLiteral{ LogN: 13, LogQ: []int{54, 54, 54}, LogP: []int{55}, @@ -140,14 +140,14 @@ func main() { elapsedCKGParty+elapsedRKGParty+elapsedGKGParty) // Pre-loading memory - encoder := heint.NewEncoder(params) + encoder := bgv.NewEncoder(params) l.Println("> Memory alloc Phase") encInputs := make([]*rlwe.Ciphertext, N) plainMask := make([]*rlwe.Plaintext, N) // Ciphertexts to be retrieved for i := range encInputs { - encInputs[i] = heint.NewCiphertext(params, 1, params.MaxLevel()) + encInputs[i] = bgv.NewCiphertext(params, 1, params.MaxLevel()) } // Plaintext masks: plainmask[i] = encode([0, ..., 0, 1_i, 0, ..., 0]) @@ -155,7 +155,7 @@ func main() { for i := range plainMask { maskCoeffs := make([]uint64, params.N()) maskCoeffs[i] = 1 - plainMask[i] = heint.NewPlaintext(params, params.MaxLevel()) + plainMask[i] = bgv.NewPlaintext(params, params.MaxLevel()) if err := encoder.Encode(maskCoeffs, plainMask[i]); err != nil { panic(err) } @@ -164,7 +164,7 @@ func main() { // Ciphertexts encrypted under collective public key and stored in the cloud l.Println("> Encrypt Phase") encryptor := rlwe.NewEncryptor(params, pk) - pt := heint.NewPlaintext(params, params.MaxLevel()) + pt := bgv.NewPlaintext(params, params.MaxLevel()) elapsedEncryptParty := runTimedParty(func() { for i, pi := range P { if err := encoder.Encode(pi.input, pt); err != nil { @@ -191,7 +191,7 @@ func main() { // Decryption by the external party decryptor := rlwe.NewDecryptor(params, P[0].sk) - ptres := heint.NewPlaintext(params, params.MaxLevel()) + ptres := bgv.NewPlaintext(params, params.MaxLevel()) elapsedDecParty := runTimed(func() { decryptor.Decrypt(encOut, ptres) }) @@ -207,7 +207,7 @@ func main() { elapsedCKGParty+elapsedRKGParty+elapsedGKGParty+elapsedEncryptParty+elapsedRequestParty+elapsedPCKSParty+elapsedDecParty) } -func cksphase(params heint.Parameters, P []*party, result *rlwe.Ciphertext) *rlwe.Ciphertext { +func cksphase(params bgv.Parameters, P []*party, result *rlwe.Ciphertext) *rlwe.Ciphertext { l := log.New(os.Stderr, "", 0) l.Println("> KeySwitch Phase") @@ -230,7 +230,7 @@ func cksphase(params heint.Parameters, P []*party, result *rlwe.Ciphertext) *rlw } }, len(P)-1) - encOut := heint.NewCiphertext(params, 1, params.MaxLevel()) + encOut := bgv.NewCiphertext(params, 1, params.MaxLevel()) elapsedCKSCloud = runTimed(func() { for _, pi := range P { if err := cks.AggregateShares(pi.cksShare, cksCombined, &cksCombined); err != nil { @@ -244,7 +244,7 @@ func cksphase(params heint.Parameters, P []*party, result *rlwe.Ciphertext) *rlw return encOut } -func genparties(params heint.Parameters, N int) []*party { +func genparties(params bgv.Parameters, N int) []*party { P := make([]*party, N) @@ -265,7 +265,7 @@ func genparties(params heint.Parameters, N int) []*party { return P } -func ckgphase(params heint.Parameters, crs sampling.PRNG, P []*party) *rlwe.PublicKey { +func ckgphase(params bgv.Parameters, crs sampling.PRNG, P []*party) *rlwe.PublicKey { l := log.New(os.Stderr, "", 0) @@ -301,7 +301,7 @@ func ckgphase(params heint.Parameters, crs sampling.PRNG, P []*party) *rlwe.Publ return pk } -func rkgphase(params heint.Parameters, crs sampling.PRNG, P []*party) *rlwe.RelinearizationKey { +func rkgphase(params bgv.Parameters, crs sampling.PRNG, P []*party) *rlwe.RelinearizationKey { l := log.New(os.Stderr, "", 0) l.Println("> RelinearizationKeyGen Phase") @@ -351,7 +351,7 @@ func rkgphase(params heint.Parameters, crs sampling.PRNG, P []*party) *rlwe.Reli return rlk } -func gkgphase(params heint.Parameters, crs sampling.PRNG, P []*party) (galKeys []*rlwe.GaloisKey) { +func gkgphase(params bgv.Parameters, crs sampling.PRNG, P []*party) (galKeys []*rlwe.GaloisKey) { l := log.New(os.Stderr, "", 0) @@ -408,11 +408,11 @@ func gkgphase(params heint.Parameters, crs sampling.PRNG, P []*party) (galKeys [ return } -func genquery(params heint.Parameters, queryIndex int, encoder *heint.Encoder, encryptor *rlwe.Encryptor) *rlwe.Ciphertext { +func genquery(params bgv.Parameters, queryIndex int, encoder *bgv.Encoder, encryptor *rlwe.Encryptor) *rlwe.Ciphertext { // Query ciphertext queryCoeffs := make([]uint64, params.N()) queryCoeffs[queryIndex] = 1 - query := heint.NewPlaintext(params, params.MaxLevel()) + query := bgv.NewPlaintext(params, params.MaxLevel()) var encQuery *rlwe.Ciphertext elapsedRequestParty += runTimed(func() { var err error @@ -427,7 +427,7 @@ func genquery(params heint.Parameters, queryIndex int, encoder *heint.Encoder, e return encQuery } -func requestphase(params heint.Parameters, queryIndex, NGoRoutine int, encQuery *rlwe.Ciphertext, encInputs []*rlwe.Ciphertext, plainMask []*rlwe.Plaintext, evk rlwe.EvaluationKeySet) *rlwe.Ciphertext { +func requestphase(params bgv.Parameters, queryIndex, NGoRoutine int, encQuery *rlwe.Ciphertext, encInputs []*rlwe.Ciphertext, plainMask []*rlwe.Plaintext, evk rlwe.EvaluationKeySet) *rlwe.Ciphertext { l := log.New(os.Stderr, "", 0) @@ -436,10 +436,10 @@ func requestphase(params heint.Parameters, queryIndex, NGoRoutine int, encQuery // Buffer for the intermediate computation done by the cloud encPartial := make([]*rlwe.Ciphertext, len(encInputs)) for i := range encPartial { - encPartial[i] = heint.NewCiphertext(params, 2, params.MaxLevel()) + encPartial[i] = bgv.NewCiphertext(params, 2, params.MaxLevel()) } - evaluator := heint.NewEvaluator(params, evk) + evaluator := bgv.NewEvaluator(params, evk) // Split the task among the Go routines tasks := make(chan *maskTask) @@ -448,7 +448,7 @@ func requestphase(params heint.Parameters, queryIndex, NGoRoutine int, encQuery for i := 1; i <= NGoRoutine; i++ { go func(i int) { evaluator := evaluator.ShallowCopy() // creates a shallow evaluator copy for this goroutine - tmp := heint.NewCiphertext(params, 1, params.MaxLevel()) + tmp := bgv.NewCiphertext(params, 1, params.MaxLevel()) for task := range tasks { task.elapsedmaskTask = runTimed(func() { // 1) Multiplication BFV-style of the query with the plaintext mask @@ -502,8 +502,8 @@ func requestphase(params heint.Parameters, queryIndex, NGoRoutine int, encQuery elapsedRequestCloudCPU += t.elapsedmaskTask } - resultDeg2 := heint.NewCiphertext(params, 2, params.MaxLevel()) - result := heint.NewCiphertext(params, 1, params.MaxLevel()) + resultDeg2 := bgv.NewCiphertext(params, 2, params.MaxLevel()) + result := bgv.NewCiphertext(params, 1, params.MaxLevel()) // Summation of all the partial result among the different Go routines finalAddDuration := runTimed(func() { diff --git a/examples/multi_party/int_psi/main.go b/examples/multi_party/int_psi/main.go index e0e179e0..b559fefe 100644 --- a/examples/multi_party/int_psi/main.go +++ b/examples/multi_party/int_psi/main.go @@ -8,9 +8,9 @@ import ( "time" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/heint" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" "github.com/tuneinsight/lattigo/v5/utils/sampling" ) @@ -88,7 +88,7 @@ func main() { } // Creating encryption parameters from a default params with logN=14, logQP=438 with a plaintext modulus T=65537 - params, err := heint.NewParametersFromLiteral(heint.ParametersLiteral{ + params, err := bgv.NewParametersFromLiteral(bgv.ParametersLiteral{ LogN: 14, LogQ: []int{56, 55, 55, 54, 54, 54}, LogP: []int{55, 55}, @@ -103,7 +103,7 @@ func main() { panic(err) } - encoder := heint.NewEncoder(params) + encoder := bgv.NewEncoder(params) // Target private and public keys tsk, tpk := rlwe.NewKeyGenerator(params).GenKeyPairNew() @@ -136,7 +136,7 @@ func main() { // Decrypt the result with the target secret key l.Println("> ResulPlaintextModulus:") decryptor := rlwe.NewDecryptor(params, tsk) - ptres := heint.NewPlaintext(params, params.MaxLevel()) + ptres := bgv.NewPlaintext(params, params.MaxLevel()) elapsedDecParty := runTimed(func() { decryptor.Decrypt(encOut, ptres) }) @@ -161,20 +161,20 @@ func main() { } -func encPhase(params heint.Parameters, P []*party, pk *rlwe.PublicKey, encoder *heint.Encoder) (encInputs []*rlwe.Ciphertext) { +func encPhase(params bgv.Parameters, P []*party, pk *rlwe.PublicKey, encoder *bgv.Encoder) (encInputs []*rlwe.Ciphertext) { l := log.New(os.Stderr, "", 0) encInputs = make([]*rlwe.Ciphertext, len(P)) for i := range encInputs { - encInputs[i] = heint.NewCiphertext(params, 1, params.MaxLevel()) + encInputs[i] = bgv.NewCiphertext(params, 1, params.MaxLevel()) } // Each party encrypts its input vector l.Println("> Encrypt Phase") encryptor := rlwe.NewEncryptor(params, pk) - pt := heint.NewPlaintext(params, params.MaxLevel()) + pt := bgv.NewPlaintext(params, params.MaxLevel()) elapsedEncryptParty = runTimedParty(func() { for i, pi := range P { if err := encoder.Encode(pi.input, pt); err != nil { @@ -192,7 +192,7 @@ func encPhase(params heint.Parameters, P []*party, pk *rlwe.PublicKey, encoder * return } -func evalPhase(params heint.Parameters, NGoRoutine int, encInputs []*rlwe.Ciphertext, evk rlwe.EvaluationKeySet) (encRes *rlwe.Ciphertext) { +func evalPhase(params bgv.Parameters, NGoRoutine int, encInputs []*rlwe.Ciphertext, evk rlwe.EvaluationKeySet) (encRes *rlwe.Ciphertext) { l := log.New(os.Stderr, "", 0) @@ -201,13 +201,13 @@ func evalPhase(params heint.Parameters, NGoRoutine int, encInputs []*rlwe.Cipher for nLvl := len(encInputs) / 2; nLvl > 0; nLvl = nLvl >> 1 { encLvl := make([]*rlwe.Ciphertext, nLvl) for i := range encLvl { - encLvl[i] = heint.NewCiphertext(params, 2, params.MaxLevel()) + encLvl[i] = bgv.NewCiphertext(params, 2, params.MaxLevel()) } encLvls = append(encLvls, encLvl) } encRes = encLvls[len(encLvls)-1][0] - evaluator := heint.NewEvaluator(params, evk) + evaluator := bgv.NewEvaluator(params, evk) // Split the task among the Go routines tasks := make(chan *multTask) workers := &sync.WaitGroup{} @@ -267,7 +267,7 @@ func evalPhase(params heint.Parameters, NGoRoutine int, encInputs []*rlwe.Cipher return } -func genparties(params heint.Parameters, N int) []*party { +func genparties(params bgv.Parameters, N int) []*party { // Create each party, and allocate the memory for all the shares that the protocols will need P := make([]*party, N) @@ -281,7 +281,7 @@ func genparties(params heint.Parameters, N int) []*party { return P } -func genInputs(params heint.Parameters, P []*party) (expRes []uint64) { +func genInputs(params bgv.Parameters, P []*party) (expRes []uint64) { expRes = make([]uint64, params.N()) for i := range expRes { @@ -303,7 +303,7 @@ func genInputs(params heint.Parameters, P []*party) (expRes []uint64) { return } -func pcksPhase(params heint.Parameters, tpk *rlwe.PublicKey, encRes *rlwe.Ciphertext, P []*party) (encOut *rlwe.Ciphertext) { +func pcksPhase(params bgv.Parameters, tpk *rlwe.PublicKey, encRes *rlwe.Ciphertext, P []*party) (encOut *rlwe.Ciphertext) { l := log.New(os.Stderr, "", 0) @@ -328,7 +328,7 @@ func pcksPhase(params heint.Parameters, tpk *rlwe.PublicKey, encRes *rlwe.Cipher }, len(P)) pcksCombined := pcks.AllocateShare(params.MaxLevel()) - encOut = heint.NewCiphertext(params, 1, params.MaxLevel()) + encOut = bgv.NewCiphertext(params, 1, params.MaxLevel()) elapsedPCKSCloud = runTimed(func() { for _, pi := range P { if err = pcks.AggregateShares(pi.pcksShare, pcksCombined, &pcksCombined); err != nil { @@ -343,7 +343,7 @@ func pcksPhase(params heint.Parameters, tpk *rlwe.PublicKey, encRes *rlwe.Cipher return } -func rkgphase(params heint.Parameters, crs sampling.PRNG, P []*party) *rlwe.RelinearizationKey { +func rkgphase(params bgv.Parameters, crs sampling.PRNG, P []*party) *rlwe.RelinearizationKey { l := log.New(os.Stderr, "", 0) l.Println("> RelinearizationKeyGen Phase") @@ -392,7 +392,7 @@ func rkgphase(params heint.Parameters, crs sampling.PRNG, P []*party) *rlwe.Reli return rlk } -func ckgphase(params heint.Parameters, crs sampling.PRNG, P []*party) *rlwe.PublicKey { +func ckgphase(params bgv.Parameters, crs sampling.PRNG, P []*party) *rlwe.PublicKey { l := log.New(os.Stderr, "", 0) diff --git a/examples/params.go b/examples/params.go index 614b25b4..52e69706 100644 --- a/examples/params.go +++ b/examples/params.go @@ -1,135 +1,135 @@ package examples import ( - "github.com/tuneinsight/lattigo/v5/he/hefloat" - "github.com/tuneinsight/lattigo/v5/he/heint" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" + "github.com/tuneinsight/lattigo/v5/schemes/ckks" ) var ( - // HEIntParamsN12QP109 is an example parameter set for the `heint` package logN=12 and logQP=109. + // BGVParamsN12QP109 is an example parameter set for the `bgv` package logN=12 and logQP=109. // These parameters expect the user to use the regular tensoring (i.e. Evaluator.Mul) followed // by the rescaling (i.e. Evaluator.Rescale). - HEIntParamsN12QP109 = heint.ParametersLiteral{ + BGVParamsN12QP109 = bgv.ParametersLiteral{ LogN: 12, LogQ: []int{39, 31}, LogP: []int{39}, PlaintextModulus: 0x10001, } - // HEIntParamsN13QP218 is an example parameter set for the `heint` package with logN=13 and logQP=218. + // BGVParamsN13QP218 is an example parameter set for the `bgv` package with logN=13 and logQP=218. // These parameters expect the user to use the regular tensoring (i.e. Evaluator.Mul) followed // by the rescaling (i.e. Evaluator.Rescale). - HEIntParamsN13QP218 = heint.ParametersLiteral{ + BGVParamsN13QP218 = bgv.ParametersLiteral{ LogN: 13, LogQ: []int{42, 33, 33, 33, 33}, LogP: []int{44}, PlaintextModulus: 0x10001, } - // HEIntParamsN14QP438 is an example parameter set for the `heint` package with logN=14 and logQP=438. + // BGVParamsN14QP438 is an example parameter set for the `bgv` package with logN=14 and logQP=438. // These parameters expect the user to use the regular tensoring (i.e. Evaluator.Mul) followed // by the rescaling (i.e. Evaluator.Rescale). - HEIntParamsN14QP438 = heint.ParametersLiteral{ + BGVParamsN14QP438 = bgv.ParametersLiteral{ LogN: 14, LogQ: []int{44, 34, 34, 34, 34, 34, 34, 34, 34, 34}, LogP: []int{44, 44}, PlaintextModulus: 0x10001, } - // HEIntParamsN15QP880 is an example parameter set for the `heint` package with logN=15 and logQP=881. + // BGVParamsN15QP880 is an example parameter set for the `bgv` package with logN=15 and logQP=881. // These parameters expect the user to use the regular tensoring (i.e. Evaluator.Mul) followed // by the rescaling (i.e. Evaluator.Rescale). - HEIntParamsN15QP880 = heint.ParametersLiteral{ + BGVParamsN15QP880 = bgv.ParametersLiteral{ LogN: 15, LogQ: []int{47, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34}, LogP: []int{47, 47, 47, 47}, PlaintextModulus: 0x10001, } - // HEIntScaleInvariantParamsN12QP109 is an example parameter set for the `heint` package logN=12 and logQP=109. + // BGVScaleInvariantParamsN12QP109 is an example parameter set for the `bgv` package logN=12 and logQP=109. // These parameters expect the user to use the scale invariant tensoring (i.e. Evaluator.MulScaleInvariant). - HEIntScaleInvariantParamsN12QP109 = heint.ParametersLiteral{ + BGVScaleInvariantParamsN12QP109 = bgv.ParametersLiteral{ LogN: 12, LogQ: []int{39, 39}, LogP: []int{31}, PlaintextModulus: 0x10001, } - // HEIntScaleInvariantParamsN13QP218 is an example parameter set for the `heint` package with logN=13 and logQP=218. + // BGVScaleInvariantParamsN13QP218 is an example parameter set for the `bgv` package with logN=13 and logQP=218. // These parameters expect the user to use the scale invariant tensoring (i.e. Evaluator.MulScaleInvariant). - HEIntScaleInvariantParamsN13QP218 = heint.ParametersLiteral{ + BGVScaleInvariantParamsN13QP218 = bgv.ParametersLiteral{ LogN: 13, LogQ: []int{55, 54, 54}, LogP: []int{55}, PlaintextModulus: 0x10001, } - // HEIntScaleInvariantParamsN14QP438 is an example parameter set for the `heint` package with logN=14 and logQP=438. + // BGVScaleInvariantParamsN14QP438 is an example parameter set for the `bgv` package with logN=14 and logQP=438. // These parameters expect the user to use the scale invariant tensoring (i.e. Evaluator.MulScaleInvariant). - HEIntScaleInvariantParamsN14QP438 = heint.ParametersLiteral{ + BGVScaleInvariantParamsN14QP438 = bgv.ParametersLiteral{ LogN: 14, LogQ: []int{55, 55, 55, 54, 54, 54}, LogP: []int{56, 55}, PlaintextModulus: 0x10001, } - // HEIntScaleInvariantParamsN15QP880 is an example parameter set for the `heint` package with logN=15 and logQP=881. + // BGVScaleInvariantParamsN15QP880 is an example parameter set for the `bgv` package with logN=15 and logQP=881. // These parameters expect the user to use the scale invariant tensoring (i.e. Evaluator.MulScaleInvariant). - HEIntScaleInvariantParamsN15QP880 = heint.ParametersLiteral{ + BGVScaleInvariantParamsN15QP880 = bgv.ParametersLiteral{ LogN: 15, LogQ: []int{60, 60, 59, 58, 58, 58, 58, 58, 58, 58, 58, 58}, LogP: []int{60, 60, 60}, PlaintextModulus: 0x10001, } - // HEFloatComplexParamsN12QP109 is an example parameter set for the `hefloat` package with logN=12 and logQP=109. - // These parameters instantiate `hefloat` over the complex field with N/2 SIMD slots. - HEFloatComplexParamsN12QP109 = hefloat.ParametersLiteral{ + // CKKSComplexParamsN12QP109 is an example parameter set for the `ckks` package with logN=12 and logQP=109. + // These parameters instantiate `ckks` over the complex field with N/2 SIMD slots. + CKKSComplexParamsN12QP109 = ckks.ParametersLiteral{ LogN: 12, LogQ: []int{38, 32}, LogP: []int{39}, LogDefaultScale: 32, } - // HEFloatComplexParamsN13QP218 is an example parameter set for the `hefloat` package with logN=13 and logQP=218. - // These parameters instantiate `hefloat` over the complex field with N/2 SIMD slots. - HEFloatComplexParamsN13QP218 = hefloat.ParametersLiteral{ + // CKKSComplexParamsN13QP218 is an example parameter set for the `ckks` package with logN=13 and logQP=218. + // These parameters instantiate `ckks` over the complex field with N/2 SIMD slots. + CKKSComplexParamsN13QP218 = ckks.ParametersLiteral{ LogN: 13, LogQ: []int{33, 30, 30, 30, 30, 30}, LogP: []int{35}, LogDefaultScale: 30, } - // HEFloatComplexParamsN14QP438 is an example parameter set for the `hefloat` package with logN=14 and logQP=438. - // These parameters instantiate `hefloat` over the complex field with N/2 SIMD slots. - HEFloatComplexParamsN14QP438 = hefloat.ParametersLiteral{ + // CKKSComplexParamsN14QP438 is an example parameter set for the `ckks` package with logN=14 and logQP=438. + // These parameters instantiate `ckks` over the complex field with N/2 SIMD slots. + CKKSComplexParamsN14QP438 = ckks.ParametersLiteral{ LogN: 14, LogQ: []int{45, 34, 34, 34, 34, 34, 34, 34, 34, 34}, LogP: []int{44, 43}, LogDefaultScale: 34, } - // HEFloatComplexParamsN15QP880 is an example parameter set for the `hefloat` package with logN=15 and logQP=881. - // These parameters instantiate `hefloat` over the complex field with N/2 SIMD slots. - HEFloatComplexParamsN15QP881 = hefloat.ParametersLiteral{ + // CKKSComplexParamsN15QP880 is an example parameter set for the `ckks` package with logN=15 and logQP=881. + // These parameters instantiate `ckks` over the complex field with N/2 SIMD slots. + CKKSComplexParamsN15QP881 = ckks.ParametersLiteral{ LogN: 15, LogQ: []int{51, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, LogP: []int{50, 50, 50}, LogDefaultScale: 40, } - // HEFloatComplexParamsPN16QP1761 is an example parameter set for the `hefloat` package with logN=16 and logQP = 1761. - // These parameters instantiate `hefloat` over the complex field with N/2 SIMD slots. - HEFloatComplexParamsPN16QP1761 = hefloat.ParametersLiteral{ + // CKKSComplexParamsPN16QP1761 is an example parameter set for the `ckks` package with logN=16 and logQP = 1761. + // These parameters instantiate `ckks` over the complex field with N/2 SIMD slots. + CKKSComplexParamsPN16QP1761 = ckks.ParametersLiteral{ LogN: 16, LogQ: []int{56, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45}, LogP: []int{55, 55, 55, 55}, LogDefaultScale: 45, } - // HEFloatRealParamsN12QP109 is an example parameter set for the `hefloat` package with conjugate-invariant CKKS and logN=12 and logQP=109. - // These parameters instantiate `hefloat` over the real field with N SIMD slots. - HEFloatRealParamsN12QP109 = hefloat.ParametersLiteral{ + // CKKSRealParamsN12QP109 is an example parameter set for the `ckks` package with conjugate-invariant CKKS and logN=12 and logQP=109. + // These parameters instantiate `ckks` over the real field with N SIMD slots. + CKKSRealParamsN12QP109 = ckks.ParametersLiteral{ LogN: 12, LogQ: []int{38, 32}, LogP: []int{39}, @@ -137,9 +137,9 @@ var ( RingType: ring.ConjugateInvariant, } - // HEFloatRealParamsN13QP218 is an example parameter set for the `hefloat` package with conjugate-invariant CKKS and logN=13 and logQP=218 - // These parameters instantiate `hefloat` over the real field with N SIMD slots. - HEFloatRealParamsN13QP218 = hefloat.ParametersLiteral{ + // CKKSRealParamsN13QP218 is an example parameter set for the `ckks` package with conjugate-invariant CKKS and logN=13 and logQP=218 + // These parameters instantiate `ckks` over the real field with N SIMD slots. + CKKSRealParamsN13QP218 = ckks.ParametersLiteral{ LogN: 13, LogQ: []int{33, 30, 30, 30, 30, 30}, LogP: []int{35}, @@ -147,9 +147,9 @@ var ( RingType: ring.ConjugateInvariant, } - // HEFloatRealParamsN14QP438 is an example parameter set for the `hefloat` package with logN=14 and logQP=438. - // These parameters instantiate `hefloat` over the real field with N SIMD slots. - HEFloatRealParamsN14QP438 = hefloat.ParametersLiteral{ + // CKKSRealParamsN14QP438 is an example parameter set for the `ckks` package with logN=14 and logQP=438. + // These parameters instantiate `ckks` over the real field with N SIMD slots. + CKKSRealParamsN14QP438 = ckks.ParametersLiteral{ LogN: 14, LogQ: []int{46, 34, 34, 34, 34, 34, 34, 34, 34, 34}, LogP: []int{43, 43}, @@ -157,9 +157,9 @@ var ( RingType: ring.ConjugateInvariant, } - // HEFloatRealParamsN15QP880 is an example parameter set for the `hefloat` package with logN=15 and logQP=881. - // These parameters instantiate `hefloat` over the real field with N SIMD slots. - HEFloatRealParamsN15QP881 = hefloat.ParametersLiteral{ + // CKKSRealParamsN15QP880 is an example parameter set for the `ckks` package with logN=15 and logQP=881. + // These parameters instantiate `ckks` over the real field with N SIMD slots. + CKKSRealParamsN15QP881 = ckks.ParametersLiteral{ LogN: 15, LogQ: []int{51, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, LogP: []int{50, 50, 50}, @@ -167,9 +167,9 @@ var ( RingType: ring.ConjugateInvariant, } - // HEFloatRealParamsPN16QP1761 is an example parameter set for the `hefloat` package with logN=16 and logQP = 1761 - // These parameters instantiate `hefloat` over the real field with N SIMD slots. - HEFloatRealParamsPN16QP1761 = hefloat.ParametersLiteral{ + // CKKSRealParamsPN16QP1761 is an example parameter set for the `ckks` package with logN=16 and logQP = 1761 + // These parameters instantiate `ckks` over the real field with N SIMD slots. + CKKSRealParamsPN16QP1761 = ckks.ParametersLiteral{ LogN: 16, LogQ: []int{56, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45}, LogP: []int{55, 55, 55, 55}, @@ -178,10 +178,10 @@ var ( } ) -var HEIntParams = []heint.ParametersLiteral{HEIntParamsN12QP109, HEIntParamsN13QP218, HEIntParamsN14QP438, HEIntParamsN15QP880} +var BGVParams = []bgv.ParametersLiteral{BGVParamsN12QP109, BGVParamsN13QP218, BGVParamsN14QP438, BGVParamsN15QP880} -var HEIntScaleInvariantParams = []heint.ParametersLiteral{HEIntScaleInvariantParamsN12QP109, HEIntScaleInvariantParamsN13QP218, HEIntScaleInvariantParamsN14QP438, HEIntScaleInvariantParamsN15QP880} +var BGVScaleInvariantParams = []bgv.ParametersLiteral{BGVScaleInvariantParamsN12QP109, BGVScaleInvariantParamsN13QP218, BGVScaleInvariantParamsN14QP438, BGVScaleInvariantParamsN15QP880} -var HEFloatComplexParams = []hefloat.ParametersLiteral{HEFloatComplexParamsN12QP109, HEFloatComplexParamsN13QP218, HEFloatComplexParamsN14QP438, HEFloatComplexParamsN15QP881, HEFloatComplexParamsPN16QP1761} +var CKKSComplexParams = []ckks.ParametersLiteral{CKKSComplexParamsN12QP109, CKKSComplexParamsN13QP218, CKKSComplexParamsN14QP438, CKKSComplexParamsN15QP881, CKKSComplexParamsPN16QP1761} -var HEFloatRealParams = []hefloat.ParametersLiteral{HEFloatRealParamsN12QP109, HEFloatRealParamsN13QP218, HEFloatRealParamsN14QP438, HEFloatRealParamsN15QP881, HEFloatRealParamsPN16QP1761} +var CKKSRealParams = []ckks.ParametersLiteral{CKKSRealParamsN12QP109, CKKSRealParamsN13QP218, CKKSRealParamsN14QP438, CKKSRealParamsN15QP881, CKKSRealParamsPN16QP1761} diff --git a/examples/single_party/applications/int_ride_hailing/main.go b/examples/single_party/applications/int_ride_hailing/main.go index c82885eb..252da0ea 100644 --- a/examples/single_party/applications/int_ride_hailing/main.go +++ b/examples/single_party/applications/int_ride_hailing/main.go @@ -7,10 +7,9 @@ import ( "math/bits" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/utils/sampling" - - "github.com/tuneinsight/lattigo/v5/he/heint" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" + "github.com/tuneinsight/lattigo/v5/utils/sampling" ) var flagShort = flag.Bool("short", false, "run the example with a smaller and insecure ring degree.") @@ -58,7 +57,7 @@ func obliviousRiding() { // Parameters (128 bit security) with plaintext modulus 65929217 // Creating encryption parameters from a default params with logN=14, logQP=438 with a plaintext modulus T=65929217 - params, err := heint.NewParametersFromLiteral(heint.ParametersLiteral{ + params, err := bgv.NewParametersFromLiteral(bgv.ParametersLiteral{ LogN: 14, LogQ: []int{56, 55, 55, 54, 54, 54}, LogP: []int{55, 55}, @@ -68,7 +67,7 @@ func obliviousRiding() { panic(err) } - encoder := heint.NewEncoder(params) + encoder := bgv.NewEncoder(params) // Rider's keygen kgen := rlwe.NewKeyGenerator(params) @@ -79,7 +78,7 @@ func obliviousRiding() { encryptorRiderPk := rlwe.NewEncryptor(params, riderPk) encryptorRiderSk := rlwe.NewEncryptor(params, riderSk) - evaluator := heint.NewEvaluator(params, nil) + evaluator := bgv.NewEvaluator(params, nil) fmt.Println("============================================") fmt.Println("Homomorphic computations on batched integers") @@ -109,7 +108,7 @@ func obliviousRiding() { Rider[(i<<1)+1] = riderPosY } - riderPlaintext := heint.NewPlaintext(params, params.MaxLevel()) + riderPlaintext := bgv.NewPlaintext(params, params.MaxLevel()) if err := encoder.Encode(Rider, riderPlaintext); err != nil { panic(err) } @@ -122,7 +121,7 @@ func obliviousRiding() { driversData[i] = make([]uint64, 1< `rlwe` -> `ckks` -> `he/float`. + // The `ckks` package relies on the `rlwe` package, which themselves relies on the `ring` package: `ring` -> `rlwe` -> `ckks`. // // The lowest layer is the `ring` package. // The `ring` package provides optimized arithmetic in rings `Z_{Q}[X]/(X^{N}+1)` for `N` a power of two and @@ -40,14 +41,12 @@ func main() { // The top layer is the `ckks` package. // This package implements the CKKS scheme, and mostly consist in defining the encoding and scheme specific homomorphic operations. // - // The user facing layer is the `he/float` package which implements high level functionalities and provides the a user with a - // friendly API for the homomorphic operations. // ======================================================= // `rlwe.Ciphertext`, `rlwe.Plaintext` and `rlwe.MetaData` // ======================================================= // - // Before talking about the capabilities of the `he/float` package, we have to give some information about the `rlwe.Ciphertext` and `rlwe.Plaintext` objects. + // Before talking about the capabilities of the `ckks` package, we have to give some information about the `rlwe.Ciphertext` and `rlwe.Plaintext` objects. // // Both contain the `rlwe.MetaData` struct, which notably holds the following fields: // - `Scale`: the scaling factor. This field is updated dynamically during computations. @@ -60,10 +59,10 @@ func main() { // These are all public fields which can be manually edited by advanced users if needed. // // ====================================================== - // Capabilities of the HE/FLOAT Package in the Lattigo Library + // Capabilities of the CKKS Package in the Lattigo Library // ====================================================== // - // The current capabilities of the `he/float` package are the following: + // The current capabilities of the `schemes/ckks` package are the following: // // - Encoding: encode vectors of type `[]complex128`, `[]float64`, `[]*big.Float` or `[]*bignum.Complex` on `rlwe.Plaintext` // @@ -87,6 +86,9 @@ func main() { // // - Rotations & Conjugation // + // On top of the `ckks` package resides the `circuits` module in which specific circuits based on the schemes in `schemes` are implemented. + // The most salient for the CKKS cryptosystem being: + // // - Polynomial Evaluation: // - `Single polynomial`: evaluate the same polynomial on all slots of a `rlwe.Ciphertext` // - `Vector polynomial`: evaluate different polynomials on different slots of a `rlwe.Ciphertext` @@ -100,26 +102,26 @@ func main() { // // - All methods of the `rlwe.Evaluator`, which are not described here. // - // The `he/float` package also contains the sub-packages: `bootstrapper` which implements bootstrapping to refresh ciphertexts, enabling arbitrary depth circuits. + // The `circuits/bootstrapping` package also contains the sub-packages: `bootstrapper` which implements bootstrapping to refresh ciphertexts, enabling arbitrary depth circuits. // // Note that the package `he/float` also supports a real variant, i.e. plaintext vector of R^{N} (instead of complex vectors C^{N/2}). // A homomorphic bridge between the two schemes is also available. - // This variant can be activated by specifying the `ring.Type` to `ring.ConjugateInvariant` (i.e the ring Z[X + X^{-1}]/(X^{N}+1)) in the `hefloat.Parameters` struct. + // This variant can be activated by specifying the `ring.Type` to `ring.ConjugateInvariant` (i.e the ring Z[X + X^{-1}]/(X^{N}+1)) in the `ckks.Parameters` struct. // ================================= - // Instantiating the hefloat.Parameters + // Instantiating the ckks.Parameters // ================================= // - // We will instantiate a `hefloat.Parameters` struct. + // We will instantiate a `ckks.Parameters` struct. // Unlike other libraries, `Lattigo` doesn't have, yet, a quick constructor. // Users must specify all parameters, up to each individual prime size. // // We will create parameters that are 128-bit secure and allow a depth 7 computation with a scaling factor of 2^{45}. var err error - var params hefloat.Parameters - if params, err = hefloat.NewParametersFromLiteral( - hefloat.ParametersLiteral{ + var params ckks.Parameters + if params, err = ckks.NewParametersFromLiteral( + ckks.ParametersLiteral{ LogN: 14, // A ring degree of 2^{14} LogQ: []int{55, 45, 45, 45, 45, 45, 45, 45}, // An initial prime of 55 bits and 7 primes of 45 bits LogP: []int{61}, // The log2 size of the key-switching prime @@ -139,7 +141,7 @@ func main() { // This precision is notably the precision used by the encoder to encode/decode values. prec := params.EncodingPrecision() // we will need this value later - // Note that the following fields in the `hefloat.ParametersLiteral`are optional, but can be manually specified by advanced users: + // Note that the following fields in the `ckks.ParametersLiteral`are optional, but can be manually specified by advanced users: // - `Xs`: the secret distribution (default uniform ternary) // - `Xe`: the error distribution (default discrete Gaussian with standard deviation of 3.2 and truncated to 19) // - `PowBase`: the log2 of the binary decomposition (default 0, i.e. infinity, i.e. no decomposition) @@ -192,14 +194,14 @@ func main() { // - `EncodingDomain`: `rlwe.SlotsDomain` (this is the default value) // - `LogSlots`: `params.MaxLogSlots` (which is LogN-1=13 in this example) // We can check that the plaintext was created at the maximum level with pt1.Level(). - pt1 := hefloat.NewPlaintext(params, params.MaxLevel()) + pt1 := ckks.NewPlaintext(params, params.MaxLevel()) // Then we need to instantiate the encoder, which will enable us to embed our `values` of type `[]complex128` on a `rlwe.Plaintext`. // By default the encoder will use the params.DefaultPrecision(), but a user can specify a custom precision as an optional argument, - // for example `hefloat.NewEncoder(params, 256)`. - ecd := hefloat.NewEncoder(params) + // for example `ckks.NewEncoder(params, 256)`. + ecd := ckks.NewEncoder(params) - ecd2 := hefloat.NewEncoder(hefloat.Parameters(params)) + ecd2 := ckks.NewEncoder(ckks.Parameters(params)) // And we encode our `values` on the plaintext. // Note that the encoder will check the metadata of the plaintext and adapt the encoding accordingly. @@ -225,7 +227,7 @@ func main() { } // It is also possible to first allocate the ciphertext the same way it was done - // for the plaintext with with `ct := hefloat.NewCiphertext(params, 1, pt.Level())`, + // for the plaintext with with `ct := ckks.NewCiphertext(params, 1, pt.Level())`, // enabling allocation free encryptions (for example if the ciphertext has to be // serialized right away). @@ -243,7 +245,7 @@ func main() { // ================ // // Before anything, we must instantiate the evaluator, and we provide the evaluation key struct. - eval := hefloat.NewEvaluator(params, evk) + eval := ckks.NewEvaluator(params, evk) // For the purpose of the example, we will create a second vector of random values. values2 := make([]complex128, Slots) @@ -251,7 +253,7 @@ func main() { values2[i] = complex(2*r.Float64()-1, 2*r.Float64()-1) } - pt2 := hefloat.NewPlaintext(params, params.MaxLevel()) + pt2 := ckks.NewPlaintext(params, params.MaxLevel()) // =========================== // Managing the Scaling Factor @@ -329,14 +331,14 @@ func main() { if err != nil { panic(err) } - fmt.Printf("Addition - ct + ct%s", hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Addition - ct + ct%s", ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) // ciphertext + plaintext ct3, err = eval.AddNew(ct1, pt2) if err != nil { panic(err) } - fmt.Printf("Addition - ct + pt%s", hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Addition - ct + pt%s", ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) // ciphertext + vector // Note that the evaluator will encode this vector at the scale of the input ciphertext to ensure a noiseless addition. @@ -344,7 +346,7 @@ func main() { if err != nil { panic(err) } - fmt.Printf("Addition - ct + vector%s", hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Addition - ct + vector%s", ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) // ciphertext + scalar scalar := 3.141592653589793 + 1.4142135623730951i @@ -357,7 +359,7 @@ func main() { if err != nil { panic(err) } - fmt.Printf("Addition - ct + scalar%s", hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Addition - ct + scalar%s", ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) fmt.Printf("==============\n") fmt.Printf("MULTIPLICATION\n") @@ -421,14 +423,14 @@ func main() { // For the sake of conciseness, we will not rescale the output for the other multiplication example. // But this maintenance operation should usually be called (either before of after the multiplication depending on the choice of noise management) // to control the magnitude of the plaintext scale. - fmt.Printf("Multiplication - ct * ct%s", hefloat.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) + fmt.Printf("Multiplication - ct * ct%s", ckks.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) // ciphertext + plaintext ct3, err = eval.MulRelinNew(ct1, pt2) if err != nil { panic(err) } - fmt.Printf("Multiplication - ct * pt%s", hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Multiplication - ct * pt%s", ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) // ciphertext + vector // Note that when giving non-encoded vectors, the evaluator will internally encode this vector with the appropriate scale that ensure that @@ -437,7 +439,7 @@ func main() { if err != nil { panic(err) } - fmt.Printf("Multiplication - ct * vector%s", hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Multiplication - ct * vector%s", ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) // ciphertext + scalar (scalar = pi + sqrt(2) * i) for i := 0; i < Slots; i++ { @@ -451,7 +453,7 @@ func main() { if err != nil { panic(err) } - fmt.Printf("Multiplication - ct * scalar%s", hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Multiplication - ct * scalar%s", ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) fmt.Printf("======================\n") fmt.Printf("ROTATION & CONJUGATION\n") @@ -488,7 +490,7 @@ func main() { if err != nil { panic(err) } - fmt.Printf("Rotation by k=%d %s", rot, hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Rotation by k=%d %s", rot, ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) // Conjugation for i := 0; i < Slots; i++ { @@ -499,7 +501,7 @@ func main() { if err != nil { panic(err) } - fmt.Printf("Conjugation %s", hefloat.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) + fmt.Printf("Conjugation %s", ckks.GetPrecisionStats(params, ecd, dec, want, ct3, 0, false).String()) // Note that rotations and conjugation only add a fixed additive noise independent of the ciphertext noise. // If the parameters are set correctly, this noise can be rounding error (thus negligible). @@ -563,7 +565,7 @@ func main() { panic(err) } - polyEval := polyfloat.NewPolynomialEvaluator(params.Parameters, eval) + polyEval := polyfloat.NewPolynomialEvaluator(params, eval) // And we evaluate this polynomial on the ciphertext // The last argument, `params.DefaultScale()` is the scale that we want the ciphertext @@ -574,20 +576,19 @@ func main() { panic(err) } - fmt.Printf("Polynomial Evaluation %s", hefloat.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) + fmt.Printf("Polynomial Evaluation %s", ckks.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) // ============================= // Vector Polynomials Evaluation // ============================= // - // See `examples/hefloat/polyeval` fmt.Printf("======================\n") fmt.Printf("LINEAR TRANSFORMATIONS\n") fmt.Printf("======================\n") fmt.Printf("\n") - // The `he/float` package provides a multiple handy linear transformations. + // The `circuits/linear_transformation` package provides a multiple handy linear transformations. // We will start with the inner sum. // Thus method allows to aggregate `n` sub-vectors of size `batch`. // For example given a vector [x0, x1, x2, x3, x4, x5, x6, x7], batch = 2 and n = 3 @@ -616,7 +617,7 @@ func main() { // Note that this method can obviously be used to average values. // For a good noise management, it is recommended to first multiply the values by 1/n, then // apply the innersum and then only apply the rescaling. - fmt.Printf("Innersum %s", hefloat.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) + fmt.Printf("Innersum %s", ckks.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) // The replicate operation is exactly the same as the innersum operation, but in reverse eval = eval.WithKey(rlwe.NewMemEvaluationKeySet(rlk, kgen.GenGaloisKeysNew(params.GaloisElementsForReplicate(batch, n), sk)...)) @@ -633,7 +634,7 @@ func main() { panic(err) } - fmt.Printf("Replicate %s", hefloat.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) + fmt.Printf("Replicate %s", ckks.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) // And we arrive to the linear transformation. // This method enables to evaluate arbitrary Slots x Slots matrices on a ciphertext. @@ -690,7 +691,7 @@ func main() { // Not that trying to encode a linear transformation with different non-zero diagonals, // plaintext dimensions or baby-step giant-step ratio than the one used to allocate the // rlwe.LinearTransformation will return an error. - if err := ltfloat.EncodeLinearTransformation[complex128](ecd, diagonals, lt); err != nil { + if err := ltfloat.EncodeLinearTransformation(ecd, diagonals, lt); err != nil { panic(err) } @@ -714,19 +715,17 @@ func main() { // We evaluate the same circuit in plaintext want = diagonals.Evaluate(values1, newVec, add, muladd) - fmt.Printf("vector x matrix %s", hefloat.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) + fmt.Printf("vector x matrix %s", ckks.GetPrecisionStats(params, ecd, dec, want, res, 0, false).String()) // ============================= // Homomorphic Encoding/Decoding // ============================= // - // See `examples/hefloat/advanced/lut` // ============ // Bootstrapping // ============ // - // See `examples/hefloat/bootstrapping` // ========== // CONCURRENCY diff --git a/he/bootstrapper.go b/he/bootstrapper.go deleted file mode 100644 index 50ecdece..00000000 --- a/he/bootstrapper.go +++ /dev/null @@ -1,34 +0,0 @@ -package he - -// Bootstrapper is a scheme-independent generic interface to handle bootstrapping. -type Bootstrapper[CiphertextType any] interface { - - // Bootstrap defines a method that takes a single Ciphertext as input and applies - // an in place scheme-specific bootstrapping. The result is also returned. - // An error should notably be returned if ct.Level() < Bootstrapper.MinimumInputLevel(). - Bootstrap(ct *CiphertextType) (*CiphertextType, error) - - // BootstrapMany defines a method that takes a slice of Ciphertexts as input and applies an - // in place scheme-specific bootstrapping to each Ciphertext. The result is also returned. - // An error should notably be returned if cts[i].Level() < Bootstrapper.MinimumInputLevel(). - BootstrapMany(cts []CiphertextType) ([]CiphertextType, error) - - // Depth is the number of levels consumed by the bootstrapping circuit. - // This value is equivalent to params.MaxLevel() - OutputLevel(). - Depth() int - - // MinimumInputLevel defines the minimum level that the ciphertext - // must be at when given to the bootstrapper. - // For the centralized bootstrapping this value is usually zero. - // For the collective bootstrapping it is given by the user-defined - // security parameters - MinimumInputLevel() int - - // OutputLevel defines the level that the ciphertext will be at - // after the bootstrapping. - // For the centralized bootstrapping this value is the maximum - // level minus the depth of the bootstrapping circuit. - // For the collective bootstrapping this value is usually the - // maximum level. - OutputLevel() int -} diff --git a/he/he.go b/he/he.go deleted file mode 100644 index 726a6209..00000000 --- a/he/he.go +++ /dev/null @@ -1,30 +0,0 @@ -// Package he implements scheme agnostic functionalities for RLWE-based Homomorphic Encryption schemes implemented in Lattigo. -package he - -import ( - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/ring" - "github.com/tuneinsight/lattigo/v5/ring/ringqp" -) - -// Encoder defines a set of common and scheme agnostic method provided by an Encoder struct. -type Encoder[T any, U *ring.Poly | ringqp.Poly | *rlwe.Plaintext] interface { - Encode(values []T, metaData *rlwe.MetaData, output U) (err error) -} - -// Evaluator defines a set of common and scheme agnostic method provided by an Evaluator struct. -type Evaluator interface { - rlwe.ParameterProvider - Add(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) - AddNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlwe.Ciphertext, err error) - Sub(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) - SubNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlwe.Ciphertext, err error) - Mul(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) - MulNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlwe.Ciphertext, err error) - MulRelin(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) - MulRelinNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlwe.Ciphertext, err error) - MulThenAdd(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) - Relinearize(op0, op1 *rlwe.Ciphertext) (err error) - Rescale(op0, op1 *rlwe.Ciphertext) (err error) - GetEvaluatorBuffer() *rlwe.EvaluatorBuffers // TODO extract -} diff --git a/he/hebin/README.md b/he/hebin/README.md deleted file mode 100644 index 00592df0..00000000 --- a/he/hebin/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## References - -1. Efficient FHEW Bootstrapping with Small Evaluation Keys, and Applications to Threshold Homomorphic Encryption () \ No newline at end of file diff --git a/he/hebin/blindrotation.go b/he/hebin/blindrotation.go deleted file mode 100644 index 34be7890..00000000 --- a/he/hebin/blindrotation.go +++ /dev/null @@ -1,39 +0,0 @@ -// Package hebin implements blind rotations evaluation for RLWE schemes. -package hebin - -import ( - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/ring" -) - -// InitTestPolynomial takes a function g, and creates a test polynomial polynomial for the function in the interval [a, b]. -// Inputs to the blind rotation evaluation are assumed to have been normalized with the change of basis (2*x - a - b)/(b-a). -// Interval [a, b] should take into account the "drift" of the value x, caused by the change of modulus from Q to 2N. -func InitTestPolynomial(g func(x float64) (y float64), scale rlwe.Scale, ringQ *ring.Ring, a, b float64) (F ring.Poly) { - F = ringQ.NewPoly() - Q := ringQ.ModuliChain()[:ringQ.Level()+1] - - sf64 := scale.Float64() - - N := ringQ.N() - - // Discretization interval - interval := 2.0 / float64(N) - - for j, qi := range Q { - - // Interval [-1, 0] of g(x) - for i := 0; i < (N>>1)+1; i++ { - F.Coeffs[j][i] = scaleUp(g(normalizeInv(-interval*float64(i), a, b)), sf64, qi) - } - - // Interval ]0, 1[ of g(x) - for i := (N >> 1) + 1; i < N; i++ { - F.Coeffs[j][i] = scaleUp(-g(normalizeInv(interval*float64(N-i), a, b)), sf64, qi) - } - } - - ringQ.NTT(F, F) - - return -} diff --git a/he/hebin/blindrotation_benchmark_test.go b/he/hebin/blindrotation_benchmark_test.go deleted file mode 100644 index a6019ffa..00000000 --- a/he/hebin/blindrotation_benchmark_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package hebin - -import ( - "testing" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/utils" - "github.com/tuneinsight/lattigo/v5/utils/sampling" - - "github.com/stretchr/testify/require" -) - -func BenchmarkHEBin(b *testing.B) { - - b.Run("BlindRotateCore/LogN=(9, 10)/LogQ=(13.6,26.99)/Gadget=2^7", func(b *testing.B) { - - // RLWE parameters of the BlindRotation - // N=1024, Q=0x7fff801 -> 131 bit secure - paramsBR, err := rlwe.NewParametersFromLiteral(rlwe.ParametersLiteral{ - LogN: 10, - Q: []uint64{0x7fff801}, - NTTFlag: NTTFlag, - }) - - require.NoError(b, err) - - // RLWE parameters of the samples - // N=512, Q=0x3001 -> 135 bit secure - paramsLWE, err := rlwe.NewParametersFromLiteral(rlwe.ParametersLiteral{ - LogN: 9, - Q: []uint64{0x3001}, - NTTFlag: NTTFlag, - }) - - require.NoError(b, err) - - evkParams := rlwe.EvaluationKeyParameters{BaseTwoDecomposition: utils.Pointy(7)} - - // RLWE secret for the samples - skLWE := rlwe.NewKeyGenerator(paramsLWE).GenSecretKeyNew() - - // Secret of the RGSW ciphertexts encrypting the bits of skLWE - skBR := rlwe.NewKeyGenerator(paramsBR).GenSecretKeyNew() - - // Collection of RGSW ciphertexts encrypting the bits of skLWE under skBR - BRK := GenEvaluationKeyNew(paramsBR, skBR, paramsLWE, skLWE, evkParams) - - // Random LWE mask mod 2N with odd coefficients - a := make([]uint64, paramsLWE.N()) - mask := uint64(2*paramsLWE.N() - 1) - for i := range a { - ai := sampling.RandUint64() & mask - if ai&1 == 0 && ai != 0 { - ai ^= 1 - } - a[i] = ai - } - - acc := rlwe.NewCiphertext(paramsBR, 1, paramsBR.MaxLevel()) - - // Evaluator for the Blind Rotation evaluation - eval := NewEvaluator(paramsBR, paramsLWE) - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - if err := eval.BlindRotateCore(a, acc, BRK); err != nil { - panic(err) - } - } - }) -} diff --git a/he/hebin/evaluator.go b/he/hebin/evaluator.go deleted file mode 100644 index 64d20aaa..00000000 --- a/he/hebin/evaluator.go +++ /dev/null @@ -1,298 +0,0 @@ -package hebin - -import ( - "fmt" - "math/big" - - "github.com/tuneinsight/lattigo/v5/core/rgsw" - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/ring" - "github.com/tuneinsight/lattigo/v5/utils/bignum" -) - -// Evaluator is a struct that stores the necessary -// data to handle LWE <-> RLWE conversion and -// blind rotations. -type Evaluator struct { - *rgsw.Evaluator - paramsBR rlwe.Parameters - paramsLWE rlwe.Parameters - - poolMod2N [2]ring.Poly - - accumulator *rlwe.Ciphertext - - galoisGenDiscreteLog map[uint64]int -} - -// NewEvaluator instantiates a new [Evaluator]. -func NewEvaluator(paramsBR, paramsLWE rlwe.ParameterProvider) (eval *Evaluator) { - eval = new(Evaluator) - eval.Evaluator = rgsw.NewEvaluator(paramsBR, nil) - eval.paramsBR = *paramsBR.GetRLWEParameters() - eval.paramsLWE = *paramsLWE.GetRLWEParameters() - - eval.poolMod2N = [2]ring.Poly{eval.paramsLWE.RingQ().NewPoly(), eval.paramsLWE.RingQ().NewPoly()} - eval.accumulator = rlwe.NewCiphertext(paramsBR, 1, eval.paramsBR.MaxLevel()) - eval.accumulator.IsNTT = true // This flag is always true - - // Generates a map for the discrete log of (+/- 1) * GaloisGen^k for 0 <= k < N-1. - // galoisGenDiscreteLog: map[+/-G^{k} mod 2N] = k - eval.galoisGenDiscreteLog = getGaloisElementInverseMap(ring.GaloisGen, eval.paramsBR.N()) - - return -} - -// Evaluate extracts on the fly LWE samples and evaluates the provided blind rotation on the LWE. -// testPolyWithSlotIndex : a map with [slot_index] -> blind rotation -// Returns a map[slot_index] -> BlindRotate(ct[slot_index]) -func (eval *Evaluator) Evaluate(ct *rlwe.Ciphertext, testPolyWithSlotIndex map[int]*ring.Poly, BRK BlindRotationEvaluationKeySet) (res map[int]*rlwe.Ciphertext, err error) { - - bRLWEMod2N := eval.poolMod2N[0] - aRLWEMod2N := eval.poolMod2N[1] - - acc := eval.accumulator - - brk, err := BRK.GetBlindRotationKey(0) - - if err != nil { - return nil, err - } - - ringQBR := eval.paramsBR.RingQ().AtLevel(brk.LevelQ()) - ringQLWE := eval.paramsLWE.RingQ().AtLevel(ct.Level()) - - if ct.IsNTT { - ringQLWE.INTT(ct.Value[0], acc.Value[0]) - ringQLWE.INTT(ct.Value[1], acc.Value[1]) - } else { - acc.Value[0].CopyLvl(ct.Level(), ct.Value[0]) - acc.Value[1].CopyLvl(ct.Level(), ct.Value[1]) - } - - // Switch modulus from Q to 2N and ensure they are odd - eval.modSwitchRLWETo2NLvl(ct.Level(), acc.Value[1], acc.Value[1], true) - - // Conversion from Convolution(a, sk) to DotProd(a, sk) for LWE decryption. - // Copy coefficients multiplied by X^{N-1} in reverse order: - // a_{0} -a_{N-1} -a2_{N-2} ... -a_{1} - tmp0 := aRLWEMod2N.Coeffs[0] - tmp1 := acc.Value[1].Coeffs[0] - tmp0[0] = tmp1[0] - NLWE := ringQLWE.N() - mask := uint64(ringQBR.N()<<1) - 1 - for j := 1; j < NLWE; j++ { - tmp0[j] = -tmp1[ringQLWE.N()-j] & mask - } - - // Switch modulus from Q to 2N - eval.modSwitchRLWETo2NLvl(ct.Level(), acc.Value[0], bRLWEMod2N, false) - - res = make(map[int]*rlwe.Ciphertext) - - var prevIndex int - for index := 0; index < NLWE; index++ { - - if testPoly, ok := testPolyWithSlotIndex[index]; ok { - - mulBySmallMonomialMod2N(mask, aRLWEMod2N, index-prevIndex) - prevIndex = index - - a := aRLWEMod2N.Coeffs[0] - b := bRLWEMod2N.Coeffs[0][index] - - // Line 2 of Algorithm 7 of https://eprint.iacr.org/2022/198 - // Acc = (f(X^{-g}) * X^{-g * b}, 0) - Xb := ringQBR.NewMonomialXi(int(b)) - ringQBR.NTT(Xb, Xb) - ringQBR.MForm(Xb, Xb) - ringQBR.MulCoeffsMontgomery(*testPoly, Xb, acc.Value[1]) // use unused buffer because AutomorphismNTT is not in place - ringQBR.AutomorphismNTT(acc.Value[1], ringQBR.NthRoot()-ring.GaloisGen, acc.Value[0]) - acc.Value[1].Zero() - - // Line 3 of Algorithm 7 https://eprint.iacr.org/2022/198 (Algorithm 3 of https://eprint.iacr.org/2022/198) - if err = eval.BlindRotateCore(a, acc, BRK); err != nil { - return nil, fmt.Errorf("BlindRotateCore: %s", err) - } - - // f(X) * X^{b + } - res[index] = acc.CopyNew() - - if !eval.paramsBR.NTTFlag() { - ringQBR.INTT(res[index].Value[0], res[index].Value[0]) - ringQBR.INTT(res[index].Value[1], res[index].Value[1]) - res[index].IsNTT = false - } - } - } - - return -} - -// BlindRotateCore implements Algorithm 3 of https://eprint.iacr.org/2022/198 -func (eval *Evaluator) BlindRotateCore(a []uint64, acc *rlwe.Ciphertext, BRK BlindRotationEvaluationKeySet) (err error) { - - evk, err := BRK.GetEvaluationKeySet() - - if err != nil { - return err - } - - eval.Evaluator = eval.Evaluator.WithKey(evk) - - // GaloisElement(k) = GaloisGen^{k} mod 2N - GaloisElement := eval.paramsBR.GaloisElement - - // Maps a[i] to (+/-) g^{k} mod 2N - discreteLogSets := eval.getDiscreteLogSets(a) - - Nhalf := eval.paramsBR.N() >> 1 - - // Algorithm 3 of https://eprint.iacr.org/2022/198 - var v int - // Lines 3 to 9 (negative set of a[i] = -g^{k} mod 2N) - for i := Nhalf - 1; i > 0; i-- { - if v, err = eval.evaluateFromDiscreteLogSets(GaloisElement, discreteLogSets, -i, v, acc, BRK); err != nil { - return - } - } - - // Line 10 (0 in the negative set is 2N) - if _, err = eval.evaluateFromDiscreteLogSets(GaloisElement, discreteLogSets, eval.paramsBR.N()<<1, 0, acc, BRK); err != nil { - return - } - - // Line 12 - // acc = acc(X^{-g}) - if err = eval.Automorphism(acc, eval.paramsBR.RingQ().NthRoot()-ring.GaloisGen, acc); err != nil { - return - } - - // Lines 13 - 19 (positive set of a[i] = g^{k} mod 2N) - for i := Nhalf - 1; i > 0; i-- { - if v, err = eval.evaluateFromDiscreteLogSets(GaloisElement, discreteLogSets, i, v, acc, BRK); err != nil { - return - } - } - - // Lines 20 - 21 (0 in the positive set is 0) - if _, err = eval.evaluateFromDiscreteLogSets(GaloisElement, discreteLogSets, 0, 0, acc, BRK); err != nil { - return - } - - return -} - -// evaluateFromDiscreteLogSets loops of Algorithm 3 of https://eprint.iacr.org/2022/198 -func (eval *Evaluator) evaluateFromDiscreteLogSets(GaloisElement func(k int) (galEl uint64), sets map[int][]int, k, v int, acc *rlwe.Ciphertext, BRK BlindRotationEvaluationKeySet) (int, error) { - - // Checks if k is in the discrete log sets - if set, ok := sets[k]; ok { - - // First condition of line 7 or 17 - if v != 0 { - - if err := eval.Automorphism(acc, GaloisElement(v), acc); err != nil { - return v, err - } - - v = 0 - } - - for _, j := range set { - - brk, err := BRK.GetBlindRotationKey(j) - if err != nil { - return v, err - } - - // acc = acc * RGSW(X^{s[j]}) - eval.ExternalProduct(acc, brk, acc) - } - } - - v++ - - // Second and third conditions of line 7 or 17 - if v == windowSize || k == 1 { - - if err := eval.Automorphism(acc, GaloisElement(v), acc); err != nil { - return v, err - } - - v = 0 - } - - return v, nil -} - -// getGaloisElementInverseMap generates a map [(+/-) g^{k} mod 2N] = +/- k -func getGaloisElementInverseMap(GaloisGen uint64, N int) (GaloisGenDiscreteLog map[uint64]int) { - - twoN := N << 1 - NHalf := N >> 1 - mask := uint64(twoN - 1) - - GaloisGenDiscreteLog = map[uint64]int{} - - var pow uint64 = 1 - for i := 0; i < NHalf; i++ { - GaloisGenDiscreteLog[pow] = i - GaloisGenDiscreteLog[uint64(twoN)-pow] = -i - pow *= GaloisGen - pow &= mask - } - - return -} - -// getDiscreteLogSets returns map[+/-k] = [i...] for a[0 <= i < N] = {(+/-) g^{k} mod 2N for +/- k} -func (eval *Evaluator) getDiscreteLogSets(a []uint64) (discreteLogSets map[int][]int) { - - GaloisGenDiscreteLog := eval.galoisGenDiscreteLog - - // Maps (2*N*a[i]/QLWE) to -N/2 < k <= N/2 for a[i] = (+/- 1) * g^{k} - discreteLogSets = map[int][]int{} - for i, ai := range a { - - if ai&1 != 1 && ai != 0 { - panic("getDiscreteLogSets: a[i] is not odd and thus not an element of Z_{2N}^{*} -> a[i] = (+/- 1) * g^{k} does not exist.") - } - - dlog := GaloisGenDiscreteLog[ai] - - if _, ok := discreteLogSets[dlog]; !ok { - discreteLogSets[dlog] = []int{i} - } else { - discreteLogSets[dlog] = append(discreteLogSets[dlog], i) - } - } - - return -} - -// modSwitchRLWETo2NLvl applies round(x * 2N / Q) to the coefficients of polQ and returns the result on pol2N. -// makeOdd ensures that output coefficients are odd by xoring with 1 (if not already zero). -func (eval *Evaluator) modSwitchRLWETo2NLvl(level int, polQ, pol2N ring.Poly, makeOdd bool) { - coeffsBigint := make([]*big.Int, len(polQ.Coeffs[0])) - - ringQ := eval.paramsLWE.RingQ().AtLevel(level) - - ringQ.PolyToBigint(polQ, 1, coeffsBigint) - - QBig := ringQ.ModulusAtLevel[level] - - twoN := uint64(eval.paramsBR.N() << 1) - twoNBig := bignum.NewInt(twoN) - tmp := pol2N.Coeffs[0] - N := ringQ.N() - for i := 0; i < N; i++ { - coeffsBigint[i].Mul(coeffsBigint[i], twoNBig) - bignum.DivRound(coeffsBigint[i], QBig, coeffsBigint[i]) - tmp[i] = coeffsBigint[i].Uint64() & (twoN - 1) - - if makeOdd && tmp[i]&1 == 0 && tmp[i] != 0 { - tmp[i] ^= 1 - } - } -} diff --git a/he/hebin/utils.go b/he/hebin/utils.go deleted file mode 100644 index 191ab17c..00000000 --- a/he/hebin/utils.go +++ /dev/null @@ -1,53 +0,0 @@ -package hebin - -import ( - "math/big" - - "github.com/tuneinsight/lattigo/v5/ring" - "github.com/tuneinsight/lattigo/v5/utils/bignum" -) - -// MulBySmallMonomialMod2N multiplies pol by x^n, with 0 <= n < N -func mulBySmallMonomialMod2N(mask uint64, pol ring.Poly, n int) { - if n != 0 { - N := len(pol.Coeffs[0]) - pol.Coeffs[0] = append(pol.Coeffs[0][N-n:], pol.Coeffs[0][:N-n]...) - tmp := pol.Coeffs[0] - for j := 0; j < n; j++ { - tmp[j] = -tmp[j] & mask - } - } -} - -func normalizeInv(x, a, b float64) (y float64) { - return (x*(b-a) + b + a) / 2.0 -} - -func scaleUp(value float64, scale float64, Q uint64) (res uint64) { - - var isNegative bool - var xFlo *big.Float - var xInt *big.Int - - isNegative = false - if value < 0 { - isNegative = true - xFlo = big.NewFloat(-scale * value) - } else { - xFlo = big.NewFloat(scale * value) - } - - xFlo.Add(xFlo, big.NewFloat(0.5)) - - xInt = new(big.Int) - xFlo.Int(xInt) - xInt.Mod(xInt, bignum.NewInt(Q)) - - res = xInt.Uint64() - - if isNegative { - res = Q - res - } - - return -} diff --git a/he/hefloat/bootstrapping/README.md b/he/hefloat/bootstrapping/README.md deleted file mode 100644 index cce909b8..00000000 --- a/he/hefloat/bootstrapping/README.md +++ /dev/null @@ -1,11 +0,0 @@ -## References - -1. Bootstrapping for Approximate Homomorphic Encryption () -2. Improved Bootstrapping for Approximate Homomorphic Encryption () -3. Better Bootstrapping for Approximate Homomorphic Encryption () -4. Faster Homomorphic Discrete Fourier Transforms and Improved FHE Bootstrapping () -5. Efficient Bootstrapping for Approximate Homomorphic Encryption with Non-Sparse Keys () -6. High-Precision Bootstrapping for Approximate Homomorphic Encryption by Error Variance Minimization () -7. High-Precision Bootstrapping of RNS-CKKS Homomorphic Encryption Using Optimal Minimax Polynomial Approximation and Inverse Sine Function () -8. Bootstrapping for Approximate Homomorphic Encryption with Negligible Failure-Probability by Using Sparse-Secret Encapsulation () -9. META-BTS: Bootstrapping Precision Beyond the Limit () \ No newline at end of file diff --git a/he/hefloat/bootstrapping/bootstrapper_test.go b/he/hefloat/bootstrapping/bootstrapper_test.go deleted file mode 100644 index bb0455f0..00000000 --- a/he/hefloat/bootstrapping/bootstrapper_test.go +++ /dev/null @@ -1,374 +0,0 @@ -package bootstrapping - -import ( - "flag" - "math" - "testing" - - "github.com/stretchr/testify/require" - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" - "github.com/tuneinsight/lattigo/v5/ring" - "github.com/tuneinsight/lattigo/v5/utils" - "github.com/tuneinsight/lattigo/v5/utils/sampling" -) - -var flagLongTest = flag.Bool("long", false, "run the long test suite (all parameters + secure bootstrapping). Overrides -short and requires -timeout=0.") -var printPrecisionStats = flag.Bool("print-precision", false, "print precision stats") - -var testPrec45 = hefloat.ParametersLiteral{ - LogN: 10, - LogQ: []int{60, 40}, - LogP: []int{61}, - LogDefaultScale: 40, -} - -func TestBootstrapping(t *testing.T) { - - t.Run("BootstrappingWithoutRingDegreeSwitch", func(t *testing.T) { - - schemeParamsLit := testPrec45 - btpParamsLit := ParametersLiteral{} - - if *flagLongTest { - schemeParamsLit.LogN = 16 - } - - params, err := hefloat.NewParametersFromLiteral(schemeParamsLit) - require.Nil(t, err) - - btpParamsLit.LogN = utils.Pointy(params.LogN()) - - btpParams, err := NewParametersFromLiteral(params, btpParamsLit) - require.Nil(t, err) - - // Insecure params for fast testing only - if !*flagLongTest { - btpParams.SlotsToCoeffsParameters.LogSlots = btpParams.BootstrappingParameters.LogN() - 1 - btpParams.CoeffsToSlotsParameters.LogSlots = btpParams.BootstrappingParameters.LogN() - 1 - - // Corrects the message ratio to take into account the smaller number of slots and keep the same precision - btpParams.Mod1ParametersLiteral.LogMessageRatio += 16 - params.LogN() - } - - t.Logf("ParamsN2: LogN=%d/LogSlots=%d/LogQP=%f", params.LogN(), params.LogMaxSlots(), params.LogQP()) - - sk := rlwe.NewKeyGenerator(btpParams.BootstrappingParameters).GenSecretKeyNew() - - t.Log("Generating Bootstrapping Keys") - btpKeys, _, err := btpParams.GenEvaluationKeys(sk) - require.NoError(t, err) - - evaluator, err := NewEvaluator(btpParams, btpKeys) - require.NoError(t, err) - - ecd := hefloat.NewEncoder(params) - enc := rlwe.NewEncryptor(params, sk) - dec := rlwe.NewDecryptor(params, sk) - - values := make([]complex128, params.MaxSlots()) - for i := range values { - values[i] = sampling.RandComplex128(-1, 1) - } - - values[0] = complex(0.9238795325112867, 0.3826834323650898) - values[1] = complex(0.9238795325112867, 0.3826834323650898) - if len(values) > 2 { - values[2] = complex(0.9238795325112867, 0.3826834323650898) - values[3] = complex(0.9238795325112867, 0.3826834323650898) - } - - t.Run("Bootstrapping", func(t *testing.T) { - - plaintext := hefloat.NewPlaintext(params, 0) - ecd.Encode(values, plaintext) - - ctQ0, err := enc.EncryptNew(plaintext) - require.NoError(t, err) - - // Checks that the input ciphertext is at the level 0 - require.True(t, ctQ0.Level() == 0) - - // Bootstrapps the ciphertext - ctQL, err := evaluator.Bootstrap(ctQ0) - require.NoError(t, err) - - // Checks that the output ciphertext is at the max level of paramsN1 - require.True(t, ctQL.Level() == params.MaxLevel()) - require.True(t, ctQL.Scale.Equal(params.DefaultScale())) - - verifyTestVectorsBootstrapping(params, ecd, dec, values, ctQL, t) - }) - }) - - t.Run("BootstrappingWithRingDegreeSwitch", func(t *testing.T) { - - schemeParamsLit := testPrec45 - btpParamsLit := ParametersLiteral{} - - if *flagLongTest { - schemeParamsLit.LogN = 16 - } - - schemeParamsLit.LogNthRoot = schemeParamsLit.LogN + 1 - schemeParamsLit.LogN-- - - params, err := hefloat.NewParametersFromLiteral(schemeParamsLit) - require.Nil(t, err) - - btpParamsLit.LogN = utils.Pointy(params.LogN() + 1) - - btpParams, err := NewParametersFromLiteral(params, btpParamsLit) - require.Nil(t, err) - - // Insecure params for fast testing only - if !*flagLongTest { - btpParams.SlotsToCoeffsParameters.LogSlots = btpParams.BootstrappingParameters.LogN() - 1 - btpParams.CoeffsToSlotsParameters.LogSlots = btpParams.BootstrappingParameters.LogN() - 1 - - // Corrects the message ratio to take into account the smaller number of slots and keep the same precision - btpParams.Mod1ParametersLiteral.LogMessageRatio += 16 - params.LogN() - } - - t.Logf("Params: LogN=%d/LogSlots=%d/LogQP=%f", btpParams.ResidualParameters.LogN(), btpParams.ResidualParameters.LogMaxSlots(), btpParams.ResidualParameters.LogQP()) - t.Logf("BTPParams: LogN=%d/LogSlots=%d/LogQP=%f", btpParams.BootstrappingParameters.LogN(), btpParams.BootstrappingParameters.LogMaxSlots(), btpParams.BootstrappingParameters.LogQP()) - - sk := rlwe.NewKeyGenerator(params).GenSecretKeyNew() - - t.Log("Generating Bootstrapping Keys") - btpKeys, _, err := btpParams.GenEvaluationKeys(sk) - require.Nil(t, err) - - evaluator, err := NewEvaluator(btpParams, btpKeys) - require.Nil(t, err) - - ecd := hefloat.NewEncoder(params) - enc := rlwe.NewEncryptor(params, sk) - dec := rlwe.NewDecryptor(params, sk) - - values := make([]complex128, params.MaxSlots()) - for i := range values { - values[i] = sampling.RandComplex128(-1, 1) - } - - values[0] = complex(0.9238795325112867, 0.3826834323650898) - values[1] = complex(0.9238795325112867, 0.3826834323650898) - if len(values) > 2 { - values[2] = complex(0.9238795325112867, 0.3826834323650898) - values[3] = complex(0.9238795325112867, 0.3826834323650898) - } - - t.Run("N1ToN2->Bootstrapping->N2ToN1", func(t *testing.T) { - - plaintext := hefloat.NewPlaintext(params, 0) - ecd.Encode(values, plaintext) - - ctQ0, err := enc.EncryptNew(plaintext) - require.NoError(t, err) - - // Checks that the input ciphertext is at the level 0 - require.True(t, ctQ0.Level() == 0) - - // Bootstrapps the ciphertext - ctQL, err := evaluator.Bootstrap(ctQ0) - - if err != nil { - t.Fatal(err) - } - - // Checks that the output ciphertext is at the max level of params - require.True(t, ctQL.Level() == params.MaxLevel()) - require.True(t, ctQL.Scale.Equal(params.DefaultScale())) - - verifyTestVectorsBootstrapping(params, ecd, dec, values, ctQL, t) - - }) - }) - - t.Run("BootstrappingPackedWithRingDegreeSwitch", func(t *testing.T) { - - schemeParamsLit := testPrec45 - btpParamsLit := ParametersLiteral{} - - if *flagLongTest { - schemeParamsLit.LogN = 16 - } - - btpParamsLit.LogN = utils.Pointy(schemeParamsLit.LogN) - schemeParamsLit.LogNthRoot = schemeParamsLit.LogN + 1 - schemeParamsLit.LogN -= 3 - - params, err := hefloat.NewParametersFromLiteral(schemeParamsLit) - require.Nil(t, err) - - btpParams, err := NewParametersFromLiteral(params, btpParamsLit) - require.Nil(t, err) - - // Insecure params for fast testing only - if !*flagLongTest { - btpParams.SlotsToCoeffsParameters.LogSlots = btpParams.BootstrappingParameters.LogN() - 1 - btpParams.CoeffsToSlotsParameters.LogSlots = btpParams.BootstrappingParameters.LogN() - 1 - - // Corrects the message ratio to take into account the smaller number of slots and keep the same precision - btpParams.Mod1ParametersLiteral.LogMessageRatio += 16 - params.LogN() - } - - t.Logf("Params: LogN=%d/LogSlots=%d/LogQP=%f", btpParams.ResidualParameters.LogN(), btpParams.ResidualParameters.LogMaxSlots(), btpParams.ResidualParameters.LogQP()) - t.Logf("BTPParams: LogN=%d/LogSlots=%d/LogQP=%f", btpParams.BootstrappingParameters.LogN(), btpParams.BootstrappingParameters.LogMaxSlots(), btpParams.BootstrappingParameters.LogQP()) - - sk := rlwe.NewKeyGenerator(params).GenSecretKeyNew() - - t.Log("Generating Bootstrapping Keys") - btpKeys, _, err := btpParams.GenEvaluationKeys(sk) - require.Nil(t, err) - - evaluator, err := NewEvaluator(btpParams, btpKeys) - require.Nil(t, err) - - ecd := hefloat.NewEncoder(params) - enc := rlwe.NewEncryptor(params, sk) - dec := rlwe.NewDecryptor(params, sk) - - values := make([]complex128, params.MaxSlots()) - for i := range values { - values[i] = sampling.RandComplex128(-1, 1) - } - - values[0] = complex(0.9238795325112867, 0.3826834323650898) - values[1] = complex(0.9238795325112867, 0.3826834323650898) - if len(values) > 2 { - values[2] = complex(0.9238795325112867, 0.3826834323650898) - values[3] = complex(0.9238795325112867, 0.3826834323650898) - } - - pt := hefloat.NewPlaintext(params, 0) - - cts := make([]rlwe.Ciphertext, 7) - for i := range cts { - - require.NoError(t, ecd.Encode(utils.RotateSlice(values, i), pt)) - - ct, err := enc.EncryptNew(pt) - require.NoError(t, err) - - cts[i] = *ct - } - - if cts, err = evaluator.BootstrapMany(cts); err != nil { - t.Fatal(err) - } - - for i := range cts { - // Checks that the output ciphertext is at the max level of paramsN1 - require.True(t, cts[i].Level() == params.MaxLevel()) - require.True(t, cts[i].Scale.Equal(params.DefaultScale())) - - verifyTestVectorsBootstrapping(params, ecd, dec, utils.RotateSlice(values, i), &cts[i], t) - } - }) - - t.Run("BootstrappingWithRingTypeSwitch", func(t *testing.T) { - - schemeParamsLit := testPrec45 - schemeParamsLit.RingType = ring.ConjugateInvariant - btpParamsLit := ParametersLiteral{} - - if *flagLongTest { - schemeParamsLit.LogN = 16 - } - - btpParamsLit.LogN = utils.Pointy(schemeParamsLit.LogN) - schemeParamsLit.LogNthRoot = schemeParamsLit.LogN + 1 - schemeParamsLit.LogN-- - - params, err := hefloat.NewParametersFromLiteral(schemeParamsLit) - require.Nil(t, err) - - btpParams, err := NewParametersFromLiteral(params, btpParamsLit) - require.Nil(t, err) - - // Insecure params for fast testing only - if !*flagLongTest { - // Corrects the message ratio to take into account the smaller number of slots and keep the same precision - btpParams.Mod1ParametersLiteral.LogMessageRatio += 16 - params.LogN() - } - - t.Logf("Params: LogN=%d/LogSlots=%d/LogQP=%f", btpParams.ResidualParameters.LogN(), btpParams.ResidualParameters.LogMaxSlots(), btpParams.ResidualParameters.LogQP()) - t.Logf("BTPParams: LogN=%d/LogSlots=%d/LogQP=%f", btpParams.BootstrappingParameters.LogN(), btpParams.BootstrappingParameters.LogMaxSlots(), btpParams.BootstrappingParameters.LogQP()) - - sk := rlwe.NewKeyGenerator(params).GenSecretKeyNew() - - t.Log("Generating Bootstrapping Keys") - btpKeys, _, err := btpParams.GenEvaluationKeys(sk) - require.Nil(t, err) - - evaluator, err := NewEvaluator(btpParams, btpKeys) - require.Nil(t, err) - - ecd := hefloat.NewEncoder(params) - enc := rlwe.NewEncryptor(params, sk) - dec := rlwe.NewDecryptor(params, sk) - - values := make([]float64, params.MaxSlots()) - for i := range values { - values[i] = sampling.RandFloat64(-1, 1) - } - - values[0] = 0.9238795325112867 - values[1] = 0.9238795325112867 - if len(values) > 2 { - values[2] = 0.9238795325112867 - values[3] = 0.9238795325112867 - } - - t.Run("ConjugateInvariant->Standard->Bootstrapping->Standard->ConjugateInvariant", func(t *testing.T) { - - plaintext := hefloat.NewPlaintext(params, 0) - require.NoError(t, ecd.Encode(values, plaintext)) - - ctLeftQ0, err := enc.EncryptNew(plaintext) - require.NoError(t, err) - ctRightQ0, err := enc.EncryptNew(plaintext) - require.NoError(t, err) - - // Checks that the input ciphertext is at the level 0 - require.True(t, ctLeftQ0.Level() == 0) - require.True(t, ctRightQ0.Level() == 0) - - // Bootstraps the ciphertext - ctLeftQL, ctRightQL, err := evaluator.EvaluateConjugateInvariant(ctLeftQ0, ctRightQ0) - - require.NoError(t, err) - - // Checks that the output ciphertext is at the max level of paramsN1 - require.True(t, ctLeftQL.Level() == params.MaxLevel()) - require.True(t, ctLeftQL.Scale.Equal(params.DefaultScale())) - - verifyTestVectorsBootstrapping(params, ecd, dec, values, ctLeftQL, t) - - require.True(t, ctRightQL.Level() == params.MaxLevel()) - require.True(t, ctRightQL.Scale.Equal(params.DefaultScale())) - verifyTestVectorsBootstrapping(params, ecd, dec, values, ctRightQL, t) - }) - }) -} - -func verifyTestVectorsBootstrapping(params hefloat.Parameters, encoder *hefloat.Encoder, decryptor *rlwe.Decryptor, valuesWant, element interface{}, t *testing.T) { - precStats := hefloat.GetPrecisionStats(params, encoder, decryptor, valuesWant, element, 0, false) - if *printPrecisionStats { - t.Log(precStats.String()) - } - - rf64, _ := precStats.MeanPrecision.Real.Float64() - if64, _ := precStats.MeanPrecision.Imag.Float64() - - minPrec := math.Log2(params.DefaultScale().Float64()) - float64(params.LogN()+2) - if minPrec < 0 { - minPrec = 0 - } - - minPrec -= 10 - - require.GreaterOrEqual(t, rf64, minPrec) - require.GreaterOrEqual(t, if64, minPrec) -} diff --git a/he/hefloat/bootstrapping/default_parameter.go b/he/hefloat/bootstrapping/default_parameter.go deleted file mode 100644 index 4c9c3a85..00000000 --- a/he/hefloat/bootstrapping/default_parameter.go +++ /dev/null @@ -1,195 +0,0 @@ -package bootstrapping - -import ( - "github.com/tuneinsight/lattigo/v5/he/hefloat" - "github.com/tuneinsight/lattigo/v5/ring" - "github.com/tuneinsight/lattigo/v5/utils" -) - -type defaultParametersLiteral struct { - SchemeParams hefloat.ParametersLiteral - BootstrappingParams ParametersLiteral -} - -// The parameters provided hereunder are the parameters used in the paper -// Bootstrapping for Approximate Homomorphic Encryption with Negligible -// Failure-Probability by Using Sparse-Secret Encapsulation, -// https://eprint.iacr.org/2022/024 - -// DefaultParametersSparse is a set of default bootstrapping parameters with H=192 as main secret and H=32 as ephemeral secret. -var DefaultParametersSparse = []defaultParametersLiteral{N16QP1546H192H32, N16QP1547H192H32, N16QP1553H192H32, N15QP768H192H32} - -// DefaultParametersDense is a set of default bootstrapping parameters with H=N/2 as main secret and H=32 as ephemeral secret. -var DefaultParametersDense = []defaultParametersLiteral{N16QP1767H32768H32, N16QP1788H32768H32, N16QP1793H32768H32, N15QP880H16384H32} - -var ( - // N16QP1546H192H32 is a default bootstrapping parameters for a main secret with H=192 and an ephemeral secret with H=32. - // Residual Q : []int{60, 40, 40, 40, 40, 40, 40, 40, 40, 40} (420 bits). - // SlotsToCoeffs Q: []int{39, 39, 39}. - // EvalMod Q: []int{60, 60, 60, 60, 60, 60, 60, 60}. - // CoeffsToSlots Q: []int{56, 56, 56, 56}. - // Precision : 26.6 bits for 2^{15} slots. - // Failure : 2^{-138.7} for 2^{15} slots. - N16QP1546H192H32 = defaultParametersLiteral{ - hefloat.ParametersLiteral{ - LogN: 16, - LogQ: []int{60, 40, 40, 40, 40, 40, 40, 40, 40, 40}, - LogP: []int{61, 61, 61, 61, 61}, - Xs: ring.Ternary{H: 192}, - LogDefaultScale: 40, - }, - ParametersLiteral{}, - } - - // N16QP1547H192H32 is a default bootstrapping parameters for a main secret with H=192 and an ephemeral secret with H=32. - // Residual Q : []int{60, 45, 45, 45, 45} (285 bits). - // SlotsToCoeffs Q: []int{42, 42, 42}. - // EvalMod Q: []int{60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60}. - // CoeffsToSlots Q: []int{58, 58, 58, 58}. - // Precision : 32.1 bits for 2^{15} slots. - // Failure : 2^{-138.7} for 2^{15} slots. - N16QP1547H192H32 = defaultParametersLiteral{ - hefloat.ParametersLiteral{ - LogN: 16, - LogQ: []int{60, 45, 45, 45, 45, 45}, - LogP: []int{61, 61, 61, 61}, - Xs: ring.Ternary{H: 192}, - LogDefaultScale: 45, - }, - ParametersLiteral{ - SlotsToCoeffsFactorizationDepthAndLogScales: [][]int{{42}, {42}, {42}}, - CoeffsToSlotsFactorizationDepthAndLogScales: [][]int{{58}, {58}, {58}, {58}}, - LogMessageRatio: utils.Pointy(2), - Mod1InvDegree: utils.Pointy(7), - }, - } - - // N16QP1553H192H32 is a default bootstrapping parameters for a main secret with H=192 and an ephemeral secret with H=32. - // Residual Q : []int{55, 60, 60, 60, 60, 60, 60, 60, 30} (505 bits). - // SlotsToCoeffs Q: []int{30, {30, 30}}. - // EvalMod Q: []int{55, 55, 55, 55, 55, 55, 55, 55}. - // CoeffsToSlots Q: []int{53, 53, 53, 53}. - // Precision : 19.1 bits for 2^{15} slots. - // Failure : 2^{-138.7} for 2^{15} slots. - N16QP1553H192H32 = defaultParametersLiteral{ - hefloat.ParametersLiteral{ - LogN: 16, - LogQ: []int{55, 60, 60, 60, 60, 60, 60, 60}, - LogP: []int{61, 61, 61, 61, 61}, - Xs: ring.Ternary{H: 192}, - LogDefaultScale: 30, - }, - ParametersLiteral{ - SlotsToCoeffsFactorizationDepthAndLogScales: [][]int{{30}, {30, 30}}, - CoeffsToSlotsFactorizationDepthAndLogScales: [][]int{{53}, {53}, {53}, {53}}, - EvalModLogScale: utils.Pointy(55), - }, - } - - // N15QP768H192H32 is a default bootstrapping parameters for a main secret with H=192 and an ephemeral secret with H=32. - // Residual Q : []int{32, 50, 25} (110 bits). - // SlotsToCoeffs Q: []int{60}. - // EvalMod Q: []int{50, 50, 50, 50, 50, 50, 50, 50}. - // CoeffsToSlots Q: []int{49, 49}. - // Precision : 15.4 bits for 2^{14} slots. - // Failure : 2^{-139.7} for 2^{14} slots. - N15QP768H192H32 = defaultParametersLiteral{ - hefloat.ParametersLiteral{ - LogN: 15, - LogQ: []int{33, 50, 25}, - LogP: []int{51, 51}, - Xs: ring.Ternary{H: 192}, - LogDefaultScale: 25, - }, - ParametersLiteral{ - SlotsToCoeffsFactorizationDepthAndLogScales: [][]int{{30, 30}}, - CoeffsToSlotsFactorizationDepthAndLogScales: [][]int{{49}, {49}}, - EvalModLogScale: utils.Pointy(50), - }, - } - - // N16QP1767H32768H32 is a default bootstrapping parameters for a main secret with H=32768 and an ephemeral secret with H=32. - // Residual Q : []int{60, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40} (580 bits). - // SlotsToCoeffs Q: []int{39, 39, 39}. - // EvalMod Q: []int{60, 60, 60, 60, 60, 60, 60, 60, 60}. - // CoeffsToSlots Q: []int{56, 56, 56, 56}. - // Precision : 23.8 bits for 2^{15} slots. - // Failure : 2^{-138.7} for 2^{15} slots. - N16QP1767H32768H32 = defaultParametersLiteral{ - hefloat.ParametersLiteral{ - LogN: 16, - LogQ: []int{60, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, - LogP: []int{61, 61, 61, 61, 61, 61}, - Xs: ring.Ternary{H: 32768}, - LogDefaultScale: 40, - }, - ParametersLiteral{}, - } - - // N16QP1788H32768H32 is a default bootstrapping parameters for a main secret with H=32768 and an ephemeral secret with H=32. - // Residual Q : []int{60, 45, 45, 45, 45, 45, 45, 45, 45, 45} (465 bits). - // SlotsToCoeffs Q: []int{42, 42, 42}. - // EvalMod Q: []int{60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60}. - // CoeffsToSlots Q: []int{58, 58, 58, 58}. - // Precision : 29.8 bits for 2^{15} slots. - // Failure : 2^{-138.7} for 2^{15} slots. - N16QP1788H32768H32 = defaultParametersLiteral{ - hefloat.ParametersLiteral{ - LogN: 16, - LogQ: []int{60, 45, 45, 45, 45, 45, 45, 45, 45, 45}, - LogP: []int{61, 61, 61, 61, 61}, - Xs: ring.Ternary{H: 32768}, - LogDefaultScale: 45, - }, - ParametersLiteral{ - SlotsToCoeffsFactorizationDepthAndLogScales: [][]int{{42}, {42}, {42}}, - CoeffsToSlotsFactorizationDepthAndLogScales: [][]int{{58}, {58}, {58}, {58}}, - LogMessageRatio: utils.Pointy(2), - Mod1InvDegree: utils.Pointy(7), - }, - } - - // N16QP1793H32768H32 is a default bootstrapping parameters for a main secret with H=32768 and an ephemeral secret with H=32. - // Residual Q : []int{55, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 30} 745 bits. - // SlotsToCoeffs Q: []int{30, 60}. - // EvalMod Q: []int{55, 55, 55, 55, 55, 55, 55, 55}. - // CoeffsToSlots Q: []int{53, 53, 53, 53}. - // Precision : 17.8 bits for 2^{15} slots. - // Failure : 2^{-138.7} for 2^{15} slots. - N16QP1793H32768H32 = defaultParametersLiteral{ - hefloat.ParametersLiteral{ - LogN: 16, - LogQ: []int{55, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 30}, - LogP: []int{61, 61, 61, 61, 61}, - Xs: ring.Ternary{H: 32768}, - LogDefaultScale: 30, - }, - ParametersLiteral{ - SlotsToCoeffsFactorizationDepthAndLogScales: [][]int{{30}, {30, 30}}, - CoeffsToSlotsFactorizationDepthAndLogScales: [][]int{{53}, {53}, {53}, {53}}, - EvalModLogScale: utils.Pointy(55), - }, - } - - // N15QP880H16384H32 is a default bootstrapping parameters for a main secret with H=16384 and an ephemeral secret with H=32. - // Residual Q : []int{40, 31, 31, 31, 31} (166 bits). - // SlotsToCoeffs Q: []int{60}. - // EvalMod Q: []int{55, 55, 55, 55, 55, 55, 55, 55}. - // CoeffsToSlots Q: []int{52, 52}. - // Precision : 17.3 bits for 2^{14} slots. - // Failure : 2^{-139.7} for 2^{14} slots. - N15QP880H16384H32 = defaultParametersLiteral{ - hefloat.ParametersLiteral{ - LogN: 15, - LogQ: []int{40, 31, 31, 31, 31}, - LogP: []int{56, 56}, - Xs: ring.Ternary{H: 16384}, - LogDefaultScale: 31, - }, - ParametersLiteral{ - SlotsToCoeffsFactorizationDepthAndLogScales: [][]int{{30, 30}}, - CoeffsToSlotsFactorizationDepthAndLogScales: [][]int{{52}, {52}}, - EvalModLogScale: utils.Pointy(55), - }, - } -) diff --git a/he/hefloat/bootstrapping/evaluator.go b/he/hefloat/bootstrapping/evaluator.go deleted file mode 100644 index bd582f21..00000000 --- a/he/hefloat/bootstrapping/evaluator.go +++ /dev/null @@ -1,223 +0,0 @@ -package bootstrapping - -import ( - "fmt" - "math" - "math/big" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he" - "github.com/tuneinsight/lattigo/v5/he/hefloat" - "github.com/tuneinsight/lattigo/v5/ring" - "github.com/tuneinsight/lattigo/v5/schemes/ckks" -) - -// Evaluator is a struct to store a memory buffer with the plaintext matrices, -// the polynomial approximation, and the keys for the bootstrapping. -// It is used to evaluate the bootstrapping circuit on single ciphertexts. -type Evaluator struct { - Parameters - *hefloat.Evaluator - *hefloat.DFTEvaluator - *hefloat.Mod1Evaluator - *EvaluationKeys - - ckks.DomainSwitcher - - // [1, x, x^2, x^4, ..., x^N1/2] / (X^N1 +1) - xPow2N1 []ring.Poly - // [1, x, x^2, x^4, ..., x^N2/2] / (X^N2 +1) - xPow2N2 []ring.Poly - // [1, x^-1, x^-2, x^-4, ..., x^-N2/2] / (X^N2 +1) - xPow2InvN2 []ring.Poly - - Mod1Parameters hefloat.Mod1Parameters - S2CDFTMatrix hefloat.DFTMatrix - C2SDFTMatrix hefloat.DFTMatrix - - SkDebug *rlwe.SecretKey -} - -// NewEvaluator creates a new [Evaluator]. -func NewEvaluator(btpParams Parameters, evk *EvaluationKeys) (eval *Evaluator, err error) { - - eval = &Evaluator{} - - paramsN1 := btpParams.ResidualParameters - paramsN2 := btpParams.BootstrappingParameters - - switch paramsN1.RingType() { - case ring.Standard: - if paramsN1.N() != paramsN2.N() && (evk.EvkN1ToN2 == nil || evk.EvkN2ToN1 == nil) { - return nil, fmt.Errorf("cannot NewBootstrapper: evk.(BootstrappingKeys) is missing EvkN1ToN2 and EvkN2ToN1") - } - case ring.ConjugateInvariant: - if evk.EvkCmplxToReal == nil || evk.EvkRealToCmplx == nil { - return nil, fmt.Errorf("cannot NewBootstrapper: evk.(BootstrappingKeys) is missing EvkN1ToN2 and EvkN2ToN1") - } - - var err error - if eval.DomainSwitcher, err = ckks.NewDomainSwitcher(paramsN2.Parameters, evk.EvkCmplxToReal, evk.EvkRealToCmplx); err != nil { - return nil, fmt.Errorf("cannot NewBootstrapper: ckks.NewDomainSwitcher: %w", err) - } - - // The switch to standard to conjugate invariant multiplies the scale by 2 - btpParams.SlotsToCoeffsParameters.Scaling = new(big.Float).SetFloat64(0.5) - } - - eval.Parameters = btpParams - - if paramsN1.N() != paramsN2.N() { - eval.xPow2N1 = he.GenXPow2NTT(paramsN1.RingQ().AtLevel(0), paramsN2.LogN(), false) - eval.xPow2N2 = he.GenXPow2NTT(paramsN2.RingQ().AtLevel(0), paramsN2.LogN(), false) - eval.xPow2InvN2 = he.GenXPow2NTT(paramsN2.RingQ(), paramsN2.LogN(), true) - } - - if btpParams.Mod1ParametersLiteral.Mod1Type == hefloat.SinContinuous && btpParams.Mod1ParametersLiteral.DoubleAngle != 0 { - return nil, fmt.Errorf("cannot use double angle formula for Mod1Type = Sin -> must use Mod1Type = Cos") - } - - if btpParams.Mod1ParametersLiteral.Mod1Type == hefloat.CosDiscrete && btpParams.Mod1ParametersLiteral.Mod1Degree < 2*(btpParams.Mod1ParametersLiteral.K-1) { - return nil, fmt.Errorf("Mod1Type 'hefloat.CosDiscrete' uses a minimum degree of 2*(K-1) but EvalMod degree is smaller") - } - - switch btpParams.CircuitOrder { - case ModUpThenEncode: - if btpParams.CoeffsToSlotsParameters.LevelQ-btpParams.CoeffsToSlotsParameters.Depth(true) != btpParams.Mod1ParametersLiteral.LevelQ { - return nil, fmt.Errorf("starting level and depth of CoeffsToSlotsParameters inconsistent starting level of Mod1ParametersLiteral") - } - - if btpParams.Mod1ParametersLiteral.LevelQ-btpParams.Mod1ParametersLiteral.Depth() != btpParams.SlotsToCoeffsParameters.LevelQ { - return nil, fmt.Errorf("starting level and depth of Mod1ParametersLiteral inconsistent starting level of CoeffsToSlotsParameters") - } - case DecodeThenModUp: - if btpParams.BootstrappingParameters.MaxLevel()-btpParams.CoeffsToSlotsParameters.Depth(true) != btpParams.Mod1ParametersLiteral.LevelQ { - return nil, fmt.Errorf("starting level and depth of Mod1ParametersLiteral inconsistent starting level of CoeffsToSlotsParameters") - } - case Custom: - default: - return nil, fmt.Errorf("invalid CircuitOrder value") - } - - if err = eval.initialize(btpParams); err != nil { - return - } - - if err = eval.checkKeys(evk); err != nil { - return - } - - params := btpParams.BootstrappingParameters - - eval.EvaluationKeys = evk - - eval.Evaluator = hefloat.NewEvaluator(params, evk) - - eval.DFTEvaluator = hefloat.NewDFTEvaluator(params, eval.Evaluator) - - eval.Mod1Evaluator = hefloat.NewMod1Evaluator(eval.Evaluator, hefloat.NewPolynomialEvaluator(params, eval.Evaluator), eval.Mod1Parameters) - - return -} - -// ShallowCopy creates a shallow copy of this [Evaluator] in which all the read-only data-structures are -// shared with the receiver and the temporary buffers are reallocated. The receiver and the returned -// Evaluator can be used concurrently. -func (eval Evaluator) ShallowCopy() *Evaluator { - heEvaluator := eval.Evaluator.ShallowCopy() - params := eval.BootstrappingParameters - return &Evaluator{ - Mod1Parameters: eval.Mod1Parameters, - S2CDFTMatrix: eval.S2CDFTMatrix, - C2SDFTMatrix: eval.C2SDFTMatrix, - Evaluator: heEvaluator, - DFTEvaluator: hefloat.NewDFTEvaluator(params, heEvaluator), - Mod1Evaluator: hefloat.NewMod1Evaluator(heEvaluator, hefloat.NewPolynomialEvaluator(params, heEvaluator), eval.Mod1Parameters), - } -} - -// CheckKeys checks if all the necessary keys are present in the instantiated [Evaluator] -func (eval Evaluator) checkKeys(evk *EvaluationKeys) (err error) { - - if _, err = evk.GetRelinearizationKey(); err != nil { - return - } - - for _, galEl := range eval.GaloisElements(eval.BootstrappingParameters) { - if _, err = evk.GetGaloisKey(galEl); err != nil { - return - } - } - - if evk.EvkDenseToSparse == nil && eval.EphemeralSecretWeight != 0 { - return fmt.Errorf("rlwe.EvaluationKey key dense to sparse is nil") - } - - if evk.EvkSparseToDense == nil && eval.EphemeralSecretWeight != 0 { - return fmt.Errorf("rlwe.EvaluationKey key sparse to dense is nil") - } - - return -} - -func (eval *Evaluator) initialize(btpParams Parameters) (err error) { - - eval.Parameters = btpParams - params := btpParams.BootstrappingParameters - - if eval.Mod1Parameters, err = hefloat.NewMod1ParametersFromLiteral(params, btpParams.Mod1ParametersLiteral); err != nil { - return - } - - scFac := eval.Mod1Parameters.ScFac() - K := eval.Mod1Parameters.K() / scFac - - // Correcting factor for approximate division by Q - // The second correcting factor for approximate multiplication by Q is included in the coefficients of the EvalMod polynomials - qDiff := eval.Mod1Parameters.QDiff() - - // If the scale used during the EvalMod step is smaller than Q0, then we cannot increase the scale during - // the EvalMod step to get a free division by MessageRatio, and we need to do this division (totally or partly) - // during the CoeffstoSlots step - qDiv := eval.Mod1Parameters.ScalingFactor().Float64() / math.Exp2(math.Round(math.Log2(float64(params.Q()[0])))) - - // Sets qDiv to 1 if there is enough room for the division to happen using scale manipulation. - if qDiv > 1 { - qDiv = 1 - } - - encoder := hefloat.NewEncoder(params) - - // CoeffsToSlots vectors - // Change of variable for the evaluation of the Chebyshev polynomial + cancelling factor for the DFT and SubSum + eventual scaling factor for the double angle formula - - scale := eval.BootstrappingParameters.DefaultScale().Float64() - offset := eval.Mod1Parameters.ScalingFactor().Float64() / eval.Mod1Parameters.MessageRatio() - - C2SScaling := new(big.Float).SetFloat64(qDiv / (K * scFac * qDiff)) - StCScaling := new(big.Float).SetFloat64(scale / offset) - - if eval.CoeffsToSlotsParameters.Scaling == nil { - eval.CoeffsToSlotsParameters.Scaling = C2SScaling - } else { - eval.CoeffsToSlotsParameters.Scaling.Mul(eval.CoeffsToSlotsParameters.Scaling, C2SScaling) - } - - if eval.SlotsToCoeffsParameters.Scaling == nil { - eval.SlotsToCoeffsParameters.Scaling = StCScaling - } else { - eval.SlotsToCoeffsParameters.Scaling.Mul(eval.SlotsToCoeffsParameters.Scaling, StCScaling) - } - - if eval.C2SDFTMatrix, err = hefloat.NewDFTMatrixFromLiteral(params, eval.CoeffsToSlotsParameters, encoder); err != nil { - return - } - - if eval.S2CDFTMatrix, err = hefloat.NewDFTMatrixFromLiteral(params, eval.SlotsToCoeffsParameters, encoder); err != nil { - return - } - - encoder = nil // For the GC - - return -} diff --git a/he/hefloat/bootstrapping/evaluator_bench_test.go b/he/hefloat/bootstrapping/evaluator_bench_test.go deleted file mode 100644 index 817e7ca4..00000000 --- a/he/hefloat/bootstrapping/evaluator_bench_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package bootstrapping - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" -) - -func BenchmarkBootstrap(b *testing.B) { - - paramSet := DefaultParametersDense[0] - - params, err := hefloat.NewParametersFromLiteral(paramSet.SchemeParams) - require.NoError(b, err) - - btpParams, err := NewParametersFromLiteral(params, paramSet.BootstrappingParams) - require.Nil(b, err) - - kgen := rlwe.NewKeyGenerator(params) - sk := kgen.GenSecretKeyNew() - - evk, _, err := btpParams.GenEvaluationKeys(sk) - require.NoError(b, err) - - eval, err := NewEvaluator(btpParams, evk) - require.NoError(b, err) - - b.Run(ParamsToString(params, btpParams.LogMaxDimensions().Cols, "Bootstrap/"), func(b *testing.B) { - - var err error - - for i := 0; i < b.N; i++ { - - b.StopTimer() - ct := hefloat.NewCiphertext(params, 1, 0) - b.StartTimer() - - var t time.Time - var ct0, ct1 *rlwe.Ciphertext - - // ScaleDown - t = time.Now() - ct, _, err = eval.ScaleDown(ct) - require.NoError(b, err) - b.Log("ScaleDown:", time.Since(t), ct.Level(), ct.Scale.Float64()) - - // ModUp ct_{Q_0} -> ct_{Q_L} - t = time.Now() - ct, err = eval.ModUp(ct) - require.NoError(b, err) - b.Log("ModUp :", time.Since(t), ct.Level(), ct.Scale.Float64()) - - // Part 1 : Coeffs to slots - t = time.Now() - ct0, ct1, err = eval.CoeffsToSlots(ct) - require.NoError(b, err) - b.Log("CtS :", time.Since(t), ct0.Level(), ct0.Scale.Float64()) - - // Part 2 : SineEval - t = time.Now() - ct0, err = eval.EvalMod(ct0) - require.NoError(b, err) - if ct1 != nil { - ct1, err = eval.EvalMod(ct1) - require.NoError(b, err) - } - b.Log("EvalMod :", time.Since(t), ct0.Level(), ct0.Scale.Float64()) - - // Part 3 : Slots to coeffs - t = time.Now() - ct0, err = eval.SlotsToCoeffs(ct0, ct1) - require.NoError(b, err) - b.Log("StC :", time.Since(t), ct0.Level(), ct0.Scale.Float64()) - } - }) -} diff --git a/he/hefloat/bootstrapping/evaluator_test.go b/he/hefloat/bootstrapping/evaluator_test.go deleted file mode 100644 index 434c6c4f..00000000 --- a/he/hefloat/bootstrapping/evaluator_test.go +++ /dev/null @@ -1,319 +0,0 @@ -package bootstrapping - -import ( - "fmt" - "runtime" - "sync" - "testing" - - "github.com/stretchr/testify/require" - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" - "github.com/tuneinsight/lattigo/v5/utils" - "github.com/tuneinsight/lattigo/v5/utils/sampling" -) - -var minPrec float64 = 12.0 - -func ParamsToString(params hefloat.Parameters, LogSlots int, opname string) string { - return fmt.Sprintf("%slogN=%d/LogSlots=%d/logQP=%f/levels=%d/a=%d/b=%d", - opname, - params.LogN(), - LogSlots, - params.LogQP(), - params.MaxLevel()+1, - params.PCount(), - params.BaseRNSDecompositionVectorSize(params.MaxLevelQ(), params.MaxLevelP())) -} - -func TestParametersMarshalling(t *testing.T) { - - t.Run("ParametersLiteral", func(t *testing.T) { - - paramsLit := ParametersLiteral{ - CoeffsToSlotsFactorizationDepthAndLogScales: [][]int{{53}, {53}, {53}, {53}}, - SlotsToCoeffsFactorizationDepthAndLogScales: [][]int{{30}, {30, 30}}, - EvalModLogScale: utils.Pointy(59), - EphemeralSecretWeight: utils.Pointy(1), - IterationsParameters: &IterationsParameters{BootstrappingPrecision: []float64{20, 20}, ReservedPrimeBitSize: 20}, - Mod1Degree: utils.Pointy(32), - Mod1InvDegree: utils.Pointy(7), - } - - data, err := paramsLit.MarshalBinary() - require.Nil(t, err) - - paramsLitNew := new(ParametersLiteral) - if err := paramsLitNew.UnmarshalBinary(data); err != nil { - require.Nil(t, err) - } - require.Equal(t, paramsLit, *paramsLitNew) - }) - - t.Run("Parameters", func(t *testing.T) { - paramSet := DefaultParametersSparse[0] - - params, err := hefloat.NewParametersFromLiteral(paramSet.SchemeParams) - require.Nil(t, err) - - btpParams, err := NewParametersFromLiteral(params, paramSet.BootstrappingParams) - require.Nil(t, err) - - data, err := btpParams.MarshalBinary() - require.Nil(t, err) - btpParamsNew := new(Parameters) - if err := btpParamsNew.UnmarshalBinary(data); err != nil { - require.Nil(t, err) - } - - require.True(t, btpParams.Equal(btpParamsNew)) - }) -} - -func TestCircuitWithEncapsulation(t *testing.T) { - - if runtime.GOARCH == "wasm" { - t.Skip("skipping bootstrapping tests for GOARCH=wasm") - } - - paramSet := DefaultParametersSparse[0] - - if !*flagLongTest { - paramSet.SchemeParams.LogN -= 3 - } - - paramSet.BootstrappingParams.LogN = utils.Pointy(paramSet.SchemeParams.LogN) - - for _, LogSlots := range []int{1, paramSet.SchemeParams.LogN - 2, paramSet.SchemeParams.LogN - 1} { - paramsSetCpy := paramSet - - level := utils.Min(1, len(paramSet.SchemeParams.LogQ)) - - paramsSetCpy.SchemeParams.LogQ = paramSet.SchemeParams.LogQ[:level+1] - - paramsSetCpy.BootstrappingParams.LogSlots = &LogSlots - - params, err := hefloat.NewParametersFromLiteral(paramsSetCpy.SchemeParams) - require.NoError(t, err) - - btpParams, err := NewParametersFromLiteral(params, paramsSetCpy.BootstrappingParams) - require.NoError(t, err) - - // Insecure params for fast testing only - if !*flagLongTest { - // Corrects the message ratio to take into account the smaller number of slots and keep the same precision - btpParams.Mod1ParametersLiteral.LogMessageRatio += utils.Min(utils.Max(15-LogSlots, 0), 8) - } - - testRawCircuit(params, btpParams, level, t) - runtime.GC() - } - - testRawCircuitHighPrecision(paramSet, t) -} - -func TestCircuitOriginal(t *testing.T) { - - if runtime.GOARCH == "wasm" { - t.Skip("skipping bootstrapping tests for GOARCH=wasm") - } - - paramSet := DefaultParametersDense[0] - - if !*flagLongTest { - paramSet.SchemeParams.LogN -= 3 - } - - paramSet.BootstrappingParams.LogN = utils.Pointy(paramSet.SchemeParams.LogN) - - for _, LogSlots := range []int{1, paramSet.SchemeParams.LogN - 2, paramSet.SchemeParams.LogN - 1} { - - paramsSetCpy := paramSet - - level := utils.Min(1, len(paramSet.SchemeParams.LogQ)) - - paramsSetCpy.SchemeParams.LogQ = paramSet.SchemeParams.LogQ[:level+1] - - paramsSetCpy.BootstrappingParams.LogSlots = &LogSlots - - params, err := hefloat.NewParametersFromLiteral(paramsSetCpy.SchemeParams) - require.NoError(t, err) - - btpParams, err := NewParametersFromLiteral(params, paramsSetCpy.BootstrappingParams) - require.NoError(t, err) - - // Insecure params for fast testing only - if !*flagLongTest { - // Corrects the message ratio to take into account the smaller number of slots and keep the same precision - btpParams.Mod1ParametersLiteral.LogMessageRatio += utils.Min(utils.Max(15-LogSlots, 0), 8) - } - - testRawCircuit(params, btpParams, level, t) - runtime.GC() - } - - testRawCircuitHighPrecision(paramSet, t) -} - -func testRawCircuit(params hefloat.Parameters, btpParams Parameters, level int, t *testing.T) { - - t.Run(ParamsToString(params, btpParams.LogMaxSlots(), ""), func(t *testing.T) { - - kgen := rlwe.NewKeyGenerator(btpParams.BootstrappingParameters) - sk := kgen.GenSecretKeyNew() - encoder := hefloat.NewEncoder(params) - - encryptor := rlwe.NewEncryptor(params, sk) - decryptor := rlwe.NewDecryptor(params, sk) - - evk, _, err := btpParams.GenEvaluationKeys(sk) - require.NoError(t, err) - - eval, err := NewEvaluator(btpParams, evk) - require.NoError(t, err) - - values := make([]complex128, 1< 1 { - values[2] = complex(0.9238795325112867, 0.3826834323650898) - values[3] = complex(0.9238795325112867, 0.3826834323650898) - } - - plaintext := hefloat.NewPlaintext(params, 0) - plaintext.Scale = params.DefaultScale() - plaintext.LogDimensions = btpParams.LogMaxDimensions() - encoder.Encode(values, plaintext) - - n := 1 - - ciphertexts := make([]*rlwe.Ciphertext, n) - evaluators := make([]*Evaluator, n) - evaluators[0] = eval - ciphertexts[0], err = encryptor.EncryptNew(plaintext) - require.NoError(t, err) - for i := 1; i < len(ciphertexts); i++ { - ciphertexts[i], err = encryptor.EncryptNew(plaintext) - require.NoError(t, err) - evaluators[i] = evaluators[0].ShallowCopy() - } - - var wg sync.WaitGroup - wg.Add(n) - for i := range ciphertexts { - go func(index int) { - var err error - ciphertexts[index], err = evaluators[index].Evaluate(ciphertexts[index]) - require.NoError(t, err) - wg.Done() - }(i) - } - wg.Wait() - - for i := range ciphertexts { - require.True(t, ciphertexts[i].Level() == level) - } - - for i := range ciphertexts { - verifyTestVectors(params, encoder, decryptor, values, ciphertexts[i], t) - } - }) -} - -func testRawCircuitHighPrecision(paramSet defaultParametersLiteral, t *testing.T) { - - t.Run("HighPrecision", func(t *testing.T) { - - level := utils.Min(1, len(paramSet.SchemeParams.LogQ)) - - paramSet.SchemeParams.LogQ = paramSet.SchemeParams.LogQ[:level+1] - - paramSet.SchemeParams.LogDefaultScale = 80 - - paramSet.BootstrappingParams.IterationsParameters = &IterationsParameters{ - BootstrappingPrecision: []float64{25, 25}, - ReservedPrimeBitSize: 28, - } - - params, err := hefloat.NewParametersFromLiteral(paramSet.SchemeParams) - if err != nil { - panic(err) - } - - btpParams, err := NewParametersFromLiteral(params, paramSet.BootstrappingParams) - - if err != nil { - t.Fatal(err) - } - - // Insecure params for fast testing only - if !*flagLongTest { - // Corrects the message ratio to take into account the smaller number of slots and keep the same precision - btpParams.Mod1ParametersLiteral.LogMessageRatio += utils.Min(utils.Max(16-params.LogN(), 0), 8) - } - - t.Run(ParamsToString(params, btpParams.LogMaxSlots(), ""), func(t *testing.T) { - - kgen := rlwe.NewKeyGenerator(btpParams.BootstrappingParameters) - sk := kgen.GenSecretKeyNew() - encoder := hefloat.NewEncoder(params) - encryptor := rlwe.NewEncryptor(params, sk) - decryptor := rlwe.NewDecryptor(params, sk) - - evk, _, err := btpParams.GenEvaluationKeys(sk) - require.NoError(t, err) - - eval, err := NewEvaluator(btpParams, evk) - require.NoError(t, err) - - values := make([]complex128, 1< 1 { - values[2] = complex(0.9238795325112867, 0.3826834323650898) - values[3] = complex(0.9238795325112867, 0.3826834323650898) - } - - plaintext := hefloat.NewPlaintext(params, level) - plaintext.Scale = params.DefaultScale() - - plaintext.LogDimensions = btpParams.LogMaxDimensions() - encoder.Encode(values, plaintext) - - ciphertext, err := encryptor.EncryptNew(plaintext) - require.NoError(t, err) - - ciphertext, err = eval.Evaluate(ciphertext) - require.NoError(t, err) - - require.True(t, ciphertext.Level() == level) - - verifyTestVectors(params, encoder, decryptor, values, ciphertext, t) - }) - - runtime.GC() - }) -} - -func verifyTestVectors(params hefloat.Parameters, encoder *hefloat.Encoder, decryptor *rlwe.Decryptor, valuesWant, valuesHave interface{}, t *testing.T) { - precStats := hefloat.GetPrecisionStats(params, encoder, decryptor, valuesWant, valuesHave, 0, false) - if *printPrecisionStats { - t.Log(precStats.String()) - } - - rf64, _ := precStats.MeanPrecision.Real.Float64() - if64, _ := precStats.MeanPrecision.Imag.Float64() - - require.GreaterOrEqual(t, rf64, minPrec) - require.GreaterOrEqual(t, if64, minPrec) -} diff --git a/he/hefloat/comparisons.go b/he/hefloat/comparisons.go deleted file mode 100644 index 4a0ab260..00000000 --- a/he/hefloat/comparisons.go +++ /dev/null @@ -1,196 +0,0 @@ -package hefloat - -import ( - "math/big" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he" - "github.com/tuneinsight/lattigo/v5/utils" - "github.com/tuneinsight/lattigo/v5/utils/bignum" -) - -// ComparisonEvaluator is an evaluator providing an API for homomorphic comparisons. -// All fields of this struct are public, enabling custom instantiations. -type ComparisonEvaluator struct { - MinimaxCompositePolynomialEvaluator - MinimaxCompositeSignPolynomial MinimaxCompositePolynomial -} - -// NewComparisonEvaluator instantiates a new ComparisonEvaluator. -// The default hefloat.Evaluator is compliant with the EvaluatorForMinimaxCompositePolynomial interface. -// The field he.Bootstrapper[rlwe.Ciphertext] can be nil if the parameters have enough level to support the computation. -// -// Giving a MinimaxCompositePolynomial is optional, but it is highly recommended to provide one that is optimized -// for the circuit requiring the comparisons as this polynomial will define the internal precision of all computations -// performed by this evaluator. -// -// The MinimaxCompositePolynomial must be a composite minimax approximation of the sign function: -// f(x) = 1 if x > 0, -1 if x < 0, else 0, in the interval [-1, 1]. -// Such composite polynomial can be obtained with the function GenMinimaxCompositePolynomialForSign. -// -// If no MinimaxCompositePolynomial is given, then it will use by default the variable DefaultMinimaxCompositePolynomialForSign. -// See the doc of DefaultMinimaxCompositePolynomialForSign for additional information about the performance of this approximation. -// -// This method is allocation free if a MinimaxCompositePolynomial is given. -func NewComparisonEvaluator(params Parameters, eval EvaluatorForMinimaxCompositePolynomial, bootstrapper he.Bootstrapper[rlwe.Ciphertext], signPoly ...MinimaxCompositePolynomial) *ComparisonEvaluator { - if len(signPoly) == 1 { - return &ComparisonEvaluator{*NewMinimaxCompositePolynomialEvaluator(params, eval, bootstrapper), signPoly[0]} - } else { - return &ComparisonEvaluator{*NewMinimaxCompositePolynomialEvaluator(params, eval, bootstrapper), NewMinimaxCompositePolynomial(DefaultMinimaxCompositePolynomialForSign)} - } -} - -// DefaultMinimaxCompositePolynomialForSign is an example of composite minimax polynomial -// for the sign function that is able to distinguish between value with a delta of up to -// 2^{-alpha=30}, tolerates a scheme error of 2^{-35} and outputs a binary value (-1, or 1) -// of up to 20x4 bits of precision. -// -// It was computed with GenMinimaxCompositePolynomialForSign(256, 30, 35, []int{15, 15, 15, 17, 31, 31, 31, 31}) -// which outputs a minimax composite polynomial of precision 21.926741, which is further composed with -// CoeffsSignX4Cheby to bring it to ~80bits of precision. -var DefaultMinimaxCompositePolynomialForSign = [][]string{ - {"0", "0.6371462957672043333", "0", "-0.2138032460610765328", "0", "0.1300439303835664499", "0", "-0.0948842756566191044", "0", "0.0760417811618939909", "0", "-0.0647714820920817557", "0", "0.0577904411211959048", "0", "-0.5275634328386103792"}, - {"0", "0.6371463830322414578", "0", "-0.2138032749880402509", "0", "0.1300439475440832118", "0", "-0.0948842877009570762", "0", "0.0760417903036533484", "0", "-0.0647714893343788749", "0", "0.0577904470018789283", "0", "-0.5275633669027163690"}, - {"0", "0.6371474873319408921", "0", "-0.2138036410457105809", "0", "0.1300441647026617059", "0", "-0.0948844401165889295", "0", "0.0760419059884502454", "0", "-0.0647715809823254389", "0", "0.0577905214191996406", "0", "-0.5275625325136631842"}, - {"0", "0.6370469776996076431", "0", "-0.2134526779726600620", "0", "0.1294300181775238920", "0", "-0.0939692999460324791", "0", "0.0747629355709698798", "0", "-0.0630298319949635571", "0", "0.0554299627688379896", "0", "-0.0504549111784642023", "0", "0.5242368268605847996"}, - {"0", "0.6371925153898374380", "0", "-0.2127272333844484291", "0", "0.1280350175397897124", "0", "-0.0918861831051024970", "0", "0.0719237384158242601", "0", "-0.0593247422790627989", "0", "0.0506973946536399213", "0", "-0.0444605229007162961", "0", "0.0397788020190944552", "0", "-0.0361705584687241925", "0", "0.0333397971860406254", "0", "-0.0310960060432036761", "0", "0.0293126335952747929", "0", "-0.0279042579223662982", "0", "0.0268135229627401517", "0", "-0.5128179323757194002"}, - {"0", "0.6484328404896112084", "0", "-0.2164688471885406655", "0", "0.1302737771018761402", "0", "-0.0934786176742356885", "0", "0.0731553324133884104", "0", "-0.0603252338481440981", "0", "0.0515366139595849853", "0", "-0.0451803385226980999", "0", "0.0404062758116036740", "0", "-0.0367241775307736352", "0", "0.0338327393147257876", "0", "-0.0315379870551266008", "0", "0.0297110181467332488", "0", "-0.0282647625290482803", "0", "0.0271406820054187399", "0", "-0.5041440308249296747"}, - {"0", "0.8988231150519633581", "0", "-0.2996064625122592138", "0", "0.1797645789317822353", "0", "-0.1284080039344265678", "0", "0.0998837306152582349", "0", "-0.0817422066647773587", "0", "0.0691963884439569899", "0", "-0.0600136111161848355", "0", "0.0530132660795356506", "0", "-0.0475133961913746909", "0", "0.0430936248086665091", "0", "-0.0394819050695222720", "0", "0.0364958013826412785", "0", "-0.0340100990129699835", "0", "0.0319381346687564699", "0", "-0.3095637759472512887"}, - {"0", "1.2654405107323937767", "0", "-0.4015427502443620045", "0", "0.2182109348265640036", "0", "-0.1341692540177466882", "0", "0.0852282854825304735", "0", "-0.0539043807248265057", "0", "0.0332611560159092728", "0", "-0.0197419082926337129", "0", "0.0111368708758574529", "0", "-0.0058990205011466309", "0", "0.0028925861201479251", "0", "-0.0012889673944941461", "0", "0.0005081425552893727", "0", "-0.0001696330470066833", "0", "0.0000440808328172753", "0", "-0.0000071549240608255"}, - CoeffsSignX4Cheby, // Quadruples the output precision (up to the scheme error) -} - -// Sign evaluates f(x) = 1 if x > 0, -1 if x < 0, else 0. -// This will ensure that sign.Scale = params.DefaultScale(). -func (eval ComparisonEvaluator) Sign(op0 *rlwe.Ciphertext) (sign *rlwe.Ciphertext, err error) { - return eval.Evaluate(op0, eval.MinimaxCompositeSignPolynomial) -} - -// Step evaluates f(x) = 1 if x > 0, 0 if x < 0, else 0.5 (i.e. (sign+1)/2). -// This will ensure that step.Scale = params.DefaultScale(). -func (eval ComparisonEvaluator) Step(op0 *rlwe.Ciphertext) (step *rlwe.Ciphertext, err error) { - - n := len(eval.MinimaxCompositeSignPolynomial) - - stepPoly := make([]bignum.Polynomial, n) - - for i := 0; i < n; i++ { - stepPoly[i] = eval.MinimaxCompositeSignPolynomial[i] - } - - half := new(big.Float).SetFloat64(0.5) - - // (x+1)/2 - lastPoly := eval.MinimaxCompositeSignPolynomial[n-1].Clone() - for i := range lastPoly.Coeffs { - lastPoly.Coeffs[i][0].Mul(lastPoly.Coeffs[i][0], half) - } - lastPoly.Coeffs[0][0].Add(lastPoly.Coeffs[0][0], half) - - stepPoly[n-1] = lastPoly - - return eval.Evaluate(op0, stepPoly) -} - -// Max returns the smooth maximum of op0 and op1, which is defined as: op0 * x + op1 * (1-x) where x = step(diff = op0-op1). -// Use must ensure that: -// - op0 + op1 is in the interval [-1, 1]. -// - op0.Scale = op1.Scale. -// -// This method ensures that max.Scale = params.DefaultScale. -func (eval ComparisonEvaluator) Max(op0, op1 *rlwe.Ciphertext) (max *rlwe.Ciphertext, err error) { - - // step * diff - var stepdiff *rlwe.Ciphertext - if stepdiff, err = eval.stepdiff(op0, op1); err != nil { - return - } - - // max = step * diff + op1 - if err = eval.Add(stepdiff, op1, stepdiff); err != nil { - return - } - - return stepdiff, nil -} - -// Min returns the smooth min of op0 and op1, which is defined as: op0 * (1-x) + op1 * x where x = step(diff = op0-op1) -// Use must ensure that: -// - op0 + op1 is in the interval [-1, 1]. -// - op0.Scale = op1.Scale. -// -// This method ensures that min.Scale = params.DefaultScale. -func (eval ComparisonEvaluator) Min(op0, op1 *rlwe.Ciphertext) (min *rlwe.Ciphertext, err error) { - - // step * diff - var stepdiff *rlwe.Ciphertext - if stepdiff, err = eval.stepdiff(op0, op1); err != nil { - return - } - - // min = op0 - step * diff - if err = eval.Sub(op0, stepdiff, stepdiff); err != nil { - return - } - - return stepdiff, nil -} - -func (eval ComparisonEvaluator) stepdiff(op0, op1 *rlwe.Ciphertext) (stepdiff *rlwe.Ciphertext, err error) { - params := eval.Parameters - - // diff = op0 - op1 - var diff *rlwe.Ciphertext - if diff, err = eval.SubNew(op0, op1); err != nil { - return - } - - // Required for the scale matching before the last multiplication. - if diff.Level() < params.LevelsConsumedPerRescaling()*2 { - if diff, err = eval.Bootstrap(diff); err != nil { - return - } - } - - // step = 1 if diff > 0, 0 if diff < 0 else 0.5 - var step *rlwe.Ciphertext - if step, err = eval.Step(diff); err != nil { - return - } - - // Required for the following multiplication - if step.Level() < params.LevelsConsumedPerRescaling() { - if step, err = eval.Bootstrap(step); err != nil { - return - } - } - - // Extremum gate: op0 * step + op1 * (1 - step) = step * diff + op1 - level := utils.Min(diff.Level(), step.Level()) - - ratio := rlwe.NewScale(1) - for i := 0; i < params.LevelsConsumedPerRescaling(); i++ { - ratio = ratio.Mul(rlwe.NewScale(params.Q()[level-i])) - } - - ratio = ratio.Div(diff.Scale) - if err = eval.Mul(diff, &ratio.Value, diff); err != nil { - return - } - - if err = eval.Rescale(diff, diff); err != nil { - return - } - diff.Scale = diff.Scale.Mul(ratio) - - // max = step * diff - if err = eval.MulRelin(diff, step, diff); err != nil { - return - } - - if err = eval.Rescale(diff, diff); err != nil { - return - } - - return diff, nil -} diff --git a/he/hefloat/comparisons_test.go b/he/hefloat/comparisons_test.go deleted file mode 100644 index 667c31f4..00000000 --- a/he/hefloat/comparisons_test.go +++ /dev/null @@ -1,154 +0,0 @@ -package hefloat_test - -import ( - "math/big" - "testing" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" - "github.com/tuneinsight/lattigo/v5/he/hefloat/bootstrapping" - "github.com/tuneinsight/lattigo/v5/ring" - - "github.com/stretchr/testify/require" -) - -func TestComparisons(t *testing.T) { - - paramsLiteral := testInsecurePrec90 - - for _, ringType := range []ring.Type{ring.Standard, ring.ConjugateInvariant} { - - paramsLiteral.RingType = ringType - - if testing.Short() { - paramsLiteral.LogN = 10 - } - - params, err := hefloat.NewParametersFromLiteral(paramsLiteral) - require.NoError(t, err) - - var tc *testContext - if tc, err = genTestParams(params); err != nil { - t.Fatal(err) - } - - enc := tc.encryptorSk - sk := tc.sk - ecd := tc.encoder - dec := tc.decryptor - kgen := tc.kgen - - btp := bootstrapping.NewSecretKeyBootstrapper(params, sk) - - var galKeys []*rlwe.GaloisKey - if params.RingType() == ring.Standard { - galKeys = append(galKeys, kgen.GenGaloisKeyNew(params.GaloisElementForComplexConjugation(), sk)) - } - - eval := tc.evaluator.WithKey(rlwe.NewMemEvaluationKeySet(kgen.GenRelinearizationKeyNew(sk), galKeys...)) - - polys := hefloat.NewMinimaxCompositePolynomial(hefloat.DefaultMinimaxCompositePolynomialForSign) - - CmpEval := hefloat.NewComparisonEvaluator(params, eval, btp, polys) - - t.Run(GetTestName(params, "Sign"), func(t *testing.T) { - - values, _, ct := newTestVectors(tc, enc, complex(-1, 0), complex(1, 0), t) - - var sign *rlwe.Ciphertext - sign, err = CmpEval.Sign(ct) - require.NoError(t, err) - - have := make([]*big.Float, params.MaxSlots()) - - require.NoError(t, ecd.Decode(dec.DecryptNew(sign), have)) - - want := make([]*big.Float, params.MaxSlots()) - - for i := range have { - want[i] = polys.Evaluate(values[i])[0] - } - - hefloat.VerifyTestVectors(params, ecd, nil, want, have, params.LogDefaultScale(), 0, *printPrecisionStats, t) - }) - - t.Run(GetTestName(params, "Step"), func(t *testing.T) { - - values, _, ct := newTestVectors(tc, enc, complex(-1, 0), complex(1, 0), t) - - var step *rlwe.Ciphertext - step, err = CmpEval.Step(ct) - require.NoError(t, err) - - have := make([]*big.Float, params.MaxSlots()) - - require.NoError(t, ecd.Decode(dec.DecryptNew(step), have)) - - want := make([]*big.Float, params.MaxSlots()) - - half := new(big.Float).SetFloat64(0.5) - - for i := range have { - want[i] = polys.Evaluate(values[i])[0] - want[i].Mul(want[i], half) - want[i].Add(want[i], half) - } - - hefloat.VerifyTestVectors(params, ecd, nil, want, have, params.LogDefaultScale(), 0, *printPrecisionStats, t) - }) - - t.Run(GetTestName(params, "Max"), func(t *testing.T) { - - values0, _, ct0 := newTestVectors(tc, enc, complex(-0.5, 0), complex(0.5, 0), t) - values1, _, ct1 := newTestVectors(tc, enc, complex(-0.5, 0), complex(0.5, 0), t) - - var max *rlwe.Ciphertext - max, err = CmpEval.Max(ct0, ct1) - require.NoError(t, err) - - have := make([]*big.Float, params.MaxSlots()) - - require.NoError(t, ecd.Decode(dec.DecryptNew(max), have)) - - want := make([]*big.Float, params.MaxSlots()) - - for i := range have { - - if values0[i][0].Cmp(values1[i][0]) == -1 { - want[i] = values1[i][0] - } else { - want[i] = values0[i][0] - } - } - - hefloat.VerifyTestVectors(params, ecd, nil, want, have, params.LogDefaultScale(), 0, *printPrecisionStats, t) - }) - - t.Run(GetTestName(params, "Min"), func(t *testing.T) { - - values0, _, ct0 := newTestVectors(tc, enc, complex(-0.5, 0), complex(0.5, 0), t) - values1, _, ct1 := newTestVectors(tc, enc, complex(-0.5, 0), complex(0.5, 0), t) - - var max *rlwe.Ciphertext - max, err = CmpEval.Min(ct0, ct1) - require.NoError(t, err) - - have := make([]*big.Float, params.MaxSlots()) - - require.NoError(t, ecd.Decode(dec.DecryptNew(max), have)) - - want := make([]*big.Float, params.MaxSlots()) - - for i := range have { - - if values0[i][0].Cmp(values1[i][0]) == 1 { - want[i] = values1[i][0] - } else { - want[i] = values0[i][0] - } - } - - hefloat.VerifyTestVectors(params, ecd, nil, want, have, params.LogDefaultScale(), 0, *printPrecisionStats, t) - }) - } -} diff --git a/he/hefloat/cosine/cosine_approx.go b/he/hefloat/cosine/cosine_approx.go deleted file mode 100644 index 83f229e9..00000000 --- a/he/hefloat/cosine/cosine_approx.go +++ /dev/null @@ -1,377 +0,0 @@ -// Package cosine method is the Go implementation of the polynomial-approximation algorithm by Han and Ki in -// -// "Better Bootstrapping for Approximate Homomorphic Encryption", . -// -// The algorithm was originally implemented in C++, available at -// -// https://github.com/DohyeongKi/better-homomorphic-sine-evaluation -package cosine - -import ( - "math" - "math/big" - - "github.com/tuneinsight/lattigo/v5/utils/bignum" -) - -const ( - EncodingPrecision = uint(256) -) - -var ( - log2TwoPi = math.Log2(2 * math.Pi) - aQuarter = bignum.NewFloat(0.25, EncodingPrecision) - pi = bignum.Pi(EncodingPrecision) -) - -// ApproximateCos computes a polynomial approximation of degree "degree" in Chebyshev basis of the function -// cos(2*pi*x/2^"scnum") in the range -"K" to "K" -// The nodes of the Chebyshev approximation are are located from -dev to +dev at each integer value between -K and -K -func ApproximateCos(K, degree int, dev float64, scnum int) []*big.Float { - - // Gets the list of degree per interval and the total degree - deg, totdeg := genDegrees(degree, K, dev) - - // Generates the nodes for each interval, updates the total degree if needed - nodes, y := genNodes(deg, dev, totdeg, K, scnum) - - // Solves the linear system and returns the coefficients - return solve(totdeg, K, scnum, nodes, y)[:totdeg] -} - -// y = cos(2 * pi * (x - 0.25)/r) -func cos2PiXMinusQuarterOverR(x, r *big.Float) (y *big.Float) { - //y = 2 * pi - y = bignum.NewFloat(2.0, EncodingPrecision) - y.Mul(y, pi) - - // x = (x - 0.25)/r - x.Sub(x, aQuarter) - x.Quo(x, r) - - // y = 2 * pi * (x - 0.25)/r - y.Mul(y, x) - - // y = cos(2 * pi * (x - 0.25)/r) - return bignum.Cos(y) -} - -func log2(x float64) float64 { - return math.Log2(x) -} - -func abs(x float64) float64 { - return math.Abs(x) -} - -func maxIndex(array []float64) (maxind int) { - max := array[0] - for i := 1; i < len(array); i++ { - if array[i] > max { - maxind = i - max = array[i] - } - } - - return -} - -// genDegrees returns the optimal list of nodes for each of the 0 <= i < K intervals [i +/- dev] -// such that the sum of the nodes of all intervals is equal to degree. -func genDegrees(degree, K int, dev float64) ([]int, int) { - - var degbdd = degree + 1 - - var totdeg = 2*K - 1 - - var err = 1.0 / dev - - var deg = make([]int, K) - for i := 0; i < K; i++ { - deg[i] = 1 - } - - var bdd = make([]float64, K) - var temp = float64(0) - for i := 1; i <= (2*K - 1); i++ { - temp -= log2(float64(i)) - } - temp += (2*float64(K) - 1) * log2TwoPi - temp += log2(err) - - for i := 0; i < K; i++ { - bdd[i] = temp - for j := 1; j <= K-1-i; j++ { - bdd[i] += log2(float64(j) + err) - } - for j := 1; j <= K-1+i; j++ { - bdd[i] += log2(float64(j) + err) - } - } - - var maxiter = 200 - var iter int - - for iter = 0; iter < maxiter; iter++ { - if totdeg >= degbdd { - break - } - var maxi = maxIndex(bdd) - - if maxi != 0 { - if totdeg+2 > degbdd { - break - } - - for i := 0; i < K; i++ { - bdd[i] -= log2(float64(totdeg + 1)) - bdd[i] -= log2(float64(totdeg + 2)) - bdd[i] += 2.0 * log2TwoPi - - if i != maxi { - bdd[i] += log2(abs(float64(i-maxi)) + err) - bdd[i] += log2(float64(i+maxi) + err) - } else { - bdd[i] += log2(err) - 1.0 - bdd[i] += log2(2.0*float64(i) + err) - } - } - - totdeg += 2 - } else { - bdd[0] -= log2(float64(totdeg + 1)) - bdd[0] += log2(err) - 1.0 - bdd[0] += log2TwoPi - for i := 1; i < K; i++ { - bdd[i] -= log2(float64(totdeg + 1)) - bdd[i] += log2TwoPi - bdd[i] += log2(float64(i) + err) - } - - totdeg++ - } - - deg[maxi]++ - } - - return deg, totdeg -} - -func genNodes(deg []int, dev float64, totdeg, K, scnum int) ([]*big.Float, []*big.Float) { - - var scfac = bignum.NewFloat(1< 0; i-- { - - twodegi := bignum.NewFloat(2*deg[i], EncodingPrecision) - iF := bignum.NewFloat(i, EncodingPrecision) - - // For each node in the interval - for j := 0; j < deg[i]; j++ { - - tmp.Mul(pi, new(big.Float).SetInt64(int64((2 * j)))) - tmp.Quo(tmp, twodegi) - tmp.Mul(bignum.Cos(tmp), intersize) - - // i + cos(pi * (2j-1) / (2*deg[i])) * (1/intersize) - nodes[cnt].Add(iF, tmp) - cnt++ - - // -i - cos(pi * (2j-1) / (2*deg[i])) * (1/intersize) - nodes[cnt].Neg(nodes[cnt-1]) - cnt++ - } - } - - // Center interval - // [+/- nodes] - twodegi := new(big.Float).SetInt64(int64(2 * deg[0])) - for j := 0; j < deg[0]/2; j++ { - - tmp.Mul(pi, new(big.Float).SetInt64(int64((2 * j)))) - tmp.Quo(tmp, twodegi) - tmp.Mul(bignum.Cos(tmp), intersize) - - // 0 + cos(pi * (2j-1) / (2*deg[i])) * (1/intersize) - nodes[cnt].Set(tmp) - cnt++ - - // 0 - cos(pi * (2j-1) / (2*deg[i])) * (1/intersize) - nodes[cnt].Neg(nodes[cnt-1]) - cnt++ - } - - // Evaluates the nodes y[i] = f(nodes[i]) - var y = make([]*big.Float, totdeg) - for i := 0; i < totdeg; i++ { - // y[i] = cos(2*pi*(nodes[i]-0.25)/r) - y[i] = cos2PiXMinusQuarterOverR(nodes[i], scfac) - } - - return nodes, y -} - -func solve(totdeg, K, scnum int, nodes, y []*big.Float) []*big.Float { - - // 2^r - scfac := bignum.NewFloat(float64(int(1<= 0; i-- { - c[i] = new(big.Float).Set(p[i]) - for j := i + 1; j < totdeg; j++ { - tmp.Mul(T[i][j], c[j]) - c[i].Sub(c[i], tmp) - } - } - - return c -} diff --git a/he/hefloat/hefloat.go b/he/hefloat/hefloat.go deleted file mode 100644 index fd848323..00000000 --- a/he/hefloat/hefloat.go +++ /dev/null @@ -1,112 +0,0 @@ -// Package hefloat implements Homomorphic Encryption with fixed-point approximate arithmetic over the complex or real numbers. -package hefloat - -import ( - "testing" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/schemes/ckks" -) - -type Float interface { - ckks.Float -} - -type ParametersLiteral ckks.ParametersLiteral - -func NewParametersFromLiteral(paramsLit ParametersLiteral) (Parameters, error) { - params, err := ckks.NewParametersFromLiteral(ckks.ParametersLiteral(paramsLit)) - return Parameters{Parameters: params}, err -} - -type Parameters struct { - ckks.Parameters -} - -func (p Parameters) MarshalJSON() (d []byte, err error) { - return p.Parameters.MarshalJSON() -} - -func (p *Parameters) UnmarshalJSON(d []byte) (err error) { - return p.Parameters.UnmarshalJSON(d) -} - -func (p Parameters) MarshalBinary() (d []byte, err error) { - return p.Parameters.MarshalBinary() -} - -func (p *Parameters) UnmarshalBinary(d []byte) (err error) { - return p.Parameters.UnmarshalBinary(d) -} - -func (p Parameters) Equal(other *Parameters) bool { - return p.Parameters.Equal(&other.Parameters) -} - -func NewPlaintext(params Parameters, level int) *rlwe.Plaintext { - return ckks.NewPlaintext(params.Parameters, level) -} - -func NewCiphertext(params Parameters, degree, level int) *rlwe.Ciphertext { - return ckks.NewCiphertext(params.Parameters, degree, level) -} - -func NewEncryptor(params Parameters, key rlwe.EncryptionKey) *rlwe.Encryptor { - return rlwe.NewEncryptor(params, key) -} - -func NewDecryptor(params Parameters, key *rlwe.SecretKey) *rlwe.Decryptor { - return rlwe.NewDecryptor(params, key) -} - -func NewKeyGenerator(params Parameters) *rlwe.KeyGenerator { - return rlwe.NewKeyGenerator(params) -} - -type Encoder struct { - ckks.Encoder -} - -func NewEncoder(params Parameters, prec ...uint) *Encoder { - - var ecd *ckks.Encoder - if len(prec) == 0 { - ecd = ckks.NewEncoder(params.Parameters) - } else { - ecd = ckks.NewEncoder(params.Parameters, prec[0]) - } - - return &Encoder{Encoder: *ecd} -} - -func (ecd Encoder) ShallowCopy() *Encoder { - return &Encoder{Encoder: *ecd.Encoder.ShallowCopy()} -} - -type Evaluator struct { - ckks.Evaluator -} - -func NewEvaluator(params Parameters, evk rlwe.EvaluationKeySet) *Evaluator { - return &Evaluator{Evaluator: *ckks.NewEvaluator(params.Parameters, evk)} -} - -func (eval Evaluator) GetParameters() *Parameters { - return &Parameters{*eval.Evaluator.GetParameters()} -} - -func (eval Evaluator) WithKey(evk rlwe.EvaluationKeySet) *Evaluator { - return &Evaluator{Evaluator: *eval.Evaluator.WithKey(evk)} -} - -func (eval Evaluator) ShallowCopy() *Evaluator { - return &Evaluator{Evaluator: *eval.Evaluator.ShallowCopy()} -} - -func GetPrecisionStats(params Parameters, encoder *Encoder, decryptor *rlwe.Decryptor, want, have interface{}, logprec float64, computeDCF bool) (prec ckks.PrecisionStats) { - return ckks.GetPrecisionStats(params.Parameters, &encoder.Encoder, decryptor, want, have, logprec, computeDCF) -} - -func VerifyTestVectors(params Parameters, encoder *Encoder, decryptor *rlwe.Decryptor, valuesWant, valuesHave interface{}, log2MinPrec int, logprec float64, printPrecisionStats bool, t *testing.T) { - ckks.VerifyTestVectors(params.Parameters, &encoder.Encoder, decryptor, valuesWant, valuesHave, log2MinPrec, logprec, printPrecisionStats, t) -} diff --git a/he/hefloat/hefloat_benchmark_test.go b/he/hefloat/hefloat_benchmark_test.go deleted file mode 100644 index 5afee702..00000000 --- a/he/hefloat/hefloat_benchmark_test.go +++ /dev/null @@ -1,438 +0,0 @@ -package hefloat_test - -import ( - "encoding/json" - "fmt" - "runtime" - "testing" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" - "github.com/tuneinsight/lattigo/v5/ring" - "github.com/tuneinsight/lattigo/v5/schemes/ckks" - "github.com/tuneinsight/lattigo/v5/utils/sampling" -) - -func GetBenchName(params hefloat.Parameters, opname string) string { - - var PrecisionMod string - switch params.PrecisionMode() { - case ckks.PREC64: - PrecisionMod = "PREC64" - case ckks.PREC128: - PrecisionMod = "PREC128" - } - - return fmt.Sprintf("%s/RingType=%s/logN=%d/Qi=%d/Pi=%d/LogSlots=%d/%s", - opname, - params.RingType(), - params.LogN(), - params.QCount(), - params.PCount(), - params.LogMaxSlots(), - PrecisionMod) -} - -func BenchmarkHEFloat(b *testing.B) { - - var err error - - var testParams []hefloat.ParametersLiteral - switch { - case *flagParamString != "": // the custom test suite reads the parameters from the -params flag - testParams = append(testParams, hefloat.ParametersLiteral{}) - if err = json.Unmarshal([]byte(*flagParamString), &testParams[0]); err != nil { - b.Fatal(err) - } - default: - testParams = []hefloat.ParametersLiteral{ - { - LogN: 14, - LogQ: []int{50, 40, 40, 40, 40, 40, 40, 40}, - LogP: []int{60}, - LogDefaultScale: 40, - RingType: ring.Standard, - }, - } - } - - for _, paramsLiteral := range testParams { - - var params hefloat.Parameters - if params, err = hefloat.NewParametersFromLiteral(paramsLiteral); err != nil { - b.Error(err) - b.Fail() - } - - var tc *testContext - if tc, err = genTestParams(params); err != nil { - b.Fatal(err) - } - - for _, testSet := range []func(tc *testContext, b *testing.B){ - benchKeyGenerator, - benchEncoder, - benchEncryptor, - benchEvaluator, - } { - testSet(tc, b) - runtime.GC() - } - } -} - -func benchKeyGenerator(tc *testContext, b *testing.B) { - - params := tc.params - - b.Run(GetBenchName(params, "KeyGenerator/GenSecretKey"), func(b *testing.B) { - sk := rlwe.NewSecretKey(params) - kgen := tc.kgen - b.ResetTimer() - for i := 0; i < b.N; i++ { - kgen.GenSecretKey(sk) - } - }) - - b.Run(GetBenchName(params, "KeyGenerator/GenPublicKey"), func(b *testing.B) { - sk := tc.sk - pk := rlwe.NewPublicKey(params) - kgen := tc.kgen - b.ResetTimer() - for i := 0; i < b.N; i++ { - kgen.GenPublicKey(sk, pk) - } - }) - - b.Run(GetBenchName(params, "KeyGenerator/GenEvaluationKey"), func(b *testing.B) { - sk := tc.sk - kgen := tc.kgen - evk := rlwe.NewEvaluationKey(params) - b.ResetTimer() - for i := 0; i < b.N; i++ { - kgen.GenEvaluationKey(sk, sk, evk) - } - }) -} - -func benchEncoder(tc *testContext, b *testing.B) { - - encoder := tc.encoder - - b.Run(GetBenchName(tc.params, "Encoder/Encode"), func(b *testing.B) { - - pt := hefloat.NewPlaintext(tc.params, tc.params.MaxLevel()) - - values := make([]complex128, 1< 0 { - - sqrt2pi = 1.0 - - coeffs := make([]complex128, evm.Mod1InvDegree+1) - - coeffs[1] = 0.15915494309189535 * complex(qDiff*scaling, 0) - - for i := 3; i < evm.Mod1InvDegree+1; i += 2 { - coeffs[i] = coeffs[i-2] * complex(float64(i*i-4*i+4)/float64(i*i-i), 0) - } - - p := bignum.NewPolynomial(bignum.Monomial, coeffs, nil) - - mod1InvPoly = &p - mod1InvPoly.IsEven = false - - for i := range mod1InvPoly.Coeffs { - if i&1 == 0 { - mod1InvPoly.Coeffs[i] = nil - } - } - - } else { - sqrt2pi = math.Pow(0.15915494309189535*qDiff*scaling, 1.0/scFac) - } - - switch evm.Mod1Type { - case SinContinuous: - - mod1Poly = bignum.ChebyshevApproximation(sin2pi, bignum.Interval{ - Nodes: evm.Mod1Degree, - A: *new(big.Float).SetPrec(cosine.EncodingPrecision).SetFloat64(-K), - B: *new(big.Float).SetPrec(cosine.EncodingPrecision).SetFloat64(K), - }) - mod1Poly.IsEven = false - - for i := range mod1Poly.Coeffs { - if i&1 == 0 { - mod1Poly.Coeffs[i] = nil - } - } - - case CosDiscrete: - mod1Poly = bignum.NewPolynomial(bignum.Chebyshev, cosine.ApproximateCos(evm.K, evm.Mod1Degree, float64(uint(1< 0 { - x = math.Asin(x) - } - - x *= mod1Parameters.MessageRatio() - x *= mod1Parameters.QDiff() - x /= 6.28318530717958 - - values[i] = x - } - - return values, ciphertext -} - -func newTestVectorsMod1(params hefloat.Parameters, encryptor *rlwe.Encryptor, encoder *hefloat.Encoder, evm hefloat.Mod1Parameters, t *testing.T) (values []float64, plaintext *rlwe.Plaintext, ciphertext *rlwe.Ciphertext) { - - logSlots := params.LogMaxDimensions().Cols - - values = make([]float64, 1<> 1 - - *ciphertext1.MetaData = *plaintext.MetaData - *ciphertext2.MetaData = *plaintext.MetaData - - vector := plaintext.Value.Coeffs[0][:params.MaxSlots()] - - b.Run(GetBenchName(params, "Evaluator/Add/Scalar"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Add(ciphertext1, scalar, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Add/Vector"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Add(ciphertext1, vector, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Add/Plaintext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Add(ciphertext1, plaintext, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Add/Ciphertext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Add(ciphertext1, ciphertext2, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Mul/Scalar"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Mul(ciphertext1, scalar, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Mul/Plaintext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Mul(ciphertext1, plaintext, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Mul/Vector"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Mul(ciphertext1, vector, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Mul/Ciphertext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 2, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Mul(ciphertext1, ciphertext2, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/MulRelin/Ciphertext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.MulRelin(ciphertext1, ciphertext2, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/MulInvariant/Ciphertext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 2, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.MulScaleInvariant(ciphertext1, ciphertext2, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/MulRelinInvariant/Ciphertext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.MulRelinScaleInvariant(ciphertext1, ciphertext2, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/MulThenAdd/Scalar"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.MulThenAdd(ciphertext1, scalar, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/MulThenAdd/Vector"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.MulThenAdd(ciphertext1, vector, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/MulThenAdd/Plaintext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.MulThenAdd(ciphertext1, plaintext, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/MulThenAdd/Ciphertext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.MulThenAdd(ciphertext1, plaintext, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/MulRelinThenAdd/Ciphertext"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 2, ciphertext1.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.MulRelinThenAdd(ciphertext1, ciphertext2, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Rescale"), func(b *testing.B) { - receiver := heint.NewCiphertext(params, 1, ciphertext1.Level()-1) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.Rescale(ciphertext1, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) - - b.Run(GetBenchName(params, "Evaluator/Rotate"), func(b *testing.B) { - gk := tc.kgen.GenGaloisKeyNew(5, tc.sk) - evk := rlwe.NewMemEvaluationKeySet(nil, gk) - eval := eval.WithKey(evk) - receiver := heint.NewCiphertext(params, 1, ciphertext2.Level()) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := eval.RotateColumns(ciphertext2, 1, receiver); err != nil { - b.Log(err) - b.Fail() - } - } - }) -} diff --git a/he/heint/heint_test.go b/he/heint/heint_test.go deleted file mode 100644 index ebf12205..00000000 --- a/he/heint/heint_test.go +++ /dev/null @@ -1,466 +0,0 @@ -package heint_test - -import ( - "encoding/json" - "flag" - "fmt" - "math" - "math/big" - "math/rand" - "runtime" - "slices" - "testing" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/heint" - "github.com/tuneinsight/lattigo/v5/ring" - - "github.com/stretchr/testify/require" - "github.com/tuneinsight/lattigo/v5/utils/bignum" - "github.com/tuneinsight/lattigo/v5/utils/sampling" -) - -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 heint.Parameters, lvl int) string { - return fmt.Sprintf("%s/LogN=%d/logQ=%d/logP=%d/LogSlots=%dx%d/logT=%d/Qi=%d/Pi=%d/lvl=%d", - opname, - p.LogN(), - int(math.Round(p.LogQ())), - int(math.Round(p.LogP())), - p.LogMaxDimensions().Rows, - p.LogMaxDimensions().Cols, - int(math.Round(p.LogT())), - p.QCount(), - p.PCount(), - lvl) -} - -func TestInteger(t *testing.T) { - - var err error - - paramsLiterals := testParams - - if *flagParamString != "" { - var jsonParams heint.ParametersLiteral - if err = json.Unmarshal([]byte(*flagParamString), &jsonParams); err != nil { - t.Fatal(err) - } - paramsLiterals = []heint.ParametersLiteral{jsonParams} // the custom test suite reads the parameters from the -params flag - } - - for _, p := range paramsLiterals[:] { - - for _, plaintextModulus := range testPlaintextModulus[:] { - - p.PlaintextModulus = plaintextModulus - - var params heint.Parameters - if params, err = heint.NewParametersFromLiteral(p); err != nil { - t.Error(err) - t.Fail() - } - - var tc *testContext - if tc, err = genTestParams(params); err != nil { - t.Error(err) - t.Fail() - } - - for _, testSet := range []func(tc *testContext, t *testing.T){ - testLinearTransformation, - } { - testSet(tc, t) - runtime.GC() - } - } - } -} - -type testContext struct { - params heint.Parameters - ringQ *ring.Ring - ringT *ring.Ring - prng sampling.PRNG - uSampler *ring.UniformSampler - encoder *heint.Encoder - kgen *rlwe.KeyGenerator - sk *rlwe.SecretKey - pk *rlwe.PublicKey - encryptorPk *rlwe.Encryptor - encryptorSk *rlwe.Encryptor - decryptor *rlwe.Decryptor - evaluator *heint.Evaluator - testLevel []int -} - -func genTestParams(params heint.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 = rlwe.NewKeyGenerator(tc.params) - tc.sk, tc.pk = tc.kgen.GenKeyPairNew() - tc.encoder = heint.NewEncoder(tc.params) - - tc.encryptorPk = rlwe.NewEncryptor(tc.params, tc.pk) - tc.encryptorSk = rlwe.NewEncryptor(tc.params, tc.sk) - tc.decryptor = rlwe.NewDecryptor(tc.params, tc.sk) - tc.evaluator = heint.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 = heint.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.Error("invalid test object to verify") - } - - require.True(t, slices.Equal(coeffs.Coeffs[0], coeffsTest)) -} - -func testLinearTransformation(tc *testContext, t *testing.T) { - - rT := tc.params.RingT().SubRings[0] - - add := func(a, b, c []uint64) { - rT.Add(a, b, c) - } - - muladd := func(a, b, c []uint64) { - rT.MulCoeffsBarrettThenAdd(a, b, c) - } - - newVec := func(size int) (vec []uint64) { - return make([]uint64, size) - } - - params := tc.params - - T := params.PlaintextModulus() - - level := tc.params.MaxLevel() - - t.Run(GetTestName("Evaluator/LinearTransformationBSGS=true", params, level), func(t *testing.T) { - - values, _, ciphertext := newTestVectorsLvl(level, params.DefaultScale(), tc, tc.encryptorSk) - - slots := ciphertext.Slots() - - nonZeroDiags := []int{-15, -4, -1, 0, 1, 2, 3, 4, 15} - - diagonals := make(heint.Diagonals[uint64]) - for _, i := range nonZeroDiags { - diagonals[i] = make([]uint64, slots) - for j := 0; j < slots>>1; j++ { - diagonals[i][j] = sampling.RandUint64() % T - } - } - - ltparams := heint.LinearTransformationParameters{ - DiagonalsIndexList: diagonals.DiagonalsIndexList(), - LevelQ: ciphertext.Level(), - LevelP: params.MaxLevelP(), - Scale: tc.params.DefaultScale(), - LogDimensions: ciphertext.LogDimensions, - LogBabyStepGianStepRatio: 1, - } - - // Allocate the linear transformation - linTransf := heint.NewLinearTransformation(params, ltparams) - - // Encode on the linear transformation - require.NoError(t, heint.EncodeLinearTransformation[uint64](tc.encoder, diagonals, linTransf)) - - galEls := heint.GaloisElementsForLinearTransformation(params, ltparams) - - eval := tc.evaluator.WithKey(rlwe.NewMemEvaluationKeySet(nil, tc.kgen.GenGaloisKeysNew(galEls, tc.sk)...)) - ltEval := heint.NewLinearTransformationEvaluator(eval) - - require.NoError(t, ltEval.Evaluate(ciphertext, linTransf, ciphertext)) - - values.Coeffs[0] = diagonals.Evaluate(values.Coeffs[0], newVec, add, muladd) - - verifyTestVectors(tc, tc.decryptor, values, ciphertext, t) - }) - - t.Run(GetTestName("Evaluator/LinearTransformationBSGS=false", params, level), func(t *testing.T) { - - values, _, ciphertext := newTestVectorsLvl(level, params.DefaultScale(), tc, tc.encryptorSk) - - slots := ciphertext.Slots() - - nonZeroDiags := []int{-15, -4, -1, 0, 1, 2, 3, 4, 15} - - diagonals := make(heint.Diagonals[uint64]) - for _, i := range nonZeroDiags { - diagonals[i] = make([]uint64, slots) - for j := 0; j < slots>>1; j++ { - diagonals[i][j] = sampling.RandUint64() % T - } - } - - ltparams := heint.LinearTransformationParameters{ - DiagonalsIndexList: diagonals.DiagonalsIndexList(), - LevelQ: ciphertext.Level(), - LevelP: params.MaxLevelP(), - Scale: params.DefaultScale(), - LogDimensions: ciphertext.LogDimensions, - LogBabyStepGianStepRatio: -1, - } - - // Allocate the linear transformation - linTransf := heint.NewLinearTransformation(params, ltparams) - - // Encode on the linear transformation - require.NoError(t, heint.EncodeLinearTransformation[uint64](tc.encoder, diagonals, linTransf)) - - galEls := heint.GaloisElementsForLinearTransformation(params, ltparams) - - eval := tc.evaluator.WithKey(rlwe.NewMemEvaluationKeySet(nil, tc.kgen.GenGaloisKeysNew(galEls, tc.sk)...)) - ltEval := heint.NewLinearTransformationEvaluator(eval) - - require.NoError(t, ltEval.Evaluate(ciphertext, linTransf, ciphertext)) - - values.Coeffs[0] = diagonals.Evaluate(values.Coeffs[0], newVec, add, muladd) - - verifyTestVectors(tc, tc.decryptor, values, ciphertext, t) - }) - - t.Run(GetTestName("Evaluator/LinearTransformation/Permutation", params, level), func(t *testing.T) { - - idx := [2][]int{ - make([]int, params.MaxSlots()>>1), - make([]int, params.MaxSlots()>>1), - } - - for i := range idx[0] { - idx[0][i] = i - idx[1][i] = i - } - - r := rand.New(rand.NewSource(0)) - r.Shuffle(len(idx[0]), func(i, j int) { - idx[0][i], idx[0][j] = idx[0][j], idx[0][i] - }) - r.Shuffle(len(idx[1]), func(i, j int) { - idx[1][i], idx[1][j] = idx[1][j], idx[1][i] - }) - - idx[0] = idx[0][:len(idx[0])>>1] - idx[1] = idx[1][:len(idx[1])>>1] // truncates to test partial permutation - - permutation := [2][]heint.PermutationMapping[uint64]{ - make([]heint.PermutationMapping[uint64], len(idx[0])), - make([]heint.PermutationMapping[uint64], len(idx[1])), - } - - for i := range permutation { - for j := range permutation[i] { - permutation[i][j] = heint.PermutationMapping[uint64]{ - From: j, - To: idx[i][j], - Scaling: sampling.RandUint64() % T, - } - permutation[i][j] = heint.PermutationMapping[uint64]{ - From: j, - To: idx[i][j], - Scaling: sampling.RandUint64() % T, - } - } - } - - diagonals := heint.Permutation[uint64](permutation).GetDiagonals(params.LogMaxSlots()) - - values, _, ciphertext := newTestVectorsLvl(level, tc.params.NewScale(1), tc, tc.encryptorSk) - - ltparams := heint.LinearTransformationParameters{ - DiagonalsIndexList: diagonals.DiagonalsIndexList(), - LevelQ: ciphertext.Level(), - LevelP: params.MaxLevelP(), - Scale: params.DefaultScale(), - LogDimensions: ciphertext.LogDimensions, - LogBabyStepGianStepRatio: 1, - } - - // Allocate the linear transformation - linTransf := heint.NewLinearTransformation(params, ltparams) - - // Encode on the linear transformation - require.NoError(t, heint.EncodeLinearTransformation[uint64](tc.encoder, diagonals, linTransf)) - - galEls := heint.GaloisElementsForLinearTransformation(params, ltparams) - - evk := rlwe.NewMemEvaluationKeySet(nil, tc.kgen.GenGaloisKeysNew(galEls, tc.sk)...) - - ltEval := heint.NewLinearTransformationEvaluator(tc.evaluator.WithKey(evk)) - - require.NoError(t, ltEval.Evaluate(ciphertext, linTransf, ciphertext)) - - values.Coeffs[0] = diagonals.Evaluate(values.Coeffs[0], newVec, add, muladd) - - verifyTestVectors(tc, tc.decryptor, values, ciphertext, t) - }) - - t.Run("Evaluator/PolyEval", func(t *testing.T) { - - t.Run("Single", func(t *testing.T) { - - if tc.params.MaxLevel() < 4 { - t.Skip("MaxLevel() to low") - } - - values, _, ciphertext := newTestVectorsLvl(tc.params.MaxLevel(), tc.params.NewScale(1), tc, tc.encryptorSk) - - coeffs := []uint64{0, 0, 1} - - T := tc.params.PlaintextModulus() - for i := range values.Coeffs[0] { - values.Coeffs[0][i] = ring.EvalPolyModP(values.Coeffs[0][i], coeffs, T) - } - - poly := bignum.NewPolynomial(bignum.Monomial, coeffs, nil) - - t.Run(GetTestName("Standard", tc.params, tc.params.MaxLevel()), func(t *testing.T) { - - polyEval := heint.NewPolynomialEvaluator(tc.params, tc.evaluator, false) - - res, err := polyEval.Evaluate(ciphertext, poly, tc.params.DefaultScale()) - require.NoError(t, err) - - require.Equal(t, res.Scale.Cmp(tc.params.DefaultScale()), 0) - - verifyTestVectors(tc, tc.decryptor, values, res, t) - }) - - t.Run(GetTestName("Invariant", tc.params, tc.params.MaxLevel()), func(t *testing.T) { - - polyEval := heint.NewPolynomialEvaluator(tc.params, tc.evaluator, true) - - res, err := polyEval.Evaluate(ciphertext, poly, tc.params.DefaultScale()) - require.NoError(t, err) - - require.Equal(t, res.Level(), ciphertext.Level()) - require.Equal(t, res.Scale.Cmp(tc.params.DefaultScale()), 0) - - verifyTestVectors(tc, tc.decryptor, values, res, t) - }) - }) - - t.Run("Vector", func(t *testing.T) { - - if tc.params.MaxLevel() < 4 { - t.Skip("MaxLevel() to low") - } - - values, _, ciphertext := newTestVectorsLvl(tc.params.MaxLevel(), tc.params.NewScale(7), tc, tc.encryptorSk) - - coeffs0 := []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} - coeffs1 := []uint64{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17} - - slots := values.N() - - mapping := make(map[int][]int) - idx0 := make([]int, slots>>1) - idx1 := make([]int, slots>>1) - for i := 0; i < slots>>1; i++ { - idx0[i] = 2 * i - idx1[i] = 2*i + 1 - } - - mapping[0] = idx0 - mapping[1] = idx1 - - polyVector, err := heint.NewPolynomialVector([][]uint64{ - coeffs0, - coeffs1, - }, mapping) - require.NoError(t, err) - - TInt := new(big.Int).SetUint64(tc.params.PlaintextModulus()) - 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() - } - } - - t.Run(GetTestName("Standard", tc.params, tc.params.MaxLevel()), func(t *testing.T) { - - polyEval := heint.NewPolynomialEvaluator(tc.params, tc.evaluator, false) - - res, err := polyEval.Evaluate(ciphertext, polyVector, tc.params.DefaultScale()) - require.NoError(t, err) - - require.Equal(t, res.Scale.Cmp(tc.params.DefaultScale()), 0) - - verifyTestVectors(tc, tc.decryptor, values, res, t) - }) - - t.Run(GetTestName("Invariant", tc.params, tc.params.MaxLevel()), func(t *testing.T) { - - polyEval := heint.NewPolynomialEvaluator(tc.params, tc.evaluator, true) - - res, err := polyEval.Evaluate(ciphertext, polyVector, tc.params.DefaultScale()) - require.NoError(t, err) - - require.Equal(t, res.Level(), ciphertext.Level()) - require.Equal(t, res.Scale.Cmp(tc.params.DefaultScale()), 0) - - verifyTestVectors(tc, tc.decryptor, values, res, t) - }) - }) - }) - -} diff --git a/he/heint/parameters_test.go b/he/heint/parameters_test.go deleted file mode 100644 index ef49fd59..00000000 --- a/he/heint/parameters_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package heint_test - -import ( - "github.com/tuneinsight/lattigo/v5/he/heint" -) - -var ( - - // testInsecure are insecure parameters used for the sole purpose of fast testing. - testInsecure = heint.ParametersLiteral{ - LogN: 10, - Q: []uint64{0x3fffffa8001, 0x1000090001, 0x10000c8001, 0x10000f0001, 0xffff00001}, - P: []uint64{0x7fffffd8001}, - } - - testPlaintextModulus = []uint64{0x101, 0xffc001} - - testParams = []heint.ParametersLiteral{testInsecure} -) diff --git a/he/heint/polynomial_evaluator_sim.go b/he/heint/polynomial_evaluator_sim.go deleted file mode 100644 index 23b0f39d..00000000 --- a/he/heint/polynomial_evaluator_sim.go +++ /dev/null @@ -1,98 +0,0 @@ -package heint - -import ( - "math/big" - "math/bits" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he" - "github.com/tuneinsight/lattigo/v5/schemes/bgv" - "github.com/tuneinsight/lattigo/v5/utils" -) - -// simEvaluator is a struct used to pre-computed the scaling -// factors of the polynomial coefficients used by the inlined -// polynomial evaluation by running the polynomial evaluation -// with dummy operands. -// This struct implements the interface he.SimEvaluator. -type simEvaluator struct { - params Parameters - InvariantTensoring bool -} - -// PolynomialDepth returns the depth of the polynomial. -func (d simEvaluator) PolynomialDepth(degree int) int { - if d.InvariantTensoring { - return 0 - } - return bits.Len64(uint64(degree)) - 1 -} - -// Rescale rescales the target he.SimOperand n times and returns it. -func (d simEvaluator) Rescale(op0 *he.SimOperand) { - if !d.InvariantTensoring { - op0.Scale = op0.Scale.Div(rlwe.NewScale(d.params.Q()[op0.Level])) - op0.Level-- - } -} - -// MulNew multiplies two he.SimOperand, stores the result the target he.SimOperand and returns the result. -func (d simEvaluator) MulNew(op0, op1 *he.SimOperand) (opOut *he.SimOperand) { - opOut = new(he.SimOperand) - opOut.Level = utils.Min(op0.Level, op1.Level) - - if d.InvariantTensoring { - opOut.Scale = bgv.MulScaleInvariant(d.params.Parameters, op0.Scale, op1.Scale, opOut.Level) - } else { - opOut.Scale = op0.Scale.Mul(op1.Scale) - } - - return -} - -// UpdateLevelAndScaleBabyStep returns the updated level and scale for a baby-step. -func (d simEvaluator) UpdateLevelAndScaleBabyStep(lead bool, tLevelOld int, tScaleOld rlwe.Scale) (tLevelNew int, tScaleNew rlwe.Scale) { - tLevelNew = tLevelOld - tScaleNew = tScaleOld - if !d.InvariantTensoring && lead { - tScaleNew = tScaleOld.Mul(d.params.NewScale(d.params.Q()[tLevelOld])) - } - return -} - -// UpdateLevelAndScaleGiantStep returns the updated level and scale for a giant-step. -func (d simEvaluator) UpdateLevelAndScaleGiantStep(lead bool, tLevelOld int, tScaleOld, xPowScale rlwe.Scale) (tLevelNew int, tScaleNew rlwe.Scale) { - - Q := d.params.Q() - - tLevelNew = tLevelOld - tScaleNew = tScaleOld.Div(xPowScale) - - // tScaleNew = targetScale*currentQi/XPow.Scale - if !d.InvariantTensoring { - - var currentQi uint64 - if lead { - currentQi = Q[tLevelNew] - } else { - currentQi = Q[tLevelNew+1] - } - - tScaleNew = tScaleNew.Mul(d.params.NewScale(currentQi)) - - } else { - - T := d.params.PlaintextModulus() - - // -Q mod T - qModTNeg := new(big.Int).Mod(d.params.RingQ().ModulusAtLevel[tLevelNew], new(big.Int).SetUint64(T)).Uint64() - qModTNeg = T - qModTNeg - tScaleNew = tScaleNew.Mul(d.params.NewScale(qModTNeg)) - } - - if !d.InvariantTensoring { - tLevelNew++ - } - - return -} diff --git a/he/polynomial_evaluator_sim.go b/he/polynomial_evaluator_sim.go deleted file mode 100644 index 6a7546c5..00000000 --- a/he/polynomial_evaluator_sim.go +++ /dev/null @@ -1,40 +0,0 @@ -package he - -import ( - "github.com/tuneinsight/lattigo/v5/core/rlwe" -) - -// SimOperand is a dummy operand that -// only stores its level and scale. -type SimOperand struct { - Level int - Scale rlwe.Scale -} - -// SimEvaluator defines a set of method on SimOperands. -type SimEvaluator interface { - MulNew(op0, op1 *SimOperand) *SimOperand - Rescale(op0 *SimOperand) - PolynomialDepth(degree int) int - UpdateLevelAndScaleGiantStep(lead bool, tLevelOld int, tScaleOld, xPowScale rlwe.Scale) (tLevelNew int, tScaleNew rlwe.Scale) - UpdateLevelAndScaleBabyStep(lead bool, tLevelOld int, tScaleOld rlwe.Scale) (tLevelNew int, tScaleNew rlwe.Scale) -} - -// SimPowerBasis is a map storing powers of SimOperands indexed by their power. -type SimPowerBasis map[int]*SimOperand - -// GenPower populates the target SimPowerBasis with the nth power. -func (d SimPowerBasis) GenPower(params rlwe.ParameterProvider, n int, eval SimEvaluator) { - - if n < 2 { - return - } - - a, b := SplitDegree(n) - - d.GenPower(params, a, eval) - d.GenPower(params, b, eval) - - d[n] = eval.MulNew(d[a], d[b]) - eval.Rescale(d[n]) -} diff --git a/he/power_basis_test.go b/he/power_basis_test.go deleted file mode 100644 index 3c34e246..00000000 --- a/he/power_basis_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package he - -import ( - "testing" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/utils/bignum" - "github.com/tuneinsight/lattigo/v5/utils/buffer" - "github.com/tuneinsight/lattigo/v5/utils/sampling" -) - -func TestPowerBasis(t *testing.T) { - t.Run("WriteAndRead", func(t *testing.T) { - var err error - var params rlwe.Parameters - if params, err = rlwe.NewParametersFromLiteral(rlwe.ParametersLiteral{ - LogN: 10, - Q: []uint64{0x200000440001, 0x7fff80001}, - P: []uint64{0x3ffffffb80001, 0x4000000800001}, - }); err != nil { - t.Fatal(err) - } - - levelQ := params.MaxLevelQ() - - prng, _ := sampling.NewPRNG() - - ct := rlwe.NewCiphertextRandom(prng, params, 1, levelQ) - - basis := NewPowerBasis(ct, bignum.Chebyshev) - - basis.Value[2] = rlwe.NewCiphertextRandom(prng, params, 1, levelQ) - basis.Value[3] = rlwe.NewCiphertextRandom(prng, params, 2, levelQ) - basis.Value[4] = rlwe.NewCiphertextRandom(prng, params, 1, levelQ) - basis.Value[8] = rlwe.NewCiphertextRandom(prng, params, 1, levelQ) - - buffer.RequireSerializerCorrect(t, &basis) - }) -} diff --git a/he/ring_packing_keys.go b/he/ring_packing_keys.go deleted file mode 100644 index 7fbeccbb..00000000 --- a/he/ring_packing_keys.go +++ /dev/null @@ -1,181 +0,0 @@ -package he - -import ( - "fmt" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/ring" - "github.com/tuneinsight/lattigo/v5/utils" -) - -// RingPackingEvaluationKey is a struct storing the -// ring packing evaluation keys. -// All fields of this struct are public, enabling -// custom instantiations. -type RingPackingEvaluationKey struct { - // Parameters are the different Parameters among - // which a ciphertext will be switched during the - // procedure. These parameters share the same primes - // but support different ring degrees. - Parameters map[int]rlwe.ParameterProvider - - // RingSwitchingKeys are the ring degree switching keys - // indexed as map[inputLogN][outputLogN] - RingSwitchingKeys map[int]map[int]*rlwe.EvaluationKey - - // RepackKeys are the [rlwe.EvaluationKey] used for the - // RLWE repacking. - RepackKeys map[int]rlwe.EvaluationKeySet - - // ExtractKeys are the [rlwe.EvaluationKey] used for the - // RLWE extraction. - ExtractKeys map[int]rlwe.EvaluationKeySet -} - -// MinLogN returns the minimum Log(N) among the supported ring degrees. -// This method requires that the field Parameters of [RingPackingEvaluationKey] -// has been populated. -func (rpk RingPackingEvaluationKey) MinLogN() (minLogN int) { - return utils.GetSortedKeys(rpk.Parameters)[0] -} - -// MaxLogN returns the maximum Log(N) among the supported ring degrees. -// This method requires that the field Parameters of [RingPackingEvaluationKey] -// has been populated. -func (rpk RingPackingEvaluationKey) MaxLogN() (maxLogN int) { - return utils.GetSortedKeys(rpk.Parameters)[len(rpk.Parameters)-1] -} - -// GenRingSwitchingKeys generates the [rlwe.Parameter]s and [rlwe.EvaluationKey]s -// to be able to split an [rlwe.Ciphertext] into two [rlwe.Ciphertext]s of half -// the ring degree and merge two [rlwe.Ciphertext]s into one [rlwe.Ciphertext] -// of twice the ring degree. -// -// The method returns the [rlwe.Parameter]s, [rlwe.EvaluationKey]s and ephemeral -// [rlwe.SecretKey]s used to generate the ring-switching [rlwe.EvaluationKey]s. -// -// See the methods [RingPackingEvaluator.Split] and [RingPackingEvaluator.Repack]. -// -// This function will return an error if minLogN >= params.LogN(). -func (rpk *RingPackingEvaluationKey) GenRingSwitchingKeys(params rlwe.ParameterProvider, sk *rlwe.SecretKey, minLogN int, evkParams rlwe.EvaluationKeyParameters) (ski map[int]*rlwe.SecretKey, err error) { - - p := *params.GetRLWEParameters() - - if minLogN >= p.LogN() { - return nil, fmt.Errorf("invalid minLogN: cannot be equal or larger than params.LogN()") - } - - LevelQ, LevelP, _ := rlwe.ResolveEvaluationKeyParameters(p, []rlwe.EvaluationKeyParameters{evkParams}) - - Q := p.Q() - P := p.P() - - Parameters := map[int]rlwe.ParameterProvider{} - Parameters[p.LogN()] = &p - - ski = map[int]*rlwe.SecretKey{} - ski[p.LogN()] = sk - - kgen := map[int]*rlwe.KeyGenerator{} - kgen[p.LogN()] = rlwe.NewKeyGenerator(p) - - for i := minLogN; i < p.LogN(); i++ { - - var pi rlwe.Parameters - if pi, err = rlwe.NewParametersFromLiteral(rlwe.ParametersLiteral{ - LogN: i, - Q: Q[:LevelQ+1], - P: P[:LevelP+1], - NTTFlag: p.NTTFlag(), - DefaultScale: p.DefaultScale(), - }); err != nil { - return nil, fmt.Errorf("rlwe.NewParametersFromLiteral: %w", err) - } - - kgen[i] = rlwe.NewKeyGenerator(pi) - ski[i] = kgen[i].GenSecretKeyNew() - Parameters[i] = &pi - } - - // Ring switching evaluation keys - RingSwitchingKeys := map[int]map[int]*rlwe.EvaluationKey{} - - for i := minLogN; i < p.LogN()+1; i++ { - RingSwitchingKeys[i] = map[int]*rlwe.EvaluationKey{} - } - - for i := minLogN; i < p.LogN(); i++ { - RingSwitchingKeys[i][i+1] = kgen[i+1].GenEvaluationKeyNew(ski[i], ski[i+1], evkParams) - RingSwitchingKeys[i+1][i] = kgen[i+1].GenEvaluationKeyNew(ski[i+1], ski[i], evkParams) - } - - rpk.Parameters = Parameters - rpk.RingSwitchingKeys = RingSwitchingKeys - - return ski, nil -} - -// GenRepackEvaluationKeys generates the set of params.LogN() [rlwe.EvaluationKey]s necessary to perform the repacking operation. -// See [RingPackingEvaluator.Repack] for additional information. -func (rpk *RingPackingEvaluationKey) GenRepackEvaluationKeys(params rlwe.ParameterProvider, sk *rlwe.SecretKey, evkParams rlwe.EvaluationKeyParameters) { - p := *params.GetRLWEParameters() - - if rpk.RepackKeys == nil { - rpk.RepackKeys = map[int]rlwe.EvaluationKeySet{} - } - - rpk.RepackKeys[p.LogN()] = rlwe.NewMemEvaluationKeySet(nil, rlwe.NewKeyGenerator(p).GenGaloisKeysNew(GaloisElementsForPack(p, p.LogN()), sk, evkParams)...) -} - -// GenExtractEvaluationKeys generates the set of params.LogN() [rlwe.EvaluationKey]s necessary to perform the extraction operation. -// See [RingPackingEvaluator.Extract] for additional information. -func (rpk *RingPackingEvaluationKey) GenExtractEvaluationKeys(params rlwe.ParameterProvider, sk *rlwe.SecretKey, evkParams rlwe.EvaluationKeyParameters) { - p := *params.GetRLWEParameters() - - if rpk.ExtractKeys == nil { - rpk.ExtractKeys = map[int]rlwe.EvaluationKeySet{} - } - - rpk.ExtractKeys[p.LogN()] = rlwe.NewMemEvaluationKeySet(nil, rlwe.NewKeyGenerator(p).GenGaloisKeysNew(GaloisElementsForExpand(p, p.LogN()), sk, evkParams)...) -} - -// GaloisElementsForExpand returns the list of Galois elements required -// to perform the `Expand` operation with parameter `logN`. -func GaloisElementsForExpand(params rlwe.ParameterProvider, logN int) (galEls []uint64) { - galEls = make([]uint64, logN) - - NthRoot := params.GetRLWEParameters().RingQ().NthRoot() - - for i := 0; i < logN; i++ { - galEls[i] = uint64(NthRoot/(2< p.LogN() || logGap < 0 { - panic(fmt.Errorf("cannot GaloisElementsForPack: logGap > logN || logGap < 0")) - } - - galEls = make([]uint64, 0, logGap) - for i := 0; i < logGap; i++ { - galEls = append(galEls, p.GaloisElement(1<) -2. An Efficient Threshold Access-Structure for RLWE-Based Multiparty Homomorphic Encryption () \ No newline at end of file +2. An Efficient Threshold Access-Structure for RLWE-Based Multiparty Homomorphic Encryption () diff --git a/mhe/mhefloat/mhe_test.go b/mhe/mhefloat/mhe_test.go index 565cee5f..fe7ad7f8 100644 --- a/mhe/mhefloat/mhe_test.go +++ b/mhe/mhefloat/mhe_test.go @@ -12,9 +12,9 @@ import ( "github.com/stretchr/testify/require" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/utils" "github.com/tuneinsight/lattigo/v5/utils/bignum" "github.com/tuneinsight/lattigo/v5/utils/sampling" @@ -23,7 +23,7 @@ import ( var flagParamString = flag.String("params", "", "specify the test cryptographic parameters as a JSON string. Overrides -short and -long.") var printPrecisionStats = flag.Bool("print-precision", false, "print precision stats") -func GetTestName(opname string, parties int, params hefloat.Parameters) string { +func GetTestName(opname string, parties int, params ckks.Parameters) string { return fmt.Sprintf("%s/RingType=%s/logN=%d/logQP=%d/Qi=%d/Pi=%d/LogDefaultScale=%d/Parties=%d", opname, params.RingType(), @@ -36,14 +36,14 @@ func GetTestName(opname string, parties int, params hefloat.Parameters) string { } type testContext struct { - params hefloat.Parameters + params ckks.Parameters NParties int ringQ *ring.Ring ringP *ring.Ring - encoder *hefloat.Encoder - evaluator *hefloat.Evaluator + encoder *ckks.Encoder + evaluator *ckks.Evaluator encryptorPk0 *rlwe.Encryptor decryptorSk0 *rlwe.Decryptor @@ -66,10 +66,10 @@ func TestMHEFloat(t *testing.T) { var err error - var testParams []hefloat.ParametersLiteral + var testParams []ckks.ParametersLiteral switch { case *flagParamString != "": // the custom test suite reads the parameters from the -params flag - testParams = append(testParams, hefloat.ParametersLiteral{}) + testParams = append(testParams, ckks.ParametersLiteral{}) if err = json.Unmarshal([]byte(*flagParamString), &testParams[0]); err != nil { t.Fatal(err) } @@ -83,8 +83,8 @@ func TestMHEFloat(t *testing.T) { paramsLiteral.RingType = ringType - var params hefloat.Parameters - if params, err = hefloat.NewParametersFromLiteral(paramsLiteral); err != nil { + var params ckks.Parameters + if params, err = ckks.NewParametersFromLiteral(paramsLiteral); err != nil { t.Fatal(err) } N := 3 @@ -104,7 +104,7 @@ func TestMHEFloat(t *testing.T) { } } -func genTestParams(params hefloat.Parameters, NParties int) (tc *testContext, err error) { +func genTestParams(params ckks.Parameters, NParties int) (tc *testContext, err error) { tc = new(testContext) @@ -119,8 +119,8 @@ func genTestParams(params hefloat.Parameters, NParties int) (tc *testContext, er tc.crs = prng tc.uniformSampler = ring.NewUniformSampler(prng, params.RingQ()) - tc.encoder = hefloat.NewEncoder(tc.params) - tc.evaluator = hefloat.NewEvaluator(tc.params, nil) + tc.encoder = ckks.NewEncoder(tc.params) + tc.evaluator = ckks.NewEvaluator(tc.params, nil) kgen := rlwe.NewKeyGenerator(tc.params) @@ -216,12 +216,12 @@ func testEncToShareProtocol(tc *testContext, t *testing.T) { } } - pt := hefloat.NewPlaintext(params, ciphertext.Level()) + pt := ckks.NewPlaintext(params, ciphertext.Level()) pt.IsNTT = false pt.Scale = ciphertext.Scale tc.ringQ.AtLevel(pt.Level()).SetCoefficientsBigint(rec.Value, pt.Value) - hefloat.VerifyTestVectors(params, tc.encoder, nil, coeffs, pt, params.LogDefaultScale(), 0, *printPrecisionStats, t) + ckks.VerifyTestVectors(params, tc.encoder, nil, coeffs, pt, params.LogDefaultScale(), 0, *printPrecisionStats, t) crp := P[0].s2e.SampleCRP(params.MaxLevel(), tc.crs) @@ -232,11 +232,11 @@ func testEncToShareProtocol(tc *testContext, t *testing.T) { } } - ctRec := hefloat.NewCiphertext(params, 1, params.MaxLevel()) + ctRec := ckks.NewCiphertext(params, 1, params.MaxLevel()) ctRec.Scale = params.DefaultScale() P[0].s2e.GetEncryption(P[0].publicShareS2E, crp, ctRec) - hefloat.VerifyTestVectors(params, tc.encoder, tc.decryptorSk0, coeffs, ctRec, params.LogDefaultScale(), 0, *printPrecisionStats, t) + ckks.VerifyTestVectors(params, tc.encoder, tc.decryptorSk0, coeffs, ctRec, params.LogDefaultScale(), 0, *printPrecisionStats, t) }) } @@ -253,9 +253,9 @@ func testRefresh(tc *testContext, t *testing.T) { t.Run(GetTestName("N->2N/Transform=nil", tc.NParties, paramsIn), func(t *testing.T) { - var paramsOut hefloat.Parameters + var paramsOut ckks.Parameters var err error - paramsOut, err = hefloat.NewParametersFromLiteral(hefloat.ParametersLiteral{ + paramsOut, err = ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: paramsIn.LogN() + 1, LogQ: []int{54, 54, 54, 49, 49, 49, 49, 49, 49}, LogP: []int{52, 52}, @@ -277,9 +277,9 @@ func testRefresh(tc *testContext, t *testing.T) { t.Run(GetTestName("2N->N/Transform=nil", tc.NParties, tc.params), func(t *testing.T) { - var paramsOut hefloat.Parameters + var paramsOut ckks.Parameters var err error - paramsOut, err = hefloat.NewParametersFromLiteral(hefloat.ParametersLiteral{ + paramsOut, err = ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: paramsIn.LogN() - 1, LogQ: []int{54, 54, 54, 49, 49, 49, 49, 49, 49}, LogP: []int{52, 52}, @@ -317,9 +317,9 @@ func testRefresh(tc *testContext, t *testing.T) { t.Run(GetTestName("N->2N/Transform=true", tc.NParties, paramsIn), func(t *testing.T) { - var paramsOut hefloat.Parameters + var paramsOut ckks.Parameters var err error - paramsOut, err = hefloat.NewParametersFromLiteral(hefloat.ParametersLiteral{ + paramsOut, err = ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: paramsIn.LogN() + 1, LogQ: []int{54, 54, 54, 49, 49, 49, 49, 49, 49}, LogP: []int{52, 52}, @@ -352,9 +352,9 @@ func testRefresh(tc *testContext, t *testing.T) { t.Run(GetTestName("2N->N/Transform=true", tc.NParties, tc.params), func(t *testing.T) { - var paramsOut hefloat.Parameters + var paramsOut ckks.Parameters var err error - paramsOut, err = hefloat.NewParametersFromLiteral(hefloat.ParametersLiteral{ + paramsOut, err = ckks.NewParametersFromLiteral(ckks.ParametersLiteral{ LogN: paramsIn.LogN() - 1, LogQ: []int{54, 54, 54, 49, 49, 49, 49, 49, 49}, LogP: []int{52, 52}, @@ -386,7 +386,7 @@ func testRefresh(tc *testContext, t *testing.T) { }) } -func testRefreshParameterized(tc *testContext, paramsOut hefloat.Parameters, skOut []*rlwe.SecretKey, transform *MaskedLinearTransformationFunc, t *testing.T) { +func testRefreshParameterized(tc *testContext, paramsOut ckks.Parameters, skOut []*rlwe.SecretKey, transform *MaskedLinearTransformationFunc, t *testing.T) { var err error @@ -464,7 +464,7 @@ func testRefreshParameterized(tc *testContext, paramsOut hefloat.Parameters, skO transform.Func(coeffs) } - hefloat.VerifyTestVectors(paramsOut, hefloat.NewEncoder(paramsOut), rlwe.NewDecryptor(paramsOut, skIdealOut), coeffs, ciphertext, paramsOut.LogDefaultScale(), 0, *printPrecisionStats, t) + ckks.VerifyTestVectors(paramsOut, ckks.NewEncoder(paramsOut), rlwe.NewDecryptor(paramsOut, skIdealOut), coeffs, ciphertext, paramsOut.LogDefaultScale(), 0, *printPrecisionStats, t) } func newTestVectors(tc *testContext, encryptor *rlwe.Encryptor, a, b complex128, logSlots int) (values []*bignum.Complex, plaintext *rlwe.Plaintext, ciphertext *rlwe.Ciphertext) { @@ -475,7 +475,7 @@ func newTestVectorsAtScale(tc *testContext, encryptor *rlwe.Encryptor, a, b comp prec := tc.encoder.Prec() - pt = hefloat.NewPlaintext(tc.params, tc.params.MaxLevel()) + pt = ckks.NewPlaintext(tc.params, tc.params.MaxLevel()) pt.Scale = scale pt.LogDimensions.Cols = logSlots diff --git a/mhe/mhefloat/mhefloat_benchmark_test.go b/mhe/mhefloat/mhefloat_benchmark_test.go index ed850a2a..5b085ca6 100644 --- a/mhe/mhefloat/mhefloat_benchmark_test.go +++ b/mhe/mhefloat/mhefloat_benchmark_test.go @@ -5,10 +5,11 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/hefloat" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/utils/bignum" ) @@ -16,10 +17,10 @@ func BenchmarkMHEFloat(b *testing.B) { var err error - var testParams []hefloat.ParametersLiteral + var testParams []ckks.ParametersLiteral switch { case *flagParamString != "": // the custom test suite reads the parameters from the -params flag - testParams = append(testParams, hefloat.ParametersLiteral{}) + testParams = append(testParams, ckks.ParametersLiteral{}) if err = json.Unmarshal([]byte(*flagParamString), &testParams[0]); err != nil { b.Fatal(err) } @@ -33,8 +34,8 @@ func BenchmarkMHEFloat(b *testing.B) { paramsLiteral.RingType = ringType - var params hefloat.Parameters - if params, err = hefloat.NewParametersFromLiteral(paramsLiteral); err != nil { + var params ckks.Parameters + if params, err = ckks.NewParametersFromLiteral(paramsLiteral); err != nil { b.Fatal(err) } N := 3 @@ -72,7 +73,7 @@ func benchRefresh(tc *testContext, b *testing.B) { p.s = sk0Shards[0] p.share = p.AllocateShare(minLevel, params.MaxLevel()) - ciphertext := hefloat.NewCiphertext(params, 1, minLevel) + ciphertext := ckks.NewCiphertext(params, 1, minLevel) crp := p.SampleCRP(params.MaxLevel(), tc.crs) @@ -91,7 +92,7 @@ func benchRefresh(tc *testContext, b *testing.B) { }) b.Run(GetTestName("Refresh/Finalize", tc.NParties, params), func(b *testing.B) { - opOut := hefloat.NewCiphertext(params, 1, params.MaxLevel()) + opOut := ckks.NewCiphertext(params, 1, params.MaxLevel()) for i := 0; i < b.N; i++ { p.Finalize(ciphertext, crp, p.share, opOut) } @@ -118,7 +119,7 @@ func benchMaskedTransform(tc *testContext, b *testing.B) { share mhe.RefreshShare } - ciphertext := hefloat.NewCiphertext(params, 1, minLevel) + ciphertext := ckks.NewCiphertext(params, 1, minLevel) p := new(Party) p.MaskedLinearTransformationProtocol, _ = NewMaskedLinearTransformationProtocol(params, params, logBound, params.Xe()) @@ -153,7 +154,7 @@ func benchMaskedTransform(tc *testContext, b *testing.B) { }) b.Run(GetTestName("Refresh&Transform/Transform", tc.NParties, params), func(b *testing.B) { - opOut := hefloat.NewCiphertext(params, 1, params.MaxLevel()) + opOut := ckks.NewCiphertext(params, 1, params.MaxLevel()) for i := 0; i < b.N; i++ { p.Transform(ciphertext, transform, crp, p.share, opOut) } diff --git a/mhe/mhefloat/refresh.go b/mhe/mhefloat/refresh.go index f9f4f483..72627232 100644 --- a/mhe/mhefloat/refresh.go +++ b/mhe/mhefloat/refresh.go @@ -1,9 +1,9 @@ package mhefloat import ( - "github.com/tuneinsight/lattigo/v5/he/hefloat" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/core/rlwe" ) @@ -15,7 +15,7 @@ type RefreshProtocol struct { // NewRefreshProtocol creates a new [RefreshProtocol] instance. // prec : the log2 of decimal precision of the internal encoder. -func NewRefreshProtocol(params hefloat.Parameters, prec uint, noise ring.DistributionParameters) (rfp RefreshProtocol, err error) { +func NewRefreshProtocol(params ckks.Parameters, prec uint, noise ring.DistributionParameters) (rfp RefreshProtocol, err error) { rfp = RefreshProtocol{} mt, err := NewMaskedLinearTransformationProtocol(params, params, prec, noise) rfp.MaskedLinearTransformationProtocol = mt diff --git a/mhe/mhefloat/sharing.go b/mhe/mhefloat/sharing.go index 60d4a849..6199b3ed 100644 --- a/mhe/mhefloat/sharing.go +++ b/mhe/mhefloat/sharing.go @@ -4,11 +4,10 @@ import ( "fmt" "math/big" - "github.com/tuneinsight/lattigo/v5/he/hefloat" + "github.com/tuneinsight/lattigo/v5/core/rlwe" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" + "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/utils" "github.com/tuneinsight/lattigo/v5/utils/bignum" "github.com/tuneinsight/lattigo/v5/utils/sampling" @@ -19,13 +18,13 @@ import ( type EncToShareProtocol struct { mhe.KeySwitchProtocol - params hefloat.Parameters + params ckks.Parameters zero *rlwe.SecretKey maskBigint []*big.Int buff ring.Poly } -func NewAdditiveShare(params hefloat.Parameters, logSlots int) mhe.AdditiveShareBigint { +func NewAdditiveShare(params ckks.Parameters, logSlots int) mhe.AdditiveShareBigint { nValues := 1 << logSlots if params.RingType() == ring.Standard { @@ -54,8 +53,8 @@ func (e2s EncToShareProtocol) ShallowCopy() EncToShareProtocol { } } -// NewEncToShareProtocol creates a new [EncToShareProtocol] struct from the passed parameters. -func NewEncToShareProtocol(params hefloat.Parameters, noise ring.DistributionParameters) (EncToShareProtocol, error) { +// NewEncToShareProtocol creates a new EncToShareProtocol struct from the passed parameters. +func NewEncToShareProtocol(params ckks.Parameters, noise ring.DistributionParameters) (EncToShareProtocol, error) { e2s := EncToShareProtocol{} var err error @@ -190,7 +189,7 @@ func (e2s EncToShareProtocol) GetShare(secretShare *mhe.AdditiveShareBigint, agg // required by the shares-to-encryption protocol. type ShareToEncProtocol struct { mhe.KeySwitchProtocol - params hefloat.Parameters + params ckks.Parameters tmp ring.Poly ssBigint []*big.Int zero *rlwe.SecretKey @@ -209,8 +208,8 @@ func (s2e ShareToEncProtocol) ShallowCopy() ShareToEncProtocol { } } -// NewShareToEncProtocol creates a new [ShareToEncProtocol] struct from the passed parameters. -func NewShareToEncProtocol(params hefloat.Parameters, noise ring.DistributionParameters) (ShareToEncProtocol, error) { +// NewShareToEncProtocol creates a new ShareToEncProtocol struct from the passed parameters. +func NewShareToEncProtocol(params ckks.Parameters, noise ring.DistributionParameters) (ShareToEncProtocol, error) { s2e := ShareToEncProtocol{} var err error diff --git a/mhe/mhefloat/test_params.go b/mhe/mhefloat/test_params.go index 9a4a3adc..42e496c6 100644 --- a/mhe/mhefloat/test_params.go +++ b/mhe/mhefloat/test_params.go @@ -1,13 +1,11 @@ package mhefloat -import ( - "github.com/tuneinsight/lattigo/v5/he/hefloat" -) +import "github.com/tuneinsight/lattigo/v5/schemes/ckks" var ( // testInsecurePrec45 are insecure parameters used for the sole purpose of fast testing. - testInsecurePrec45 = hefloat.ParametersLiteral{ + testInsecurePrec45 = ckks.ParametersLiteral{ LogN: 10, Q: []uint64{ 0x80000000080001, @@ -26,7 +24,7 @@ var ( } // testInsecurePrec90 are insecure parameters used for the sole purpose of fast testing. - testInsecurePrec90 = hefloat.ParametersLiteral{ + testInsecurePrec90 = ckks.ParametersLiteral{ LogN: 10, Q: []uint64{ 0x80000000080001, @@ -49,5 +47,5 @@ var ( LogDefaultScale: 90, } - testParamsLiteral = []hefloat.ParametersLiteral{testInsecurePrec45, testInsecurePrec90} + testParamsLiteral = []ckks.ParametersLiteral{testInsecurePrec45, testInsecurePrec90} ) diff --git a/mhe/mhefloat/transform.go b/mhe/mhefloat/transform.go index 84aef21e..925d9393 100644 --- a/mhe/mhefloat/transform.go +++ b/mhe/mhefloat/transform.go @@ -4,9 +4,9 @@ import ( "fmt" "math/big" - "github.com/tuneinsight/lattigo/v5/he/hefloat" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/ckks" "github.com/tuneinsight/lattigo/v5/core/rlwe" "github.com/tuneinsight/lattigo/v5/utils/bignum" @@ -24,7 +24,7 @@ type MaskedLinearTransformationProtocol struct { prec uint mask []*big.Int - encoder *hefloat.Encoder + encoder *ckks.Encoder } // ShallowCopy creates a shallow copy of [MaskedLinearTransformationProtocol] in which all the read-only data-structures are @@ -49,7 +49,7 @@ func (mltp MaskedLinearTransformationProtocol) ShallowCopy() MaskedLinearTransfo // WithParams creates a shallow copy of the target [MaskedLinearTransformationProtocol] but with new output parameters. // The expected input parameters remain unchanged. -func (mltp MaskedLinearTransformationProtocol) WithParams(paramsOut hefloat.Parameters) MaskedLinearTransformationProtocol { +func (mltp MaskedLinearTransformationProtocol) WithParams(paramsOut ckks.Parameters) MaskedLinearTransformationProtocol { s2e, err := NewShareToEncProtocol(paramsOut, mltp.noise) @@ -73,13 +73,13 @@ func (mltp MaskedLinearTransformationProtocol) WithParams(paramsOut hefloat.Para prec: mltp.prec, defaultScale: defaultScale, mask: mask, - encoder: hefloat.NewEncoder(paramsOut, mltp.prec), + encoder: ckks.NewEncoder(paramsOut, mltp.prec), } } // MaskedLinearTransformationFunc represents a user-defined in-place function that can be evaluated on masked float plaintexts, as a part of the // Masked Transform Protocol. -// The function is called with a vector of *[bignum.Complex] modulo [hefloat.Parameters.Slots]() as input, and must write +// The function is called with a vector of *Complex modulo ckks.Parameters.Slots() as input, and must write // its output on the same buffer. // Transform can be the identity. // @@ -94,13 +94,11 @@ type MaskedLinearTransformationFunc struct { } // NewMaskedLinearTransformationProtocol creates a new instance of the PermuteProtocol. -// -// - paramsIn: the [hefloat.Parameters] of the ciphertext before the protocol. -// - paramsOut: the [hefloat.Parameters] of the ciphertext after the protocol. -// - prec : the log2 of decimal precision of the internal encoder. -// +// paramsIn: the ckks.Parameters of the ciphertext before the protocol. +// paramsOut: the ckks.Parameters of the ciphertext after the protocol. +// prec : the log2 of decimal precision of the internal encoder. // The method will return an error if the maximum number of slots of the output parameters is smaller than the number of slots of the input ciphertext. -func NewMaskedLinearTransformationProtocol(paramsIn, paramsOut hefloat.Parameters, prec uint, noise ring.DistributionParameters) (mltp MaskedLinearTransformationProtocol, err error) { +func NewMaskedLinearTransformationProtocol(paramsIn, paramsOut ckks.Parameters, prec uint, noise ring.DistributionParameters) (mltp MaskedLinearTransformationProtocol, err error) { mltp = MaskedLinearTransformationProtocol{} @@ -125,7 +123,7 @@ func NewMaskedLinearTransformationProtocol(paramsIn, paramsOut hefloat.Parameter mltp.mask[i] = new(big.Int) } - mltp.encoder = hefloat.NewEncoder(paramsOut, prec) + mltp.encoder = ckks.NewEncoder(paramsOut, prec) return } diff --git a/mhe/mheint/mheint.go b/mhe/mheint/mheint.go index 221fb346..08525692 100644 --- a/mhe/mheint/mheint.go +++ b/mhe/mheint/mheint.go @@ -1,4 +1,4 @@ // Package mheint implements homomorphic decryption to Linear-Secret-Shared-Shares (LSSS) -// and homomorphic re-encryption from LSSS, as well as interactive bootstrapping for the package [he/heint] -// See mhe/README.md for additional information on multiparty schemes. +// and homomorphic re-encryption from LSSS, as well as interactive bootstrapping for the package `schemes/bgv` +// See `mhe/README.md` for additional information on multiparty schemes. package mheint diff --git a/mhe/mheint/mheint_benchmark_test.go b/mhe/mheint/mheint_benchmark_test.go index 511e741c..4d56ffc6 100644 --- a/mhe/mheint/mheint_benchmark_test.go +++ b/mhe/mheint/mheint_benchmark_test.go @@ -5,9 +5,10 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/heint" "github.com/tuneinsight/lattigo/v5/mhe" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" ) func BenchmarkInteger(b *testing.B) { @@ -17,11 +18,11 @@ func BenchmarkInteger(b *testing.B) { paramsLiterals := testParams if *flagParamString != "" { - var jsonParams heint.ParametersLiteral + var jsonParams bgv.ParametersLiteral if err = json.Unmarshal([]byte(*flagParamString), &jsonParams); err != nil { b.Fatal(err) } - paramsLiterals = []heint.ParametersLiteral{jsonParams} // the custom test suite reads the parameters from the -params flag + paramsLiterals = []bgv.ParametersLiteral{jsonParams} // the custom test suite reads the parameters from the -params flag } for _, p := range paramsLiterals { @@ -30,8 +31,8 @@ func BenchmarkInteger(b *testing.B) { p.PlaintextModulus = plaintextModulus - var params heint.Parameters - if params, err = heint.NewParametersFromLiteral(p); err != nil { + var params bgv.Parameters + if params, err = bgv.NewParametersFromLiteral(p); err != nil { b.Fatal(err) } @@ -67,7 +68,7 @@ func benchRefresh(tc *testContext, b *testing.B) { p.s = sk0Shards[0] p.share = p.AllocateShare(minLevel, maxLevel) - ciphertext := heint.NewCiphertext(tc.params, 1, minLevel) + ciphertext := bgv.NewCiphertext(tc.params, 1, minLevel) crp := p.SampleCRP(maxLevel, tc.crs) @@ -86,7 +87,7 @@ func benchRefresh(tc *testContext, b *testing.B) { }) b.Run(GetTestName("Refresh/Finalize", tc.params, tc.NParties), func(b *testing.B) { - opOut := heint.NewCiphertext(tc.params, 1, maxLevel) + opOut := bgv.NewCiphertext(tc.params, 1, maxLevel) for i := 0; i < b.N; i++ { p.Finalize(ciphertext, crp, p.share, opOut) } diff --git a/mhe/mheint/mheint_test.go b/mhe/mheint/mheint_test.go index 758cdccd..640eb283 100644 --- a/mhe/mheint/mheint_test.go +++ b/mhe/mheint/mheint_test.go @@ -11,16 +11,17 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/heint" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" "github.com/tuneinsight/lattigo/v5/utils/sampling" ) var flagParamString = flag.String("params", "", "specify the test cryptographic parameters as a JSON string. Overrides -short and -long.") -func GetTestName(opname string, p heint.Parameters, parties int) string { +func GetTestName(opname string, p bgv.Parameters, parties int) string { return fmt.Sprintf("%s/LogN=%d/logQ=%d/logP=%d/LogSlots=%dx%d/logT=%d/Qi=%d/Pi=%d/parties=%d", opname, p.LogN(), @@ -35,7 +36,7 @@ func GetTestName(opname string, p heint.Parameters, parties int) string { } type testContext struct { - params heint.Parameters + params bgv.Parameters // Number of parties NParties int @@ -48,7 +49,7 @@ type testContext struct { ringQ *ring.Ring ringP *ring.Ring - encoder *heint.Encoder + encoder *bgv.Encoder sk0Shards []*rlwe.SecretKey sk0 *rlwe.SecretKey @@ -62,7 +63,7 @@ type testContext struct { encryptorPk0 *rlwe.Encryptor decryptorSk0 *rlwe.Decryptor decryptorSk1 *rlwe.Decryptor - evaluator *heint.Evaluator + evaluator *bgv.Evaluator crs mhe.CRS uniformSampler *ring.UniformSampler @@ -75,11 +76,11 @@ func TestInteger(t *testing.T) { paramsLiterals := testParams if *flagParamString != "" { - var jsonParams heint.ParametersLiteral + var jsonParams bgv.ParametersLiteral if err = json.Unmarshal([]byte(*flagParamString), &jsonParams); err != nil { t.Fatal(err) } - paramsLiterals = []heint.ParametersLiteral{jsonParams} // the custom test suite reads the parameters from the -params flag + paramsLiterals = []bgv.ParametersLiteral{jsonParams} // the custom test suite reads the parameters from the -params flag } for _, p := range paramsLiterals { @@ -88,8 +89,8 @@ func TestInteger(t *testing.T) { p.PlaintextModulus = plaintextModulus - var params heint.Parameters - if params, err = heint.NewParametersFromLiteral(p); err != nil { + var params bgv.Parameters + if params, err = bgv.NewParametersFromLiteral(p); err != nil { t.Fatal(err) } @@ -112,7 +113,7 @@ func TestInteger(t *testing.T) { } } -func gentestContext(nParties int, params heint.Parameters) (tc *testContext, err error) { +func gentestContext(nParties int, params bgv.Parameters) (tc *testContext, err error) { tc = new(testContext) @@ -130,8 +131,8 @@ func gentestContext(nParties int, params heint.Parameters) (tc *testContext, err tc.crs = prng tc.uniformSampler = ring.NewUniformSampler(prng, params.RingQ()) - tc.encoder = heint.NewEncoder(tc.params) - tc.evaluator = heint.NewEvaluator(tc.params, nil) + tc.encoder = bgv.NewEncoder(tc.params) + tc.evaluator = bgv.NewEvaluator(tc.params, nil) kgen := rlwe.NewKeyGenerator(tc.params) @@ -229,7 +230,7 @@ func testEncToShares(tc *testContext, t *testing.T) { } } - ctRec := heint.NewCiphertext(tc.params, 1, tc.params.MaxLevel()) + ctRec := bgv.NewCiphertext(tc.params, 1, tc.params.MaxLevel()) *ctRec.MetaData = *ciphertext.MetaData P[0].s2e.GetEncryption(P[0].publicShare, crp, ctRec) @@ -392,9 +393,9 @@ func testRefreshAndTransformSwitchParams(tc *testContext, t *testing.T) { t.Run(GetTestName("RefreshAndTransformSwitchparams", tc.params, tc.NParties), func(t *testing.T) { - var paramsOut heint.Parameters + var paramsOut bgv.Parameters var err error - paramsOut, err = heint.NewParametersFromLiteral(heint.ParametersLiteral{ + paramsOut, err = bgv.NewParametersFromLiteral(bgv.ParametersLiteral{ LogN: paramsIn.LogN(), LogQ: []int{54, 49, 49, 49}, LogP: []int{52, 52}, @@ -476,7 +477,7 @@ func testRefreshAndTransformSwitchParams(tc *testContext, t *testing.T) { coeffsHave := make([]uint64, tc.params.MaxSlots()) dec := rlwe.NewDecryptor(paramsOut.Parameters, skIdealOut) - heint.NewEncoder(paramsOut).Decode(dec.DecryptNew(ciphertext), coeffsHave) + bgv.NewEncoder(paramsOut).Decode(dec.DecryptNew(ciphertext), coeffsHave) //Decrypts and compares require.True(t, ciphertext.Level() == maxLevel) @@ -495,7 +496,7 @@ func newTestVectors(tc *testContext, encryptor *rlwe.Encryptor, t *testing.T) (c coeffsPol.Coeffs[0][i] = uint64(1) } - plaintext = heint.NewPlaintext(tc.params, tc.params.MaxLevel()) + plaintext = bgv.NewPlaintext(tc.params, tc.params.MaxLevel()) plaintext.Scale = tc.params.NewScale(2) require.NoError(t, tc.encoder.Encode(coeffsPol.Coeffs[0], plaintext)) ciphertext, err = encryptor.EncryptNew(plaintext) diff --git a/mhe/mheint/refresh.go b/mhe/mheint/refresh.go index 2a9dda5d..7e19627a 100644 --- a/mhe/mheint/refresh.go +++ b/mhe/mheint/refresh.go @@ -1,11 +1,10 @@ package mheint import ( - "github.com/tuneinsight/lattigo/v5/he/heint" + "github.com/tuneinsight/lattigo/v5/core/rlwe" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" ) // RefreshProtocol is a struct storing the relevant parameters for the Refresh protocol. @@ -21,7 +20,7 @@ func (rfp *RefreshProtocol) ShallowCopy() RefreshProtocol { } // NewRefreshProtocol creates a new Refresh protocol instance. -func NewRefreshProtocol(params heint.Parameters, noiseFlooding ring.DistributionParameters) (rfp RefreshProtocol, err error) { +func NewRefreshProtocol(params bgv.Parameters, noiseFlooding ring.DistributionParameters) (rfp RefreshProtocol, err error) { rfp = RefreshProtocol{} mt, err := NewMaskedTransformProtocol(params, params, noiseFlooding) rfp.MaskedTransformProtocol = mt diff --git a/mhe/mheint/sharing.go b/mhe/mheint/sharing.go index 39a44032..2766641f 100644 --- a/mhe/mheint/sharing.go +++ b/mhe/mheint/sharing.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/tuneinsight/lattigo/v5/core/rlwe" - "github.com/tuneinsight/lattigo/v5/he/heint" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" "github.com/tuneinsight/lattigo/v5/utils" "github.com/tuneinsight/lattigo/v5/utils/sampling" ) @@ -15,17 +15,17 @@ import ( // required by the encryption-to-shares protocol. type EncToShareProtocol struct { mhe.KeySwitchProtocol - params heint.Parameters + params bgv.Parameters maskSampler *ring.UniformSampler - encoder *heint.Encoder + encoder *bgv.Encoder zero *rlwe.SecretKey tmpPlaintextRingT ring.Poly tmpPlaintextRingQ ring.Poly } -func NewAdditiveShare(params heint.Parameters) mhe.AdditiveShare { +func NewAdditiveShare(params bgv.Parameters) mhe.AdditiveShare { return mhe.NewAdditiveShare(params.RingT()) } @@ -54,8 +54,8 @@ func (e2s EncToShareProtocol) ShallowCopy() EncToShareProtocol { } } -// NewEncToShareProtocol creates a new [EncToShareProtocol] struct from the passed [heint.Parameters]. -func NewEncToShareProtocol(params heint.Parameters, noiseFlooding ring.DistributionParameters) (EncToShareProtocol, error) { +// NewEncToShareProtocol creates a new EncToShareProtocol struct from the passed bgv.Parameters. +func NewEncToShareProtocol(params bgv.Parameters, noiseFlooding ring.DistributionParameters) (EncToShareProtocol, error) { e2s := EncToShareProtocol{} var err error @@ -64,7 +64,7 @@ func NewEncToShareProtocol(params heint.Parameters, noiseFlooding ring.Distribut } e2s.params = params - e2s.encoder = heint.NewEncoder(params) + e2s.encoder = bgv.NewEncoder(params) prng, err := sampling.NewPRNG() // Sanity check, this error should not happen. @@ -120,16 +120,16 @@ func (e2s EncToShareProtocol) GetShare(secretShare *mhe.AdditiveShare, aggregate // required by the shares-to-encryption protocol. type ShareToEncProtocol struct { mhe.KeySwitchProtocol - params heint.Parameters + params bgv.Parameters - encoder *heint.Encoder + encoder *bgv.Encoder zero *rlwe.SecretKey tmpPlaintextRingQ ring.Poly } // NewShareToEncProtocol creates a new ShareToEncProtocol struct from the passed integer parameters. -func NewShareToEncProtocol(params heint.Parameters, noiseFlooding ring.DistributionParameters) (ShareToEncProtocol, error) { +func NewShareToEncProtocol(params bgv.Parameters, noiseFlooding ring.DistributionParameters) (ShareToEncProtocol, error) { s2e := ShareToEncProtocol{} var err error @@ -138,7 +138,7 @@ func NewShareToEncProtocol(params heint.Parameters, noiseFlooding ring.Distribut } s2e.params = params - s2e.encoder = heint.NewEncoder(params) + s2e.encoder = bgv.NewEncoder(params) s2e.zero = rlwe.NewSecretKey(params.Parameters) s2e.tmpPlaintextRingQ = params.RingQ().NewPoly() return s2e, nil diff --git a/mhe/mheint/test_parameters.go b/mhe/mheint/test_parameters.go index 8e6810af..21265833 100644 --- a/mhe/mheint/test_parameters.go +++ b/mhe/mheint/test_parameters.go @@ -1,13 +1,11 @@ package mheint -import ( - "github.com/tuneinsight/lattigo/v5/he/heint" -) +import "github.com/tuneinsight/lattigo/v5/schemes/bgv" var ( // testInsecure are insecure parameters used for the sole purpose of fast testing. - testInsecure = heint.ParametersLiteral{ + testInsecure = bgv.ParametersLiteral{ LogN: 10, Q: []uint64{0x3fffffa8001, 0x1000090001, 0x10000c8001, 0x10000f0001, 0xffff00001}, P: []uint64{0x7fffffd8001}, @@ -15,5 +13,5 @@ var ( testPlaintextModulus = []uint64{0x101, 0xffc001} - testParams = []heint.ParametersLiteral{testInsecure} + testParams = []bgv.ParametersLiteral{testInsecure} ) diff --git a/mhe/mheint/transform.go b/mhe/mheint/transform.go index 34d1b302..429fce10 100644 --- a/mhe/mheint/transform.go +++ b/mhe/mheint/transform.go @@ -3,11 +3,10 @@ package mheint import ( "fmt" - "github.com/tuneinsight/lattigo/v5/he/heint" + "github.com/tuneinsight/lattigo/v5/core/rlwe" "github.com/tuneinsight/lattigo/v5/mhe" "github.com/tuneinsight/lattigo/v5/ring" - - "github.com/tuneinsight/lattigo/v5/core/rlwe" + "github.com/tuneinsight/lattigo/v5/schemes/bgv" "github.com/tuneinsight/lattigo/v5/utils/sampling" ) @@ -38,7 +37,7 @@ func (rfp MaskedTransformProtocol) ShallowCopy() MaskedTransformProtocol { // MaskedTransformFunc is a struct containing a user-defined in-place function that can be applied to masked integer plaintexts, as a part of the // Masked Transform Protocol. -// The function is called with a vector of integers modulo [heint.Parameters.PlaintextModulus]() of size [heint.Parameters.N]() as input, and must write +// The function is called with a vector of integers modulo bgv.Parameters.PlaintextModulus() of size bgv.Parameters.N() as input, and must write // its output on the same buffer. // Transform can be the identity. // @@ -53,7 +52,7 @@ type MaskedTransformFunc struct { } // NewMaskedTransformProtocol creates a new instance of the PermuteProtocol. -func NewMaskedTransformProtocol(paramsIn, paramsOut heint.Parameters, noiseFlooding ring.DistributionParameters) (rfp MaskedTransformProtocol, err error) { +func NewMaskedTransformProtocol(paramsIn, paramsOut bgv.Parameters, noiseFlooding ring.DistributionParameters) (rfp MaskedTransformProtocol, err error) { if paramsIn.N() > paramsOut.N() { return MaskedTransformProtocol{}, fmt.Errorf("newMaskedTransformProtocol: paramsIn.N() != paramsOut.N()")