forked from onflow/flow-go
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdkg.go
237 lines (212 loc) · 8.5 KB
/
dkg.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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
package crypto
import (
"errors"
"fmt"
)
// DKG stands for distributed key generation. In this library, DKG
// refers to discrete-log based protocols.
// The protocols implemented in the package for now generate keys for a BLS-based
// threshold signature scheme.
// BLS is used with the BLS12-381 curve.
//
// These protocols mainly generate a BLS key pair and share the secret key
// among (n) participants in a way that any (t+1) key shares allow reconstructing
// the initial key (and also reconstructing a BLS threshold signature under the initial key).
// Up to (t) shares don't reveal any information about the initial key (or a signature generated
// by that key).
//
// We refer to the initial key pair by group private and group public key.
// (t) is the threshold parameter.
// Flow uses DKG with the value t = floor((n-1)/2) to optimize for unforgeability and robustness
// of the threshold signature scheme using the output keys.
//
// Private keys are scalar in Zr, where r is the group order of G1/G2.
// Public keys are in G2.
const (
// DKG and Threshold Signatures
// MinimumThreshold is the minimum value of the threshold parameter in all threshold-based protocols.
MinimumThreshold = 1
// DKGMinSize is the minimum size of a group participating in a DKG protocol
DKGMinSize int = MinimumThreshold + 1
// DKGMaxSize is the maximum size of a group participating in a DKG protocol
DKGMaxSize int = 254
// SeedMinLenDKG is the minumum seed length required to participate in a DKG protocol
SeedMinLenDKG = securityBits / 8
SeedMaxLenDKG = maxRelicPrgSeed
)
type DKGState interface {
// Size returns the size of the DKG group n
Size() int
// Threshold returns the threshold value t
Threshold() int
// Start starts running a DKG in the current participant
Start(seed []byte) error
// HandleBroadcastMsg processes a new broadcasted message received by the current participant.
// orig is the message origin index
HandleBroadcastMsg(orig int, msg []byte) error
// HandlePrivateMsg processes a new private message received by the current participant.
// orig is the message origin index
HandlePrivateMsg(orig int, msg []byte) error
// End ends a DKG protocol in the current participant.
// It returns the finalized public data and participant private key share.
// - the group public key corresponding to the group secret key
// - all the public key shares corresponding to the participants private
// key shares
// - the finalized private key which is the current participant's own private key share
End() (PrivateKey, PublicKey, []PublicKey, error)
// NextTimeout set the next timeout of the protocol if any timeout applies.
// Some protocols could require more than one timeout
NextTimeout() error
// Running returns the running state of the DKG protocol
Running() bool
// ForceDisqualify forces a participant to get disqualified
// for a reason outside of the DKG protocol.
// The caller should make sure all honest participants call this function,
// otherwise, the protocol can be broken.
ForceDisqualify(participant int) error
}
// dkgFailureError is an error returned when a participant
// detects a failure in the protocol and is not able to compute output keys.
// Such a failure can be local and only depends on the participant's view of what
// happened in the protocol. The error can only be returned using the End() function.
type dkgFailureError struct {
error
}
// dkgFailureErrorf constructs a new dkgFailureError
func dkgFailureErrorf(msg string, args ...interface{}) error {
return &dkgFailureError{
error: fmt.Errorf(msg, args...),
}
}
// IsDKGFailureError checks if the input error is of a dkgFailureError type.
// dkgFailureError is an error returned when a participant
// detects a failure in the protocol and is not able to compute output keys.
func IsDKGFailureError(err error) bool {
var target *dkgFailureError
return errors.As(err, &target)
}
type dkgInvalidStateTransitionError struct {
error
}
func (e dkgInvalidStateTransitionError) Unwrap() error {
return e.error
}
// dkgInvalidStateTransitionErrorf constructs a new dkgInvalidStateTransitionError
func dkgInvalidStateTransitionErrorf(msg string, args ...interface{}) error {
return &dkgInvalidStateTransitionError{
error: fmt.Errorf(msg, args...),
}
}
// IsDkgInvalidStateTransitionError checks if the input error is of a dkgInvalidStateTransition type.
// invalidStateTransition is returned when a caller
// triggers an invalid state transition in the local DKG instance.
// Such a failure can only happen if the API is misued by not respecting
// the state machine conditions.
func IsDKGInvalidStateTransitionError(err error) bool {
var target *dkgInvalidStateTransitionError
return errors.As(err, &target)
}
// index is the node index type used as participants ID
type index byte
// newDKGCommon initializes the common structure of DKG protocols
func newDKGCommon(size int, threshold int, myIndex int,
processor DKGProcessor, dealerIndex int) (*dkgCommon, error) {
if size < DKGMinSize || size > DKGMaxSize {
return nil, invalidInputsErrorf(
"size should be between %d and %d",
DKGMinSize,
DKGMaxSize)
}
if myIndex >= size || dealerIndex >= size || myIndex < 0 || dealerIndex < 0 {
return nil, invalidInputsErrorf(
"indices of current and dealer nodes must be between 0 and %d, got %d",
size-1,
myIndex)
}
if threshold >= size || threshold < MinimumThreshold {
return nil, invalidInputsErrorf(
"The threshold must be between %d and %d, got %d",
MinimumThreshold,
size-1,
threshold)
}
return &dkgCommon{
size: size,
threshold: threshold,
myIndex: index(myIndex),
processor: processor,
}, nil
}
// dkgCommon holds the common data of all DKG protocols
type dkgCommon struct {
size int
threshold int
myIndex index
// running is true when the DKG protocol is running, is false otherwise
running bool
// processes the action of the DKG interface outputs
processor DKGProcessor
}
// Running returns the running state of the DKG protocol.
// The state is equal to true when the DKG protocol is running, and is equal to false otherwise.
func (s *dkgCommon) Running() bool {
return s.running
}
// Size returns the size of the DKG group n
func (s *dkgCommon) Size() int {
return s.size
}
// Threshold returns the threshold value t
func (s *dkgCommon) Threshold() int {
return s.threshold
}
// NextTimeout sets the next protocol timeout if there is any.
// This function should be overwritten by any protocol that uses timeouts.
func (s *dkgCommon) NextTimeout() error {
return nil
}
// dkgMsgTag is the type used to encode message tags
type dkgMsgTag byte
const (
feldmanVSSShare dkgMsgTag = iota
feldmanVSSVerifVec
feldmanVSSComplaint
feldmanVSSComplaintAnswer
)
// DKGProcessor is an interface that implements the DKG output actions.
//
// An instance of a DKGProcessor is needed for each participant in order to
// particpate in a DKG protocol
type DKGProcessor interface {
// PrivateSend sends a message to a destination over
// a private channel. The channel must preserve the
// confidentiality of the message and should authenticate
// the sender.
// It is recommended that the private channel is unique per
// protocol instance. This can be achieved by prepending all
// messages by a unique instance ID.
PrivateSend(dest int, data []byte)
// Broadcast broadcasts a message to all participants.
// This function assumes all participants have received the same message,
// failing to do so, the protocol can be broken.
// The broadcasted message is public and not confidential.
// The broadcasting channel should authenticate the sender.
// It is recommended that the broadcasting channel is unique per
// protocol instance. This can be achieved by prepending all
// messages by a unique instance ID.
Broadcast(data []byte)
// Disqualify flags that a participant is misbehaving and that it got
// disqualified from the protocol. Such behavior deserves
// disqualifying as it is flagged to all honest participants in
// the protocol.
// log describes the disqualification reason.
Disqualify(participant int, log string)
// FlagMisbehavior warns that a participant is misbehaving.
// Such behavior is not necessarily flagged to all participants and therefore
// the participant is not disqualified from the protocol. Other mechanisms
// outside DKG could be implemented to synchronize slashing the misbehaving
// participant by all participating participants, using the api `ForceDisqualify`. Failing to
// do so, the protocol can be broken.
// log describes the misbehavior.
FlagMisbehavior(participant int, log string)
}