Merge pull request #10 from keep-network/public-key-bit-length

Pass a public key bit length when creating a threshold key generator
This commit is contained in:
Jakub Nowakowski authored and GitHub committed 2018-08-08 15:31:49 +02:00
commit 3571790b8a
5 files changed
+277 -70

No files matched your search

+1 -1
View File
@@ -60,7 +60,7 @@ func TestAsyncGenerator(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
AreSafePrimes(p, q, test.bitLen, t) IsSafePrime(p, q, test.bitLen, t)
} }
}) })
} }
+44 -22
View File
@@ -2,6 +2,7 @@ package paillier
import ( import (
"crypto/rand" "crypto/rand"
"errors"
"io" "io"
"math/big" "math/big"
"time" "time"
@@ -19,18 +20,18 @@ import (
// with Applications to Electronic Voting // with Applications to Electronic Voting
// Aarhus University, Dept. of Computer Science, BRICS // Aarhus University, Dept. of Computer Science, BRICS
type ThresholdKeyGenerator struct { type ThresholdKeyGenerator struct {
nbits int PublicKeyBitLength int
TotalNumberOfDecryptionServers int TotalNumberOfDecryptionServers int
Threshold int Threshold int
Random io.Reader random io.Reader
// Both p1 and q1 are primes of length nbits - 1 p *big.Int // p is prime of `PublicKeyBitLength/2` bits and `p = 2*p1 + 1`
p1 *big.Int q *big.Int // q is prime of `PublicKeyBitLength/2` bits and `q = 2*q1 + 1`
q1 *big.Int
p *big.Int // p is prime and p=2*p1+1 p1 *big.Int // p1 is prime of `PublicKeyBitLength/2 - 1` bits
q *big.Int // q is prime and q=2*q1+1 q1 *big.Int // q1 is prime of `PublicKeyBitLength/2 - 1` bits
n *big.Int // n=p*q
n *big.Int // n=p*q and is of `PublicKeyBitLength` bits
m *big.Int // m = p1*q1 m *big.Int // m = p1*q1
nSquare *big.Int // nSquare = n*n nSquare *big.Int // nSquare = n*n
nm *big.Int // nm = n*m nm *big.Int // nm = n*m
@@ -45,23 +46,44 @@ type ThresholdKeyGenerator struct {
polynomialCoefficients []*big.Int polynomialCoefficients []*big.Int
} }
// Preferable way to construct the ThresholdKeyGenerator. No verification // GetThresholdKeyGenerator is a preferable way to construct the
// is done on the input values. You need to be sure that nbits is big enough // ThresholdKeyGenerator.
// and that Threshold > TotalNumberOfDecryptionServers / 2. // Due to the various properties that must be met for the threshold key to be
// The plaintext space for the key will be Z_n. // considered valid, the minimum public key `N` bit length is 18 bits and the
func GetThresholdKeyGenerator(nbits, TotalNumberOfDecryptionServers, Threshold int, random io.Reader) *ThresholdKeyGenerator { // public key bit length should be an even number.
ret := new(ThresholdKeyGenerator) // The plaintext space for the key will be `Z_N`.
ret.nbits = nbits func GetThresholdKeyGenerator(
ret.TotalNumberOfDecryptionServers = TotalNumberOfDecryptionServers publicKeyBitLength int,
ret.Threshold = Threshold totalNumberOfDecryptionServers int,
ret.Random = random threshold int,
return ret random io.Reader,
) (*ThresholdKeyGenerator, error) {
if publicKeyBitLength%2 == 1 {
// For an odd n-bit number, we can't find two n/2-bit numbers with two
// the most significant bits set on which multiplied gives an n-bit
// number.
return nil, errors.New("Public key bit length must be an even number")
}
if publicKeyBitLength < 18 {
// We need to find two n/2-bit safe primes, P and Q which are not equal.
// This is not possible for n<18.
return nil, errors.New("Public key bit length must be at least 18 bits")
}
return &ThresholdKeyGenerator{
PublicKeyBitLength: publicKeyBitLength,
TotalNumberOfDecryptionServers: totalNumberOfDecryptionServers,
Threshold: threshold,
random: random,
}, nil
} }
func (tkg *ThresholdKeyGenerator) generateSafePrimes() (*big.Int, *big.Int, error) { func (tkg *ThresholdKeyGenerator) generateSafePrimes() (*big.Int, *big.Int, error) {
concurrencyLevel := 4 concurrencyLevel := 4
timeout := 120 * time.Second timeout := 120 * time.Second
return GenerateSafePrime(tkg.nbits, concurrencyLevel, timeout, tkg.Random) safePrimeBitLength := tkg.PublicKeyBitLength / 2
return GenerateSafePrime(safePrimeBitLength, concurrencyLevel, timeout, tkg.random)
} }
func (tkg *ThresholdKeyGenerator) initPandP1() error { func (tkg *ThresholdKeyGenerator) initPandP1() error {
@@ -112,7 +134,7 @@ func (tkg *ThresholdKeyGenerator) initPsAndQs() error {
// v generates a cyclic group of squares in Zn^2. // v generates a cyclic group of squares in Zn^2.
func (tkg *ThresholdKeyGenerator) computeV() error { func (tkg *ThresholdKeyGenerator) computeV() error {
var err error var err error
tkg.v, err = GetRandomGeneratorOfTheQuadraticResidue(tkg.nSquare, tkg.Random) tkg.v, err = GetRandomGeneratorOfTheQuadraticResidue(tkg.nSquare, tkg.random)
return err return err
} }
@@ -165,7 +187,7 @@ func (tkg *ThresholdKeyGenerator) generateHidingPolynomial() error {
tkg.polynomialCoefficients[0] = tkg.d tkg.polynomialCoefficients[0] = tkg.d
var err error var err error
for i := 1; i < tkg.Threshold; i++ { for i := 1; i < tkg.Threshold; i++ {
tkg.polynomialCoefficients[i], err = rand.Int(tkg.Random, tkg.nm) tkg.polynomialCoefficients[i], err = rand.Int(tkg.random, tkg.nm)
if err != nil { if err != nil {
return err return err
} }
+194 -39
View File
@@ -2,6 +2,7 @@ package paillier
import ( import (
"crypto/rand" "crypto/rand"
"errors"
"math/big" "math/big"
"reflect" "reflect"
"testing" "testing"
@@ -11,44 +12,183 @@ var MockGenerateSafePrimes = func() (*big.Int, *big.Int, error) {
return big.NewInt(887), big.NewInt(443), nil return big.NewInt(887), big.NewInt(443), nil
} }
func TestGenerateSafePrimesOfThresholdKeyGenerator(t *testing.T) { func TestCreateThresholdKeyGenerator(t *testing.T) {
tkh := new(ThresholdKeyGenerator) var tests = map[string]struct {
tkh.nbits = 10 publicKeyBitLength int
tkh.Random = rand.Reader totalNumberOfDecryptionServers int
p, q, err := tkh.generateSafePrimes() threshold int
expectedError error
}{
"generator successfully created for 20 bit key length": {
publicKeyBitLength: 20,
totalNumberOfDecryptionServers: 6,
threshold: 5,
},
"generator can't be created for 19 bit key length": {
publicKeyBitLength: 19,
totalNumberOfDecryptionServers: 4,
threshold: 3,
expectedError: errors.New("Public key bit length must be an even number"),
},
"generator successfully created for 18 bit key length": {
publicKeyBitLength: 18,
totalNumberOfDecryptionServers: 4,
threshold: 3,
},
"generator can't be created for 17 bit key length": {
publicKeyBitLength: 17,
totalNumberOfDecryptionServers: 4,
threshold: 3,
expectedError: errors.New("Public key bit length must be an even number"),
},
"generator can't be created for 16 bit key length": {
publicKeyBitLength: 16,
totalNumberOfDecryptionServers: 4,
threshold: 3,
expectedError: errors.New("Public key bit length must be at least 18 bits"),
},
}
for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
gen, err := GetThresholdKeyGenerator(
test.publicKeyBitLength,
test.totalNumberOfDecryptionServers,
test.threshold,
rand.Reader,
)
if !reflect.DeepEqual(test.expectedError, err) {
t.Fatalf(
"Unexpected error\nActual: %v\nExpected: %v",
err,
test.expectedError,
)
}
if test.expectedError == nil {
if gen == nil {
t.Fatal(
"Got nil generator, it should be successfully created",
)
}
if test.publicKeyBitLength != gen.PublicKeyBitLength {
t.Fatalf(
"Unexpected public key length\nExpected: %v\nActual: %v",
test.publicKeyBitLength,
gen.PublicKeyBitLength,
)
}
if test.threshold != gen.Threshold {
t.Fatalf(
"Unexpected threshold\nExpected: %v\nActual: %v",
test.threshold,
gen.Threshold,
)
}
if test.totalNumberOfDecryptionServers != gen.TotalNumberOfDecryptionServers {
t.Fatalf(
"Unexpected number of decryption servers\nExpected: %v\nActual: %v",
test.totalNumberOfDecryptionServers,
gen.TotalNumberOfDecryptionServers,
)
}
}
})
}
}
func TestGenerateNumbersOfCorrectBitLength(t *testing.T) {
var tests = map[string]struct {
publicKeyLength int
expectedPrimeLength int
}{
"public key bit length = 32, prime bit length = 16": {
publicKeyLength: 32,
expectedPrimeLength: 16,
},
"public key bit length = 64, prime bit length = 32": {
publicKeyLength: 64,
expectedPrimeLength: 32,
},
}
for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
gen, err := GetThresholdKeyGenerator(test.publicKeyLength, 10, 6, rand.Reader)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
}
err = gen.initNumerialValues()
if err != nil {
t.Fatal(err)
}
if gen.p.BitLen() != test.expectedPrimeLength {
t.Fatalf(
"Unexpected prime bit length\nExpected %v\n Actual %v",
test.expectedPrimeLength,
gen.p.BitLen(),
)
}
if gen.q.BitLen() != test.expectedPrimeLength {
t.Fatalf(
"Unexpected prime bit length\nExpected %v\n Actual %v",
test.expectedPrimeLength,
gen.q.BitLen(),
)
}
if gen.n.BitLen() != test.publicKeyLength {
t.Fatalf(
"Unexpected modulus bit length\nExpected %v\n Actual %v",
test.publicKeyLength,
gen.n.BitLen(),
)
}
if new(big.Int).Mul(gen.p, gen.q).Cmp(gen.n) != 0 {
t.Fatal("n != pq")
}
})
} }
AreSafePrimes(p, q, 10, t)
} }
func TestInitPandP1(t *testing.T) { func TestInitPandP1(t *testing.T) {
tkh := new(ThresholdKeyGenerator) tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
tkh.nbits = 10 if err != nil {
tkh.Random = rand.Reader t.Fatal(err)
}
tkh.initPandP1() tkh.initPandP1()
AreSafePrimes(tkh.p, tkh.p1, 10, t) IsSafePrime(tkh.p, tkh.p1, 16, t)
} }
func TestInitQandQ1(t *testing.T) { func TestInitQandQ1(t *testing.T) {
tkh := new(ThresholdKeyGenerator) tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
tkh.nbits = 10 if err != nil {
tkh.Random = rand.Reader t.Fatal(err)
}
tkh.initQandQ1() tkh.initQandQ1()
AreSafePrimes(tkh.q, tkh.q1, 10, t) IsSafePrime(tkh.q, tkh.q1, 16, t)
} }
func TestInitPsAndQs(t *testing.T) { func TestInitPsAndQs(t *testing.T) {
tkh := new(ThresholdKeyGenerator) tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
tkh.nbits = 10 if err != nil {
tkh.Random = rand.Reader t.Fatal(err)
}
tkh.initPsAndQs() tkh.initPsAndQs()
AreSafePrimes(tkh.p, tkh.p1, 10, t) IsSafePrime(tkh.p, tkh.p1, 16, t)
AreSafePrimes(tkh.q, tkh.q1, 10, t) IsSafePrime(tkh.q, tkh.q1, 16, t)
} }
func TestArePsAndQsGood(t *testing.T) { func TestArePsAndQsGood(t *testing.T) {
@@ -102,9 +242,10 @@ func TestInitD(t *testing.T) {
} }
func TestInitNumerialValues(t *testing.T) { func TestInitNumerialValues(t *testing.T) {
tkh := new(ThresholdKeyGenerator) tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
tkh.nbits = 10 if err != nil {
tkh.Random = rand.Reader t.Fatal(err)
}
if err := tkh.initNumerialValues(); err != nil { if err := tkh.initNumerialValues(); err != nil {
t.Error(err) t.Error(err)
@@ -112,10 +253,11 @@ func TestInitNumerialValues(t *testing.T) {
} }
func TestGenerateHidingPolynomial(t *testing.T) { func TestGenerateHidingPolynomial(t *testing.T) {
tkh := new(ThresholdKeyGenerator) tkh, err := GetThresholdKeyGenerator(32, 15, 10, rand.Reader)
tkh.nbits = 10 if err != nil {
tkh.Threshold = 10 t.Fatal(err)
tkh.Random = rand.Reader }
if err := tkh.initNumerialValues(); err != nil { if err := tkh.initNumerialValues(); err != nil {
t.Error(err) t.Error(err)
} }
@@ -137,10 +279,11 @@ func TestGenerateHidingPolynomial(t *testing.T) {
} }
func TestComputeShare(t *testing.T) { func TestComputeShare(t *testing.T) {
tkh := new(ThresholdKeyGenerator) tkh, err := GetThresholdKeyGenerator(32, 5, 3, rand.Reader)
tkh.nbits = 10 if err != nil {
tkh.Threshold = 3 t.Fatal(err)
tkh.TotalNumberOfDecryptionServers = 5 }
tkh.nm = b(103) tkh.nm = b(103)
tkh.polynomialCoefficients = []*big.Int{b(29), b(88), b(51)} tkh.polynomialCoefficients = []*big.Int{b(29), b(88), b(51)}
share := tkh.computeShare(2) share := tkh.computeShare(2)
@@ -150,11 +293,11 @@ func TestComputeShare(t *testing.T) {
} }
func TestCreateShares(t *testing.T) { func TestCreateShares(t *testing.T) {
tkh := new(ThresholdKeyGenerator) tkh, err := GetThresholdKeyGenerator(32, 100, 10, rand.Reader)
tkh.nbits = 10 if err != nil {
tkh.Threshold = 10 t.Fatal(err)
tkh.TotalNumberOfDecryptionServers = 100 }
tkh.Random = rand.Reader
if err := tkh.initNumerialValues(); err != nil { if err := tkh.initNumerialValues(); err != nil {
t.Error(err) t.Error(err)
} }
@@ -180,14 +323,22 @@ func TestCreateViArray(t *testing.T) {
} }
func TestGetThresholdKeyGenerator(t *testing.T) { func TestGetThresholdKeyGenerator(t *testing.T) {
tkh := GetThresholdKeyGenerator(50, 10, 6, rand.Reader) tkh, err := GetThresholdKeyGenerator(50, 10, 6, rand.Reader)
if err != nil {
t.Fatal(err)
}
if err := tkh.initNumerialValues(); err != nil { if err := tkh.initNumerialValues(); err != nil {
t.Error(nil) t.Error(nil)
} }
} }
func TestGenerate(t *testing.T) { func TestGenerate(t *testing.T) {
tkh := GetThresholdKeyGenerator(32, 10, 6, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 10, 6, rand.Reader)
if err != nil {
t.Fatal(err)
}
tpks, err := tkh.Generate() tpks, err := tkh.Generate()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -213,7 +364,11 @@ func TestGenerate(t *testing.T) {
} }
func TestComputeV(t *testing.T) { func TestComputeV(t *testing.T) {
tkh := GetThresholdKeyGenerator(32, 10, 6, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 10, 6, rand.Reader)
if err != nil {
t.Fatal(err)
}
tkh.n = b(1907 * 1823) tkh.n = b(1907 * 1823)
tkh.nSquare = new(big.Int).Mul(tkh.n, tkh.n) tkh.nSquare = new(big.Int).Mul(tkh.n, tkh.n)
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
+35 -7
View File
@@ -8,7 +8,11 @@ import (
) )
func getThresholdPrivateKey() *ThresholdPrivateKey { func getThresholdPrivateKey() *ThresholdPrivateKey {
tkh := GetThresholdKeyGenerator(32, 10, 6, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 10, 6, rand.Reader)
if err != nil {
panic(err)
}
tpks, err := tkh.Generate() tpks, err := tkh.Generate()
if err != nil { if err != nil {
panic(err) panic(err)
@@ -184,7 +188,11 @@ func TestupdateCprime(t *testing.T) {
} }
func TestEncryptingDecryptingSimple(t *testing.T) { func TestEncryptingDecryptingSimple(t *testing.T) {
tkh := GetThresholdKeyGenerator(10, 2, 1, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 2, 1, rand.Reader)
if err != nil {
t.Fatal(err)
}
tpks, err := tkh.Generate() tpks, err := tkh.Generate()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -205,7 +213,11 @@ func TestEncryptingDecryptingSimple(t *testing.T) {
} }
func TestEncryptingDecrypting(t *testing.T) { func TestEncryptingDecrypting(t *testing.T) {
tkh := GetThresholdKeyGenerator(10, 2, 2, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 2, 2, rand.Reader)
if err != nil {
t.Fatal(err)
}
tpks, err := tkh.Generate() tpks, err := tkh.Generate()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -227,7 +239,11 @@ func TestEncryptingDecrypting(t *testing.T) {
} }
func TestHomomorphicThresholdEncryption(t *testing.T) { func TestHomomorphicThresholdEncryption(t *testing.T) {
tkh := GetThresholdKeyGenerator(10, 2, 2, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 2, 2, rand.Reader)
if err != nil {
t.Fatal(err)
}
tpks, _ := tkh.Generate() tpks, _ := tkh.Generate()
plainText1 := b(13) plainText1 := b(13)
@@ -278,7 +294,11 @@ func TestValidate(t *testing.T) {
} }
func TestCombinePartialDecryptionsZKP(t *testing.T) { func TestCombinePartialDecryptionsZKP(t *testing.T) {
tkh := GetThresholdKeyGenerator(10, 2, 2, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 2, 2, rand.Reader)
if err != nil {
t.Fatal(err)
}
tpks, err := tkh.Generate() tpks, err := tkh.Generate()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -311,7 +331,11 @@ func TestCombinePartialDecryptionsZKP(t *testing.T) {
} }
func TestCombinePartialDecryptionsWith100Shares(t *testing.T) { func TestCombinePartialDecryptionsWith100Shares(t *testing.T) {
tkh := GetThresholdKeyGenerator(10, 100, 50, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 100, 50, rand.Reader)
if err != nil {
t.Fatal(err)
}
tpks, err := tkh.Generate() tpks, err := tkh.Generate()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@@ -338,7 +362,11 @@ func TestCombinePartialDecryptionsWith100Shares(t *testing.T) {
} }
func TestVerifyDecryption(t *testing.T) { func TestVerifyDecryption(t *testing.T) {
tkh := GetThresholdKeyGenerator(10, 2, 2, rand.Reader) tkh, err := GetThresholdKeyGenerator(32, 2, 2, rand.Reader)
if err != nil {
t.Fatal(err)
}
tpks, err := tkh.Generate() tpks, err := tkh.Generate()
pk := &tpks[0].ThresholdPublicKey pk := &tpks[0].ThresholdPublicKey
+3 -1
View File
@@ -59,7 +59,9 @@ func TestFactorial(t *testing.T) {
} }
} }
func AreSafePrimes(p, q *big.Int, expectedLength int, t *testing.T) { // IsSafePrime checks whether `p` is a safe prime. A safe prime is a prime
// number of the form `2q + 1`, where `q` is also a prime.
func IsSafePrime(p, q *big.Int, expectedLength int, t *testing.T) {
if l := p.BitLen(); l != expectedLength { if l := p.BitLen(); l != expectedLength {
t.Error("p does not have the good length. ", l) t.Error("p does not have the good length. ", l)
} }