diff --git a/.gitignore b/.gitignore index daf913b..c3d7296 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,7 @@ _testmain.go *.exe *.test *.prof + +# IDEs +.vscode/ +.idea/ diff --git a/safe_prime_generator_test.go b/safe_prime_generator_test.go index 4b57efe..f4a29db 100644 --- a/safe_prime_generator_test.go +++ b/safe_prime_generator_test.go @@ -60,7 +60,7 @@ func TestAsyncGenerator(t *testing.T) { t.Fatal(err) } - AreSafePrimes(p, q, test.bitLen, t) + IsSafePrime(p, q, test.bitLen, t) } }) } diff --git a/thresholdkey_generator.go b/thresholdkey_generator.go index 96948a0..f7ef687 100644 --- a/thresholdkey_generator.go +++ b/thresholdkey_generator.go @@ -2,6 +2,7 @@ package paillier import ( "crypto/rand" + "errors" "io" "math/big" "time" @@ -19,18 +20,18 @@ import ( // with Applications to Electronic Voting // Aarhus University, Dept. of Computer Science, BRICS type ThresholdKeyGenerator struct { - nbits int + PublicKeyBitLength int TotalNumberOfDecryptionServers int Threshold int - Random io.Reader + random io.Reader - // Both p1 and q1 are primes of length nbits - 1 - p1 *big.Int - q1 *big.Int + p *big.Int // p is prime of `PublicKeyBitLength/2` bits and `p = 2*p1 + 1` + q *big.Int // q is prime of `PublicKeyBitLength/2` bits and `q = 2*q1 + 1` - p *big.Int // p is prime and p=2*p1+1 - q *big.Int // q is prime and q=2*q1+1 - n *big.Int // n=p*q + p1 *big.Int // p1 is prime of `PublicKeyBitLength/2 - 1` bits + q1 *big.Int // q1 is prime of `PublicKeyBitLength/2 - 1` bits + + n *big.Int // n=p*q and is of `PublicKeyBitLength` bits m *big.Int // m = p1*q1 nSquare *big.Int // nSquare = n*n nm *big.Int // nm = n*m @@ -45,23 +46,44 @@ type ThresholdKeyGenerator struct { polynomialCoefficients []*big.Int } -// Preferable way to construct the ThresholdKeyGenerator. No verification -// is done on the input values. You need to be sure that nbits is big enough -// and that Threshold > TotalNumberOfDecryptionServers / 2. -// The plaintext space for the key will be Z_n. -func GetThresholdKeyGenerator(nbits, TotalNumberOfDecryptionServers, Threshold int, random io.Reader) *ThresholdKeyGenerator { - ret := new(ThresholdKeyGenerator) - ret.nbits = nbits - ret.TotalNumberOfDecryptionServers = TotalNumberOfDecryptionServers - ret.Threshold = Threshold - ret.Random = random - return ret +// GetThresholdKeyGenerator is a preferable way to construct the +// ThresholdKeyGenerator. +// Due to the various properties that must be met for the threshold key to be +// considered valid, the minimum public key `N` bit length is 18 bits and the +// public key bit length should be an even number. +// The plaintext space for the key will be `Z_N`. +func GetThresholdKeyGenerator( + publicKeyBitLength int, + totalNumberOfDecryptionServers int, + threshold int, + 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) { concurrencyLevel := 4 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 { @@ -112,7 +134,7 @@ func (tkg *ThresholdKeyGenerator) initPsAndQs() error { // v generates a cyclic group of squares in Zn^2. func (tkg *ThresholdKeyGenerator) computeV() error { var err error - tkg.v, err = GetRandomGeneratorOfTheQuadraticResidue(tkg.nSquare, tkg.Random) + tkg.v, err = GetRandomGeneratorOfTheQuadraticResidue(tkg.nSquare, tkg.random) return err } @@ -165,7 +187,7 @@ func (tkg *ThresholdKeyGenerator) generateHidingPolynomial() error { tkg.polynomialCoefficients[0] = tkg.d var err error 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 { return err } diff --git a/thresholdkey_generator_test.go b/thresholdkey_generator_test.go index bccf4a5..754db8d 100644 --- a/thresholdkey_generator_test.go +++ b/thresholdkey_generator_test.go @@ -2,6 +2,7 @@ package paillier import ( "crypto/rand" + "errors" "math/big" "reflect" "testing" @@ -11,44 +12,183 @@ var MockGenerateSafePrimes = func() (*big.Int, *big.Int, error) { return big.NewInt(887), big.NewInt(443), nil } -func TestGenerateSafePrimesOfThresholdKeyGenerator(t *testing.T) { - tkh := new(ThresholdKeyGenerator) - tkh.nbits = 10 - tkh.Random = rand.Reader - p, q, err := tkh.generateSafePrimes() - if err != nil { - t.Error(err) +func TestCreateThresholdKeyGenerator(t *testing.T) { + var tests = map[string]struct { + publicKeyBitLength int + totalNumberOfDecryptionServers int + 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 { + 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) { - tkh := new(ThresholdKeyGenerator) - tkh.nbits = 10 - tkh.Random = rand.Reader + tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader) + if err != nil { + t.Fatal(err) + } tkh.initPandP1() - AreSafePrimes(tkh.p, tkh.p1, 10, t) + IsSafePrime(tkh.p, tkh.p1, 16, t) } func TestInitQandQ1(t *testing.T) { - tkh := new(ThresholdKeyGenerator) - tkh.nbits = 10 - tkh.Random = rand.Reader + tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader) + if err != nil { + t.Fatal(err) + } tkh.initQandQ1() - AreSafePrimes(tkh.q, tkh.q1, 10, t) + IsSafePrime(tkh.q, tkh.q1, 16, t) } func TestInitPsAndQs(t *testing.T) { - tkh := new(ThresholdKeyGenerator) - tkh.nbits = 10 - tkh.Random = rand.Reader + tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader) + if err != nil { + t.Fatal(err) + } tkh.initPsAndQs() - AreSafePrimes(tkh.p, tkh.p1, 10, t) - AreSafePrimes(tkh.q, tkh.q1, 10, t) + IsSafePrime(tkh.p, tkh.p1, 16, t) + IsSafePrime(tkh.q, tkh.q1, 16, t) } func TestArePsAndQsGood(t *testing.T) { @@ -102,9 +242,10 @@ func TestInitD(t *testing.T) { } func TestInitNumerialValues(t *testing.T) { - tkh := new(ThresholdKeyGenerator) - tkh.nbits = 10 - tkh.Random = rand.Reader + tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader) + if err != nil { + t.Fatal(err) + } if err := tkh.initNumerialValues(); err != nil { t.Error(err) @@ -112,10 +253,11 @@ func TestInitNumerialValues(t *testing.T) { } func TestGenerateHidingPolynomial(t *testing.T) { - tkh := new(ThresholdKeyGenerator) - tkh.nbits = 10 - tkh.Threshold = 10 - tkh.Random = rand.Reader + tkh, err := GetThresholdKeyGenerator(32, 15, 10, rand.Reader) + if err != nil { + t.Fatal(err) + } + if err := tkh.initNumerialValues(); err != nil { t.Error(err) } @@ -137,10 +279,11 @@ func TestGenerateHidingPolynomial(t *testing.T) { } func TestComputeShare(t *testing.T) { - tkh := new(ThresholdKeyGenerator) - tkh.nbits = 10 - tkh.Threshold = 3 - tkh.TotalNumberOfDecryptionServers = 5 + tkh, err := GetThresholdKeyGenerator(32, 5, 3, rand.Reader) + if err != nil { + t.Fatal(err) + } + tkh.nm = b(103) tkh.polynomialCoefficients = []*big.Int{b(29), b(88), b(51)} share := tkh.computeShare(2) @@ -150,11 +293,11 @@ func TestComputeShare(t *testing.T) { } func TestCreateShares(t *testing.T) { - tkh := new(ThresholdKeyGenerator) - tkh.nbits = 10 - tkh.Threshold = 10 - tkh.TotalNumberOfDecryptionServers = 100 - tkh.Random = rand.Reader + tkh, err := GetThresholdKeyGenerator(32, 100, 10, rand.Reader) + if err != nil { + t.Fatal(err) + } + if err := tkh.initNumerialValues(); err != nil { t.Error(err) } @@ -180,14 +323,22 @@ func TestCreateViArray(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 { t.Error(nil) } } 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() if err != nil { t.Error(err) @@ -213,7 +364,11 @@ func TestGenerate(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.nSquare = new(big.Int).Mul(tkh.n, tkh.n) for i := 0; i < 100; i++ { diff --git a/thresholdkey_test.go b/thresholdkey_test.go index b610a85..ce7525e 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -8,7 +8,11 @@ import ( ) 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() if err != nil { panic(err) @@ -184,7 +188,11 @@ func TestupdateCprime(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() if err != nil { t.Error(err) @@ -205,7 +213,11 @@ func TestEncryptingDecryptingSimple(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() if err != nil { t.Error(err) @@ -227,7 +239,11 @@ func TestEncryptingDecrypting(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() plainText1 := b(13) @@ -278,7 +294,11 @@ func TestValidate(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() if err != nil { t.Error(err) @@ -311,7 +331,11 @@ func TestCombinePartialDecryptionsZKP(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() if err != nil { t.Error(err) @@ -338,7 +362,11 @@ func TestCombinePartialDecryptionsWith100Shares(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() pk := &tpks[0].ThresholdPublicKey diff --git a/utils_test.go b/utils_test.go index cd86b9b..81a3772 100644 --- a/utils_test.go +++ b/utils_test.go @@ -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 { t.Error("p does not have the good length. ", l) }