making the evaluation keys independant of the OperandQP type

As for the public keys, I think it is better to keep evaluation key types
as simple as possible. The "Operand/OperandQP" types are more adapted to
the "data" path, i.e. as operands in a circuit. One obvious exemple is that
there is no point for keys to have the metadata of a ciphertext.Also, we'll
have easier time designing the evaluation logic and evolving the Operand
types if the keys do not depend on them.
This commit is contained in:
Christian Mouchet
2023-06-15 22:20:59 +02:00
parent e232cdcad0
commit 2d7f0e42b1
9 changed files with 194 additions and 127 deletions

View File

@@ -229,8 +229,8 @@ func (gkg *GaloisKeyGenProtocol) GenGaloisKey(share *GaloisKeyGenShare, crp Galo
BITDecomp := len(m[0])
for i := 0; i < RNSDecomp; i++ {
for j := 0; j < BITDecomp; j++ {
gk.Value[i][j].Value[0].Copy(&m[i][j])
gk.Value[i][j].Value[1].Copy(&p[i][j])
gk.Value[i][j][0].Copy(&m[i][j])
gk.Value[i][j][1].Copy(&p[i][j])
}
}

View File

@@ -141,13 +141,13 @@ func (ekg *RelinKeyGenProtocol) GenShareRoundOne(sk *rlwe.SecretKey, crp RelinKe
for j := 0; j < BITDecomp; j++ {
for i := 0; i < RNSDecomp; i++ {
// h = e
ekg.gaussianSamplerQ.Read(shareOut.Value[i][j].Value[0].Q)
ekg.gaussianSamplerQ.Read(shareOut.Value[i][j][0].Q)
if hasModulusP {
ringQP.ExtendBasisSmallNormAndCenter(shareOut.Value[i][j].Value[0].Q, levelP, nil, shareOut.Value[i][j].Value[0].P)
ringQP.ExtendBasisSmallNormAndCenter(shareOut.Value[i][j][0].Q, levelP, nil, shareOut.Value[i][j][0].P)
}
ringQP.NTT(&shareOut.Value[i][j].Value[0], &shareOut.Value[i][j].Value[0])
ringQP.NTT(&shareOut.Value[i][j][0], &shareOut.Value[i][j][0])
// h = sk*CrtBaseDecompQi + e
for k := 0; k < levelP+1; k++ {
@@ -161,7 +161,7 @@ func (ekg *RelinKeyGenProtocol) GenShareRoundOne(sk *rlwe.SecretKey, crp RelinKe
qi := ringQ.SubRings[index].Modulus
skP := ekg.buf[0].Q.Coeffs[index]
h := shareOut.Value[i][j].Value[0].Q.Coeffs[index]
h := shareOut.Value[i][j][0].Q.Coeffs[index]
for w := 0; w < N; w++ {
h[w] = ring.CRed(h[w]+skP[w], qi)
@@ -169,19 +169,19 @@ func (ekg *RelinKeyGenProtocol) GenShareRoundOne(sk *rlwe.SecretKey, crp RelinKe
}
// h = sk*CrtBaseDecompQi + -u*a + e
ringQP.MulCoeffsMontgomeryThenSub(&ephSkOut.Value, &c[i][j], &shareOut.Value[i][j].Value[0])
ringQP.MulCoeffsMontgomeryThenSub(&ephSkOut.Value, &c[i][j], &shareOut.Value[i][j][0])
// Second Element
// e_2i
ekg.gaussianSamplerQ.Read(shareOut.Value[i][j].Value[1].Q)
ekg.gaussianSamplerQ.Read(shareOut.Value[i][j][1].Q)
if hasModulusP {
ringQP.ExtendBasisSmallNormAndCenter(shareOut.Value[i][j].Value[1].Q, levelP, nil, shareOut.Value[i][j].Value[1].P)
ringQP.ExtendBasisSmallNormAndCenter(shareOut.Value[i][j][1].Q, levelP, nil, shareOut.Value[i][j][1].P)
}
ringQP.NTT(&shareOut.Value[i][j].Value[1], &shareOut.Value[i][j].Value[1])
ringQP.NTT(&shareOut.Value[i][j][1], &shareOut.Value[i][j][1])
// s*a + e_2i
ringQP.MulCoeffsMontgomeryThenAdd(&sk.Value, &c[i][j], &shareOut.Value[i][j].Value[1])
ringQP.MulCoeffsMontgomeryThenAdd(&sk.Value, &c[i][j], &shareOut.Value[i][j][1])
}
ringQ.MulScalar(ekg.buf[0].Q, 1<<ekg.params.Pow2Base(), ekg.buf[0].Q)
@@ -220,7 +220,7 @@ func (ekg *RelinKeyGenProtocol) GenShareRoundTwo(ephSk, sk *rlwe.SecretKey, roun
// Computes [(sum samples)*sk + e_1i, sk*a + e_2i]
// (AggregateShareRoundTwo samples) * sk
ringQP.MulCoeffsMontgomeryLazy(&round1.Value[i][j].Value[0], &sk.Value, &shareOut.Value[i][j].Value[0])
ringQP.MulCoeffsMontgomeryLazy(&round1.Value[i][j][0], &sk.Value, &shareOut.Value[i][j][0])
// (AggregateShareRoundTwo samples) * sk + e_1i
ekg.gaussianSamplerQ.Read(ekg.buf[1].Q)
@@ -230,18 +230,18 @@ func (ekg *RelinKeyGenProtocol) GenShareRoundTwo(ephSk, sk *rlwe.SecretKey, roun
}
ringQP.NTT(ekg.buf[1], ekg.buf[1])
ringQP.Add(&shareOut.Value[i][j].Value[0], ekg.buf[1], &shareOut.Value[i][j].Value[0])
ringQP.Add(&shareOut.Value[i][j][0], ekg.buf[1], &shareOut.Value[i][j][0])
// second part
// (u_i - s_i) * (sum [x][s*a_i + e_2i]) + e3i
ekg.gaussianSamplerQ.Read(shareOut.Value[i][j].Value[1].Q)
ekg.gaussianSamplerQ.Read(shareOut.Value[i][j][1].Q)
if levelP > -1 {
ringQP.ExtendBasisSmallNormAndCenter(shareOut.Value[i][j].Value[1].Q, levelP, nil, shareOut.Value[i][j].Value[1].P)
ringQP.ExtendBasisSmallNormAndCenter(shareOut.Value[i][j][1].Q, levelP, nil, shareOut.Value[i][j][1].P)
}
ringQP.NTT(&shareOut.Value[i][j].Value[1], &shareOut.Value[i][j].Value[1])
ringQP.MulCoeffsMontgomeryThenAdd(ekg.buf[0], &round1.Value[i][j].Value[1], &shareOut.Value[i][j].Value[1])
ringQP.NTT(&shareOut.Value[i][j][1], &shareOut.Value[i][j][1])
ringQP.MulCoeffsMontgomeryThenAdd(ekg.buf[0], &round1.Value[i][j][1], &shareOut.Value[i][j][1])
}
}
}
@@ -249,8 +249,8 @@ func (ekg *RelinKeyGenProtocol) GenShareRoundTwo(ephSk, sk *rlwe.SecretKey, roun
// AggregateShares combines two RelinKeyGen shares into a single one.
func (ekg *RelinKeyGenProtocol) AggregateShares(share1, share2, shareOut *RelinKeyGenShare) {
levelQ := share1.Value[0][0].LevelQ()
levelP := share1.Value[0][0].LevelP()
levelQ := share1.Value[0][0][0].LevelQ()
levelP := share1.Value[0][0][0].LevelP()
ringQP := ekg.params.RingQP().AtLevel(levelQ, levelP)
@@ -258,8 +258,8 @@ func (ekg *RelinKeyGenProtocol) AggregateShares(share1, share2, shareOut *RelinK
BITDecomp := len(shareOut.Value[0])
for i := 0; i < RNSDecomp; i++ {
for j := 0; j < BITDecomp; j++ {
ringQP.Add(&share1.Value[i][j].Value[0], &share2.Value[i][j].Value[0], &shareOut.Value[i][j].Value[0])
ringQP.Add(&share1.Value[i][j].Value[1], &share2.Value[i][j].Value[1], &shareOut.Value[i][j].Value[1])
ringQP.Add(&share1.Value[i][j][0], &share2.Value[i][j][0], &shareOut.Value[i][j][0])
ringQP.Add(&share1.Value[i][j][1], &share2.Value[i][j][1], &shareOut.Value[i][j][1])
}
}
}
@@ -277,8 +277,8 @@ func (ekg *RelinKeyGenProtocol) AggregateShares(share1, share2, shareOut *RelinK
// = [s * b + P * s^2 + s*e0 + u*e1 + e2 + e3, b]
func (ekg *RelinKeyGenProtocol) GenRelinearizationKey(round1 *RelinKeyGenShare, round2 *RelinKeyGenShare, evalKeyOut *rlwe.RelinearizationKey) {
levelQ := round1.Value[0][0].LevelQ()
levelP := round1.Value[0][0].LevelP()
levelQ := round1.Value[0][0][0].LevelQ()
levelP := round1.Value[0][0][0].LevelP()
ringQP := ekg.params.RingQP().AtLevel(levelQ, levelP)
@@ -286,10 +286,10 @@ func (ekg *RelinKeyGenProtocol) GenRelinearizationKey(round1 *RelinKeyGenShare,
BITDecomp := len(round1.Value[0])
for i := 0; i < RNSDecomp; i++ {
for j := 0; j < BITDecomp; j++ {
ringQP.Add(&round2.Value[i][j].Value[0], &round2.Value[i][j].Value[1], &evalKeyOut.Value[i][j].Value[0])
evalKeyOut.Value[i][j].Value[1].Copy(&round1.Value[i][j].Value[1])
ringQP.MForm(&evalKeyOut.Value[i][j].Value[0], &evalKeyOut.Value[i][j].Value[0])
ringQP.MForm(&evalKeyOut.Value[i][j].Value[1], &evalKeyOut.Value[i][j].Value[1])
ringQP.Add(&round2.Value[i][j][0], &round2.Value[i][j][1], &evalKeyOut.Value[i][j][0])
evalKeyOut.Value[i][j][1].Copy(&round1.Value[i][j][1])
ringQP.MForm(&evalKeyOut.Value[i][j][0], &evalKeyOut.Value[i][j][0])
ringQP.MForm(&evalKeyOut.Value[i][j][1], &evalKeyOut.Value[i][j][1])
}
}
}

View File

@@ -69,8 +69,8 @@ func (enc *Encryptor) EncryptZero(ct interface{}) {
for j := 0; j < decompPw2; j++ {
for i := 0; i < decompRNS; i++ {
enc.EncryptorInterface.EncryptZero(rgswCt.Value[0].Value[i][j])
enc.EncryptorInterface.EncryptZero(rgswCt.Value[1].Value[i][j])
enc.EncryptorInterface.EncryptZero(&rlwe.OperandQP{MetaData: rlwe.MetaData{IsNTT: true, IsMontgomery: true}, Value: rgswCt.Value[0].Value[i][j][:]})
enc.EncryptorInterface.EncryptZero(&rlwe.OperandQP{MetaData: rlwe.MetaData{IsNTT: true, IsMontgomery: true}, Value: rgswCt.Value[1].Value[i][j][:]})
}
}
}

View File

@@ -103,12 +103,12 @@ func (eval *Evaluator) externalProduct32Bit(ct0 *rlwe.Ciphertext, rgsw *Cipherte
ring.MaskVec(eval.BuffInvNTT.Coeffs[0], j*pw2, mask, cw)
if j == 0 && i == 0 {
subRing.NTTLazy(cw, cwNTT)
subRing.MulCoeffsLazy(el.Value[0][j].Value[0].Q.Coeffs[0], cwNTT, acc0)
subRing.MulCoeffsLazy(el.Value[0][j].Value[1].Q.Coeffs[0], cwNTT, acc1)
subRing.MulCoeffsLazy(el.Value[0][j][0].Q.Coeffs[0], cwNTT, acc0)
subRing.MulCoeffsLazy(el.Value[0][j][1].Q.Coeffs[0], cwNTT, acc1)
} else {
subRing.NTTLazy(cw, cwNTT)
subRing.MulCoeffsLazyThenAddLazy(el.Value[0][j].Value[0].Q.Coeffs[0], cwNTT, acc0)
subRing.MulCoeffsLazyThenAddLazy(el.Value[0][j].Value[1].Q.Coeffs[0], cwNTT, acc1)
subRing.MulCoeffsLazyThenAddLazy(el.Value[0][j][0].Q.Coeffs[0], cwNTT, acc0)
subRing.MulCoeffsLazyThenAddLazy(el.Value[0][j][1].Q.Coeffs[0], cwNTT, acc1)
}
}
}
@@ -148,15 +148,15 @@ func (eval *Evaluator) externalProductInPlaceSinglePAndBitDecomp(ct0 *rlwe.Ciphe
for u, s := range ringQ.SubRings[:levelQ+1] {
s.NTTLazy(cw, cwNTT)
s.MulCoeffsMontgomery(el.Value[i][j].Value[0].Q.Coeffs[u], cwNTT, c0QP.Q.Coeffs[u])
s.MulCoeffsMontgomery(el.Value[i][j].Value[1].Q.Coeffs[u], cwNTT, c1QP.Q.Coeffs[u])
s.MulCoeffsMontgomery(el.Value[i][j][0].Q.Coeffs[u], cwNTT, c0QP.Q.Coeffs[u])
s.MulCoeffsMontgomery(el.Value[i][j][1].Q.Coeffs[u], cwNTT, c1QP.Q.Coeffs[u])
}
if ringP != nil {
for u, s := range ringP.SubRings[:levelP+1] {
s.NTTLazy(cw, cwNTT)
s.MulCoeffsMontgomery(el.Value[i][j].Value[0].P.Coeffs[u], cwNTT, c0QP.P.Coeffs[u])
s.MulCoeffsMontgomery(el.Value[i][j].Value[1].P.Coeffs[u], cwNTT, c1QP.P.Coeffs[u])
s.MulCoeffsMontgomery(el.Value[i][j][0].P.Coeffs[u], cwNTT, c0QP.P.Coeffs[u])
s.MulCoeffsMontgomery(el.Value[i][j][1].P.Coeffs[u], cwNTT, c1QP.P.Coeffs[u])
}
}
@@ -164,15 +164,15 @@ func (eval *Evaluator) externalProductInPlaceSinglePAndBitDecomp(ct0 *rlwe.Ciphe
for u, s := range ringQ.SubRings[:levelQ+1] {
s.NTTLazy(cw, cwNTT)
s.MulCoeffsMontgomeryThenAdd(el.Value[i][j].Value[0].Q.Coeffs[u], cwNTT, c0QP.Q.Coeffs[u])
s.MulCoeffsMontgomeryThenAdd(el.Value[i][j].Value[1].Q.Coeffs[u], cwNTT, c1QP.Q.Coeffs[u])
s.MulCoeffsMontgomeryThenAdd(el.Value[i][j][0].Q.Coeffs[u], cwNTT, c0QP.Q.Coeffs[u])
s.MulCoeffsMontgomeryThenAdd(el.Value[i][j][1].Q.Coeffs[u], cwNTT, c1QP.Q.Coeffs[u])
}
if ringP != nil {
for u, s := range ringP.SubRings[:levelP+1] {
s.NTTLazy(cw, cwNTT)
s.MulCoeffsMontgomeryThenAdd(el.Value[i][j].Value[0].P.Coeffs[u], cwNTT, c0QP.P.Coeffs[u])
s.MulCoeffsMontgomeryThenAdd(el.Value[i][j].Value[1].P.Coeffs[u], cwNTT, c1QP.P.Coeffs[u])
s.MulCoeffsMontgomeryThenAdd(el.Value[i][j][0].P.Coeffs[u], cwNTT, c0QP.P.Coeffs[u])
s.MulCoeffsMontgomeryThenAdd(el.Value[i][j][1].P.Coeffs[u], cwNTT, c1QP.P.Coeffs[u])
}
}
}
@@ -218,11 +218,11 @@ func (eval *Evaluator) externalProductInPlaceMultipleP(levelQ, levelP int, ct0 *
eval.DecomposeSingleNTT(levelQ, levelP, levelP+1, i, c2NTT, c2InvNTT, c2QP.Q, c2QP.P)
if k == 0 && i == 0 {
ringQP.MulCoeffsMontgomeryLazy(&el.Value[i][0].Value[0], &c2QP, &c0QP)
ringQP.MulCoeffsMontgomeryLazy(&el.Value[i][0].Value[1], &c2QP, &c1QP)
ringQP.MulCoeffsMontgomeryLazy(&el.Value[i][0][0], &c2QP, &c0QP)
ringQP.MulCoeffsMontgomeryLazy(&el.Value[i][0][1], &c2QP, &c1QP)
} else {
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&el.Value[i][0].Value[0], &c2QP, &c0QP)
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&el.Value[i][0].Value[1], &c2QP, &c1QP)
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&el.Value[i][0][0], &c2QP, &c0QP)
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&el.Value[i][0][1], &c2QP, &c1QP)
}
if reduce%QiOverF == QiOverF-1 {
@@ -271,18 +271,18 @@ func AddLazy(op interface{}, ringQP ringqp.Ring, ctOut *Ciphertext) {
end = nQ
}
for k := start; k < end; k++ {
s.AddLazy(ctOut.Value[0].Value[i][j].Value[0].Q.Coeffs[k], el.Value[j].Coeffs[k], ctOut.Value[0].Value[i][j].Value[0].Q.Coeffs[k])
s.AddLazy(ctOut.Value[1].Value[i][j].Value[1].Q.Coeffs[k], el.Value[j].Coeffs[k], ctOut.Value[1].Value[i][j].Value[1].Q.Coeffs[k])
s.AddLazy(ctOut.Value[0].Value[i][j][0].Q.Coeffs[k], el.Value[j].Coeffs[k], ctOut.Value[0].Value[i][j][0].Q.Coeffs[k])
s.AddLazy(ctOut.Value[1].Value[i][j][1].Q.Coeffs[k], el.Value[j].Coeffs[k], ctOut.Value[1].Value[i][j][1].Q.Coeffs[k])
}
}
}
case *Ciphertext:
for i := range el.Value[0].Value {
for j := range el.Value[0].Value[i] {
ringQP.AddLazy(&ctOut.Value[0].Value[i][j].Value[0], &el.Value[0].Value[i][j].Value[0], &ctOut.Value[0].Value[i][j].Value[0])
ringQP.AddLazy(&ctOut.Value[0].Value[i][j].Value[1], &el.Value[0].Value[i][j].Value[1], &ctOut.Value[0].Value[i][j].Value[1])
ringQP.AddLazy(&ctOut.Value[1].Value[i][j].Value[0], &el.Value[1].Value[i][j].Value[0], &ctOut.Value[1].Value[i][j].Value[0])
ringQP.AddLazy(&ctOut.Value[1].Value[i][j].Value[1], &el.Value[1].Value[i][j].Value[1], &ctOut.Value[1].Value[i][j].Value[1])
ringQP.AddLazy(&ctOut.Value[0].Value[i][j][0], &el.Value[0].Value[i][j][0], &ctOut.Value[0].Value[i][j][0])
ringQP.AddLazy(&ctOut.Value[0].Value[i][j][1], &el.Value[0].Value[i][j][1], &ctOut.Value[0].Value[i][j][1])
ringQP.AddLazy(&ctOut.Value[1].Value[i][j][0], &el.Value[1].Value[i][j][0], &ctOut.Value[1].Value[i][j][0])
ringQP.AddLazy(&ctOut.Value[1].Value[i][j][1], &el.Value[1].Value[i][j][1], &ctOut.Value[1].Value[i][j][1])
}
}
default:
@@ -294,10 +294,10 @@ func AddLazy(op interface{}, ringQP ringqp.Ring, ctOut *Ciphertext) {
func Reduce(ctIn *Ciphertext, ringQP ringqp.Ring, ctOut *Ciphertext) {
for i := range ctIn.Value[0].Value {
for j := range ctIn.Value[0].Value[i] {
ringQP.Reduce(&ctIn.Value[0].Value[i][j].Value[0], &ctOut.Value[0].Value[i][j].Value[0])
ringQP.Reduce(&ctIn.Value[0].Value[i][j].Value[1], &ctOut.Value[0].Value[i][j].Value[1])
ringQP.Reduce(&ctIn.Value[1].Value[i][j].Value[0], &ctOut.Value[1].Value[i][j].Value[0])
ringQP.Reduce(&ctIn.Value[1].Value[i][j].Value[1], &ctOut.Value[1].Value[i][j].Value[1])
ringQP.Reduce(&ctIn.Value[0].Value[i][j][0], &ctOut.Value[0].Value[i][j][0])
ringQP.Reduce(&ctIn.Value[0].Value[i][j][1], &ctOut.Value[0].Value[i][j][1])
ringQP.Reduce(&ctIn.Value[1].Value[i][j][0], &ctOut.Value[1].Value[i][j][0])
ringQP.Reduce(&ctIn.Value[1].Value[i][j][1], &ctOut.Value[1].Value[i][j][1])
}
}
}
@@ -306,10 +306,10 @@ func Reduce(ctIn *Ciphertext, ringQP ringqp.Ring, ctOut *Ciphertext) {
func MulByXPowAlphaMinusOneLazy(ctIn *Ciphertext, powXMinusOne ringqp.Poly, ringQP ringqp.Ring, ctOut *Ciphertext) {
for i := range ctIn.Value[0].Value {
for j := range ctIn.Value[0].Value[i] {
ringQP.MulCoeffsMontgomeryLazy(&ctIn.Value[0].Value[i][j].Value[0], &powXMinusOne, &ctOut.Value[0].Value[i][j].Value[0])
ringQP.MulCoeffsMontgomeryLazy(&ctIn.Value[0].Value[i][j].Value[1], &powXMinusOne, &ctOut.Value[0].Value[i][j].Value[1])
ringQP.MulCoeffsMontgomeryLazy(&ctIn.Value[1].Value[i][j].Value[0], &powXMinusOne, &ctOut.Value[1].Value[i][j].Value[0])
ringQP.MulCoeffsMontgomeryLazy(&ctIn.Value[1].Value[i][j].Value[1], &powXMinusOne, &ctOut.Value[1].Value[i][j].Value[1])
ringQP.MulCoeffsMontgomeryLazy(&ctIn.Value[0].Value[i][j][0], &powXMinusOne, &ctOut.Value[0].Value[i][j][0])
ringQP.MulCoeffsMontgomeryLazy(&ctIn.Value[0].Value[i][j][1], &powXMinusOne, &ctOut.Value[0].Value[i][j][1])
ringQP.MulCoeffsMontgomeryLazy(&ctIn.Value[1].Value[i][j][0], &powXMinusOne, &ctOut.Value[1].Value[i][j][0])
ringQP.MulCoeffsMontgomeryLazy(&ctIn.Value[1].Value[i][j][1], &powXMinusOne, &ctOut.Value[1].Value[i][j][1])
}
}
}
@@ -318,10 +318,10 @@ func MulByXPowAlphaMinusOneLazy(ctIn *Ciphertext, powXMinusOne ringqp.Poly, ring
func MulByXPowAlphaMinusOneThenAddLazy(ctIn *Ciphertext, powXMinusOne ringqp.Poly, ringQP ringqp.Ring, ctOut *Ciphertext) {
for i := range ctIn.Value[0].Value {
for j := range ctIn.Value[0].Value[i] {
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&ctIn.Value[0].Value[i][j].Value[0], &powXMinusOne, &ctOut.Value[0].Value[i][j].Value[0])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&ctIn.Value[0].Value[i][j].Value[1], &powXMinusOne, &ctOut.Value[0].Value[i][j].Value[1])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&ctIn.Value[1].Value[i][j].Value[0], &powXMinusOne, &ctOut.Value[1].Value[i][j].Value[0])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&ctIn.Value[1].Value[i][j].Value[1], &powXMinusOne, &ctOut.Value[1].Value[i][j].Value[1])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&ctIn.Value[0].Value[i][j][0], &powXMinusOne, &ctOut.Value[0].Value[i][j][0])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&ctIn.Value[0].Value[i][j][1], &powXMinusOne, &ctOut.Value[0].Value[i][j][1])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&ctIn.Value[1].Value[i][j][0], &powXMinusOne, &ctOut.Value[1].Value[i][j][0])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&ctIn.Value[1].Value[i][j][1], &powXMinusOne, &ctOut.Value[1].Value[i][j][1])
}
}
}

