Added keygen context for bfv

This commit is contained in:
Christian Grigis
2019-11-27 19:34:53 +01:00
parent 36602fabd1
commit 6991072a2f
8 changed files with 127 additions and 41 deletions

View File

@@ -18,7 +18,7 @@ func Benchmark_BFV(b *testing.B) {
var pk *PublicKey
var err error
kgen := bfvContext.NewKeyGenerator()
kgen := NewKeyGenerator(&params)
// Public Key Generation
b.Run(testString("KeyGen", &params), func(b *testing.B) {

View File

@@ -174,7 +174,7 @@ func testMarshaller(t *testing.T) {
t.Run(testString2("RotationKey/", params), func(t *testing.T) {
rotationKey := params.bfvContext.NewRotationKeys()
rotationKey := NewRotationKeys()
params.kgen.GenRot(RotationRow, params.sk, 0, rotationKey)
params.kgen.GenRot(RotationLeft, params.sk, 1, rotationKey)
@@ -246,7 +246,7 @@ func genBfvParams(contextParameters *Parameters) (params *bfvParams) {
params.bfvContext = NewContextWithParam(contextParameters)
params.kgen = params.bfvContext.NewKeyGenerator()
params.kgen = NewKeyGenerator(contextParameters)
params.sk, params.pk = params.kgen.NewKeyPair()
@@ -512,7 +512,7 @@ func testRotateRows(t *testing.T) {
params := genBfvParams(parameters)
rotkey := params.bfvContext.NewRotationKeys()
rotkey := NewRotationKeys()
params.kgen.GenRot(RotationRow, params.sk, 0, rotkey)
t.Run(testString2("InPlace/", params), func(t *testing.T) {

View File

@@ -1,13 +1,88 @@
package bfv
import (
"math"
"github.com/ldsec/lattigo/ring"
)
type keyGeneratorContext struct {
// Polynomial degree
n uint64
// Polynomial contexts
contextKeys *ring.Context
specialPrimes []uint64
alpha uint64
beta uint64
// Ternary and Gaussian samplers
gaussianSampler *ring.KYSampler
// Galois elements used to permute the batched plaintext in the encrypted domain
galElRotRow uint64
galElRotColLeft []uint64
galElRotColRight []uint64
}
func newKeyGeneratorContext(params *Parameters) *keyGeneratorContext {
n := params.N
contextKeys := ring.NewContext()
contextKeys.SetParameters(params.N, append(params.Qi, params.KeySwitchPrimes...))
err := contextKeys.GenNTTParams()
if err != nil {
panic(err)
}
specialPrimes := make([]uint64, len(params.KeySwitchPrimes))
for i := range params.KeySwitchPrimes {
specialPrimes[i] = params.KeySwitchPrimes[i]
}
alpha := uint64(len(specialPrimes))
beta := uint64(math.Ceil(float64(len(params.Qi)) / float64(alpha)))
gaussianSampler := contextKeys.NewKYSampler(params.Sigma, int(6*params.Sigma))
gen := GaloisGen
genInv := ring.ModExp(gen, (n<<1)-1, n<<1)
mask := (n << 1) - 1
galElRotColLeft := make([]uint64, n>>1)
galElRotColRight := make([]uint64, n>>1)
galElRotColRight[0] = 1
galElRotColLeft[0] = 1
for i := uint64(1); i < n>>1; i++ {
galElRotColLeft[i] = (galElRotColLeft[i-1] * gen) & mask
galElRotColRight[i] = (galElRotColRight[i-1] * genInv) & mask
}
galElRotRow := (n << 1) - 1
return &keyGeneratorContext{
n: n,
contextKeys: contextKeys,
specialPrimes: specialPrimes,
alpha: alpha,
beta: beta,
gaussianSampler: gaussianSampler,
galElRotRow: galElRotRow,
galElRotColLeft: galElRotColLeft,
galElRotColRight: galElRotColRight,
}
}
// KeyGenerator is a structure that stores the elements required to create new keys,
// as well as a small memory pool for intermediate values.
type KeyGenerator struct {
context *Context
context *keyGeneratorContext
polypool *ring.Poly
}
@@ -54,10 +129,12 @@ func (swk *SwitchingKey) Get() [][2]*ring.Poly {
// NewKeyGenerator creates a new KeyGenerator, from which the secret and public keys, as well as the evaluation,
// rotation and switching keys can be generated.
func (context *Context) NewKeyGenerator() (keygen *KeyGenerator) {
func NewKeyGenerator(params *Parameters) (keygen *KeyGenerator) {
context := newKeyGeneratorContext(params)
keygen = new(KeyGenerator)
keygen.context = context
keygen.polypool = keygen.context.ContextKeys().NewPoly()
keygen.polypool = keygen.context.contextKeys.NewPoly()
return
}
@@ -74,7 +151,9 @@ func (keygen *KeyGenerator) NewSecretkeyWithDistrib(p float64) (sk *SecretKey) {
}
// NewSecretKey creates a new SecretKey zero values.
func (context *Context) NewSecretKey() *SecretKey {
func NewSecretKey(params *Parameters) *SecretKey {
context := newKeyGeneratorContext(params)
sk := new(SecretKey)
sk.sk = context.contextKeys.NewPoly()
return sk
@@ -95,7 +174,7 @@ func (keygen *KeyGenerator) NewPublicKey(sk *SecretKey) (pk *PublicKey) {
pk = new(PublicKey)
ringContext := keygen.context.ContextKeys()
ringContext := keygen.context.contextKeys
//pk[0] = [-(a*s + e)]
//pk[1] = [a]
@@ -109,7 +188,9 @@ func (keygen *KeyGenerator) NewPublicKey(sk *SecretKey) (pk *PublicKey) {
}
// NewPublicKey creates a new PublicKey with zero values.
func (context *Context) NewPublicKey() (pk *PublicKey) {
func NewPublicKey(params *Parameters) (pk *PublicKey) {
context := newKeyGeneratorContext(params)
pk = new(PublicKey)
pk.pk[0] = context.contextKeys.NewPoly()
pk.pk[1] = context.contextKeys.NewPoly()
@@ -145,7 +226,7 @@ func (keygen *KeyGenerator) NewRelinKey(sk *SecretKey, maxDegree uint64) (evk *E
ringContext := keygen.context.contextKeys
for _, pj := range keygen.context.specialprimes {
for _, pj := range keygen.context.specialPrimes {
ringContext.MulScalar(keygen.polypool, pj, keygen.polypool)
}
@@ -160,7 +241,8 @@ func (keygen *KeyGenerator) NewRelinKey(sk *SecretKey, maxDegree uint64) (evk *E
}
// NewRelinKey creates a new EvaluationKey with zero values.
func (context *Context) NewRelinKey(maxDegree uint64) (evakey *EvaluationKey) {
func NewRelinKey(maxDegree uint64, params *Parameters) (evakey *EvaluationKey) {
context := newKeyGeneratorContext(params)
evakey = new(EvaluationKey)
@@ -211,7 +293,7 @@ func (keygen *KeyGenerator) NewSwitchingKey(skIn, skOut *SecretKey) (evk *Switch
ringContext.Sub(skIn.Get(), skOut.Get(), keygen.polypool)
for _, pj := range keygen.context.specialprimes {
for _, pj := range keygen.context.specialPrimes {
ringContext.MulScalar(keygen.polypool, pj, keygen.polypool)
}
@@ -222,7 +304,9 @@ func (keygen *KeyGenerator) NewSwitchingKey(skIn, skOut *SecretKey) (evk *Switch
}
// NewSwitchingKey creates a new SwitchingKey with zero values.
func (context *Context) NewSwitchingKey() (evakey *SwitchingKey) {
func NewSwitchingKey(params *Parameters) (evakey *SwitchingKey) {
context := newKeyGeneratorContext(params)
evakey = new(SwitchingKey)
// delta_sk = skIn - skOut = GaloisEnd(skOut, rotation) - skOut
@@ -236,7 +320,7 @@ func (context *Context) NewSwitchingKey() (evakey *SwitchingKey) {
return
}
func newswitchintkey(context *Context, skIn, skOut *ring.Poly) (switchkey *SwitchingKey) {
func newswitchintkey(context *keyGeneratorContext, skIn, skOut *ring.Poly) (switchkey *SwitchingKey) {
switchkey = new(SwitchingKey)
@@ -286,7 +370,7 @@ func newswitchintkey(context *Context, skIn, skOut *ring.Poly) (switchkey *Switc
}
// NewRotationKeys returns a new empty RotationKeys struct.
func (context *Context) NewRotationKeys() (rotKey *RotationKeys) {
func NewRotationKeys() (rotKey *RotationKeys) {
rotKey = new(RotationKeys)
return
}
@@ -382,7 +466,7 @@ func genrotkey(keygen *KeyGenerator, sk *ring.Poly, gen uint64) (switchkey *Swit
ring.PermuteNTT(sk, gen, keygen.polypool)
ringContext.Sub(keygen.polypool, sk, keygen.polypool)
for _, pj := range keygen.context.specialprimes {
for _, pj := range keygen.context.specialPrimes {
ringContext.MulScalar(keygen.polypool, pj, keygen.polypool)
}

View File

@@ -57,7 +57,7 @@ func benchPublicKeyGen(b *testing.B) {
}
})
pk := bfvContext.NewPublicKey()
pk := bfv.NewPublicKey(&parameters)
b.Run(testString("Finalize", &parameters), func(b *testing.B) {
for i := 0; i < b.N; i++ {
p.GenPublicKey(p.s1, crp, pk)
@@ -92,7 +92,7 @@ func benchRelinKeyGen(b *testing.B) {
p.u = p.RKGProtocol.NewEphemeralKey(1.0 / 3.0)
p.s = sk0Shards[0].Get()
p.share1, p.share2, p.share3 = p.RKGProtocol.AllocateShares()
p.rlk = bfvContext.NewRelinKey(2)
p.rlk = bfv.NewRelinKey(2, &parameters)
crpGenerator := ring.NewCRPGenerator(nil, bfvContext.ContextKeys())
@@ -171,7 +171,7 @@ func benchRelinKeyGenNaive(b *testing.B) {
p.RKGProtocolNaive = NewRKGProtocolNaive(bfvContext)
p.s = sk0Shards[0].Get()
p.share1, p.share2 = p.AllocateShares()
p.rlk = bfvContext.NewRelinKey(2)
p.rlk = bfv.NewRelinKey(2, &parameters)
b.Run(testString("Round1/Gen", &parameters), func(b *testing.B) {
@@ -353,7 +353,7 @@ func benchRotKeyGen(b *testing.B) {
}
})
rotKey := bfvContext.NewRotationKeys()
rotKey := bfv.NewRotationKeys()
b.Run(testString("Finalize", &parameters), func(b *testing.B) {
for i := 0; i < b.N; i++ {

View File

@@ -74,7 +74,7 @@ func genDBFVContext(contextParameters *bfv.Parameters) (params *dbfvContext) {
params.encoder = bfv.NewEncoder(contextParameters)
params.evaluator = bfv.NewEvaluator(contextParameters)
kgen := params.bfvContext.NewKeyGenerator()
kgen := bfv.NewKeyGenerator(contextParameters)
// SecretKeys
params.sk0Shards = make([]*bfv.SecretKey, testParams.parties)
@@ -236,7 +236,7 @@ func testRelinKeyGen(t *testing.T) {
}
}
evk := bfvContext.NewRelinKey(1)
evk := bfv.NewRelinKey(1, &parameters)
P0.GenRelinearizationKey(P0.share2, P0.share3, evk)
coeffs, _, ciphertext := newTestVectors(params, encryptorPk0, t)
@@ -312,7 +312,7 @@ func testRelinKeyGenNaive(t *testing.T) {
}
}
evk := bfvContext.NewRelinKey(1)
evk := bfv.NewRelinKey(1, &parameters)
P0.GenRelinearizationKey(P0.share2, evk)
coeffs, _, ciphertext := newTestVectors(params, encryptorPk0, t)
@@ -492,7 +492,7 @@ func testRotKeyGenRotRows(t *testing.T) {
}
}
rotkey := bfvContext.NewRotationKeys()
rotkey := bfv.NewRotationKeys()
P0.Finalize(P0.share, crp, rotkey)
coeffs, _, ciphertext := newTestVectors(params, encryptorPk0, t)
@@ -566,7 +566,7 @@ func testRotKeyGenRotCols(t *testing.T) {
}
}
rotkey := bfvContext.NewRotationKeys()
rotkey := bfv.NewRotationKeys()
P0.Finalize(P0.share, crp, rotkey)
evaluator.RotateColumns(ciphertext, k, rotkey, receiver)
@@ -600,7 +600,7 @@ func testRefresh(t *testing.T) {
encoder := params.encoder
decryptorSk0 := params.decryptorSk0
kgen := bfvContext.NewKeyGenerator()
kgen := bfv.NewKeyGenerator(&parameters)
rlk := kgen.NewRelinKey(params.sk0, 2)
@@ -717,17 +717,18 @@ func verifyTestVectors(contextParams *dbfvContext, decryptor *bfv.Decryptor, coe
}
func Test_Marshalling(t *testing.T) {
params := &bfv.DefaultParams[1]
//verify if the un.marshalling works properly
bfvCtx := bfv.NewContextWithParam(&bfv.DefaultParams[1])
KeyGenerator := bfvCtx.NewKeyGenerator()
bfvCtx := bfv.NewContextWithParam(params)
KeyGenerator := bfv.NewKeyGenerator(params)
crsGen := ring.NewCRPGenerator([]byte{'l', 'a', 't', 't', 'i', 'g', 'o'}, bfvCtx.ContextKeys())
sk := KeyGenerator.NewSecretKey()
crs := crsGen.ClockNew()
contextQ := bfvCtx.ContextQ()
contextPKeys := bfvCtx.ContextPKeys()
ringCtx := bfv.NewRingContext(&bfv.DefaultParams[1])
ringCtx := bfv.NewRingContext(params)
Ciphertext := bfv.NewRandomCiphertext(1, ringCtx)
t.Run(fmt.Sprintf("CPK/N=%d/limbQ=%d/limbsP=%d", contextQ.N, len(contextQ.Modulus), len(contextPKeys.Modulus)), func(t *testing.T) {
@@ -926,8 +927,9 @@ func Test_Marshalling(t *testing.T) {
}
func Test_Relin_Marshalling(t *testing.T) {
params := &bfv.DefaultParams[1]
bfvCtx := bfv.NewContextWithParam(&bfv.DefaultParams[1])
bfvCtx := bfv.NewContextWithParam(params)
contextQ := bfvCtx.ContextQ()
contextPKeys := bfvCtx.ContextPKeys()
modulus := bfvCtx.ContextQ().Modulus
@@ -946,7 +948,7 @@ func Test_Relin_Marshalling(t *testing.T) {
rlk := NewEkgProtocol(bfvCtx)
u := rlk.NewEphemeralKey(1 / 3.0)
sk := bfvCtx.NewKeyGenerator().NewSecretKey()
sk := bfv.NewKeyGenerator(params).NewSecretKey()
log.Print("Starting to test marshalling for share one")
r1, r2, r3 := rlk.AllocateShares()

View File

@@ -57,7 +57,7 @@ func obliviousRiding() {
bfvContext := bfv.NewContextWithParam(&params)
// Rider's keygen
kgen := bfvContext.NewKeyGenerator()
kgen := bfv.NewKeyGenerator(&params)
riderSk, riderPk := kgen.NewKeyPair()

View File

@@ -111,7 +111,7 @@ func main() {
P := make([]*party, N, N)
for i := range P {
pi := &party{}
pi.sk = bfvctx.NewKeyGenerator().NewSecretKey()
pi.sk = bfv.NewKeyGenerator(params).NewSecretKey()
pi.rlkEphemSk = bfvctx.ContextKeys().SampleTernaryMontgomeryNTTNew(1.0 / 3)
pi.input = make([]uint64, params.N, params.N)
for j := range pi.input {
@@ -136,7 +136,7 @@ func main() {
// 1) Collective public key generation
l.Println("> CKG Phase")
pk := bfvctx.NewPublicKey()
pk := bfv.NewPublicKey(params)
elapsedCKGParty = runTimedParty(func() {
for _, pi := range P {
ckg.GenShare(pi.sk.Get(), crs, pi.ckgShare)
@@ -185,7 +185,7 @@ func main() {
}
}, N)
rlk := bfvctx.NewRelinKey(1)
rlk := bfv.NewRelinKey(1, params)
elapsedRKGCloud += runTimed(func() {
for _, pi := range P {
rkg.AggregateShareRoundThree(pi.rkgShareThree, rkgCombined3, rkgCombined3)
@@ -196,7 +196,7 @@ func main() {
// 3) Collective rotation keys geneneration
l.Println("> RTG Phase")
rtk := bfvctx.NewRotationKeys()
rtk := bfv.NewRotationKeys()
for _, rot := range []bfv.Rotation{bfv.RotationRight, bfv.RotationLeft, bfv.RotationRow} {
for k := uint64(1); (rot == bfv.RotationRow && k == 1) || (rot != bfv.RotationRow && k < bfvctx.ContextKeys().N>>1); k <<= 1 {

View File

@@ -72,7 +72,7 @@ func main() {
crp[i] = crsGen.ClockNew()
}
tsk, tpk := bfvctx.NewKeyGenerator().NewKeyPair()
tsk, tpk := bfv.NewKeyGenerator(params).NewKeyPair()
colSk := &bfv.SecretKey{}
colSk.Set(bfvctx.ContextKeys().NewPoly())
@@ -88,7 +88,7 @@ func main() {
P := make([]*party, N, N)
for i := range P {
pi := &party{}
pi.sk = bfvctx.NewKeyGenerator().NewSecretKey()
pi.sk = bfv.NewKeyGenerator(params).NewSecretKey()
pi.rlkEphemSk = bfvctx.ContextKeys().SampleTernaryMontgomeryNTTNew(1.0 / 3)
pi.input = make([]uint64, params.N, params.N)
for i := range pi.input {
@@ -112,7 +112,7 @@ func main() {
var elapsedRKGParty time.Duration
l.Println("> CKG Phase")
pk := bfvctx.NewPublicKey()
pk := bfv.NewPublicKey(params)
elapsedCKGParty = runTimedParty(func() {
for _, pi := range P {
ckg.GenShare(pi.sk.Get(), crs, pi.ckgShare)
@@ -160,7 +160,7 @@ func main() {
}
}, N)
rlk := bfvctx.NewRelinKey(1)
rlk := bfv.NewRelinKey(1, params)
elapsedRKGCloud += runTimed(func() {
for _, pi := range P {
rkg.AggregateShareRoundThree(pi.rkgShareThree, rkgCombined3, rkgCombined3)