/
prepare.go
132 lines (119 loc) · 4.18 KB
/
prepare.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright © 2019 Binance
//
// This file is part of Binance. The full Binance copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
package keygen
import (
"errors"
"math/big"
"runtime"
"time"
"github.com/binance-chain/tss-lib/common"
"github.com/binance-chain/tss-lib/crypto/paillier"
)
const (
// Using a modulus length of 2048 is recommended in the GG18 spec
paillierModulusLen = 2048
// Two 1024-bit safe primes to produce NTilde
safePrimeBitLen = 1024
// Ticker for printing log statements while generating primes/modulus
logProgressTickInterval = 8 * time.Second
)
// GeneratePreParams finds two safe primes and computes the Paillier secret required for the protocol.
// This can be a time consuming process so it is recommended to do it out-of-band.
// If not specified, a concurrency value equal to the number of available CPU cores will be used.
func GeneratePreParams(timeout time.Duration, optionalConcurrency ...int) (*LocalPreParams, error) {
var concurrency int
if 0 < len(optionalConcurrency) {
if 1 < len(optionalConcurrency) {
panic(errors.New("GeneratePreParams: expected 0 or 1 item in `optionalConcurrency`"))
}
concurrency = optionalConcurrency[0]
} else {
concurrency = runtime.NumCPU()
}
if concurrency /= 3; concurrency < 1 {
concurrency = 1
}
// prepare for concurrent Paillier and safe prime generation
paiCh := make(chan *paillier.PrivateKey, 1)
sgpCh := make(chan []*common.GermainSafePrime, 1)
// 4. generate Paillier public key E_i, private key and proof
go func(ch chan<- *paillier.PrivateKey) {
common.Logger.Info("generating the Paillier modulus, please wait...")
start := time.Now()
// more concurrency weight is assigned here because the paillier primes have a requirement of having "large" P-Q
PiPaillierSk, _, err := paillier.GenerateKeyPair(paillierModulusLen, timeout, concurrency*2)
if err != nil {
ch <- nil
return
}
common.Logger.Infof("paillier modulus generated. took %s\n", time.Since(start))
ch <- PiPaillierSk
}(paiCh)
// 5-7. generate safe primes for ZKPs used later on
go func(ch chan<- []*common.GermainSafePrime) {
var err error
common.Logger.Info("generating the safe primes for the signing proofs, please wait...")
start := time.Now()
sgps, err := common.GetRandomSafePrimesConcurrent(safePrimeBitLen, 2, timeout, concurrency)
if err != nil {
ch <- nil
return
}
common.Logger.Infof("safe primes generated. took %s\n", time.Since(start))
ch <- sgps
}(sgpCh)
// this ticker will print a log statement while the generating is still in progress
logProgressTicker := time.NewTicker(logProgressTickInterval)
// errors can be thrown in the following code; consume chans to end goroutines here
var sgps []*common.GermainSafePrime
var paiSK *paillier.PrivateKey
consumer:
for {
select {
case <-logProgressTicker.C:
common.Logger.Info("still generating primes...")
case sgps = <-sgpCh:
if sgps == nil ||
sgps[0] == nil || sgps[1] == nil ||
!sgps[0].Prime().ProbablyPrime(30) || !sgps[1].Prime().ProbablyPrime(30) ||
!sgps[0].SafePrime().ProbablyPrime(30) || !sgps[1].SafePrime().ProbablyPrime(30) {
return nil, errors.New("timeout or error while generating the safe primes")
}
if paiSK != nil {
break consumer
}
case paiSK = <-paiCh:
if paiSK == nil {
return nil, errors.New("timeout or error while generating the Paillier secret key")
}
if sgps != nil {
break consumer
}
}
}
logProgressTicker.Stop()
P, Q := sgps[0].SafePrime(), sgps[1].SafePrime()
NTildei := new(big.Int).Mul(P, Q)
modNTildeI := common.ModInt(NTildei)
p, q := sgps[0].Prime(), sgps[1].Prime()
modPQ := common.ModInt(new(big.Int).Mul(p, q))
f1 := common.GetRandomPositiveRelativelyPrimeInt(NTildei)
alpha := common.GetRandomPositiveRelativelyPrimeInt(NTildei)
beta := modPQ.ModInverse(alpha)
h1i := modNTildeI.Mul(f1, f1)
h2i := modNTildeI.Exp(h1i, alpha)
preParams := &LocalPreParams{
PaillierSK: paiSK,
NTildei: NTildei,
H1i: h1i,
H2i: h2i,
Alpha: alpha,
Beta: beta,
P: p,
Q: q,
}
return preParams, nil
}