bfv/ckks keygen

This commit is contained in:
Jean-Philippe Bossuat
2019-09-28 13:43:07 +02:00
parent cf51291f8c
commit 589fcbec4a
14 changed files with 81 additions and 164 deletions

View File

@@ -27,7 +27,7 @@ func BenchmarkBFVScheme(b *testing.B) {
// Public Key Generation
b.Run(fmt.Sprintf("params=%d/KeyGen", params.N), func(b *testing.B) {
for i := 0; i < b.N; i++ {
sk, pk, err = kgen.NewKeyPair(1.0 / 3)
sk, pk = kgen.NewKeyPair()
if err != nil {
b.Error(err)
}

View File

@@ -10,7 +10,7 @@ import (
type BFVTESTPARAMS struct {
bfvcontext *BfvContext
batchencoder *BatchEncoder
kgen *keygenerator
kgen *KeyGenerator
sk *SecretKey
pk *PublicKey
encryptorSk *Encryptor
@@ -52,9 +52,7 @@ func Test_BFV(t *testing.T) {
log.Fatal(err)
}
if bfvTest.sk, bfvTest.pk, err = bfvTest.kgen.NewKeyPair(1.0 / 3.0); err != nil {
log.Fatal(err)
}
bfvTest.sk, bfvTest.pk = bfvTest.kgen.NewKeyPair()
if bfvTest.decryptor, err = bfvTest.bfvcontext.NewDecryptor(bfvTest.sk); err != nil {
log.Fatal(err)
@@ -1009,7 +1007,7 @@ func test_KeySwitching(bfvTest *BFVTESTPARAMS, bitDecomps []uint64, t *testing.T
Sk := bfvTest.sk
evaluator := bfvTest.evaluator
SkNew, _ := kgen.NewSecretKey(1.0 / 3)
SkNew := kgen.NewSecretKey()
decryptor_SkNew, err := bfvContext.NewDecryptor(SkNew)
if err != nil {

View File

@@ -16,34 +16,32 @@ type Encryptor struct {
// NewEncryptorFromPk creates a new Encryptor with the provided public-key.
// This encryptor can be used to encrypt plaintexts, using the stored key.
func (bfvcontext *BfvContext) NewEncryptorFromPk(pk *PublicKey) (*Encryptor, error) {
if uint64(pk.pk[0].GetDegree()+pk.pk[1].GetDegree())>>1 != bfvcontext.n {
return nil, errors.New("error : pk ring degree doesn't match bfvcontext ring degree")
}
return bfvcontext.newEncryptor(pk, nil), nil
return bfvcontext.newEncryptor(pk, nil)
}
// NewEncryptorFromSk creates a new Encryptor with the provided secret-key.
// This encryptor can be used to encrypt plaintexts, using the stored key.
func (bfvcontext *BfvContext) NewEncryptorFromSk(sk *SecretKey) (*Encryptor, error) {
return bfvcontext.newEncryptor(nil, sk)
}
func (bfvcontext *BfvContext) newEncryptor(pk *PublicKey, sk *SecretKey) (encryptor *Encryptor, err error) {
if pk != nil && uint64(pk.pk[0].GetDegree()+pk.pk[1].GetDegree())>>1 != bfvcontext.n {
return nil, errors.New("error : pk ring degree doesn't match bfvcontext ring degree")
}
if sk != nil && uint64(sk.sk.GetDegree()) != bfvcontext.n {
return nil, errors.New("error : sk ring degree doesn't match bfvcontext ring degree")
}
return bfvcontext.newEncryptor(nil, sk), nil
}
func (bfvcontext *BfvContext) newEncryptor(pk *PublicKey, sk *SecretKey) (encryptor *Encryptor) {
encryptor = new(Encryptor)
encryptor.bfvcontext = bfvcontext
encryptor.pk = pk
encryptor.sk = sk
encryptor.polypool = bfvcontext.contextQ.NewPoly()
return encryptor
return encryptor, nil
}
// EncryptFromPkNew encrypts the input plaintext using the stored public-key and returns

View File

@@ -8,9 +8,9 @@ import (
"math/bits"
)
// Keygenerator is a structure that stores the elements required to create new keys,
// 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 {
type KeyGenerator struct {
bfvcontext *BfvContext
context *ring.Context
polypool *ring.Poly
@@ -46,18 +46,24 @@ type SwitchingKey struct {
evakey [][][2]*ring.Poly
}
// NewKeyGenerator creates a new keygenerator, from which the secret and public keys, as well as the evaluation,
// 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 (bfvcontext *BfvContext) NewKeyGenerator() (keygen *keygenerator) {
keygen = new(keygenerator)
func (bfvcontext *BfvContext) NewKeyGenerator() (keygen *KeyGenerator) {
keygen = new(KeyGenerator)
keygen.bfvcontext = bfvcontext
keygen.context = bfvcontext.contextQ
keygen.polypool = keygen.context.NewPoly()
return
}
// Newsecretkey creates a new SecretKey with uniform distribution in [-1, 0, 1].
func (keygen *keygenerator) NewSecretKey(p float64) (sk *SecretKey, err error) {
// Newsecretkey creates a new SecretKey with the distribution [1/3, 1/3, 1/3]
func (keygen *KeyGenerator) NewSecretKey() (sk *SecretKey) {
sk, _ = keygen.NewSecretkeyWithDistrib(1.0 / 3)
return sk
}
// Newsecretkey creates a new SecretKey with the distribution [(p-1)/2, p, (p-1)/2]
func (keygen *KeyGenerator) NewSecretkeyWithDistrib(p float64) (sk *SecretKey, err error) {
sk = new(SecretKey)
if sk.sk, err = keygen.bfvcontext.ternarySampler.SampleMontgomeryNTTNew(p); err != nil {
@@ -68,7 +74,7 @@ func (keygen *keygenerator) NewSecretKey(p float64) (sk *SecretKey, err error) {
}
// NewSecretKeyEmpty creates a new SecretKey with all coeffcients set to zero, ready to received a marshaled SecretKey.
func (keygen *keygenerator) NewSecretKeyEmpty() *SecretKey {
func (keygen *KeyGenerator) NewSecretKeyEmpty() *SecretKey {
sk := new(SecretKey)
sk.sk = keygen.context.NewPoly()
return sk
@@ -84,8 +90,8 @@ func (sk *SecretKey) Set(poly *ring.Poly) {
sk.sk = poly.CopyNew()
}
// check_sk checks if the input secret-key complies with the keygenerator context.
func (keygen *keygenerator) check_sk(sk_output *SecretKey) (err error) {
// check_sk checks if the input secret-key complies with the KeyGenerator context.
func (keygen *KeyGenerator) check_sk(sk_output *SecretKey) (err error) {
if sk_output.Get().GetDegree() != int(keygen.context.N) {
return errors.New("error : pol degree sk != bfvcontext.n")
@@ -143,7 +149,7 @@ func (sk *SecretKey) UnMarshalBinary(data []byte) error {
}
// Newpublickey generates a new publickkey from the provided secret-key
func (keygen *keygenerator) NewPublicKey(sk *SecretKey) (pk *PublicKey, err error) {
func (keygen *KeyGenerator) NewPublicKey(sk *SecretKey) (pk *PublicKey, err error) {
if err = keygen.check_sk(sk); err != nil {
return nil, err
@@ -162,7 +168,7 @@ func (keygen *keygenerator) NewPublicKey(sk *SecretKey) (pk *PublicKey, err erro
return pk, nil
}
func (keygen *keygenerator) NewPublicKeyEmpty() (pk *PublicKey) {
func (keygen *KeyGenerator) NewPublicKeyEmpty() (pk *PublicKey) {
pk = new(PublicKey)
pk.pk[0] = keygen.context.NewPoly()
@@ -232,21 +238,17 @@ func (pk *PublicKey) UnMarshalBinary(data []byte) error {
return nil
}
// NewKeyPair generates a new (secret-key, public-key) pair.
func (keygen *keygenerator) NewKeyPair(p float64) (sk *SecretKey, pk *PublicKey, err error) {
if sk, err = keygen.NewSecretKey(p); err != nil {
return nil, nil, err
}
if pk, err = keygen.NewPublicKey(sk); err != nil {
return nil, nil, err
}
// NewKeyPair generates a new secret-key with distribution [1/3, 1/3, 1/3] and a corresponding public-key.
func (keygen *KeyGenerator) NewKeyPair() (sk *SecretKey, pk *PublicKey) {
sk = keygen.NewSecretKey()
pk, _ = keygen.NewPublicKey(sk)
return
}
// NewRelinKey generates a new evaluation key from the provided secret-key. It will be used to relinearize a ciphertext (encrypted under a public-key generated from the provided secret-key)
// of degree > 1 to a ciphertext of degree 1. Max degree is the maximum degree of the ciphertext allowed to relinearize. Bitdecomp is the power of two binary decomposition of the key.
// A higher bigdecomp will induce smaller keys, faster key-switching, but at the cost of more noise.
func (keygen *keygenerator) NewRelinKey(sk *SecretKey, maxDegree, bitDecomp uint64) (newEvakey *EvaluationKey, err error) {
func (keygen *KeyGenerator) NewRelinKey(sk *SecretKey, maxDegree, bitDecomp uint64) (newEvakey *EvaluationKey, err error) {
newEvakey = new(EvaluationKey)
newEvakey.evakey = make([]*SwitchingKey, maxDegree)
@@ -260,7 +262,7 @@ func (keygen *keygenerator) NewRelinKey(sk *SecretKey, maxDegree, bitDecomp uint
return newEvakey, nil
}
func (keygen *keygenerator) NewRelinKeyEmpty(maxDegree, bitDecomp uint64) (evakey *EvaluationKey) {
func (keygen *KeyGenerator) NewRelinKeyEmpty(maxDegree, bitDecomp uint64) (evakey *EvaluationKey) {
evakey = new(EvaluationKey)
if bitDecomp > keygen.bfvcontext.maxBit || bitDecomp == 0 {
@@ -321,7 +323,7 @@ func (newevakey *EvaluationKey) SetRelinKeys(rlk [][][][2]*ring.Poly, bitDecomp
// Newswitchintkey generates a new key-switching key, that will allow to re-encrypt under the output-key a ciphertext encrypted under the input-key. Bitdecomp
// is the power of two binary decomposition of the key. A higher bigdecomp will induce smaller keys, faster key-switching, but at the cost of more noise.
func (keygen *keygenerator) NewSwitchingKey(sk_input, sk_output *SecretKey, bitDecomp uint64) (newevakey *SwitchingKey, err error) {
func (keygen *KeyGenerator) NewSwitchingKey(sk_input, sk_output *SecretKey, bitDecomp uint64) (newevakey *SwitchingKey, err error) {
if err = keygen.check_sk(sk_input); err != nil {
return nil, err
@@ -338,7 +340,7 @@ func (keygen *keygenerator) NewSwitchingKey(sk_input, sk_output *SecretKey, bitD
return
}
func (keygen *keygenerator) NewSwitchingKeyEmpty(bitDecomp uint64) (evakey *SwitchingKey) {
func (keygen *KeyGenerator) NewSwitchingKeyEmpty(bitDecomp uint64) (evakey *SwitchingKey) {
evakey = new(SwitchingKey)
if bitDecomp > keygen.bfvcontext.maxBit || bitDecomp == 0 {
@@ -372,7 +374,7 @@ func (keygen *keygenerator) NewSwitchingKeyEmpty(bitDecomp uint64) (evakey *Swit
// Newrotationkeys generates a new struct of rotationkeys storing the keys for the specified rotations. The provided secret-key must be the secret-key used to generate the public-key under
// which the ciphertexts to rotate are encrypted under. Bitdecomp is the power of two binary decomposition of the key. A higher bigdecomp will induce smaller keys, faster key-switching,
// but at the cost of more noise. rotLeft and rotRight must be a slice of uint64 rotations, row is a boolean value indicating if the key for the row rotation must be generated.
func (keygen *keygenerator) NewRotationKeys(sk *SecretKey, bitDecomp uint64, rotLeft []uint64, rotRight []uint64, row bool) (rotKey *RotationKeys, err error) {
func (keygen *KeyGenerator) NewRotationKeys(sk *SecretKey, bitDecomp uint64, rotLeft []uint64, rotRight []uint64, row bool) (rotKey *RotationKeys, err error) {
if err = keygen.check_sk(sk); err != nil {
return nil, err
@@ -408,7 +410,7 @@ func (keygen *keygenerator) NewRotationKeys(sk *SecretKey, bitDecomp uint64, rot
}
func (keygen *keygenerator) NewRotationKeysEmpty() (rotKey *RotationKeys) {
func (keygen *KeyGenerator) NewRotationKeysEmpty() (rotKey *RotationKeys) {
rotKey = new(RotationKeys)
rotKey.bfvcontext = keygen.bfvcontext
@@ -420,7 +422,7 @@ func (keygen *keygenerator) NewRotationKeysEmpty() (rotKey *RotationKeys) {
// Newrotationkeys generates a new struct of rotationkeys storing the keys of all the left and right powers of two rotations. The provided secret-key must be the secret-key used to generate the public-key under
// which the ciphertexts to rotate are encrypted under. rows is a boolean value indicatig if the keys for the row rotation have to be generated. Bitdecomp is the power of two binary decomposition of the key.
// A higher bigdecomp will induce smaller keys, faster key-switching, but at the cost of more noise.
func (keygen *keygenerator) NewRotationKeysPow2(sk *SecretKey, bitDecomp uint64, row bool) (rotKey *RotationKeys, err error) {
func (keygen *KeyGenerator) NewRotationKeysPow2(sk *SecretKey, bitDecomp uint64, row bool) (rotKey *RotationKeys, err error) {
if err = keygen.check_sk(sk); err != nil {
return nil, err
@@ -447,7 +449,7 @@ func (keygen *keygenerator) NewRotationKeysPow2(sk *SecretKey, bitDecomp uint64,
}
// genrotkey is a methode used in the rotation-keys generation.
func genrotkey(keygen *keygenerator, sk *ring.Poly, gen, bitDecomp uint64) (switchkey *SwitchingKey) {
func genrotkey(keygen *KeyGenerator, sk *ring.Poly, gen, bitDecomp uint64) (switchkey *SwitchingKey) {
ring.PermuteNTT(sk, gen, keygen.polypool)
keygen.context.Sub(keygen.polypool, sk, keygen.polypool)

View File

@@ -54,9 +54,7 @@ func BenchmarkCKKSScheme(b *testing.B) {
kgen = ckkscontext.NewKeyGenerator()
if sk, pk, err = kgen.NewKeyPair(1.0 / 3); err != nil {
b.Error(err)
}
sk, pk = kgen.NewKeyPair()
if rlk, err = kgen.NewRelinKey(sk, bdc); err != nil {
b.Error(err)
@@ -113,10 +111,7 @@ func BenchmarkCKKSScheme(b *testing.B) {
// Key Pair Generation
b.Run(fmt.Sprintf("logN=%d/logQ=%d/levels=%d/decomp=%d/sigma=%.2f/KeyPairGen", logN, ckkscontext.LogQ(), levels, bdc, sigma), func(b *testing.B) {
for i := 0; i < b.N; i++ {
sk, pk, err = kgen.NewKeyPair(1.0 / 3)
if err != nil {
b.Error(err)
}
sk, pk = kgen.NewKeyPair()
}
})

View File

@@ -52,9 +52,7 @@ func Test_CKKS(t *testing.T) {
ckksTest.kgen = ckksTest.ckkscontext.NewKeyGenerator()
if ckksTest.sk, ckksTest.pk, err = ckksTest.kgen.NewKeyPair(1.0 / 3); err != nil {
t.Error(err)
}
ckksTest.sk, ckksTest.pk = ckksTest.kgen.NewKeyPair()
log.Printf("Generating relinearization keys")
if ckksTest.rlk, err = ckksTest.kgen.NewRelinKey(ckksTest.sk, ckksTest.ckkscontext.Scale()); err != nil {
@@ -1240,7 +1238,7 @@ func test_SwitchKeys(params *CKKSTESTPARAMS, t *testing.T) {
t.Error(err)
}
sk2, _ := params.kgen.NewSecretKey(1.0 / 3)
sk2 := params.kgen.NewSecretKey()
switchingkeys, err := params.kgen.NewSwitchingKey(params.sk, sk2, 10)
if err != nil {
@@ -1546,7 +1544,7 @@ func test_MarshalSwitchingKey(params *CKKSTESTPARAMS, t *testing.T) {
bitDecomp := uint64(15)
s1, _ := params.kgen.NewSecretKey(1.0 / 3)
s1 := params.kgen.NewSecretKey()
switchkey, _ := params.kgen.NewSwitchingKey(params.sk, s1, bitDecomp)

View File

@@ -70,8 +70,14 @@ func (keygen *KeyGenerator) check_sk(sk_output *SecretKey) error {
return nil
}
// NewSecretKey generates a new secret key.
func (keygen *KeyGenerator) NewSecretKey(p float64) (sk *SecretKey, err error) {
// NewSecretKey generates a new secret key with the distribution [1/3, 1/3, 1/3].
func (keygen *KeyGenerator) NewSecretKey() (sk *SecretKey) {
sk, _ = keygen.NewSecretKeyWithDistrib(1.0 / 3)
return sk
}
// NewSecretKey generates a new secret key with the distribution [(p-1)/2, p, (p-1)/2].
func (keygen *KeyGenerator) NewSecretKeyWithDistrib(p float64) (sk *SecretKey, err error) {
sk = new(SecretKey)
if sk.sk, err = keygen.ckkscontext.ternarySampler.SampleMontgomeryNTTNew(p); err != nil {
return nil, err
@@ -135,14 +141,10 @@ func (pk *PublicKey) Set(poly [2]*ring.Poly) {
pk.pk[1] = poly[1].CopyNew()
}
// NewKeyPair generates a new secretkey and a corresponding public key.
func (keygen *KeyGenerator) NewKeyPair(p float64) (sk *SecretKey, pk *PublicKey, err error) {
if sk, err = keygen.NewSecretKey(p); err != nil {
return nil, nil, err
}
if pk, err = keygen.NewPublicKey(sk); err != nil {
return nil, nil, err
}
// NewKeyPair generates a new secretkey with distribution [1/3, 1/3, 1/3] and a corresponding public key.
func (keygen *KeyGenerator) NewKeyPair() (sk *SecretKey, pk *PublicKey) {
sk = keygen.NewSecretKey()
pk, _ = keygen.NewPublicKey(sk)
return
}

View File

@@ -25,15 +25,8 @@ func Benchmark_DBFVScheme(b *testing.B) {
kgen := bfvContext.NewKeyGenerator()
sk0, pk0, err := kgen.NewKeyPair(1.0 / 3)
if err != nil {
log.Fatal(err)
}
sk1, pk1, err := kgen.NewKeyPair(1.0 / 3)
if err != nil {
log.Fatal(err)
}
sk0, pk0 := kgen.NewKeyPair()
sk1, pk1 := kgen.NewKeyPair()
crpGenerator, err := NewCRPGenerator(nil, context)
if err != nil {

View File

@@ -61,8 +61,8 @@ func Test_DBFVScheme(t *testing.T) {
tmp1 := context.NewPoly()
for i := 0; i < parties; i++ {
sk0_shards[i], _ = kgen.NewSecretKey(1.0 / 3)
sk1_shards[i], _ = kgen.NewSecretKey(1.0 / 3)
sk0_shards[i] = kgen.NewSecretKey()
sk1_shards[i] = kgen.NewSecretKey()
context.Add(tmp0, sk0_shards[i].Get(), tmp0)
context.Add(tmp1, sk1_shards[i].Get(), tmp1)
}

View File

@@ -54,15 +54,8 @@ func Benchmark_DCKKSScheme(b *testing.B) {
kgen := benchcontext.ckkscontext.NewKeyGenerator()
benchcontext.sk0, benchcontext.pk0, err = kgen.NewKeyPair(1.0 / 3)
if err != nil {
log.Fatal(err)
}
benchcontext.sk1, benchcontext.pk1, err = kgen.NewKeyPair(1.0 / 3)
if err != nil {
log.Fatal(err)
}
benchcontext.sk0, benchcontext.pk0 = kgen.NewKeyPair()
benchcontext.sk1, benchcontext.pk1 = kgen.NewKeyPair()
benchcontext.cprng, err = NewCRPGenerator(nil, benchcontext.ckkscontext.ContextKeys())
if err != nil {

View File

@@ -78,8 +78,8 @@ func Test_DBFVScheme(t *testing.T) {
tmp1 := context.NewPoly()
for i := uint64(0); i < parties; i++ {
sk0_shards[i], _ = kgen.NewSecretKey(1.0 / 3)
sk1_shards[i], _ = kgen.NewSecretKey(1.0 / 3)
sk0_shards[i] = kgen.NewSecretKey()
sk1_shards[i] = kgen.NewSecretKey()
context.Add(tmp0, sk0_shards[i].Get(), tmp0)
context.Add(tmp1, sk1_shards[i].Get(), tmp1)
}

View File

@@ -31,10 +31,7 @@ func ObliviousRiding() {
kgen := bfvContext.NewKeyGenerator()
Sk, Pk, err := kgen.NewKeyPair(1.0 / 3)
if err != nil {
log.Fatal(err)
}
Sk, Pk := kgen.NewKeyPair()
Decryptor, err := bfvContext.NewDecryptor(Sk)
if err != nil {

View File

@@ -36,9 +36,7 @@ func chebyshevinterpolation() {
// Keys
var sk *ckks.SecretKey
var pk *ckks.PublicKey
if sk, pk, err = kgen.NewKeyPair(1.0 / 3); err != nil {
log.Fatal(err)
}
sk, pk = kgen.NewKeyPair()
// Relinearization key
var rlk *ckks.EvaluationKey

View File

@@ -251,7 +251,7 @@ func computeMatrixTernary(p float64) (M [][]uint8) {
}
// SampleMontgomeryNew samples coefficients with ternary distribution in montgomery form on the target polynomial.
func sampleOnPol(context *Context, samplerMatrix [][]uint64, p float64, pol *Poly) (err error) {
func (sampler *TernarySampler) sample(samplerMatrix [][]uint64, p float64, pol *Poly) (err error) {
if p == 0 {
return errors.New("cannot sample -> p = 0")
@@ -263,8 +263,8 @@ func sampleOnPol(context *Context, samplerMatrix [][]uint64, p float64, pol *Pol
if p == 0.5 {
randomBytesCoeffs := make([]byte, context.N>>3)
randomBytesSign := make([]byte, context.N>>3)
randomBytesCoeffs := make([]byte, sampler.context.N>>3)
randomBytesSign := make([]byte, sampler.context.N>>3)
if _, err := rand.Read(randomBytesCoeffs); err != nil {
panic("crypto rand error")
@@ -274,13 +274,13 @@ func sampleOnPol(context *Context, samplerMatrix [][]uint64, p float64, pol *Pol
panic("crypto rand error")
}
for i := uint64(0); i < context.N; i++ {
for i := uint64(0); i < sampler.context.N; i++ {
coeff = uint64(uint8(randomBytesCoeffs[i>>3])>>(i&7)) & 1
sign = uint64(uint8(randomBytesSign[i>>3])>>(i&7)) & 1
index = (coeff & (sign ^ 1)) | ((sign & coeff) << 1)
for j := range context.Modulus {
for j := range sampler.context.Modulus {
pol.Coeffs[j][i] = samplerMatrix[j][index] //(coeff & (sign^1)) | (qi - 1) * (sign & coeff)
}
}
@@ -297,13 +297,13 @@ func sampleOnPol(context *Context, samplerMatrix [][]uint64, p float64, pol *Pol
panic("crypto rand error")
}
for i := uint64(0); i < context.N; i++ {
for i := uint64(0); i < sampler.context.N; i++ {
coeff, sign, randomBytes, pointer = kysampling(matrix, randomBytes, pointer)
index = (coeff & (sign ^ 1)) | ((sign & coeff) << 1)
for j := range context.Modulus {
for j := range sampler.context.Modulus {
pol.Coeffs[j][i] = samplerMatrix[j][index] //(coeff & (sign^1)) | (qi - 1) * (sign & coeff)
}
}
@@ -312,76 +312,19 @@ func sampleOnPol(context *Context, samplerMatrix [][]uint64, p float64, pol *Pol
return nil
}
func sampleOnArray(values []uint64, p float64) (err error) {
if p == 0 {
return errors.New("cannot sample -> p = 0")
}
var coeff uint64
var sign uint64
if p == 0.5 {
randomBytesCoeffs := make([]byte, len(values)>>3)
randomBytesSign := make([]byte, len(values)>>3)
if _, err := rand.Read(randomBytesCoeffs); err != nil {
panic("crypto rand error")
}
if _, err := rand.Read(randomBytesSign); err != nil {
panic("crypto rand error")
}
for i := uint64(0); i < uint64(len(values)); i++ {
coeff = uint64(uint8(randomBytesCoeffs[i>>3])>>(i&7)) & 1
sign = uint64(uint8(randomBytesSign[i>>3])>>(i&7)) & 1
values[i] = (coeff & (sign ^ 1)) | ((sign & coeff) << 1)
}
} else {
matrix := computeMatrixTernary(p)
randomBytes := make([]byte, 8)
pointer := uint8(0)
if _, err := rand.Read(randomBytes); err != nil {
panic("crypto rand error")
}
for i := 0; i < len(values); i++ {
coeff, sign, randomBytes, pointer = kysampling(matrix, randomBytes, pointer)
values[i] = (coeff & (sign ^ 1)) | ((sign & coeff) << 1)
}
}
return nil
}
func (sampler *TernarySampler) SampleOnArray(values []uint64, p float64) (err error) {
return sampleOnArray(values, p)
}
func (sampler *TernarySampler) SampleUniform(pol *Poly) {
_ = sampleOnPol(sampler.context, sampler.Matrix, 1.0/3.0, pol)
_ = sampler.sample(sampler.Matrix, 1.0/3.0, pol)
}
func (sampler *TernarySampler) Sample(p float64, pol *Poly) (err error) {
if err = sampleOnPol(sampler.context, sampler.Matrix, p, pol); err != nil {
if err = sampler.sample(sampler.Matrix, p, pol); err != nil {
return err
}
return nil
}
func (sampler *TernarySampler) SampleMontgomery(p float64, pol *Poly) (err error) {
if err = sampleOnPol(sampler.context, sampler.MatrixMontgomery, p, pol); err != nil {
if err = sampler.sample(sampler.MatrixMontgomery, p, pol); err != nil {
return err
}
return nil