From 7c2ec95fb807387048e362058f513df4ae69f97e Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 25 May 2018 11:17:16 +0200 Subject: [PATCH 01/22] Explained how do we compute D from Chinese Remainder Theorem --- thresholdkey_generator.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/thresholdkey_generator.go b/thresholdkey_generator.go index 8ef0f61..9ecc895 100644 --- a/thresholdkey_generator.go +++ b/thresholdkey_generator.go @@ -101,8 +101,31 @@ func (this *ThresholdKeyGenerator) ComputeV() error { return err } -// Choose d such that d=0 mod m and d=1 mod n, using Chinese remainder thm -// we can find d using Chinese remainder thm note that $d=(m. (m^-1 mod n))$ +// Choose d such that d=0 (mod m) and d=1 (mod n). +// See [DJN 10], section 5.1, "Key generation" +// +// From Chinese Remainder Theorem: +// x = a1 (mod n1) +// x = a2 (mod n2) +// +// N = n1*n2 +// y1 = N/n1 +// y2 = N/n2 +// z1 = y1^-1 mod n1 +// z2 = y2^-1 mod n2 +// Solution is x = a1*y1*z1 + a2*y2*z2 +// +// In our case: +// x = 0 (mod m) +// x = 1 (mod n) +// +// Since a1 = 0, it's enough to compute a2*y2*z2 to get x. +// +// a2 = 1 +// y2 = mn/n = m +// z2 = m^-1 mod n +// +// x = a2*y2*z2 = 1 * m * [m^-1 mod n] func (this *ThresholdKeyGenerator) InitD() { mInverse := new(big.Int).ModInverse(this.m, this.n) this.d = new(big.Int).Mul(mInverse, this.m) From ad44ab64cbe194708c9e6b6cfe704693b809a8e1 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 25 May 2018 12:28:02 +0200 Subject: [PATCH 02/22] Added documentation to the threshold Paillier key generator --- thresholdkey_generator.go | 49 +++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/thresholdkey_generator.go b/thresholdkey_generator.go index 9ecc895..0451674 100644 --- a/thresholdkey_generator.go +++ b/thresholdkey_generator.go @@ -6,21 +6,32 @@ import ( "math/big" ) +// Generates a threshold Paillier key with an algorithm based on [DJN 10], +// section 5.1, "Key generation". +// +// Bear in mind that the algorithm assumes an existence of a trusted dealer +// to generate and distribute the keys. +// +// +// [DJN 10]: Ivan Damgard, Mads Jurik, Jesper Buus Nielsen, (2010) +// A Generalization of Paillier’s Public-Key System +// with Applications to Electronic Voting +// Aarhus University, Dept. of Computer Science, BRICS type ThresholdKeyGenerator struct { nbits int TotalNumberOfDecryptionServers int Threshold int Random io.Reader - //Both p1 and q1 are primes of length nbits - 1 + // Both p1 and q1 are primes of length nbits - 1 p1 *big.Int q1 *big.Int - p *big.Int //p is prime and p=2*p1+1 - q *big.Int //q is prime 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 - m *big.Int //m = p1*q1 - nSquare *big.Int //nSquare = n*n + m *big.Int // m = p1*q1 + nSquare *big.Int // nSquare = n*n nm *big.Int // nm = n*m // As specified in the paper, d must satify d=1 mod n and d=0 mod m @@ -29,13 +40,14 @@ type ThresholdKeyGenerator struct { // A generator of QR in Z_{n^2} v *big.Int - // the polynomial coefficients to hide a secret. See Shamir. + // The polynomial coefficients to hide a secret. See Shamir. polynomialCoefficients []*big.Int } -// preferable way to counstruct the ThresholdKeyGenerator. No verification -// is done on the input values. You need to bu sure that nbits is big enough -// and that Threshold > TotalNumberOfDecryptionServers / 2 +// 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 @@ -95,6 +107,7 @@ func (this *ThresholdKeyGenerator) InitPsAndQs() error { return nil } +// v generates a cyclic group of squares in Zn^2. func (this *ThresholdKeyGenerator) ComputeV() error { var err error this.v, err = GetRandomGeneratorOfTheQuadraticResidue(this.nSquare, this.Random) @@ -102,7 +115,6 @@ func (this *ThresholdKeyGenerator) ComputeV() error { } // Choose d such that d=0 (mod m) and d=1 (mod n). -// See [DJN 10], section 5.1, "Key generation" // // From Chinese Remainder Theorem: // x = a1 (mod n1) @@ -140,6 +152,12 @@ func (this *ThresholdKeyGenerator) InitNumerialValues() error { return this.ComputeV() } +// f(X) = a_0 X^0 + a_1 X^1 + ... + a_(w-1) X^(w-1) +// +// where: +// `w` - threshold +// `a_i` - random value from {0, ... nm - 1} for 0 Date: Fri, 25 May 2018 12:57:13 +0200 Subject: [PATCH 03/22] Do not export internal threshold generator functions --- thresholdkey_generator.go | 70 +++++++++++++++++----------------- thresholdkey_generator_test.go | 40 +++++++++---------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/thresholdkey_generator.go b/thresholdkey_generator.go index 0451674..3d9a44f 100644 --- a/thresholdkey_generator.go +++ b/thresholdkey_generator.go @@ -44,7 +44,7 @@ type ThresholdKeyGenerator struct { polynomialCoefficients []*big.Int } -// Preferable way to construct the ThresholdKeyGenerator. No verification +// 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. @@ -57,23 +57,23 @@ func GetThresholdKeyGenerator(nbits, TotalNumberOfDecryptionServers, Threshold i return ret } -func (this *ThresholdKeyGenerator) GenerateSafePrimes() (*big.Int, *big.Int, error) { +func (this *ThresholdKeyGenerator) generateSafePrimes() (*big.Int, *big.Int, error) { return GenerateSafePrimes(this.nbits, this.Random) } -func (this *ThresholdKeyGenerator) InitPandP1() error { +func (this *ThresholdKeyGenerator) initPandP1() error { var err error - this.p, this.p1, err = this.GenerateSafePrimes() + this.p, this.p1, err = this.generateSafePrimes() return err } -func (this *ThresholdKeyGenerator) InitQandQ1() error { +func (this *ThresholdKeyGenerator) initQandQ1() error { var err error - this.q, this.q1, err = this.GenerateSafePrimes() + this.q, this.q1, err = this.generateSafePrimes() return err } -func (this *ThresholdKeyGenerator) InitShortcuts() { +func (this *ThresholdKeyGenerator) initShortcuts() { this.n = new(big.Int).Mul(this.p, this.q) this.m = new(big.Int).Mul(this.p1, this.q1) this.nSquare = new(big.Int).Mul(this.n, this.n) @@ -81,7 +81,7 @@ func (this *ThresholdKeyGenerator) InitShortcuts() { } -func (this *ThresholdKeyGenerator) ArePsAndQsGood() bool { +func (this *ThresholdKeyGenerator) arePsAndQsGood() bool { if this.p.Cmp(this.q) == 0 { return false } @@ -94,21 +94,21 @@ func (this *ThresholdKeyGenerator) ArePsAndQsGood() bool { return true } -func (this *ThresholdKeyGenerator) InitPsAndQs() error { - if err := this.InitPandP1(); err != nil { +func (this *ThresholdKeyGenerator) initPsAndQs() error { + if err := this.initPandP1(); err != nil { return err } - if err := this.InitQandQ1(); err != nil { + if err := this.initQandQ1(); err != nil { return err } - if !this.ArePsAndQsGood() { - return this.InitPsAndQs() + if !this.arePsAndQsGood() { + return this.initPsAndQs() } return nil } // v generates a cyclic group of squares in Zn^2. -func (this *ThresholdKeyGenerator) ComputeV() error { +func (this *ThresholdKeyGenerator) computeV() error { var err error this.v, err = GetRandomGeneratorOfTheQuadraticResidue(this.nSquare, this.Random) return err @@ -138,18 +138,18 @@ func (this *ThresholdKeyGenerator) ComputeV() error { // z2 = m^-1 mod n // // x = a2*y2*z2 = 1 * m * [m^-1 mod n] -func (this *ThresholdKeyGenerator) InitD() { +func (this *ThresholdKeyGenerator) initD() { mInverse := new(big.Int).ModInverse(this.m, this.n) this.d = new(big.Int).Mul(mInverse, this.m) } -func (this *ThresholdKeyGenerator) InitNumerialValues() error { - if err := this.InitPsAndQs(); err != nil { +func (this *ThresholdKeyGenerator) initNumerialValues() error { + if err := this.initPsAndQs(); err != nil { return err } - this.InitShortcuts() - this.InitD() - return this.ComputeV() + this.initShortcuts() + this.initD() + return this.computeV() } // f(X) = a_0 X^0 + a_1 X^1 + ... + a_(w-1) X^(w-1) @@ -158,7 +158,7 @@ func (this *ThresholdKeyGenerator) InitNumerialValues() error { // `w` - threshold // `a_i` - random value from {0, ... nm - 1} for 0 Date: Fri, 25 May 2018 15:05:09 +0200 Subject: [PATCH 04/22] Improved documentation for a secret share computation fn --- thresholdkey_generator.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/thresholdkey_generator.go b/thresholdkey_generator.go index 3d9a44f..3260277 100644 --- a/thresholdkey_generator.go +++ b/thresholdkey_generator.go @@ -171,12 +171,13 @@ func (this *ThresholdKeyGenerator) generateHidingPolynomial() error { return nil } -// The secred share of the i'th authority is `f(i)`, where `f` is +// The secred share of the i'th authority is `f(i) mod nm`, where `f` is // the polynomial we generated in `GenerateHidingPolynomial` function. func (this *ThresholdKeyGenerator) computeShare(index int) *big.Int { share := big.NewInt(0) for i := 0; i < this.Threshold; i++ { a := this.polynomialCoefficients[i] + // we index authorities from 1, that's why we do index+1 here b := new(big.Int).Exp(big.NewInt(int64(index+1)), big.NewInt(int64(i)), nil) tmp := new(big.Int).Mul(a, b) share = new(big.Int).Add(share, tmp) From e10b02e4200c7b8cd8da13396b57fedcf42d46d5 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 25 May 2018 16:01:36 +0200 Subject: [PATCH 05/22] Small improvements to the threshold key generator tests First of all, we should check both `p,p1` and `q,q1` in the `TestInitPsAndQs`. Moreover, it's better to operate on primes in `TestArePsAndQsGood` and in `TestInitShortcuts` because non-prime numbers are not allowed there in a real world and tests were a bit misleading because of it. --- thresholdkey_generator_test.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/thresholdkey_generator_test.go b/thresholdkey_generator_test.go index 681d203..78359cb 100644 --- a/thresholdkey_generator_test.go +++ b/thresholdkey_generator_test.go @@ -18,10 +18,8 @@ func TestGenerateSafePrimesOfThresholdKeyGenerator(t *testing.T) { p, q, err := tkh.generateSafePrimes() if err != nil { t.Error(err) - return } AreSafePrimes(p, q, 10, t) - } func TestInitPandP1(t *testing.T) { @@ -31,7 +29,6 @@ func TestInitPandP1(t *testing.T) { tkh.initPandP1() AreSafePrimes(tkh.p, tkh.p1, 10, t) - } func TestInitQandQ1(t *testing.T) { @@ -49,23 +46,24 @@ func TestInitPsAndQs(t *testing.T) { tkh.Random = rand.Reader tkh.initPsAndQs() - AreSafePrimes(tkh.q, tkh.q1, 10, t) + + AreSafePrimes(tkh.p, tkh.p1, 10, t) AreSafePrimes(tkh.q, tkh.q1, 10, t) } func TestArePsAndQsGood(t *testing.T) { tkh := new(ThresholdKeyGenerator) - tkh.p, tkh.p1, tkh.q, tkh.q1 = b(6), b(5), b(4), b(3) + tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(839), b(419) if !tkh.arePsAndQsGood() { t.Fail() } - tkh.p, tkh.p1, tkh.q, tkh.q1 = b(6), b(5), b(6), b(3) + tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(887), b(443) if tkh.arePsAndQsGood() { t.Fail() } - tkh.p, tkh.p1, tkh.q, tkh.q1 = b(6), b(5), b(5), b(3) + tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(443), b(221) if tkh.arePsAndQsGood() { t.Fail() } @@ -73,19 +71,19 @@ func TestArePsAndQsGood(t *testing.T) { func TestInitShortcuts(t *testing.T) { tkh := new(ThresholdKeyGenerator) - tkh.p, tkh.p1, tkh.q, tkh.q1 = b(11), b(7), b(5), b(3) + tkh.p, tkh.p1, tkh.q, tkh.q1 = b(839), b(419), b(887), b(443) tkh.initShortcuts() - if n(tkh.n) != 11*5 { + if !reflect.DeepEqual(tkh.n, b(744193)) { t.Error("wrong n", tkh.n) } - if n(tkh.m) != 7*3 { + if !reflect.DeepEqual(tkh.m, b(185617)) { t.Error("wrong m", tkh.m) } - if n(tkh.nm) != 11*5*7*3 { + if !reflect.DeepEqual(tkh.nm, new(big.Int).Mul(b(744193), b(185617))) { t.Error("wrong nm", tkh.nm) } - if n(tkh.nSquare) != 11*5*11*5 { + if !reflect.DeepEqual(tkh.nSquare, new(big.Int).Mul(b(744193), b(744193))) { t.Error("wrong nSquare", tkh.nSquare) } } From e25bc358e8842ac00df466e8c87b75136ab7565c Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Mon, 28 May 2018 16:49:10 +0200 Subject: [PATCH 06/22] G parameter removed from ThresholdKey G _MUST_ be always n+1 to make the threshold encryption algorithm safe. We assume G=n+1 both for standard and threshold version. --- paillier.go | 3 +++ thresholdkey.go | 2 -- thresholdkey_generator.go | 1 - thresholdkey_generator_test.go | 2 +- thresholdkey_test.go | 1 - 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/paillier.go b/paillier.go index 9a2ab6c..6012e09 100644 --- a/paillier.go +++ b/paillier.go @@ -37,6 +37,9 @@ func (pub *PublicKey) Encrypt(m *big.Int, random io.Reader) (*Cypher, error) { } nSquare := pub.GetNSquare() + // g is _always_ equal n+1 + // Threshold encryption is safe only for g=n+1 choice. + // See [DJN 10], section 5.1 g := new(big.Int).Add(pub.N, big.NewInt(1)) gm := new(big.Int).Exp(g, m, nSquare) rn := new(big.Int).Exp(r, pub.N, nSquare) diff --git a/thresholdkey.go b/thresholdkey.go index 3ade718..95a6371 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -14,7 +14,6 @@ type ThresholdKey struct { Threshold int V *big.Int Vi []*big.Int - G *big.Int // usually G is set to N+1 } // returns the value of (4*delta**2)** -1 mod n @@ -165,7 +164,6 @@ func (this *ThresholdPrivateKey) GetThresholdKey() *ThresholdKey { ret.V = new(big.Int).Add(this.V, big.NewInt(0)) ret.Vi = this.copyVi() ret.N = new(big.Int).Add(this.N, big.NewInt(0)) - ret.G = new(big.Int).Add(this.N, big.NewInt(1)) return ret } diff --git a/thresholdkey_generator.go b/thresholdkey_generator.go index 3260277..5e6e1c3 100644 --- a/thresholdkey_generator.go +++ b/thresholdkey_generator.go @@ -219,7 +219,6 @@ func (this *ThresholdKeyGenerator) createViArray(shares []*big.Int) (viArray []* func (this *ThresholdKeyGenerator) createPrivateKey(i int, share *big.Int, viArray []*big.Int) *ThresholdPrivateKey { ret := new(ThresholdPrivateKey) ret.N = this.n - ret.G = new(big.Int).Add(ret.N, ONE) ret.V = this.v ret.TotalNumberOfDecryptionServers = this.TotalNumberOfDecryptionServers diff --git a/thresholdkey_generator_test.go b/thresholdkey_generator_test.go index 78359cb..e03262e 100644 --- a/thresholdkey_generator_test.go +++ b/thresholdkey_generator_test.go @@ -207,7 +207,7 @@ func TestGenerate(t *testing.T) { if len(tpk.Vi) != 10 { t.Fail() } - if tpk.G == nil || tpk.N == nil { + if tpk.N == nil { t.Fail() } if tpk.Threshold != 6 || tpk.TotalNumberOfDecryptionServers != 10 { diff --git a/thresholdkey_test.go b/thresholdkey_test.go index 23578e2..99ef1c5 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -224,7 +224,6 @@ func TestDecryption(t *testing.T) { tk.Threshold = 2 tk.TotalNumberOfDecryptionServers = 2 tk.N = b(637753) - tk.G = b(637754) tk.V = b(70661107826) if msg, err := tk.CombinePartialDecryptions([]*PartialDecryption{share1, share2}); err != nil { t.Error(err) From adcb812a08470897c3bb54e5aa41bcd093459f68 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Mon, 28 May 2018 22:21:42 +0200 Subject: [PATCH 07/22] Do not export internal ThresholdKey functions --- thresholdkey.go | 32 +++++++++++++++----------------- thresholdkey_test.go | 22 +++++++++++----------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 95a6371..548dc71 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -17,17 +17,17 @@ type ThresholdKey struct { } // returns the value of (4*delta**2)** -1 mod n -func (this *ThresholdKey) CombineSharesConstant() *big.Int { - tmp := new(big.Int).Mul(FOUR, new(big.Int).Mul(this.Delta(), this.Delta())) +func (this *ThresholdKey) combineSharesConstant() *big.Int { + tmp := new(big.Int).Mul(FOUR, new(big.Int).Mul(this.delta(), this.delta())) return (&big.Int{}).ModInverse(tmp, this.N) } // returns the factorial of the number of TotalNumberOfDecryptionServers -func (this *ThresholdKey) Delta() *big.Int { +func (this *ThresholdKey) delta() *big.Int { return Factorial(this.TotalNumberOfDecryptionServers) } -func (this *ThresholdKey) MakeVerificationBeforeCombiningPartialDecryptions(shares []*PartialDecryption) error { +func (this *ThresholdKey) makeVerificationBeforeCombiningPartialDecryptions(shares []*PartialDecryption) error { if len(shares) < this.Threshold { return errors.New("Threshold not meet") } @@ -41,17 +41,17 @@ func (this *ThresholdKey) MakeVerificationBeforeCombiningPartialDecryptions(shar return nil } -func (this *ThresholdKey) UpdateLambda(share1, share2 *PartialDecryption, lambda *big.Int) *big.Int { +func (this *ThresholdKey) updateLambda(share1, share2 *PartialDecryption, lambda *big.Int) *big.Int { num := new(big.Int).Mul(lambda, big.NewInt(int64(-share2.Id))) denom := big.NewInt(int64(share1.Id - share2.Id)) return new(big.Int).Div(num, denom) } -func (this *ThresholdKey) ComputeLambda(share *PartialDecryption, shares []*PartialDecryption) *big.Int { - lambda := this.Delta() +func (this *ThresholdKey) computeLambda(share *PartialDecryption, shares []*PartialDecryption) *big.Int { + lambda := this.delta() for _, share2 := range shares { if share2.Id != share.Id { - lambda = this.UpdateLambda(share, share2, lambda) + lambda = this.updateLambda(share, share2, lambda) } } return lambda @@ -85,17 +85,17 @@ func (this *ThresholdKey) exp(a, b, c *big.Int) *big.Int { func (this *ThresholdKey) computeDecryption(cprime *big.Int) *big.Int { l := L(cprime, this.N) - return new(big.Int).Mod(new(big.Int).Mul(this.CombineSharesConstant(), l), this.N) + return new(big.Int).Mod(new(big.Int).Mul(this.combineSharesConstant(), l), this.N) } func (this *ThresholdKey) CombinePartialDecryptions(shares []*PartialDecryption) (*big.Int, error) { - if err := this.MakeVerificationBeforeCombiningPartialDecryptions(shares); err != nil { + if err := this.makeVerificationBeforeCombiningPartialDecryptions(shares); err != nil { return nil, err } cprime := ONE for _, share := range shares { - lambda := this.ComputeLambda(share, shares) + lambda := this.computeLambda(share, shares) cprime = this.updateCprime(cprime, lambda, share) } @@ -143,7 +143,7 @@ type ThresholdPrivateKey struct { func (this *ThresholdPrivateKey) Decrypt(c *big.Int) *PartialDecryption { ret := new(PartialDecryption) ret.Id = this.Id - exp := new(big.Int).Mul(this.Share, new(big.Int).Mul(TWO, this.Delta())) + exp := new(big.Int).Mul(this.Share, new(big.Int).Mul(TWO, this.delta())) ret.Decryption = new(big.Int).Exp(c, exp, this.GetNSquare()) return ret @@ -167,11 +167,10 @@ func (this *ThresholdPrivateKey) GetThresholdKey() *ThresholdKey { return ret } -func (this *ThresholdPrivateKey) ComputeZ(r, e *big.Int) *big.Int { - tmp := new(big.Int).Mul(e, this.Delta()) +func (this *ThresholdPrivateKey) computeZ(r, e *big.Int) *big.Int { + tmp := new(big.Int).Mul(e, this.delta()) tmp = new(big.Int).Mul(tmp, this.Share) return new(big.Int).Add(r, tmp) - } func (this *ThresholdPrivateKey) computeHash(a, b, c4, ci2 *big.Int) *big.Int { @@ -181,7 +180,6 @@ func (this *ThresholdPrivateKey) computeHash(a, b, c4, ci2 *big.Int) *big.Int { hash.Write(c4.Bytes()) hash.Write(ci2.Bytes()) return new(big.Int).SetBytes(hash.Sum([]byte{})) - } func (this *ThresholdPrivateKey) DecryptAndProduceZNP(c *big.Int, random io.Reader) (*PartialDecryptionZKP, error) { @@ -208,7 +206,7 @@ func (this *ThresholdPrivateKey) DecryptAndProduceZNP(c *big.Int, random io.Read pd.E = this.computeHash(a, b, c4, ci2) - pd.Z = this.ComputeZ(r, pd.E) + pd.Z = this.computeZ(r, pd.E) return pd, nil } diff --git a/thresholdkey_test.go b/thresholdkey_test.go index 99ef1c5..cac0b52 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -func GetThresholdPrivateKey() *ThresholdPrivateKey { +func getThresholdPrivateKey() *ThresholdPrivateKey { tkh := GetThresholdKeyGenerator(32, 10, 6, rand.Reader) tpks, err := tkh.Generate() if err != nil { @@ -19,7 +19,7 @@ func GetThresholdPrivateKey() *ThresholdPrivateKey { func TestDelta(t *testing.T) { tk := new(ThresholdKey) tk.TotalNumberOfDecryptionServers = 6 - if delta := tk.Delta(); 720 != n(delta) { + if delta := tk.delta(); 720 != n(delta) { t.Error("Delta is not 720 but", delta) } } @@ -29,7 +29,7 @@ func TestCombineSharesConstant(t *testing.T) { tk.N = big.NewInt(101 * 103) tk.TotalNumberOfDecryptionServers = 6 - if c := tk.CombineSharesConstant(); !reflect.DeepEqual(big.NewInt(4558), c) { + if c := tk.combineSharesConstant(); !reflect.DeepEqual(big.NewInt(4558), c) { t.Error("wrong combined key. ", c) } } @@ -66,7 +66,7 @@ func TestCopyVi(t *testing.T) { } func TestEncryptWithThresholdKey(t *testing.T) { - pd := GetThresholdPrivateKey() + pd := getThresholdPrivateKey() _, err := pd.Encrypt(big.NewInt(876), rand.Reader) if err != nil { t.Fail() @@ -74,7 +74,7 @@ func TestEncryptWithThresholdKey(t *testing.T) { } func TestDecryptWithThresholdKey(t *testing.T) { - pd := GetThresholdPrivateKey() + pd := getThresholdPrivateKey() c, err := pd.Encrypt(big.NewInt(876), rand.Reader) if err != nil { t.Fail() @@ -111,7 +111,7 @@ func TestVerifyPart2(t *testing.T) { } func TestDecryptAndProduceZNP(t *testing.T) { - pd := GetThresholdPrivateKey() + pd := getThresholdPrivateKey() c, err := pd.Encrypt(big.NewInt(876), rand.Reader) if err != nil { t.Error(err) @@ -131,16 +131,16 @@ func TestDecryptAndProduceZNP(t *testing.T) { func TestMakeVerificationBeforeCombiningPartialDecryptions(t *testing.T) { tk := new(ThresholdKey) tk.Threshold = 2 - if tk.MakeVerificationBeforeCombiningPartialDecryptions([]*PartialDecryption{}) == nil { + if tk.makeVerificationBeforeCombiningPartialDecryptions([]*PartialDecryption{}) == nil { t.Fail() } prms := []*PartialDecryption{new(PartialDecryption), new(PartialDecryption)} prms[1].Id = 1 - if tk.MakeVerificationBeforeCombiningPartialDecryptions(prms) != nil { + if tk.makeVerificationBeforeCombiningPartialDecryptions(prms) != nil { t.Fail() } prms[1].Id = 0 - if tk.MakeVerificationBeforeCombiningPartialDecryptions(prms) == nil { + if tk.makeVerificationBeforeCombiningPartialDecryptions(prms) == nil { t.Fail() } } @@ -150,7 +150,7 @@ func TestUpdateLambda(t *testing.T) { lambda := b(11) share1 := &PartialDecryption{3, b(5)} share2 := &PartialDecryption{7, b(3)} - res := tk.UpdateLambda(share1, share2, lambda) + res := tk.updateLambda(share1, share2, lambda) if n(res) != 20 { t.Error("wrong lambda", n(res)) } @@ -250,7 +250,7 @@ func TestDivide(t *testing.T) { } func TestValidate(t *testing.T) { - pk := GetThresholdPrivateKey() + pk := getThresholdPrivateKey() if err := pk.Validate(rand.Reader); err != nil { t.Error(err) } From 1dc8db4cb2d949562f8c8b7cc0b1a17cd2d7b6c5 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Mon, 28 May 2018 23:22:16 +0200 Subject: [PATCH 08/22] Improved documentation for ThresholdKey functions --- thresholdkey.go | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 548dc71..6dbf153 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -8,6 +8,20 @@ import ( "math/big" ) +// Public key for a threshold Paillier scheme. +// +// `V` is a generator in the cyclic group of squares Z_n^2 and is used to +// execute a zero-knowledge proof of a received share decryption. +// +// `Vi` is an array of verification keys for each decryption server `i`. +// +// Key generation, encryption, share decryption and combining for the threshold +// Paillier scheme has been described in [DJN 10], section 5.1. +// +// [DJN 10]: Ivan Damgard, Mads Jurik, Jesper Buus Nielsen, (2010) +// A Generalization of Paillier’s Public-Key System +// with Applications to Electronic Voting +// Aarhus University, Dept. of Computer Science, BRICS type ThresholdKey struct { PublicKey TotalNumberOfDecryptionServers int @@ -16,17 +30,23 @@ type ThresholdKey struct { Vi []*big.Int } -// returns the value of (4*delta**2)** -1 mod n +// Returns the value of [(4*delta^2)]^-1 mod n. +// It is a constant value for the given `ThresholdKey` and is used in the last +// step of share combining. func (this *ThresholdKey) combineSharesConstant() *big.Int { tmp := new(big.Int).Mul(FOUR, new(big.Int).Mul(this.delta(), this.delta())) return (&big.Int{}).ModInverse(tmp, this.N) } -// returns the factorial of the number of TotalNumberOfDecryptionServers +// Returns the factorial of the number of `TotalNumberOfDecryptionServers`. +// It is a contant value for the given `ThresholdKey`. func (this *ThresholdKey) delta() *big.Int { return Factorial(this.TotalNumberOfDecryptionServers) } +// Checks if the number of received, unique shares is less than the +// required threshold. +// This method does not execute ZKP on received shares. func (this *ThresholdKey) makeVerificationBeforeCombiningPartialDecryptions(shares []*PartialDecryption) error { if len(shares) < this.Threshold { return errors.New("Threshold not meet") @@ -47,6 +67,8 @@ func (this *ThresholdKey) updateLambda(share1, share2 *PartialDecryption, lambda return new(big.Int).Div(num, denom) } +// Evaluates lambda parameter for each decrypted share. See second figure in the +// "Share combining" paragraph in [DJK 10], section 5.2. func (this *ThresholdKey) computeLambda(share *PartialDecryption, shares []*PartialDecryption) *big.Int { lambda := this.delta() for _, share2 := range shares { @@ -64,6 +86,7 @@ func (this *ThresholdKey) updateCprime(cprime, lambda *big.Int, share *PartialDe return new(big.Int).Mod(ret, this.GetNSquare()) } +// TODO: unused? kill? func (this *ThresholdKey) divide(a, b *big.Int) *big.Int { if a.Cmp(ZERO) == -1 { if b.Cmp(ZERO) == -1 { @@ -83,11 +106,18 @@ func (this *ThresholdKey) exp(a, b, c *big.Int) *big.Int { } +// Executes the last step of message decryption. Takes `cprime` value computed +// from valid shares provided by decryption servers and multiplies this value +// by `combineSharesContant` which is specific to the given public `ThresholdKey`. func (this *ThresholdKey) computeDecryption(cprime *big.Int) *big.Int { l := L(cprime, this.N) return new(big.Int).Mod(new(big.Int).Mul(this.combineSharesConstant(), l), this.N) } +// Combines partial decryptions provided by decryption servers and returns +// decrypted message. +// This function does not verify zero knowledge proofs. Returned message can be +// incorrectly decrypted if an adversary corrupted partial decryption. func (this *ThresholdKey) CombinePartialDecryptions(shares []*PartialDecryption) (*big.Int, error) { if err := this.makeVerificationBeforeCombiningPartialDecryptions(shares); err != nil { return nil, err @@ -102,6 +132,10 @@ func (this *ThresholdKey) CombinePartialDecryptions(shares []*PartialDecryption) return this.computeDecryption(cprime), nil } +// Combines partial decryptions provided by decription servers and returns +// decrypted message. +// Function verifies zero knowledge proofs and filters out all shares that failed +// verification. func (this *ThresholdKey) CombinePartialDecryptionsZKP(shares []*PartialDecryptionZKP) (*big.Int, error) { ret := make([]*PartialDecryption, 0) for _, share := range shares { @@ -157,7 +191,7 @@ func (this *ThresholdPrivateKey) copyVi() []*big.Int { return ret } -func (this *ThresholdPrivateKey) GetThresholdKey() *ThresholdKey { +func (this *ThresholdPrivateKey) getThresholdKey() *ThresholdKey { ret := new(ThresholdKey) ret.Threshold = this.Threshold ret.TotalNumberOfDecryptionServers = this.TotalNumberOfDecryptionServers @@ -184,7 +218,7 @@ func (this *ThresholdPrivateKey) computeHash(a, b, c4, ci2 *big.Int) *big.Int { func (this *ThresholdPrivateKey) DecryptAndProduceZNP(c *big.Int, random io.Reader) (*PartialDecryptionZKP, error) { pd := new(PartialDecryptionZKP) - pd.Key = this.GetThresholdKey() + pd.Key = this.getThresholdKey() pd.C = c pd.Id = this.Id pd.Decryption = this.Decrypt(c).Decryption From 915950cb351c69ab5d9f51b1146c7101a490eff6 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Mon, 28 May 2018 23:26:44 +0200 Subject: [PATCH 09/22] Removed unused ThresholdKey.divide function --- thresholdkey.go | 21 ++++----------------- thresholdkey_test.go | 17 ----------------- 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 6dbf153..977a3fa 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -86,24 +86,12 @@ func (this *ThresholdKey) updateCprime(cprime, lambda *big.Int, share *PartialDe return new(big.Int).Mod(ret, this.GetNSquare()) } -// TODO: unused? kill? -func (this *ThresholdKey) divide(a, b *big.Int) *big.Int { - if a.Cmp(ZERO) == -1 { - if b.Cmp(ZERO) == -1 { - return new(big.Int).Div(new(big.Int).Neg(a), new(big.Int).Neg(b)) - } - return new(big.Int).Neg(new(big.Int).Div(new(big.Int).Neg(a), b)) - } - return new(big.Int).Div(a, b) -} - func (this *ThresholdKey) exp(a, b, c *big.Int) *big.Int { if b.Cmp(ZERO) == -1 { ret := new(big.Int).Exp(a, new(big.Int).Neg(b), c) return new(big.Int).ModInverse(ret, c) } return new(big.Int).Exp(a, b, c) - } // Executes the last step of message decryption. Takes `cprime` value computed @@ -146,11 +134,10 @@ func (this *ThresholdKey) CombinePartialDecryptionsZKP(shares []*PartialDecrypti return this.CombinePartialDecryptions(ret) } -// Verify if the decryption of `encryptedMessage` has well been done. -// It verifies all the zero-knoledge proofs, the value of the decrypted -// and decrypted message. -// The method returns `nil` if everything is good. Otherwise it returns an -// explicative message +// Verifies if the decryption of `encryptedMessage` has been done properly. +// It verifies all the zero-knoledge proofs, the value of the decrypted +// and decrypted message. The method returns `nil` if everything is fine. +// Otherwise, it returns an explicative message. func (this *ThresholdKey) VerifyDecryption(encryptedMessage, decryptedMessage *big.Int, shares []*PartialDecryptionZKP) error { for _, share := range shares { if share.C.Cmp(encryptedMessage) != 0 { diff --git a/thresholdkey_test.go b/thresholdkey_test.go index cac0b52..fdab2ac 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -230,23 +230,6 @@ func TestDecryption(t *testing.T) { } else if n(msg) != 100 { t.Error("decrypted message was not 100 but ", msg) } - -} - -func TestDivide(t *testing.T) { - tk := new(ThresholdKey) - if r := tk.divide(b(77), b(4)); n(r) != 19 { - t.Error("77 / 4 != 19 ( ", r, " )") - } - if r := tk.divide(b(-77), b(-4)); n(r) != 19 { - t.Error("-77 / -4 != 19 ( ", r, " )") - } - if r := tk.divide(b(-77), b(4)); n(r) != -19 { - t.Error("-77 / 4 != -19 ( ", r, " )") - } - if r := tk.divide(b(77), b(-4)); n(r) != -19 { - t.Error("77 / -4 != -19 ( ", r, " )") - } } func TestValidate(t *testing.T) { From 76f8f63a47b0e617c462ff10e3ee2d6a6cd03bc3 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Tue, 29 May 2018 22:29:17 +0200 Subject: [PATCH 10/22] Added test ensuring threshold Paillier is a partially homomorphic system --- paillier.go | 3 +++ thresholdkey_test.go | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/paillier.go b/paillier.go index 6012e09..2bd1203 100644 --- a/paillier.go +++ b/paillier.go @@ -48,6 +48,9 @@ func (pub *PublicKey) Encrypt(m *big.Int, random io.Reader) (*Cypher, error) { // Takes two cypher texts and returns a 3rd one that encode // the sum of the two plain texts. +// +// It's possible because Paillier is a homomorphic encryption scheme, where +// E(m1) * E(m2) = E(m1 + m2) func (this *PublicKey) Add(cypher1, cypher2 *Cypher) *Cypher { m := new(big.Int).Mul(cypher1.C, cypher2.C) return &Cypher{new(big.Int).Mod(m, this.GetNSquare())} diff --git a/thresholdkey_test.go b/thresholdkey_test.go index fdab2ac..ef85189 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -216,6 +216,30 @@ func TestEncryptingDecrypting(t *testing.T) { } } +func TestHomomorphicThresholdEncryption(t *testing.T) { + tkh := GetThresholdKeyGenerator(10, 2, 2, rand.Reader) + tpks, _ := tkh.Generate() + + plainText1 := b(13) + plainText2 := b(19) + + cypher1, _ := tpks[0].Encrypt(plainText1, rand.Reader) + cypher2, _ := tpks[1].Encrypt(plainText2, rand.Reader) + + cypher3 := tpks[0].Add(cypher1, cypher2) + + share1 := tpks[0].Decrypt(cypher3.C) + share2 := tpks[1].Decrypt(cypher3.C) + + combined, _ := tpks[0].CombinePartialDecryptions([]*PartialDecryption{share1, share2}) + + expected := big.NewInt(32) // 13 + 19 + + if !reflect.DeepEqual(combined, expected) { // 13 + 19 + t.Errorf("Unexpected decryption result. Expected %v but got %v", expected, combined) + } +} + func TestDecryption(t *testing.T) { // test the correct decryption of '100'. share1 := &PartialDecryption{1, b(384111638639)} @@ -347,5 +371,4 @@ func TestVerifyDecryption(t *testing.T) { if err = pk.VerifyDecryption(new(big.Int).Add(b(1), cypher.C), b(101), pds); err == nil { t.Error(err) } - } From f05e5219c2e8dfe7aa78bf1bd3efb8832e051a64 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Tue, 29 May 2018 22:44:43 +0200 Subject: [PATCH 11/22] Added documentation describing how partial decryptions are combined --- thresholdkey.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 977a3fa..190cd66 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -79,6 +79,16 @@ func (this *ThresholdKey) computeLambda(share *PartialDecryption, shares []*Part return lambda } +// Used to evaluate c' parameter which combines individual share decryptions. +// +// Modulo division is performed on the computed exponent to avoid creating +// large numbers. This is possible because of the following property of modulo: +// A^B mod C = (A mod C)^B mod C +// +// Modulo division is performed on the computed coefficient because of the +// following property of modulo: +// (AB) mod C = (A mod C * B mod C) mod C +// Note, we need to combine coefficients into single c'. func (this *ThresholdKey) updateCprime(cprime, lambda *big.Int, share *PartialDecryption) *big.Int { twoLambda := new(big.Int).Mul(TWO, lambda) ret := this.exp(share.Decryption, twoLambda, this.GetNSquare()) @@ -154,13 +164,17 @@ func (this *ThresholdKey) VerifyDecryption(encryptedMessage, decryptedMessage *b return nil } +// Private key for a threshold Paillier scheme. Holds private information +// for the given decryption server. +// `Id` is the unique identifier of a decryption server and `Share` is a secret +// share generated from hiding polynomial and is used for a partial share decryption. type ThresholdPrivateKey struct { ThresholdKey Id int Share *big.Int } -// Decrypt the cypher text and returns the partial decryption +// Decrypts the cypher text and returns the partial decryption func (this *ThresholdPrivateKey) Decrypt(c *big.Int) *PartialDecryption { ret := new(PartialDecryption) ret.Id = this.Id @@ -264,7 +278,6 @@ type PartialDecryptionZKP struct { E *big.Int // the challenge Z *big.Int // the value needed to check to verify the decryption C *big.Int // the input cypher text - } func (this *PartialDecryptionZKP) verifyPart1() *big.Int { From b715df420a75a87add85e8ffa991c4811cab39dc Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Wed, 30 May 2018 10:07:14 +0200 Subject: [PATCH 12/22] Removed unneeded return statements from tests --- thresholdkey_generator_test.go | 6 ------ thresholdkey_test.go | 15 --------------- 2 files changed, 21 deletions(-) diff --git a/thresholdkey_generator_test.go b/thresholdkey_generator_test.go index e03262e..bccf4a5 100644 --- a/thresholdkey_generator_test.go +++ b/thresholdkey_generator_test.go @@ -118,7 +118,6 @@ func TestGenerateHidingPolynomial(t *testing.T) { tkh.Random = rand.Reader if err := tkh.initNumerialValues(); err != nil { t.Error(err) - return } if err := tkh.generateHidingPolynomial(); err != nil { t.Error(err) @@ -126,7 +125,6 @@ func TestGenerateHidingPolynomial(t *testing.T) { p := tkh.polynomialCoefficients if len(p) != tkh.Threshold { t.Fail() - return } if n(p[0]) != n(tkh.d) { t.Fail() @@ -159,11 +157,9 @@ func TestCreateShares(t *testing.T) { tkh.Random = rand.Reader if err := tkh.initNumerialValues(); err != nil { t.Error(err) - return } if err := tkh.generateHidingPolynomial(); err != nil { t.Error(err) - return } if shares := tkh.createShares(); len(shares) != 100 { @@ -223,7 +219,6 @@ func TestComputeV(t *testing.T) { for i := 0; i < 100; i++ { if err := tkh.computeV(); err != nil { t.Error(err) - return } if tkh.v.Cmp(tkh.nSquare) > 0 { t.Error("v is too big") @@ -235,5 +230,4 @@ func TestComputeV(t *testing.T) { t.Error(`v has never been bigger than n. It is suspicious in the sense< than it was taken in the range 0...n**2 -1 `) - } diff --git a/thresholdkey_test.go b/thresholdkey_test.go index ef85189..62427f0 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -115,12 +115,10 @@ func TestDecryptAndProduceZNP(t *testing.T) { c, err := pd.Encrypt(big.NewInt(876), rand.Reader) if err != nil { t.Error(err) - return } znp, err := pd.DecryptAndProduceZNP(c.C, rand.Reader) if err != nil { t.Error(err) - return } if !znp.Verify() { @@ -174,13 +172,11 @@ func TestEncryptingDecryptingSimple(t *testing.T) { tpks, err := tkh.Generate() if err != nil { t.Error(err) - return } message := b(100) c, err := tpks[1].Encrypt(message, rand.Reader) if err != nil { t.Error(err) - return } share1 := tpks[0].Decrypt(c.C) message2, err := tpks[0].CombinePartialDecryptions([]*PartialDecryption{share1}) @@ -197,13 +193,11 @@ func TestEncryptingDecrypting(t *testing.T) { tpks, err := tkh.Generate() if err != nil { t.Error(err) - return } message := b(100) c, err := tpks[1].Encrypt(message, rand.Reader) if err != nil { t.Error(err) - return } share1 := tpks[0].Decrypt(c.C) share2 := tpks[1].Decrypt(c.C) @@ -272,23 +266,19 @@ func TestCombinePartialDecryptionsZKP(t *testing.T) { tpks, err := tkh.Generate() if err != nil { t.Error(err) - return } message := b(100) c, err := tpks[1].Encrypt(message, rand.Reader) if err != nil { t.Error(err) - return } share1, err := tpks[0].DecryptAndProduceZNP(c.C, rand.Reader) if err != nil { t.Error(err) - return } share2, err := tpks[1].DecryptAndProduceZNP(c.C, rand.Reader) if err != nil { t.Error(err) - return } message2, err := tpks[0].CombinePartialDecryptionsZKP([]*PartialDecryptionZKP{share1, share2}) if err != nil { @@ -338,28 +328,23 @@ func TestVerifyDecryption(t *testing.T) { pk := &tpks[0].ThresholdKey if err != nil { t.Error(err) - return } expt := b(101) cypher, err := tpks[0].Encrypt(expt, rand.Reader) if err != nil { t.Error(err) - return } pd1, err := tpks[0].DecryptAndProduceZNP(cypher.C, rand.Reader) if err != nil { t.Error(err) - return } pd2, err := tpks[1].DecryptAndProduceZNP(cypher.C, rand.Reader) if err != nil { t.Error(err) - return } pds := []*PartialDecryptionZKP{pd1, pd2} if err != nil { t.Error(err) - return } if err = pk.VerifyDecryption(cypher.C, b(101), pds); err != nil { From 5d49cb0f7295873867a1968c384c63a0e4090d94 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Wed, 30 May 2018 14:32:09 +0200 Subject: [PATCH 13/22] Added documentation to code evaluating ZKP --- thresholdkey.go | 68 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 190cd66..2758ca1 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -13,7 +13,8 @@ import ( // `V` is a generator in the cyclic group of squares Z_n^2 and is used to // execute a zero-knowledge proof of a received share decryption. // -// `Vi` is an array of verification keys for each decryption server `i`. +// `Vi` is an array of verification keys for each decryption server `i` used to +// execute a zero-knowledge proof of a received share decryption. // // Key generation, encryption, share decryption and combining for the threshold // Paillier scheme has been described in [DJN 10], section 5.1. @@ -26,8 +27,8 @@ type ThresholdKey struct { PublicKey TotalNumberOfDecryptionServers int Threshold int - V *big.Int - Vi []*big.Int + V *big.Int // needed for ZKP + Vi []*big.Int // needed for ZKP } // Returns the value of [(4*delta^2)]^-1 mod n. @@ -145,7 +146,7 @@ func (this *ThresholdKey) CombinePartialDecryptionsZKP(shares []*PartialDecrypti } // Verifies if the decryption of `encryptedMessage` has been done properly. -// It verifies all the zero-knoledge proofs, the value of the decrypted +// It verifies all the zero-knoledge proofs, the value of the encrypted // and decrypted message. The method returns `nil` if everything is fine. // Otherwise, it returns an explicative message. func (this *ThresholdKey) VerifyDecryption(encryptedMessage, decryptedMessage *big.Int, shares []*PartialDecryptionZKP) error { @@ -246,8 +247,8 @@ func (this *ThresholdPrivateKey) DecryptAndProduceZNP(c *big.Int, random io.Read return pd, nil } -// Verify if the partial decryption key is well formed. If well formed, -// the method return nil else an explicative error is returned. +// Verifies if the partial decryption key is well formed. If well formed, +// the method return nil else an explicative error is returned. func (this *ThresholdPrivateKey) Validate(random io.Reader) error { m, err := rand.Int(random, this.N) if err != nil { @@ -272,6 +273,43 @@ type PartialDecryption struct { Decryption *big.Int } +// A non-interactive ZKP based on the Fiat–Shamir heuristic. This algorithm +// proves that the decryption server indeed raised secret to his secret exponent +// (`ThresholdPrivateKey.Share`) by comparison with the public verification key +// (`ThresholdKey.Vi`). Recall that v_i = v^(delta s_i). +// +// This is essentialy a protocol for the equality of discrete logs, +// log_{c^4}(c_i^2) = log_v(v_i). +// +// The Fiat-Shamir scheme works as follows in our case: +// +// ZKP construction +// +// - Pick random r +// - Compute E as: +// E = HASH(a, b, c^4, c_i^2 ), where +// a = (c^4)^r mod n^2 +// b = V^r mod n^2 +// c is a cyphertext, +// V is a generator from ThresholdKey.V +// c_i is a partial decryption for this server +// - Compute Z as: +// delta * E * s_i + r, where +// delta is the factorial of the number of decryption servers +// s_i is a secret share for this server +// +// ZKP verification +// +// - Compute the original a from +// a = a1 * a2 mod n^2 +// a1 = (c^4)^Z +// a2 = [ (c_i^2)^E ]^-1 mod n^2 +// - Compute the original b from +// b = b1 * b2 mod n^2 +// b1 = V^Z +// b2 = [ v_i^E ] -1 mod n^2 +// - Rehash H(a, b, c^4, c_i) +// - Compare ZKP hash with the one just computed type PartialDecryptionZKP struct { PartialDecryption Key *ThresholdKey // the public key used to encrypt @@ -281,24 +319,20 @@ type PartialDecryptionZKP struct { } func (this *PartialDecryptionZKP) verifyPart1() *big.Int { - c4 := new(big.Int).Exp(this.C, FOUR, nil) - decryption2 := new(big.Int).Exp(this.Decryption, TWO, nil) + c4 := new(big.Int).Exp(this.C, FOUR, nil) // c^4 + decryption2 := new(big.Int).Exp(this.Decryption, TWO, nil) // c_i^2 - a1 := new(big.Int).Exp(c4, this.Z, this.Key.GetNSquare()) - a2 := new(big.Int).Exp(decryption2, this.E, this.Key.GetNSquare()) + a1 := new(big.Int).Exp(c4, this.Z, this.Key.GetNSquare()) // (c^4)^Z + a2 := new(big.Int).Exp(decryption2, this.E, this.Key.GetNSquare()) // (c_i^2)^E a2 = new(big.Int).ModInverse(a2, this.Key.GetNSquare()) a := new(big.Int).Mod(new(big.Int).Mul(a1, a2), this.Key.GetNSquare()) return a } -func (this *PartialDecryptionZKP) neg(n *big.Int) *big.Int { - return new(big.Int).Neg(n) -} - func (this *PartialDecryptionZKP) verifyPart2() *big.Int { - vi := this.Key.Vi[this.Id-1] - b1 := new(big.Int).Exp(this.Key.V, this.Z, this.Key.GetNSquare()) - b2 := new(big.Int).Exp(vi, this.E, this.Key.GetNSquare()) + vi := this.Key.Vi[this.Id-1] // servers are indexed from 1 + b1 := new(big.Int).Exp(this.Key.V, this.Z, this.Key.GetNSquare()) // V^Z + b2 := new(big.Int).Exp(vi, this.E, this.Key.GetNSquare()) // (v_i)^E b2 = new(big.Int).ModInverse(b2, this.Key.GetNSquare()) b := new(big.Int).Mod(new(big.Int).Mul(b1, b2), this.Key.GetNSquare()) return b From e43575684d12eaae54ed5baa4a0d8b3385ce2d5d Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Wed, 30 May 2018 15:37:53 +0200 Subject: [PATCH 14/22] Removed G parameter serialization code for ThresholdKey --- encoding.go | 15 ++++----------- encoding_test.go | 12 ++++++++---- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/encoding.go b/encoding.go index 11920fb..261b769 100644 --- a/encoding.go +++ b/encoding.go @@ -57,7 +57,6 @@ type dbThresholdKey struct { V string Vi []string N string - G string } func (this *dbThresholdKey) FromThresholdKey(key *ThresholdKey) { @@ -65,7 +64,6 @@ func (this *dbThresholdKey) FromThresholdKey(key *ThresholdKey) { this.Threshold = key.Threshold this.V = fmt.Sprintf("%x", key.V) this.N = fmt.Sprintf("%x", key.N) - this.G = fmt.Sprintf("%x", key.G) this.Vi = make([]string, len(key.Vi)) for i, vi := range key.Vi { this.Vi[i] = fmt.Sprintf("%x", vi) @@ -75,10 +73,9 @@ func (this *dbThresholdKey) FromThresholdKey(key *ThresholdKey) { func (this *dbThresholdKey) ToThresholdKey(key *ThresholdKey) error { key.TotalNumberOfDecryptionServers = this.TotalNumberOfDecryptionServers key.Threshold = this.Threshold - oks := make([]bool, 3) + oks := make([]bool, 2) key.V, oks[0] = new(big.Int).SetString(this.V, 16) key.N, oks[1] = new(big.Int).SetString(this.N, 16) - key.G, oks[2] = new(big.Int).SetString(this.G, 16) if !all(oks) { return errors.New("not hexadecimal") } @@ -110,7 +107,6 @@ func (this *ThresholdKey) SetBSON(raw bson.Raw) error { type dbPrivateKey struct { N string `bson:",omitempty"` - G string `bson:",omitempty"` Lambda string `bson:",omitempty"` Mu string `bson:",omitempty"` } @@ -154,7 +150,6 @@ type dbPartialDecryptionZKP struct { E string `json:"e"` C string `json:"c"` V string `json:"v"` - G string `json:"g"` N string `json:"n"` Vi []string `json:"vi"` Decryption string `json:"decryption"` @@ -169,7 +164,6 @@ func (this *dbPartialDecryptionZKP) FromPartialDecryptionZKP(pd *PartialDecrypti this.Threshold = pd.Key.Threshold this.Z = fmt.Sprintf("%x", pd.Z) this.E = fmt.Sprintf("%x", pd.E) - this.G = fmt.Sprintf("%x", pd.Key.G) this.N = fmt.Sprintf("%x", pd.Key.N) this.C = fmt.Sprintf("%x", pd.C) this.V = fmt.Sprintf("%x", pd.Key.V) @@ -183,7 +177,7 @@ func (this *dbPartialDecryptionZKP) FromPartialDecryptionZKP(pd *PartialDecrypti func (this *dbPartialDecryptionZKP) ToPartialDecryptionZKP(pd *PartialDecryptionZKP) error { pd.Key = new(ThresholdKey) - var oks = make([]bool, 7) + var oks = make([]bool, 6) pd.Id = this.Id pd.Key.TotalNumberOfDecryptionServers = this.TotalNumberOfDecryptionServers @@ -192,9 +186,8 @@ func (this *dbPartialDecryptionZKP) ToPartialDecryptionZKP(pd *PartialDecryption pd.E, oks[1] = new(big.Int).SetString(this.E, 16) pd.C, oks[2] = new(big.Int).SetString(this.C, 16) pd.Key.V, oks[3] = new(big.Int).SetString(this.V, 16) - pd.Key.G, oks[4] = new(big.Int).SetString(this.G, 16) - pd.Key.N, oks[5] = new(big.Int).SetString(this.N, 16) - pd.Decryption, oks[6] = new(big.Int).SetString(this.Decryption, 16) + pd.Key.N, oks[4] = new(big.Int).SetString(this.N, 16) + pd.Decryption, oks[5] = new(big.Int).SetString(this.Decryption, 16) if !all(oks) { fmt.Println(oks) diff --git a/encoding_test.go b/encoding_test.go index 9e0e945..0579c35 100644 --- a/encoding_test.go +++ b/encoding_test.go @@ -85,14 +85,13 @@ func TestPartialDecryptionZKPJsonification(t *testing.T) { pd.Key.Threshold = 98 pd.Key.TotalNumberOfDecryptionServers = 230 pd.Id = 1 - pd.Key.Vi = []*big.Int{b(77), b(67)} // vi is 67 + pd.Key.Vi = []*big.Int{b(77), b(67)} pd.Key.N = b(131) pd.Key.V = b(101) pd.Decryption = b(171) pd.E = b(112) pd.C = b(99) pd.Key.N = b(345) - pd.Key.G = b(99) pd.Z = b(88) AssertJSONIsGood(pd, new(PartialDecryptionZKP), t) @@ -111,13 +110,18 @@ func TestPartialDecryptionZKPBSONification(t *testing.T) { pd.E = b(112) pd.C = b(99) pd.Key.N = b(345) - pd.Key.G = b(99) pd.Z = b(88) AssertBSONIsGood(pd, new(PartialDecryptionZKP), t) } func TestThresholdKeyBSON(t *testing.T) { - key := &ThresholdKey{PublicKey{b(9)}, 7, 6, b(3), []*big.Int{b(2), b(34)}, b(8)} + key := &ThresholdKey{ + PublicKey: PublicKey{b(9)}, + TotalNumberOfDecryptionServers: 7, + Threshold: 6, + V: b(3), + Vi: []*big.Int{b(2), b(34)}, + } AssertBSONIsGood(key, new(ThresholdKey), t) } From bb8c3928d2ecb17b52c8b8c1d0ce56b9245fd6b8 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 1 Jun 2018 20:45:22 +0200 Subject: [PATCH 15/22] Explained how Fiat-Shamir heuristic works on a high level --- thresholdkey.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 2758ca1..0898689 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -278,16 +278,29 @@ type PartialDecryption struct { // (`ThresholdPrivateKey.Share`) by comparison with the public verification key // (`ThresholdKey.Vi`). Recall that v_i = v^(delta s_i). // +// The Fiat-Shamir is a non-interactive proof of knowledge heuristic. +// The general algorithm is as follows: +// +// - Alice wants to prove that she knows x: the discrete logarithm of y = g^x +// to the base g +// - Alice picks a random r from Z_q and computes t = g^r +// - Alice computes E = H(t, g, y), where H is a cryptographic hash function +// - Alice computes Z = Ex + r. +// The resulting proof is the pair (t, Z). +// - Anyone can check whether t = g^Z y^E (mod q) +// +// In our case: +// +// Decryption server i wants to prove that he indeed raised the cyphertext to +// his secret exponent s_i during partial decryption. // This is essentialy a protocol for the equality of discrete logs, // log_{c^4}(c_i^2) = log_v(v_i). // -// The Fiat-Shamir scheme works as follows in our case: -// // ZKP construction // -// - Pick random r +// - Pick random r mod n // - Compute E as: -// E = HASH(a, b, c^4, c_i^2 ), where +// E = HASH(a, b, c^4, c_i^2), where // a = (c^4)^r mod n^2 // b = V^r mod n^2 // c is a cyphertext, @@ -308,7 +321,7 @@ type PartialDecryption struct { // b = b1 * b2 mod n^2 // b1 = V^Z // b2 = [ v_i^E ] -1 mod n^2 -// - Rehash H(a, b, c^4, c_i) +// - Rehash H(a, b, c^4, c_i^2) // - Compare ZKP hash with the one just computed type PartialDecryptionZKP struct { PartialDecryption From df9231e7b2e0773ff2ae93042ba3bdfb51a1325b Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 1 Jun 2018 20:51:15 +0200 Subject: [PATCH 16/22] ThresholdKeyGenerator self-ref renamed from this to tkg --- thresholdkey_generator.go | 127 +++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 64 deletions(-) diff --git a/thresholdkey_generator.go b/thresholdkey_generator.go index 5e6e1c3..1dab199 100644 --- a/thresholdkey_generator.go +++ b/thresholdkey_generator.go @@ -57,60 +57,59 @@ func GetThresholdKeyGenerator(nbits, TotalNumberOfDecryptionServers, Threshold i return ret } -func (this *ThresholdKeyGenerator) generateSafePrimes() (*big.Int, *big.Int, error) { - return GenerateSafePrimes(this.nbits, this.Random) +func (tkg *ThresholdKeyGenerator) generateSafePrimes() (*big.Int, *big.Int, error) { + return GenerateSafePrimes(tkg.nbits, tkg.Random) } -func (this *ThresholdKeyGenerator) initPandP1() error { +func (tkg *ThresholdKeyGenerator) initPandP1() error { var err error - this.p, this.p1, err = this.generateSafePrimes() + tkg.p, tkg.p1, err = tkg.generateSafePrimes() return err } -func (this *ThresholdKeyGenerator) initQandQ1() error { +func (tkg *ThresholdKeyGenerator) initQandQ1() error { var err error - this.q, this.q1, err = this.generateSafePrimes() + tkg.q, tkg.q1, err = tkg.generateSafePrimes() return err } -func (this *ThresholdKeyGenerator) initShortcuts() { - this.n = new(big.Int).Mul(this.p, this.q) - this.m = new(big.Int).Mul(this.p1, this.q1) - this.nSquare = new(big.Int).Mul(this.n, this.n) - this.nm = new(big.Int).Mul(this.n, this.m) - +func (tkg *ThresholdKeyGenerator) initShortcuts() { + tkg.n = new(big.Int).Mul(tkg.p, tkg.q) + tkg.m = new(big.Int).Mul(tkg.p1, tkg.q1) + tkg.nSquare = new(big.Int).Mul(tkg.n, tkg.n) + tkg.nm = new(big.Int).Mul(tkg.n, tkg.m) } -func (this *ThresholdKeyGenerator) arePsAndQsGood() bool { - if this.p.Cmp(this.q) == 0 { +func (tkg *ThresholdKeyGenerator) arePsAndQsGood() bool { + if tkg.p.Cmp(tkg.q) == 0 { return false } - if this.p.Cmp(this.q1) == 0 { + if tkg.p.Cmp(tkg.q1) == 0 { return false } - if this.p1.Cmp(this.q) == 0 { + if tkg.p1.Cmp(tkg.q) == 0 { return false } return true } -func (this *ThresholdKeyGenerator) initPsAndQs() error { - if err := this.initPandP1(); err != nil { +func (tkg *ThresholdKeyGenerator) initPsAndQs() error { + if err := tkg.initPandP1(); err != nil { return err } - if err := this.initQandQ1(); err != nil { + if err := tkg.initQandQ1(); err != nil { return err } - if !this.arePsAndQsGood() { - return this.initPsAndQs() + if !tkg.arePsAndQsGood() { + return tkg.initPsAndQs() } return nil } // v generates a cyclic group of squares in Zn^2. -func (this *ThresholdKeyGenerator) computeV() error { +func (tkg *ThresholdKeyGenerator) computeV() error { var err error - this.v, err = GetRandomGeneratorOfTheQuadraticResidue(this.nSquare, this.Random) + tkg.v, err = GetRandomGeneratorOfTheQuadraticResidue(tkg.nSquare, tkg.Random) return err } @@ -138,18 +137,18 @@ func (this *ThresholdKeyGenerator) computeV() error { // z2 = m^-1 mod n // // x = a2*y2*z2 = 1 * m * [m^-1 mod n] -func (this *ThresholdKeyGenerator) initD() { - mInverse := new(big.Int).ModInverse(this.m, this.n) - this.d = new(big.Int).Mul(mInverse, this.m) +func (tkg *ThresholdKeyGenerator) initD() { + mInverse := new(big.Int).ModInverse(tkg.m, tkg.n) + tkg.d = new(big.Int).Mul(mInverse, tkg.m) } -func (this *ThresholdKeyGenerator) initNumerialValues() error { - if err := this.initPsAndQs(); err != nil { +func (tkg *ThresholdKeyGenerator) initNumerialValues() error { + if err := tkg.initPsAndQs(); err != nil { return err } - this.initShortcuts() - this.initD() - return this.computeV() + tkg.initShortcuts() + tkg.initD() + return tkg.computeV() } // f(X) = a_0 X^0 + a_1 X^1 + ... + a_(w-1) X^(w-1) @@ -158,12 +157,12 @@ func (this *ThresholdKeyGenerator) initNumerialValues() error { // `w` - threshold // `a_i` - random value from {0, ... nm - 1} for 0 Date: Fri, 1 Jun 2018 21:28:13 +0200 Subject: [PATCH 17/22] ThresholdKey self-ref renamed from this to tk --- thresholdkey.go | 54 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 0898689..39e33b0 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -34,22 +34,22 @@ type ThresholdKey struct { // Returns the value of [(4*delta^2)]^-1 mod n. // It is a constant value for the given `ThresholdKey` and is used in the last // step of share combining. -func (this *ThresholdKey) combineSharesConstant() *big.Int { - tmp := new(big.Int).Mul(FOUR, new(big.Int).Mul(this.delta(), this.delta())) - return (&big.Int{}).ModInverse(tmp, this.N) +func (tk *ThresholdKey) combineSharesConstant() *big.Int { + tmp := new(big.Int).Mul(FOUR, new(big.Int).Mul(tk.delta(), tk.delta())) + return (&big.Int{}).ModInverse(tmp, tk.N) } // Returns the factorial of the number of `TotalNumberOfDecryptionServers`. // It is a contant value for the given `ThresholdKey`. -func (this *ThresholdKey) delta() *big.Int { - return Factorial(this.TotalNumberOfDecryptionServers) +func (tk *ThresholdKey) delta() *big.Int { + return Factorial(tk.TotalNumberOfDecryptionServers) } // Checks if the number of received, unique shares is less than the // required threshold. // This method does not execute ZKP on received shares. -func (this *ThresholdKey) makeVerificationBeforeCombiningPartialDecryptions(shares []*PartialDecryption) error { - if len(shares) < this.Threshold { +func (tk *ThresholdKey) makeVerificationBeforeCombiningPartialDecryptions(shares []*PartialDecryption) error { + if len(shares) < tk.Threshold { return errors.New("Threshold not meet") } tmp := make(map[int]bool) @@ -62,7 +62,7 @@ func (this *ThresholdKey) makeVerificationBeforeCombiningPartialDecryptions(shar return nil } -func (this *ThresholdKey) updateLambda(share1, share2 *PartialDecryption, lambda *big.Int) *big.Int { +func (tk *ThresholdKey) updateLambda(share1, share2 *PartialDecryption, lambda *big.Int) *big.Int { num := new(big.Int).Mul(lambda, big.NewInt(int64(-share2.Id))) denom := big.NewInt(int64(share1.Id - share2.Id)) return new(big.Int).Div(num, denom) @@ -70,11 +70,11 @@ func (this *ThresholdKey) updateLambda(share1, share2 *PartialDecryption, lambda // Evaluates lambda parameter for each decrypted share. See second figure in the // "Share combining" paragraph in [DJK 10], section 5.2. -func (this *ThresholdKey) computeLambda(share *PartialDecryption, shares []*PartialDecryption) *big.Int { - lambda := this.delta() +func (tk *ThresholdKey) computeLambda(share *PartialDecryption, shares []*PartialDecryption) *big.Int { + lambda := tk.delta() for _, share2 := range shares { if share2.Id != share.Id { - lambda = this.updateLambda(share, share2, lambda) + lambda = tk.updateLambda(share, share2, lambda) } } return lambda @@ -90,14 +90,14 @@ func (this *ThresholdKey) computeLambda(share *PartialDecryption, shares []*Part // following property of modulo: // (AB) mod C = (A mod C * B mod C) mod C // Note, we need to combine coefficients into single c'. -func (this *ThresholdKey) updateCprime(cprime, lambda *big.Int, share *PartialDecryption) *big.Int { +func (tk *ThresholdKey) updateCprime(cprime, lambda *big.Int, share *PartialDecryption) *big.Int { twoLambda := new(big.Int).Mul(TWO, lambda) - ret := this.exp(share.Decryption, twoLambda, this.GetNSquare()) + ret := tk.exp(share.Decryption, twoLambda, tk.GetNSquare()) ret = new(big.Int).Mul(cprime, ret) - return new(big.Int).Mod(ret, this.GetNSquare()) + return new(big.Int).Mod(ret, tk.GetNSquare()) } -func (this *ThresholdKey) exp(a, b, c *big.Int) *big.Int { +func (tk *ThresholdKey) exp(a, b, c *big.Int) *big.Int { if b.Cmp(ZERO) == -1 { ret := new(big.Int).Exp(a, new(big.Int).Neg(b), c) return new(big.Int).ModInverse(ret, c) @@ -108,54 +108,54 @@ func (this *ThresholdKey) exp(a, b, c *big.Int) *big.Int { // Executes the last step of message decryption. Takes `cprime` value computed // from valid shares provided by decryption servers and multiplies this value // by `combineSharesContant` which is specific to the given public `ThresholdKey`. -func (this *ThresholdKey) computeDecryption(cprime *big.Int) *big.Int { - l := L(cprime, this.N) - return new(big.Int).Mod(new(big.Int).Mul(this.combineSharesConstant(), l), this.N) +func (tk *ThresholdKey) computeDecryption(cprime *big.Int) *big.Int { + l := L(cprime, tk.N) + return new(big.Int).Mod(new(big.Int).Mul(tk.combineSharesConstant(), l), tk.N) } // Combines partial decryptions provided by decryption servers and returns // decrypted message. // This function does not verify zero knowledge proofs. Returned message can be // incorrectly decrypted if an adversary corrupted partial decryption. -func (this *ThresholdKey) CombinePartialDecryptions(shares []*PartialDecryption) (*big.Int, error) { - if err := this.makeVerificationBeforeCombiningPartialDecryptions(shares); err != nil { +func (tk *ThresholdKey) CombinePartialDecryptions(shares []*PartialDecryption) (*big.Int, error) { + if err := tk.makeVerificationBeforeCombiningPartialDecryptions(shares); err != nil { return nil, err } cprime := ONE for _, share := range shares { - lambda := this.computeLambda(share, shares) - cprime = this.updateCprime(cprime, lambda, share) + lambda := tk.computeLambda(share, shares) + cprime = tk.updateCprime(cprime, lambda, share) } - return this.computeDecryption(cprime), nil + return tk.computeDecryption(cprime), nil } // Combines partial decryptions provided by decription servers and returns // decrypted message. // Function verifies zero knowledge proofs and filters out all shares that failed // verification. -func (this *ThresholdKey) CombinePartialDecryptionsZKP(shares []*PartialDecryptionZKP) (*big.Int, error) { +func (tk *ThresholdKey) CombinePartialDecryptionsZKP(shares []*PartialDecryptionZKP) (*big.Int, error) { ret := make([]*PartialDecryption, 0) for _, share := range shares { if share.Verify() { ret = append(ret, &share.PartialDecryption) } } - return this.CombinePartialDecryptions(ret) + return tk.CombinePartialDecryptions(ret) } // Verifies if the decryption of `encryptedMessage` has been done properly. // It verifies all the zero-knoledge proofs, the value of the encrypted // and decrypted message. The method returns `nil` if everything is fine. // Otherwise, it returns an explicative message. -func (this *ThresholdKey) VerifyDecryption(encryptedMessage, decryptedMessage *big.Int, shares []*PartialDecryptionZKP) error { +func (tk *ThresholdKey) VerifyDecryption(encryptedMessage, decryptedMessage *big.Int, shares []*PartialDecryptionZKP) error { for _, share := range shares { if share.C.Cmp(encryptedMessage) != 0 { return errors.New("The encrypted message is not the same than the one in the shares") } } - res, err := this.CombinePartialDecryptionsZKP(shares) + res, err := tk.CombinePartialDecryptionsZKP(shares) if err != nil { return err } From 3f301a765d7f607dc5b4f81d67710cb3c126982a Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 1 Jun 2018 21:29:43 +0200 Subject: [PATCH 18/22] ThresholdPrivateKey self-ref renamed from this to tpk --- thresholdkey.go | 60 ++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 39e33b0..89c0a0d 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -176,40 +176,40 @@ type ThresholdPrivateKey struct { } // Decrypts the cypher text and returns the partial decryption -func (this *ThresholdPrivateKey) Decrypt(c *big.Int) *PartialDecryption { +func (tpk *ThresholdPrivateKey) Decrypt(c *big.Int) *PartialDecryption { ret := new(PartialDecryption) - ret.Id = this.Id - exp := new(big.Int).Mul(this.Share, new(big.Int).Mul(TWO, this.delta())) - ret.Decryption = new(big.Int).Exp(c, exp, this.GetNSquare()) + ret.Id = tpk.Id + exp := new(big.Int).Mul(tpk.Share, new(big.Int).Mul(TWO, tpk.delta())) + ret.Decryption = new(big.Int).Exp(c, exp, tpk.GetNSquare()) return ret } -func (this *ThresholdPrivateKey) copyVi() []*big.Int { - ret := make([]*big.Int, len(this.Vi)) - for i, vi := range this.Vi { +func (tpk *ThresholdPrivateKey) copyVi() []*big.Int { + ret := make([]*big.Int, len(tpk.Vi)) + for i, vi := range tpk.Vi { ret[i] = new(big.Int).Add(vi, big.NewInt(0)) } return ret } -func (this *ThresholdPrivateKey) getThresholdKey() *ThresholdKey { +func (tpk *ThresholdPrivateKey) getThresholdKey() *ThresholdKey { ret := new(ThresholdKey) - ret.Threshold = this.Threshold - ret.TotalNumberOfDecryptionServers = this.TotalNumberOfDecryptionServers - ret.V = new(big.Int).Add(this.V, big.NewInt(0)) - ret.Vi = this.copyVi() - ret.N = new(big.Int).Add(this.N, big.NewInt(0)) + ret.Threshold = tpk.Threshold + ret.TotalNumberOfDecryptionServers = tpk.TotalNumberOfDecryptionServers + ret.V = new(big.Int).Add(tpk.V, big.NewInt(0)) + ret.Vi = tpk.copyVi() + ret.N = new(big.Int).Add(tpk.N, big.NewInt(0)) return ret } -func (this *ThresholdPrivateKey) computeZ(r, e *big.Int) *big.Int { - tmp := new(big.Int).Mul(e, this.delta()) - tmp = new(big.Int).Mul(tmp, this.Share) +func (tpk *ThresholdPrivateKey) computeZ(r, e *big.Int) *big.Int { + tmp := new(big.Int).Mul(e, tpk.delta()) + tmp = new(big.Int).Mul(tmp, tpk.Share) return new(big.Int).Add(r, tmp) } -func (this *ThresholdPrivateKey) computeHash(a, b, c4, ci2 *big.Int) *big.Int { +func (tpk *ThresholdPrivateKey) computeHash(a, b, c4, ci2 *big.Int) *big.Int { hash := sha256.New() hash.Write(a.Bytes()) hash.Write(b.Bytes()) @@ -218,47 +218,47 @@ func (this *ThresholdPrivateKey) computeHash(a, b, c4, ci2 *big.Int) *big.Int { return new(big.Int).SetBytes(hash.Sum([]byte{})) } -func (this *ThresholdPrivateKey) DecryptAndProduceZNP(c *big.Int, random io.Reader) (*PartialDecryptionZKP, error) { +func (tpk *ThresholdPrivateKey) DecryptAndProduceZNP(c *big.Int, random io.Reader) (*PartialDecryptionZKP, error) { pd := new(PartialDecryptionZKP) - pd.Key = this.getThresholdKey() + pd.Key = tpk.getThresholdKey() pd.C = c - pd.Id = this.Id - pd.Decryption = this.Decrypt(c).Decryption + pd.Id = tpk.Id + pd.Decryption = tpk.Decrypt(c).Decryption // choose random number - r, err := rand.Int(random, this.GetNSquare()) + r, err := rand.Int(random, tpk.GetNSquare()) if err != nil { return nil, err } // compute a c4 := new(big.Int).Exp(c, FOUR, nil) - a := new(big.Int).Exp(c4, r, this.GetNSquare()) + a := new(big.Int).Exp(c4, r, tpk.GetNSquare()) // compute b - b := new(big.Int).Exp(this.V, r, this.GetNSquare()) + b := new(big.Int).Exp(tpk.V, r, tpk.GetNSquare()) // compute hash ci2 := new(big.Int).Exp(pd.Decryption, big.NewInt(2), nil) - pd.E = this.computeHash(a, b, c4, ci2) + pd.E = tpk.computeHash(a, b, c4, ci2) - pd.Z = this.computeZ(r, pd.E) + pd.Z = tpk.computeZ(r, pd.E) return pd, nil } // Verifies if the partial decryption key is well formed. If well formed, // the method return nil else an explicative error is returned. -func (this *ThresholdPrivateKey) Validate(random io.Reader) error { - m, err := rand.Int(random, this.N) +func (tpk *ThresholdPrivateKey) Validate(random io.Reader) error { + m, err := rand.Int(random, tpk.N) if err != nil { return err } - c, err := this.Encrypt(m, random) + c, err := tpk.Encrypt(m, random) if err != nil { return err } - proof, err := this.DecryptAndProduceZNP(c.C, random) + proof, err := tpk.DecryptAndProduceZNP(c.C, random) if err != nil { return err } From 86b9f01f99a45e8fc6d03bbe585953d0c416e09a Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 1 Jun 2018 21:31:04 +0200 Subject: [PATCH 19/22] PartialDecryptionZKP self-ref renamed from this to pd --- thresholdkey.go | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index 89c0a0d..15f14d0 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -331,37 +331,37 @@ type PartialDecryptionZKP struct { C *big.Int // the input cypher text } -func (this *PartialDecryptionZKP) verifyPart1() *big.Int { - c4 := new(big.Int).Exp(this.C, FOUR, nil) // c^4 - decryption2 := new(big.Int).Exp(this.Decryption, TWO, nil) // c_i^2 +func (pd *PartialDecryptionZKP) verifyPart1() *big.Int { + c4 := new(big.Int).Exp(pd.C, FOUR, nil) // c^4 + decryption2 := new(big.Int).Exp(pd.Decryption, TWO, nil) // c_i^2 - a1 := new(big.Int).Exp(c4, this.Z, this.Key.GetNSquare()) // (c^4)^Z - a2 := new(big.Int).Exp(decryption2, this.E, this.Key.GetNSquare()) // (c_i^2)^E - a2 = new(big.Int).ModInverse(a2, this.Key.GetNSquare()) - a := new(big.Int).Mod(new(big.Int).Mul(a1, a2), this.Key.GetNSquare()) + a1 := new(big.Int).Exp(c4, pd.Z, pd.Key.GetNSquare()) // (c^4)^Z + a2 := new(big.Int).Exp(decryption2, pd.E, pd.Key.GetNSquare()) // (c_i^2)^E + a2 = new(big.Int).ModInverse(a2, pd.Key.GetNSquare()) + a := new(big.Int).Mod(new(big.Int).Mul(a1, a2), pd.Key.GetNSquare()) return a } -func (this *PartialDecryptionZKP) verifyPart2() *big.Int { - vi := this.Key.Vi[this.Id-1] // servers are indexed from 1 - b1 := new(big.Int).Exp(this.Key.V, this.Z, this.Key.GetNSquare()) // V^Z - b2 := new(big.Int).Exp(vi, this.E, this.Key.GetNSquare()) // (v_i)^E - b2 = new(big.Int).ModInverse(b2, this.Key.GetNSquare()) - b := new(big.Int).Mod(new(big.Int).Mul(b1, b2), this.Key.GetNSquare()) +func (pd *PartialDecryptionZKP) verifyPart2() *big.Int { + vi := pd.Key.Vi[pd.Id-1] // servers are indexed from 1 + b1 := new(big.Int).Exp(pd.Key.V, pd.Z, pd.Key.GetNSquare()) // V^Z + b2 := new(big.Int).Exp(vi, pd.E, pd.Key.GetNSquare()) // (v_i)^E + b2 = new(big.Int).ModInverse(b2, pd.Key.GetNSquare()) + b := new(big.Int).Mod(new(big.Int).Mul(b1, b2), pd.Key.GetNSquare()) return b } -func (this *PartialDecryptionZKP) Verify() bool { - a := this.verifyPart1() - b := this.verifyPart2() +func (pd *PartialDecryptionZKP) Verify() bool { + a := pd.verifyPart1() + b := pd.verifyPart2() hash := sha256.New() hash.Write(a.Bytes()) hash.Write(b.Bytes()) - c4 := new(big.Int).Exp(this.C, FOUR, nil) + c4 := new(big.Int).Exp(pd.C, FOUR, nil) hash.Write(c4.Bytes()) - ci2 := new(big.Int).Exp(this.Decryption, TWO, nil) + ci2 := new(big.Int).Exp(pd.Decryption, TWO, nil) hash.Write(ci2.Bytes()) expectedE := new(big.Int).SetBytes(hash.Sum([]byte{})) - return this.E.Cmp(expectedE) == 0 + return pd.E.Cmp(expectedE) == 0 } From 9d17da0d33f1b559c8bb8fa139b63a173a9e4df7 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 1 Jun 2018 21:36:04 +0200 Subject: [PATCH 20/22] ThresholdKey renamed to ThresholdPublicKey --- encoding.go | 14 +++++++------- encoding_test.go | 8 ++++---- thresholdkey.go | 38 +++++++++++++++++++------------------- thresholdkey_test.go | 18 +++++++++--------- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/encoding.go b/encoding.go index 261b769..d89cc01 100644 --- a/encoding.go +++ b/encoding.go @@ -59,7 +59,7 @@ type dbThresholdKey struct { N string } -func (this *dbThresholdKey) FromThresholdKey(key *ThresholdKey) { +func (this *dbThresholdKey) FromThresholdPublicKey(key *ThresholdPublicKey) { this.TotalNumberOfDecryptionServers = key.TotalNumberOfDecryptionServers this.Threshold = key.Threshold this.V = fmt.Sprintf("%x", key.V) @@ -70,7 +70,7 @@ func (this *dbThresholdKey) FromThresholdKey(key *ThresholdKey) { } } -func (this *dbThresholdKey) ToThresholdKey(key *ThresholdKey) error { +func (this *dbThresholdKey) ToThresholdPublicKey(key *ThresholdPublicKey) error { key.TotalNumberOfDecryptionServers = this.TotalNumberOfDecryptionServers key.Threshold = this.Threshold oks := make([]bool, 2) @@ -91,18 +91,18 @@ func (this *dbThresholdKey) ToThresholdKey(key *ThresholdKey) error { return nil } -func (this *ThresholdKey) GetBSON() (interface{}, error) { +func (this *ThresholdPublicKey) GetBSON() (interface{}, error) { r := new(dbThresholdKey) - r.FromThresholdKey(this) + r.FromThresholdPublicKey(this) return r, nil } -func (this *ThresholdKey) SetBSON(raw bson.Raw) error { +func (this *ThresholdPublicKey) SetBSON(raw bson.Raw) error { r := new(dbThresholdKey) if err := raw.Unmarshal(r); err != nil { return err } - return r.ToThresholdKey(this) + return r.ToThresholdPublicKey(this) } type dbPrivateKey struct { @@ -175,7 +175,7 @@ func (this *dbPartialDecryptionZKP) FromPartialDecryptionZKP(pd *PartialDecrypti } func (this *dbPartialDecryptionZKP) ToPartialDecryptionZKP(pd *PartialDecryptionZKP) error { - pd.Key = new(ThresholdKey) + pd.Key = new(ThresholdPublicKey) var oks = make([]bool, 6) diff --git a/encoding_test.go b/encoding_test.go index 0579c35..aa08577 100644 --- a/encoding_test.go +++ b/encoding_test.go @@ -81,7 +81,7 @@ func TestGetBSONEmptyKey(t *testing.T) { func TestPartialDecryptionZKPJsonification(t *testing.T) { pd := new(PartialDecryptionZKP) - pd.Key = new(ThresholdKey) + pd.Key = new(ThresholdPublicKey) pd.Key.Threshold = 98 pd.Key.TotalNumberOfDecryptionServers = 230 pd.Id = 1 @@ -99,7 +99,7 @@ func TestPartialDecryptionZKPJsonification(t *testing.T) { func TestPartialDecryptionZKPBSONification(t *testing.T) { pd := new(PartialDecryptionZKP) - pd.Key = new(ThresholdKey) + pd.Key = new(ThresholdPublicKey) pd.Key.Threshold = 98 pd.Key.TotalNumberOfDecryptionServers = 230 pd.Id = 1 @@ -116,12 +116,12 @@ func TestPartialDecryptionZKPBSONification(t *testing.T) { } func TestThresholdKeyBSON(t *testing.T) { - key := &ThresholdKey{ + key := &ThresholdPublicKey{ PublicKey: PublicKey{b(9)}, TotalNumberOfDecryptionServers: 7, Threshold: 6, V: b(3), Vi: []*big.Int{b(2), b(34)}, } - AssertBSONIsGood(key, new(ThresholdKey), t) + AssertBSONIsGood(key, new(ThresholdPublicKey), t) } diff --git a/thresholdkey.go b/thresholdkey.go index 15f14d0..a2ba51e 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -23,7 +23,7 @@ import ( // A Generalization of Paillier’s Public-Key System // with Applications to Electronic Voting // Aarhus University, Dept. of Computer Science, BRICS -type ThresholdKey struct { +type ThresholdPublicKey struct { PublicKey TotalNumberOfDecryptionServers int Threshold int @@ -34,21 +34,21 @@ type ThresholdKey struct { // Returns the value of [(4*delta^2)]^-1 mod n. // It is a constant value for the given `ThresholdKey` and is used in the last // step of share combining. -func (tk *ThresholdKey) combineSharesConstant() *big.Int { +func (tk *ThresholdPublicKey) combineSharesConstant() *big.Int { tmp := new(big.Int).Mul(FOUR, new(big.Int).Mul(tk.delta(), tk.delta())) return (&big.Int{}).ModInverse(tmp, tk.N) } // Returns the factorial of the number of `TotalNumberOfDecryptionServers`. // It is a contant value for the given `ThresholdKey`. -func (tk *ThresholdKey) delta() *big.Int { +func (tk *ThresholdPublicKey) delta() *big.Int { return Factorial(tk.TotalNumberOfDecryptionServers) } // Checks if the number of received, unique shares is less than the // required threshold. // This method does not execute ZKP on received shares. -func (tk *ThresholdKey) makeVerificationBeforeCombiningPartialDecryptions(shares []*PartialDecryption) error { +func (tk *ThresholdPublicKey) makeVerificationBeforeCombiningPartialDecryptions(shares []*PartialDecryption) error { if len(shares) < tk.Threshold { return errors.New("Threshold not meet") } @@ -62,7 +62,7 @@ func (tk *ThresholdKey) makeVerificationBeforeCombiningPartialDecryptions(shares return nil } -func (tk *ThresholdKey) updateLambda(share1, share2 *PartialDecryption, lambda *big.Int) *big.Int { +func (tk *ThresholdPublicKey) updateLambda(share1, share2 *PartialDecryption, lambda *big.Int) *big.Int { num := new(big.Int).Mul(lambda, big.NewInt(int64(-share2.Id))) denom := big.NewInt(int64(share1.Id - share2.Id)) return new(big.Int).Div(num, denom) @@ -70,7 +70,7 @@ func (tk *ThresholdKey) updateLambda(share1, share2 *PartialDecryption, lambda * // Evaluates lambda parameter for each decrypted share. See second figure in the // "Share combining" paragraph in [DJK 10], section 5.2. -func (tk *ThresholdKey) computeLambda(share *PartialDecryption, shares []*PartialDecryption) *big.Int { +func (tk *ThresholdPublicKey) computeLambda(share *PartialDecryption, shares []*PartialDecryption) *big.Int { lambda := tk.delta() for _, share2 := range shares { if share2.Id != share.Id { @@ -90,14 +90,14 @@ func (tk *ThresholdKey) computeLambda(share *PartialDecryption, shares []*Partia // following property of modulo: // (AB) mod C = (A mod C * B mod C) mod C // Note, we need to combine coefficients into single c'. -func (tk *ThresholdKey) updateCprime(cprime, lambda *big.Int, share *PartialDecryption) *big.Int { +func (tk *ThresholdPublicKey) updateCprime(cprime, lambda *big.Int, share *PartialDecryption) *big.Int { twoLambda := new(big.Int).Mul(TWO, lambda) ret := tk.exp(share.Decryption, twoLambda, tk.GetNSquare()) ret = new(big.Int).Mul(cprime, ret) return new(big.Int).Mod(ret, tk.GetNSquare()) } -func (tk *ThresholdKey) exp(a, b, c *big.Int) *big.Int { +func (tk *ThresholdPublicKey) exp(a, b, c *big.Int) *big.Int { if b.Cmp(ZERO) == -1 { ret := new(big.Int).Exp(a, new(big.Int).Neg(b), c) return new(big.Int).ModInverse(ret, c) @@ -108,7 +108,7 @@ func (tk *ThresholdKey) exp(a, b, c *big.Int) *big.Int { // Executes the last step of message decryption. Takes `cprime` value computed // from valid shares provided by decryption servers and multiplies this value // by `combineSharesContant` which is specific to the given public `ThresholdKey`. -func (tk *ThresholdKey) computeDecryption(cprime *big.Int) *big.Int { +func (tk *ThresholdPublicKey) computeDecryption(cprime *big.Int) *big.Int { l := L(cprime, tk.N) return new(big.Int).Mod(new(big.Int).Mul(tk.combineSharesConstant(), l), tk.N) } @@ -117,7 +117,7 @@ func (tk *ThresholdKey) computeDecryption(cprime *big.Int) *big.Int { // decrypted message. // This function does not verify zero knowledge proofs. Returned message can be // incorrectly decrypted if an adversary corrupted partial decryption. -func (tk *ThresholdKey) CombinePartialDecryptions(shares []*PartialDecryption) (*big.Int, error) { +func (tk *ThresholdPublicKey) CombinePartialDecryptions(shares []*PartialDecryption) (*big.Int, error) { if err := tk.makeVerificationBeforeCombiningPartialDecryptions(shares); err != nil { return nil, err } @@ -135,7 +135,7 @@ func (tk *ThresholdKey) CombinePartialDecryptions(shares []*PartialDecryption) ( // decrypted message. // Function verifies zero knowledge proofs and filters out all shares that failed // verification. -func (tk *ThresholdKey) CombinePartialDecryptionsZKP(shares []*PartialDecryptionZKP) (*big.Int, error) { +func (tk *ThresholdPublicKey) CombinePartialDecryptionsZKP(shares []*PartialDecryptionZKP) (*big.Int, error) { ret := make([]*PartialDecryption, 0) for _, share := range shares { if share.Verify() { @@ -149,7 +149,7 @@ func (tk *ThresholdKey) CombinePartialDecryptionsZKP(shares []*PartialDecryption // It verifies all the zero-knoledge proofs, the value of the encrypted // and decrypted message. The method returns `nil` if everything is fine. // Otherwise, it returns an explicative message. -func (tk *ThresholdKey) VerifyDecryption(encryptedMessage, decryptedMessage *big.Int, shares []*PartialDecryptionZKP) error { +func (tk *ThresholdPublicKey) VerifyDecryption(encryptedMessage, decryptedMessage *big.Int, shares []*PartialDecryptionZKP) error { for _, share := range shares { if share.C.Cmp(encryptedMessage) != 0 { return errors.New("The encrypted message is not the same than the one in the shares") @@ -170,7 +170,7 @@ func (tk *ThresholdKey) VerifyDecryption(encryptedMessage, decryptedMessage *big // `Id` is the unique identifier of a decryption server and `Share` is a secret // share generated from hiding polynomial and is used for a partial share decryption. type ThresholdPrivateKey struct { - ThresholdKey + ThresholdPublicKey Id int Share *big.Int } @@ -193,8 +193,8 @@ func (tpk *ThresholdPrivateKey) copyVi() []*big.Int { return ret } -func (tpk *ThresholdPrivateKey) getThresholdKey() *ThresholdKey { - ret := new(ThresholdKey) +func (tpk *ThresholdPrivateKey) getThresholdKey() *ThresholdPublicKey { + ret := new(ThresholdPublicKey) ret.Threshold = tpk.Threshold ret.TotalNumberOfDecryptionServers = tpk.TotalNumberOfDecryptionServers ret.V = new(big.Int).Add(tpk.V, big.NewInt(0)) @@ -325,10 +325,10 @@ type PartialDecryption struct { // - Compare ZKP hash with the one just computed type PartialDecryptionZKP struct { PartialDecryption - Key *ThresholdKey // the public key used to encrypt - E *big.Int // the challenge - Z *big.Int // the value needed to check to verify the decryption - C *big.Int // the input cypher text + Key *ThresholdPublicKey // the public key used to encrypt + E *big.Int // the challenge + Z *big.Int // the value needed to check to verify the decryption + C *big.Int // the input cypher text } func (pd *PartialDecryptionZKP) verifyPart1() *big.Int { diff --git a/thresholdkey_test.go b/thresholdkey_test.go index 62427f0..6c4c7c9 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -17,7 +17,7 @@ func getThresholdPrivateKey() *ThresholdPrivateKey { } func TestDelta(t *testing.T) { - tk := new(ThresholdKey) + tk := new(ThresholdPublicKey) tk.TotalNumberOfDecryptionServers = 6 if delta := tk.delta(); 720 != n(delta) { t.Error("Delta is not 720 but", delta) @@ -25,7 +25,7 @@ func TestDelta(t *testing.T) { } func TestCombineSharesConstant(t *testing.T) { - tk := new(ThresholdKey) + tk := new(ThresholdPublicKey) tk.N = big.NewInt(101 * 103) tk.TotalNumberOfDecryptionServers = 6 @@ -84,7 +84,7 @@ func TestDecryptWithThresholdKey(t *testing.T) { func TestVerifyPart1(t *testing.T) { pd := new(PartialDecryptionZKP) - pd.Key = new(ThresholdKey) + pd.Key = new(ThresholdPublicKey) pd.Key.N = b(131) pd.Decryption = b(101) pd.C = b(99) @@ -98,7 +98,7 @@ func TestVerifyPart1(t *testing.T) { func TestVerifyPart2(t *testing.T) { pd := new(PartialDecryptionZKP) - pd.Key = new(ThresholdKey) + pd.Key = new(ThresholdPublicKey) pd.Id = 1 pd.Key.Vi = []*big.Int{b(77), b(67)} // vi is 67 pd.Key.N = b(131) @@ -127,7 +127,7 @@ func TestDecryptAndProduceZNP(t *testing.T) { } func TestMakeVerificationBeforeCombiningPartialDecryptions(t *testing.T) { - tk := new(ThresholdKey) + tk := new(ThresholdPublicKey) tk.Threshold = 2 if tk.makeVerificationBeforeCombiningPartialDecryptions([]*PartialDecryption{}) == nil { t.Fail() @@ -144,7 +144,7 @@ func TestMakeVerificationBeforeCombiningPartialDecryptions(t *testing.T) { } func TestUpdateLambda(t *testing.T) { - tk := new(ThresholdKey) + tk := new(ThresholdPublicKey) lambda := b(11) share1 := &PartialDecryption{3, b(5)} share2 := &PartialDecryption{7, b(3)} @@ -155,7 +155,7 @@ func TestUpdateLambda(t *testing.T) { } func TestupdateCprime(t *testing.T) { - tk := new(ThresholdKey) + tk := new(ThresholdPublicKey) tk.N = b(99) cprime := b(77) lambda := b(52) @@ -238,7 +238,7 @@ func TestDecryption(t *testing.T) { // test the correct decryption of '100'. share1 := &PartialDecryption{1, b(384111638639)} share2 := &PartialDecryption{2, b(235243761043)} - tk := new(ThresholdKey) + tk := new(ThresholdPublicKey) tk.Threshold = 2 tk.TotalNumberOfDecryptionServers = 2 tk.N = b(637753) @@ -325,7 +325,7 @@ func TestVerifyDecryption(t *testing.T) { tkh := GetThresholdKeyGenerator(10, 2, 2, rand.Reader) tpks, err := tkh.Generate() - pk := &tpks[0].ThresholdKey + pk := &tpks[0].ThresholdPublicKey if err != nil { t.Error(err) } From ba2c5aaa5fc3d9b90d354dc026653b3095a7a91b Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Fri, 1 Jun 2018 21:42:49 +0200 Subject: [PATCH 21/22] Shortened name of the partial decryption verification function --- thresholdkey.go | 8 ++++---- thresholdkey_test.go | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/thresholdkey.go b/thresholdkey.go index a2ba51e..41dd3e8 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -48,7 +48,7 @@ func (tk *ThresholdPublicKey) delta() *big.Int { // Checks if the number of received, unique shares is less than the // required threshold. // This method does not execute ZKP on received shares. -func (tk *ThresholdPublicKey) makeVerificationBeforeCombiningPartialDecryptions(shares []*PartialDecryption) error { +func (tk *ThresholdPublicKey) verifyPartialDecryptions(shares []*PartialDecryption) error { if len(shares) < tk.Threshold { return errors.New("Threshold not meet") } @@ -118,7 +118,7 @@ func (tk *ThresholdPublicKey) computeDecryption(cprime *big.Int) *big.Int { // This function does not verify zero knowledge proofs. Returned message can be // incorrectly decrypted if an adversary corrupted partial decryption. func (tk *ThresholdPublicKey) CombinePartialDecryptions(shares []*PartialDecryption) (*big.Int, error) { - if err := tk.makeVerificationBeforeCombiningPartialDecryptions(shares); err != nil { + if err := tk.verifyPartialDecryptions(shares); err != nil { return nil, err } @@ -131,8 +131,8 @@ func (tk *ThresholdPublicKey) CombinePartialDecryptions(shares []*PartialDecrypt return tk.computeDecryption(cprime), nil } -// Combines partial decryptions provided by decription servers and returns -// decrypted message. +// Combines partial decryptions provided by decryption servers and returns +// full decrypted message. // Function verifies zero knowledge proofs and filters out all shares that failed // verification. func (tk *ThresholdPublicKey) CombinePartialDecryptionsZKP(shares []*PartialDecryptionZKP) (*big.Int, error) { diff --git a/thresholdkey_test.go b/thresholdkey_test.go index 6c4c7c9..698f3ab 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -129,16 +129,16 @@ func TestDecryptAndProduceZNP(t *testing.T) { func TestMakeVerificationBeforeCombiningPartialDecryptions(t *testing.T) { tk := new(ThresholdPublicKey) tk.Threshold = 2 - if tk.makeVerificationBeforeCombiningPartialDecryptions([]*PartialDecryption{}) == nil { + if tk.verifyPartialDecryptions([]*PartialDecryption{}) == nil { t.Fail() } prms := []*PartialDecryption{new(PartialDecryption), new(PartialDecryption)} prms[1].Id = 1 - if tk.makeVerificationBeforeCombiningPartialDecryptions(prms) != nil { + if tk.verifyPartialDecryptions(prms) != nil { t.Fail() } prms[1].Id = 0 - if tk.makeVerificationBeforeCombiningPartialDecryptions(prms) == nil { + if tk.verifyPartialDecryptions(prms) == nil { t.Fail() } } From 3acf9e6948b7ac7bc223868e3a9ba60e42b311a5 Mon Sep 17 00:00:00 2001 From: Piotr Dyraga Date: Tue, 5 Jun 2018 13:11:50 +0200 Subject: [PATCH 22/22] Explained how do we handle negative lambda parameter value --- thresholdkey.go | 8 +++++++- thresholdkey_test.go | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/thresholdkey.go b/thresholdkey.go index 41dd3e8..83f8ac6 100644 --- a/thresholdkey.go +++ b/thresholdkey.go @@ -97,8 +97,14 @@ func (tk *ThresholdPublicKey) updateCprime(cprime, lambda *big.Int, share *Parti return new(big.Int).Mod(ret, tk.GetNSquare()) } +// We use `exp` from `updateCprime` to raise decryption share to the power of lambda +// parameter. Since lambda can be a negative number and we do discrete math here, +// we need to apply multiplicative inverse modulo in this case. +// +// For instance, for b = -18: +// b^{−18} = (b^−1)^18, where b^{−1} is the multiplicative inverse modulo c. func (tk *ThresholdPublicKey) exp(a, b, c *big.Int) *big.Int { - if b.Cmp(ZERO) == -1 { + if b.Cmp(ZERO) == -1 { // b < 0 ? ret := new(big.Int).Exp(a, new(big.Int).Neg(b), c) return new(big.Int).ModInverse(ret, c) } diff --git a/thresholdkey_test.go b/thresholdkey_test.go index 698f3ab..b610a85 100644 --- a/thresholdkey_test.go +++ b/thresholdkey_test.go @@ -24,6 +24,22 @@ func TestDelta(t *testing.T) { } } +func TestExp(t *testing.T) { + tk := new(ThresholdPublicKey) + + if exp := tk.exp(big.NewInt(720), big.NewInt(10), big.NewInt(49)); 43 != n(exp) { + t.Error("Unexpected exponent. Expected 43 but got", exp) + } + + if exp := tk.exp(big.NewInt(720), big.NewInt(0), big.NewInt(49)); 1 != n(exp) { + t.Error("Unexpected exponent. Expected 0 but got", exp) + } + + if exp := tk.exp(big.NewInt(720), big.NewInt(-10), big.NewInt(49)); 8 != n(exp) { + t.Error("Unexpected exponent. Expected 8 but got", exp) + } +} + func TestCombineSharesConstant(t *testing.T) { tk := new(ThresholdPublicKey) tk.N = big.NewInt(101 * 103)