View File

@@ -141,11 +141,11 @@ func (eval *Evaluator) gadgetProductMultiplePLazy(levelQ int, cx *ring.Poly, gad
eval.DecomposeSingleNTT(levelQ, levelP, levelP+1, i, cxNTT, cxInvNTT, c2QP.Q, c2QP.P)
if i == 0 {
ringQP.MulCoeffsMontgomeryLazy(&el[i][0].Value[0], &c2QP, &ct.Value[0])
ringQP.MulCoeffsMontgomeryLazy(&el[i][0].Value[1], &c2QP, &ct.Value[1])
ringQP.MulCoeffsMontgomeryLazy(&el[i][0][0], &c2QP, &ct.Value[0])
ringQP.MulCoeffsMontgomeryLazy(&el[i][0][1], &c2QP, &ct.Value[1])
} else {
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&el[i][0].Value[0], &c2QP, &ct.Value[0])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&el[i][0].Value[1], &c2QP, &ct.Value[1])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&el[i][0][0], &c2QP, &ct.Value[0])
ringQP.MulCoeffsMontgomeryLazyThenAddLazy(&el[i][0][1], &c2QP, &ct.Value[1])
}
if reduce%QiOverF == QiOverF-1 {
@@ -218,30 +218,30 @@ func (eval *Evaluator) gadgetProductSinglePAndBitDecompLazy(levelQ int, cx *ring
if i == 0 && j == 0 {
for u, s := range ringQ.SubRings[:levelQ+1] {
s.NTTLazy(cw, cwNTT)
s.MulCoeffsMontgomeryLazy(el[i][j].Value[0].Q.Coeffs[u], cwNTT, ct.Value[0].Q.Coeffs[u])
s.MulCoeffsMontgomeryLazy(el[i][j].Value[1].Q.Coeffs[u], cwNTT, ct.Value[1].Q.Coeffs[u])
s.MulCoeffsMontgomeryLazy(el[i][j][0].Q.Coeffs[u], cwNTT, ct.Value[0].Q.Coeffs[u])
s.MulCoeffsMontgomeryLazy(el[i][j][1].Q.Coeffs[u], cwNTT, ct.Value[1].Q.Coeffs[u])
}
if ringP != nil {
for u, s := range ringP.SubRings[:levelP+1] {
s.NTTLazy(cw, cwNTT)
s.MulCoeffsMontgomeryLazy(el[i][j].Value[0].P.Coeffs[u], cwNTT, ct.Value[0].P.Coeffs[u])
s.MulCoeffsMontgomeryLazy(el[i][j].Value[1].P.Coeffs[u], cwNTT, ct.Value[1].P.Coeffs[u])
s.MulCoeffsMontgomeryLazy(el[i][j][0].P.Coeffs[u], cwNTT, ct.Value[0].P.Coeffs[u])
s.MulCoeffsMontgomeryLazy(el[i][j][1].P.Coeffs[u], cwNTT, ct.Value[1].P.Coeffs[u])
}
}
} else {
for u, s := range ringQ.SubRings[:levelQ+1] {
s.NTTLazy(cw, cwNTT)
s.MulCoeffsMontgomeryLazyThenAddLazy(el[i][j].Value[0].Q.Coeffs[u], cwNTT, ct.Value[0].Q.Coeffs[u])
s.MulCoeffsMontgomeryLazyThenAddLazy(el[i][j].Value[1].Q.Coeffs[u], cwNTT, ct.Value[1].Q.Coeffs[u])
s.MulCoeffsMontgomeryLazyThenAddLazy(el[i][j][0].Q.Coeffs[u], cwNTT, ct.Value[0].Q.Coeffs[u])
s.MulCoeffsMontgomeryLazyThenAddLazy(el[i][j][1].Q.Coeffs[u], cwNTT, ct.Value[1].Q.Coeffs[u])
}
if ringP != nil {
for u, s := range ringP.SubRings[:levelP+1] {
s.NTTLazy(cw, cwNTT)
s.MulCoeffsMontgomeryLazyThenAddLazy(el[i][j].Value[0].P.Coeffs[u], cwNTT, ct.Value[0].P.Coeffs[u])
s.MulCoeffsMontgomeryLazyThenAddLazy(el[i][j].Value[1].P.Coeffs[u], cwNTT, ct.Value[1].P.Coeffs[u])
s.MulCoeffsMontgomeryLazyThenAddLazy(el[i][j][0].P.Coeffs[u], cwNTT, ct.Value[0].P.Coeffs[u])
s.MulCoeffsMontgomeryLazyThenAddLazy(el[i][j][1].P.Coeffs[u], cwNTT, ct.Value[1].P.Coeffs[u])
}
}
}
@@ -323,7 +323,7 @@ func (eval *Evaluator) GadgetProductHoistedLazy(levelQ int, BuffQPDecompQP []rin
var reduce int
for i := 0; i < decompRNS; i++ {
gct := gadgetCt.Value[i][0].Value
gct := gadgetCt.Value[i][0]
if i == 0 {
ringQP.MulCoeffsMontgomeryLazy(&gct[0], &BuffQPDecompQP[i], c0QP)

View File

@@ -12,24 +12,19 @@ import (
// GadgetCiphertext is a struct for storing an encrypted
// plaintext times the gadget power matrix.
type GadgetCiphertext struct {
Value structs.Matrix[OperandQP]
Value structs.Matrix[tupleQP]
}
// NewGadgetCiphertext returns a new Ciphertext key with pre-allocated zero-value.
// Ciphertext is always in the NTT domain.
func NewGadgetCiphertext(params ParametersInterface, levelQ, levelP, decompRNS, decompBIT int) *GadgetCiphertext {
m := make([][]OperandQP, decompRNS)
m := make(structs.Matrix[tupleQP], decompRNS)
for i := 0; i < decompRNS; i++ {
v := make([]OperandQP, decompBIT)
for j := range v {
v[j] = *NewOperandQP(params, 1, levelQ, levelP)
v[j].IsNTT = true
v[j].IsMontgomery = true
m[i] = make([]tupleQP, decompBIT)
for j := range m[i] {
m[i][j] = newTupleQPAtLevel(params, levelQ, levelP)
}
m[i] = v
}
return &GadgetCiphertext{Value: m}
@@ -37,12 +32,12 @@ func NewGadgetCiphertext(params ParametersInterface, levelQ, levelP, decompRNS,
// LevelQ returns the level of the modulus Q of the target Ciphertext.
func (ct GadgetCiphertext) LevelQ() int {
return ct.Value[0][0].LevelQ()
return ct.Value[0][0][0].LevelQ()
}
// LevelP returns the level of the modulus P of the target Ciphertext.
func (ct GadgetCiphertext) LevelP() int {
return ct.Value[0][0].LevelP()
return ct.Value[0][0][0].LevelP()
}
// Equal checks two Ciphertexts for equality.
@@ -55,11 +50,11 @@ func (ct *GadgetCiphertext) CopyNew() (ctCopy *GadgetCiphertext) {
if ct == nil || len(ct.Value) == 0 {
return nil
}
v := make([][]OperandQP, len(ct.Value))
v := make(structs.Matrix[tupleQP], len(ct.Value))
for i := range ct.Value {
v[i] = make([]OperandQP, len(ct.Value[0]))
v[i] = make([]tupleQP, len(ct.Value[0]))
for j, el := range ct.Value[i] {
v[i][j] = *el.CopyNew()
v[i][j] = el.CopyNew()
}
}
return &GadgetCiphertext{Value: v}
@@ -162,7 +157,7 @@ func AddPolyTimesGadgetVectorToGadgetCiphertext(pt *ring.Poly, cts []GadgetCiphe
p0tmp := buff.Coeffs[index]
for u, ct := range cts {
p1tmp := ct.Value[i][j].Value[u].Q.Coeffs[index]
p1tmp := ct.Value[i][j][u].Q.Coeffs[index]
for w := 0; w < N; w++ {
p1tmp[w] = ring.CRed(p1tmp[w]+p0tmp[w], qi)
}

View File

@@ -304,7 +304,7 @@ func (kgen *KeyGenerator) genEvaluationKey(skIn *ring.Poly, skOut *SecretKey, ev
// Samples an encryption of zero for each element of the EvaluationKey.
for i := 0; i < len(evk.Value); i++ {
for j := 0; j < len(evk.Value[0]); j++ {
enc.EncryptZero(evk.Value[i][j])
enc.EncryptZero(&OperandQP{MetaData: MetaData{IsNTT: true, IsMontgomery: true}, Value: evk.Value[i][j][:]})
}
}

View File

@@ -95,29 +95,31 @@ func (sk *SecretKey) UnmarshalBinary(p []byte) (err error) {
return sk.Value.UnmarshalBinary(p)
}
// PublicKey is a type for generic RLWE public keys.
// The Value field stores the polynomials in NTT and Montgomery form.
type PublicKey struct {
Value [2]ringqp.Poly
type tupleQP [2]ringqp.Poly
// NewPublicKey returns a new PublicKey with zero values.
func newTupleQP(params ParametersInterface) (pk tupleQP) {
return [2]ringqp.Poly{*params.RingQP().NewPoly(), *params.RingQP().NewPoly()}
}
// NewPublicKey returns a new PublicKey with zero values.
func NewPublicKey(params ParametersInterface) (pk *PublicKey) {
return &PublicKey{Value: [2]ringqp.Poly{*params.RingQP().NewPoly(), *params.RingQP().NewPoly()}}
func newTupleQPAtLevel(params ParametersInterface, levelQ, levelP int) (pk tupleQP) {
rqp := params.RingQP().AtLevel(levelQ, levelP)
return [2]ringqp.Poly{*rqp.NewPoly(), *rqp.NewPoly()}
}
// CopyNew creates a deep copy of the target PublicKey and returns it.
func (p *PublicKey) CopyNew() *PublicKey {
return &PublicKey{Value: [2]ringqp.Poly{*p.Value[0].CopyNew(), *p.Value[1].CopyNew()}}
func (p *tupleQP) CopyNew() tupleQP {
return [2]ringqp.Poly{*p[0].CopyNew(), *p[1].CopyNew()}
}
// Equal performs a deep equal.
func (p *PublicKey) Equal(other *PublicKey) bool {
return p.Value[0].Equal(&other.Value[0]) && p.Value[1].Equal(&other.Value[1])
func (p *tupleQP) Equal(other tupleQP) bool {
return p[0].Equal(&other[0]) && p[1].Equal(&other[1])
}
func (p *PublicKey) BinarySize() int {
return structs.Vector[ringqp.Poly](p.Value[:]).BinarySize()
func (p *tupleQP) BinarySize() int {
return structs.Vector[ringqp.Poly](p[:]).BinarySize()
}
// WriteTo writes the object on an io.Writer. It implements the io.WriterTo
@@ -131,8 +133,8 @@ func (p *PublicKey) BinarySize() int {
// io.Writer in a pre-allocated bufio.Writer.
// - When writing to a pre-allocated var b []byte, it is preferable to pass
// buffer.NewBuffer(b) as w (see lattigo/utils/buffer/buffer.go).
func (p *PublicKey) WriteTo(w io.Writer) (n int64, err error) {
v := structs.Vector[ringqp.Poly](p.Value[:])
func (p *tupleQP) WriteTo(w io.Writer) (n int64, err error) {
v := structs.Vector[ringqp.Poly](p[:])
return v.WriteTo(w)
}
@@ -147,8 +149,8 @@ func (p *PublicKey) WriteTo(w io.Writer) (n int64, err error) {
// first wrap io.Reader in a pre-allocated bufio.Reader.
// - When reading from a var b []byte, it is preferable to pass a buffer.NewBuffer(b)
// as w (see lattigo/utils/buffer/buffer.go).
func (p *PublicKey) ReadFrom(r io.Reader) (n int64, err error) {
v := structs.Vector[ringqp.Poly](p.Value[:])
func (p *tupleQP) ReadFrom(r io.Reader) (n int64, err error) {
v := structs.Vector[ringqp.Poly](p[:])
n, err = v.ReadFrom(r)
if len(v) != 2 {
return n, fmt.Errorf("bad public key format")
@@ -157,15 +159,15 @@ func (p *PublicKey) ReadFrom(r io.Reader) (n int64, err error) {
}
// MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes.
func (p *PublicKey) MarshalBinary() ([]byte, error) {
v := structs.Vector[ringqp.Poly](p.Value[:])
func (p *tupleQP) MarshalBinary() ([]byte, error) {
v := structs.Vector[ringqp.Poly](p[:])
return v.MarshalBinary()
}
// UnmarshalBinary decodes a slice of bytes generated by
// MarshalBinary or WriteTo on the object.
func (p *PublicKey) UnmarshalBinary(b []byte) error {
v := structs.Vector[ringqp.Poly](p.Value[:])
func (p *tupleQP) UnmarshalBinary(b []byte) error {
v := structs.Vector[ringqp.Poly](p[:])
err := v.UnmarshalBinary(b)
if len(v) != 2 {
return fmt.Errorf("bad public key format")
@@ -173,6 +175,72 @@ func (p *PublicKey) UnmarshalBinary(b []byte) error {
return err
}
// PublicKey is a type for generic RLWE public keys.
// The Value field stores the polynomials in NTT and Montgomery form.
type PublicKey struct {
Value tupleQP
}
// NewPublicKey returns a new PublicKey with zero values.
func NewPublicKey(params ParametersInterface) (pk *PublicKey) {
return &PublicKey{Value: newTupleQP(params)}
}
// CopyNew creates a deep copy of the target PublicKey and returns it.
func (p *PublicKey) CopyNew() *PublicKey {
return &PublicKey{Value: p.Value.CopyNew()}
}
// Equal performs a deep equal.
func (p *PublicKey) Equal(other *PublicKey) bool {
return p.Value.Equal(other.Value)
}
func (p *PublicKey) BinarySize() int {
return p.Value.BinarySize()
}
// WriteTo writes the object on an io.Writer. It implements the io.WriterTo
// interface, and will write exactly object.BinarySize() bytes on w.
//
// Unless w implements the buffer.Writer interface (see lattigo/utils/buffer/writer.go),
// it will be wrapped into a bufio.Writer. Since this requires allocations, it
// is preferable to pass a buffer.Writer directly:
//
// - When writing multiple times to a io.Writer, it is preferable to first wrap the
// io.Writer in a pre-allocated bufio.Writer.
// - When writing to a pre-allocated var b []byte, it is preferable to pass
// buffer.NewBuffer(b) as w (see lattigo/utils/buffer/buffer.go).
func (p *PublicKey) WriteTo(w io.Writer) (n int64, err error) {
return p.Value.WriteTo(w)
}
// ReadFrom reads on the object from an io.Writer. It implements the
// io.ReaderFrom interface.
//
// Unless r implements the buffer.Reader interface (see see lattigo/utils/buffer/reader.go),
// it will be wrapped into a bufio.Reader. Since this requires allocation, it
// is preferable to pass a buffer.Reader directly:
//
// - When reading multiple values from a io.Reader, it is preferable to first
// first wrap io.Reader in a pre-allocated bufio.Reader.
// - When reading from a var b []byte, it is preferable to pass a buffer.NewBuffer(b)
// as w (see lattigo/utils/buffer/buffer.go).
func (p *PublicKey) ReadFrom(r io.Reader) (n int64, err error) {
return p.Value.ReadFrom(r)
}
// MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes.
func (p *PublicKey) MarshalBinary() ([]byte, error) {
return p.Value.MarshalBinary()
}
// UnmarshalBinary decodes a slice of bytes generated by
// MarshalBinary or WriteTo on the object.
func (p *PublicKey) UnmarshalBinary(b []byte) error {
return p.Value.UnmarshalBinary(b)
}
// EvaluationKey is a public key indended to be used during the evaluation phase of a homomorphic circuit.
// It provides a one way public and non-interactive re-encryption from a ciphertext encrypted under `skIn`
// to a ciphertext encrypted under `skOut`.
@@ -192,13 +260,17 @@ type EvaluationKey struct {
// NewEvaluationKey returns a new EvaluationKey with pre-allocated zero-value
func NewEvaluationKey(params ParametersInterface, levelQ, levelP int) *EvaluationKey {
return &EvaluationKey{GadgetCiphertext: *NewGadgetCiphertext(
params,
levelQ,
levelP,
params.DecompRNS(levelQ, levelP),
params.DecompPw2(levelQ, levelP),
)}
//evk := new(EvaluationKey)
// drns := params.DecompRNS(levelQ, levelP)
// dpw2 := params.DecompPw2(levelQ, levelP)
// evk.Value = make(structs.Matrix[tupleQP], drns)
// for i := range evk.Value {
// evk.Value[i] = make([][2]ringqp.Poly, dpw2)
// for j := range evk.Value[i] {
// evk.Value[i][j] = NewPublicKey(params).Value
// }
// }
return &EvaluationKey{GadgetCiphertext: *NewGadgetCiphertext(params, levelQ, levelP, params.DecompRNS(levelQ, levelP), params.DecompPw2(levelQ, levelP))}
}
// CopyNew creates a deep copy of the target EvaluationKey and returns it.

View File

@@ -74,7 +74,7 @@ func EvaluationKeyIsCorrect(evk *EvaluationKey, skIn, skOut *SecretKey, params P
// [-asIn + w*P*sOut + e, a] + [asIn]
for i := range evk.Value {
for j := range evk.Value[i] {
ringQP.MulCoeffsMontgomeryThenAdd(&evk.Value[i][j].Value[1], &skOut.Value, &evk.Value[i][j].Value[0])
ringQP.MulCoeffsMontgomeryThenAdd(&evk.Value[i][j][1], &skOut.Value, &evk.Value[i][j][0])
}
}
@@ -83,7 +83,7 @@ func EvaluationKeyIsCorrect(evk *EvaluationKey, skIn, skOut *SecretKey, params P
for i := range evk.Value { // RNS decomp
if i > 0 {
for j := range evk.Value[i] { // PW2 decomp
ringQP.Add(&evk.Value[0][j].Value[0], &evk.Value[i][j].Value[0], &evk.Value[0][j].Value[0])
ringQP.Add(&evk.Value[0][j][0], &evk.Value[i][j][0], &evk.Value[0][j][0])
}
}
}
@@ -96,22 +96,22 @@ func EvaluationKeyIsCorrect(evk *EvaluationKey, skIn, skOut *SecretKey, params P
for i := 0; i < decompPw2; i++ {
// P*s^i + sum(e) - P*s^i = sum(e)
ringQ.Sub(evk.Value[0][i].Value[0].Q, skIn.Value.Q, evk.Value[0][i].Value[0].Q)
ringQ.Sub(evk.Value[0][i][0].Q, skIn.Value.Q, evk.Value[0][i][0].Q)
// Checks that the error is below the bound
// Worst error bound is N * floor(6*sigma) * #Keys
ringQP.INTT(&evk.Value[0][i].Value[0], &evk.Value[0][i].Value[0])
ringQP.IMForm(&evk.Value[0][i].Value[0], &evk.Value[0][i].Value[0])
ringQP.INTT(&evk.Value[0][i][0], &evk.Value[0][i][0])
ringQP.IMForm(&evk.Value[0][i][0], &evk.Value[0][i][0])
// Worst bound of inner sum
// N*#Keys*(N * #Parties * floor(sigma*6) + #Parties * floor(sigma*6) + N * #Parties + #Parties * floor(6*sigma))
if log2Bound < ringQ.Log2OfStandardDeviation(evk.Value[0][i].Value[0].Q) {
if log2Bound < ringQ.Log2OfStandardDeviation(evk.Value[0][i][0].Q) {
return false
}
if levelP != -1 {
if log2Bound < ringP.Log2OfStandardDeviation(evk.Value[0][i].Value[0].P) {
if log2Bound < ringP.Log2OfStandardDeviation(evk.Value[0][i][0].P) {
return false
}
}