This repository has been archived by the owner on May 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 23
/
keygen.go
192 lines (166 loc) · 5.02 KB
/
keygen.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package tss
import (
"context"
"fmt"
"math/big"
"time"
"github.com/binance-chain/tss-lib/ecdsa/keygen"
"github.com/binance-chain/tss-lib/tss"
)
// GenerateTSSPreParams calculates parameters required by TSS key generation.
// It times out after defined period if the required parameters could not be generated.
// It is possible to generate the parameters way ahead of the TSS protocol
// execution.
func GenerateTSSPreParams(
preParamsGenerationTimeout time.Duration,
) (*keygen.LocalPreParams, error) {
preParams, err := keygen.GeneratePreParams(preParamsGenerationTimeout)
if err != nil {
return nil, fmt.Errorf("failed to generate tss pre-params: [%v]", err)
}
return preParams, nil
}
// initializeKeyGeneration initializes a signing group member to run a threshold
// multi-party key generation protocol.
//
// It expects unique identifiers of the current member as well as identifiers of
// all members of the signing group.
//
// TSS protocol requires pre-parameters such as safe primes to be generated for
// execution. The parameters should be generated prior to initializing the signer.
func initializeKeyGeneration(
ctx context.Context,
group *groupInfo,
tssPreParams *keygen.LocalPreParams,
network *networkBridge,
) (*member, error) {
keyGenParty, endChan, err := initializeKeyGenerationParty(
ctx,
group,
tssPreParams,
network,
)
if err != nil {
return nil, fmt.Errorf("failed to initialize key generation member: [%v]", err)
}
logger.Debugf("initialized key generation member: [%v]", keyGenParty.PartyID())
return &member{
groupInfo: group,
keygenParty: keyGenParty,
keygenEndChan: endChan,
networkBridge: network,
}, nil
}
// member represents an initialized member who is ready to start distributed key
// generation.
type member struct {
*groupInfo
// Network bridge used for messages transport.
networkBridge *networkBridge
// Party for TSS protocol execution.
keygenParty tss.Party
// Channel where a result of the key generation protocol execution will be
// written to.
keygenEndChan <-chan keygen.LocalPartySaveData
}
// generateKey executes the protocol to generate a signing key. This function
// needs to be executed only after all members finished the initialization stage.
// As a result it will return a Signer who has completed key generation, or error
// if the key generation failed.
func (s *member) generateKey(ctx context.Context) (*ThresholdSigner, error) {
if err := s.keygenParty.Start(); err != nil {
return nil, fmt.Errorf(
"failed to start key generation: [%v]",
s.keygenParty.WrapError(err),
)
}
for {
select {
case keygenData := <-s.keygenEndChan:
signer := &ThresholdSigner{
groupInfo: s.groupInfo,
thresholdKey: ThresholdKey(keygenData),
}
return signer, nil
case <-ctx.Done():
memberIDs := []MemberID{}
if s.keygenParty.WaitingFor() != nil {
for _, partyID := range s.keygenParty.WaitingFor() {
memberID, err := MemberIDFromString(partyID.GetId())
if err != nil {
logger.Errorf(
"cannot get member id from string [%v]: [%v]",
partyID.GetId(),
err,
)
continue
}
memberIDs = append(memberIDs, memberID)
}
}
return nil, timeoutError{KeyGenerationProtocolTimeout, "key generation", memberIDs}
}
}
}
func generatePartiesIDs(
thisMemberID MemberID,
groupMemberIDs []MemberID,
) (
*tss.PartyID,
[]*tss.PartyID,
error,
) {
var thisPartyID *tss.PartyID
groupPartiesIDs := []*tss.PartyID{}
for _, memberID := range groupMemberIDs {
if memberID.bigInt().Cmp(big.NewInt(0)) <= 0 {
return nil, nil, fmt.Errorf("member ID must be greater than 0, but found [%v]", memberID.bigInt())
}
newPartyID := tss.NewPartyID(
memberID.String(), // id - unique string representing this party in the network
"", // moniker - can be anything (even left blank)
memberID.bigInt(), // key - unique identifying key
)
if thisMemberID.Equal(memberID) {
thisPartyID = newPartyID
}
groupPartiesIDs = append(groupPartiesIDs, newPartyID)
}
return thisPartyID, groupPartiesIDs, nil
}
func initializeKeyGenerationParty(
ctx context.Context,
groupInfo *groupInfo,
tssPreParams *keygen.LocalPreParams,
bridge *networkBridge,
) (
tss.Party,
<-chan keygen.LocalPartySaveData,
error,
) {
tssMessageChan := make(chan tss.Message, len(groupInfo.groupMemberIDs))
endChan := make(chan keygen.LocalPartySaveData)
currentPartyID, groupPartiesIDs, err := generatePartiesIDs(
groupInfo.memberID,
groupInfo.groupMemberIDs,
)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate parties IDs: [%v]", err)
}
params := tss.NewParameters(
tss.NewPeerContext(tss.SortPartyIDs(groupPartiesIDs)),
currentPartyID,
len(groupPartiesIDs),
groupInfo.dishonestThreshold,
)
party := keygen.NewLocalParty(params, tssMessageChan, endChan, *tssPreParams)
if err := bridge.connect(
ctx,
tssMessageChan,
party,
params.Parties().IDs(),
); err != nil {
return nil, nil, fmt.Errorf("failed to connect bridge network: [%v]", err)
}
return party, endChan, nil
}