From d1e2f2de66b9be809ee5725b90884675bda415d5 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bossuat Date: Thu, 12 May 2022 17:21:10 +0200 Subject: [PATCH] Fixed potential bugs related to ciphertext/plaintext allocation --- bfv/plaintext.go | 8 ++------ ckks/ciphertext.go | 7 +++---- ckks/plaintext.go | 7 +++---- rlwe/elements.go | 19 ++++++++++++++++--- rlwe/evaluator_automorphism.go | 4 +++- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/bfv/plaintext.go b/bfv/plaintext.go index 9e90e201..f5b0d6d3 100644 --- a/bfv/plaintext.go +++ b/bfv/plaintext.go @@ -45,12 +45,8 @@ func NewPlaintextLvl(params Parameters, level int) *Plaintext { // where the message is set to the passed poly. No checks are performed on poly and // the returned Plaintext will share its backing array of coefficient. func NewPlaintextAtLevelFromPoly(level int, poly *ring.Poly) *Plaintext { - if len(poly.Coeffs) < level+1 { - panic("cannot NewPlaintextAtLevelFromPoly: provided ring.Poly level is too small") - } - v0 := new(ring.Poly) - v0.Coeffs = poly.Coeffs[:level+1] - return &Plaintext{Plaintext: &rlwe.Plaintext{Value: v0}} + pt := rlwe.NewPlaintextAtLevelFromPoly(level, poly) + return &Plaintext{Plaintext: pt} } // NewPlaintextRingT creates and allocates a new plaintext in RingT (single modulus T). diff --git a/ckks/ciphertext.go b/ckks/ciphertext.go index 8842bedc..89a7787f 100644 --- a/ckks/ciphertext.go +++ b/ckks/ciphertext.go @@ -39,10 +39,9 @@ func NewCiphertextRandom(prng utils.PRNG, params Parameters, degree, level int, // where the message is set to the passed poly. No checks are performed on poly and // the returned Ciphertext will share its backing array of coefficient. func NewCiphertextAtLevelFromPoly(level int, poly [2]*ring.Poly) *Ciphertext { - v0, v1 := new(ring.Poly), new(ring.Poly) - v0.IsNTT, v1.IsNTT = true, true - v0.Coeffs, v1.Coeffs = poly[0].Coeffs[:level+1], poly[1].Coeffs[:level+1] - return &Ciphertext{Ciphertext: &rlwe.Ciphertext{Value: []*ring.Poly{v0, v1}}, Scale: 0} + ct := rlwe.NewCiphertextAtLevelFromPoly(level, poly) + ct.Value[0].IsNTT, ct.Value[1].IsNTT = true, true + return &Ciphertext{Ciphertext: ct, Scale: 0} } // ScalingFactor returns the scaling factor of the ciphertext diff --git a/ckks/plaintext.go b/ckks/plaintext.go index 45e0bb81..8cda173b 100644 --- a/ckks/plaintext.go +++ b/ckks/plaintext.go @@ -32,8 +32,7 @@ func (p *Plaintext) SetScalingFactor(scale float64) { // where the message is set to the passed poly. No checks are performed on poly and // the returned Plaintext will share its backing array of coefficient. func NewPlaintextAtLevelFromPoly(level int, poly *ring.Poly) *Plaintext { - v0 := new(ring.Poly) - v0.IsNTT = true - v0.Coeffs = poly.Coeffs[:level+1] - return &Plaintext{Plaintext: &rlwe.Plaintext{Value: v0}, Scale: 0} + pt := rlwe.NewPlaintextAtLevelFromPoly(level, poly) + pt.Value.IsNTT = true + return &Plaintext{Plaintext: pt, Scale: 0} } diff --git a/rlwe/elements.go b/rlwe/elements.go index 0ae652c2..782d9ae0 100644 --- a/rlwe/elements.go +++ b/rlwe/elements.go @@ -61,6 +61,19 @@ func NewPlaintext(params Parameters, level int) *Plaintext { return &Plaintext{Value: ring.NewPoly(params.N(), level)} } +// NewPlaintextAtLevelFromPoly construct a new Plaintext at a specific level +// where the message is set to the passed poly. No checks are performed on poly and +// the returned Plaintext will share its backing array of coefficient. +func NewPlaintextAtLevelFromPoly(level int, poly *ring.Poly) *Plaintext { + if len(poly.Coeffs) < level+1 { + panic("cannot NewPlaintextAtLevelFromPoly: provided ring.Poly level is too small") + } + v0 := new(ring.Poly) + v0.Coeffs = poly.Coeffs[:level+1] + v0.Buff = poly.Buff[:poly.N()*(level+1)] + return &Plaintext{Value: v0} +} + // Degree returns the degree of the target element. func (pt Plaintext) Degree() int { return 0 @@ -105,13 +118,13 @@ func NewCiphertextNTT(params Parameters, degree, level int) *Ciphertext { return el } -// NewCiphertextNTTAtLevelFromPoly construct a new Ciphetext at a specific level +// NewCiphertextAtLevelFromPoly construct a new Ciphetext at a specific level // where the message is set to the passed poly. No checks are performed on poly and // the returned Ciphertext will share its backing array of coefficient. -func NewCiphertextNTTAtLevelFromPoly(level int, poly [2]*ring.Poly) *Ciphertext { +func NewCiphertextAtLevelFromPoly(level int, poly [2]*ring.Poly) *Ciphertext { v0, v1 := new(ring.Poly), new(ring.Poly) - v0.IsNTT, v1.IsNTT = true, true v0.Coeffs, v1.Coeffs = poly[0].Coeffs[:level+1], poly[1].Coeffs[:level+1] + v0.Buff, v1.Buff = poly[0].Buff[:poly[0].N()*(level+1)], poly[1].Buff[:poly[1].N()*(level+1)] return &Ciphertext{Value: []*ring.Poly{v0, v1}} } diff --git a/rlwe/evaluator_automorphism.go b/rlwe/evaluator_automorphism.go index bfc9881b..202a034b 100644 --- a/rlwe/evaluator_automorphism.go +++ b/rlwe/evaluator_automorphism.go @@ -177,7 +177,9 @@ func (eval *Evaluator) Trace(ctIn *Ciphertext, logN int, ctOut *Ciphertext) { ring.MulScalarMontgomeryVec(ctIn.Value[1].Coeffs[i], ctOut.Value[1].Coeffs[i], invN, Q, mredparams) } - buff := NewCiphertextNTTAtLevelFromPoly(levelQ, [2]*ring.Poly{eval.BuffQP[3].Q, eval.BuffQP[4].Q}) + buff := NewCiphertextAtLevelFromPoly(levelQ, [2]*ring.Poly{eval.BuffQP[3].Q, eval.BuffQP[4].Q}) + buff.Value[0].IsNTT = true + buff.Value[1].IsNTT = true for i := logN; i < eval.params.LogN()-1; i++ { eval.Automorphism(ctOut, eval.params.GaloisElementForColumnRotationBy(1<