github.com/onflow/flow-go/crypto@v0.24.8/dkg.go (about) 1 package crypto 2 3 import ( 4 "errors" 5 "fmt" 6 ) 7 8 // DKG stands for distributed key generation. In this library, DKG 9 // refers to discrete-log based protocols. 10 // The protocols implemented in the package for now generate keys for a BLS-based 11 // threshold signature scheme. 12 // BLS is used with the BLS12-381 curve. 13 // 14 // These protocols mainly generate a BLS key pair and share the secret key 15 // among (n) participants in a way that any (t+1) key shares allow reconstructing 16 // the initial key (and also reconstructing a BLS threshold signature under the initial key). 17 // Up to (t) shares don't reveal any information about the initial key (or a signature generated 18 // by that key). 19 // 20 // We refer to the initial key pair by group private and group public key. 21 // (t) is the threshold parameter. 22 // Flow uses DKG with the value t = floor((n-1)/2) to optimize for unforgeability and robustness 23 // of the threshold signature scheme using the output keys. 24 // 25 // Private keys are scalar in Zr, where r is the group order of G1/G2. 26 // Public keys are in G2. 27 28 const ( 29 // DKG and Threshold Signatures 30 31 // MinimumThreshold is the minimum value of the threshold parameter in all threshold-based protocols. 32 MinimumThreshold = 1 33 // DKGMinSize is the minimum size of a group participating in a DKG protocol 34 DKGMinSize int = MinimumThreshold + 1 35 // DKGMaxSize is the maximum size of a group participating in a DKG protocol 36 DKGMaxSize int = 254 37 // SeedMinLenDKG is the minumum seed length required to participate in a DKG protocol 38 SeedMinLenDKG = securityBits / 8 39 SeedMaxLenDKG = maxRelicPrgSeed 40 ) 41 42 type DKGState interface { 43 // Size returns the size of the DKG group n 44 Size() int 45 // Threshold returns the threshold value t 46 Threshold() int 47 // Start starts running a DKG in the current participant 48 Start(seed []byte) error 49 // HandleBroadcastMsg processes a new broadcasted message received by the current participant. 50 // orig is the message origin index 51 HandleBroadcastMsg(orig int, msg []byte) error 52 // HandlePrivateMsg processes a new private message received by the current participant. 53 // orig is the message origin index 54 HandlePrivateMsg(orig int, msg []byte) error 55 // End ends a DKG protocol in the current participant. 56 // It returns the finalized public data and participant private key share. 57 // - the group public key corresponding to the group secret key 58 // - all the public key shares corresponding to the participants private 59 // key shares 60 // - the finalized private key which is the current participant's own private key share 61 End() (PrivateKey, PublicKey, []PublicKey, error) 62 // NextTimeout set the next timeout of the protocol if any timeout applies. 63 // Some protocols could require more than one timeout 64 NextTimeout() error 65 // Running returns the running state of the DKG protocol 66 Running() bool 67 // ForceDisqualify forces a participant to get disqualified 68 // for a reason outside of the DKG protocol. 69 // The caller should make sure all honest participants call this function, 70 // otherwise, the protocol can be broken. 71 ForceDisqualify(participant int) error 72 } 73 74 // dkgFailureError is an error returned when a participant 75 // detects a failure in the protocol and is not able to compute output keys. 76 // Such a failure can be local and only depends on the participant's view of what 77 // happened in the protocol. The error can only be returned using the End() function. 78 type dkgFailureError struct { 79 error 80 } 81 82 // dkgFailureErrorf constructs a new dkgFailureError 83 func dkgFailureErrorf(msg string, args ...interface{}) error { 84 return &dkgFailureError{ 85 error: fmt.Errorf(msg, args...), 86 } 87 } 88 89 // IsDKGFailureError checks if the input error is of a dkgFailureError type. 90 // dkgFailureError is an error returned when a participant 91 // detects a failure in the protocol and is not able to compute output keys. 92 func IsDKGFailureError(err error) bool { 93 var target *dkgFailureError 94 return errors.As(err, &target) 95 } 96 97 type dkgInvalidStateTransitionError struct { 98 error 99 } 100 101 func (e dkgInvalidStateTransitionError) Unwrap() error { 102 return e.error 103 } 104 105 // dkgInvalidStateTransitionErrorf constructs a new dkgInvalidStateTransitionError 106 func dkgInvalidStateTransitionErrorf(msg string, args ...interface{}) error { 107 return &dkgInvalidStateTransitionError{ 108 error: fmt.Errorf(msg, args...), 109 } 110 } 111 112 // IsDkgInvalidStateTransitionError checks if the input error is of a dkgInvalidStateTransition type. 113 // invalidStateTransition is returned when a caller 114 // triggers an invalid state transition in the local DKG instance. 115 // Such a failure can only happen if the API is misued by not respecting 116 // the state machine conditions. 117 func IsDKGInvalidStateTransitionError(err error) bool { 118 var target *dkgInvalidStateTransitionError 119 return errors.As(err, &target) 120 } 121 122 // index is the node index type used as participants ID 123 type index byte 124 125 // newDKGCommon initializes the common structure of DKG protocols 126 func newDKGCommon(size int, threshold int, myIndex int, 127 processor DKGProcessor, dealerIndex int) (*dkgCommon, error) { 128 if size < DKGMinSize || size > DKGMaxSize { 129 return nil, invalidInputsErrorf( 130 "size should be between %d and %d", 131 DKGMinSize, 132 DKGMaxSize) 133 } 134 135 if myIndex >= size || dealerIndex >= size || myIndex < 0 || dealerIndex < 0 { 136 return nil, invalidInputsErrorf( 137 "indices of current and dealer nodes must be between 0 and %d, got %d", 138 size-1, 139 myIndex) 140 } 141 142 if threshold >= size || threshold < MinimumThreshold { 143 return nil, invalidInputsErrorf( 144 "The threshold must be between %d and %d, got %d", 145 MinimumThreshold, 146 size-1, 147 threshold) 148 } 149 150 return &dkgCommon{ 151 size: size, 152 threshold: threshold, 153 myIndex: index(myIndex), 154 processor: processor, 155 }, nil 156 } 157 158 // dkgCommon holds the common data of all DKG protocols 159 type dkgCommon struct { 160 size int 161 threshold int 162 myIndex index 163 // running is true when the DKG protocol is running, is false otherwise 164 running bool 165 // processes the action of the DKG interface outputs 166 processor DKGProcessor 167 } 168 169 // Running returns the running state of the DKG protocol. 170 // The state is equal to true when the DKG protocol is running, and is equal to false otherwise. 171 func (s *dkgCommon) Running() bool { 172 return s.running 173 } 174 175 // Size returns the size of the DKG group n 176 func (s *dkgCommon) Size() int { 177 return s.size 178 } 179 180 // Threshold returns the threshold value t 181 func (s *dkgCommon) Threshold() int { 182 return s.threshold 183 } 184 185 // NextTimeout sets the next protocol timeout if there is any. 186 // This function should be overwritten by any protocol that uses timeouts. 187 func (s *dkgCommon) NextTimeout() error { 188 return nil 189 } 190 191 // dkgMsgTag is the type used to encode message tags 192 type dkgMsgTag byte 193 194 const ( 195 feldmanVSSShare dkgMsgTag = iota 196 feldmanVSSVerifVec 197 feldmanVSSComplaint 198 feldmanVSSComplaintAnswer 199 ) 200 201 // DKGProcessor is an interface that implements the DKG output actions. 202 // 203 // An instance of a DKGProcessor is needed for each participant in order to 204 // particpate in a DKG protocol 205 type DKGProcessor interface { 206 // PrivateSend sends a message to a destination over 207 // a private channel. The channel must preserve the 208 // confidentiality of the message and should authenticate 209 // the sender. 210 // It is recommended that the private channel is unique per 211 // protocol instance. This can be achieved by prepending all 212 // messages by a unique instance ID. 213 PrivateSend(dest int, data []byte) 214 // Broadcast broadcasts a message to all participants. 215 // This function assumes all participants have received the same message, 216 // failing to do so, the protocol can be broken. 217 // The broadcasted message is public and not confidential. 218 // The broadcasting channel should authenticate the sender. 219 // It is recommended that the broadcasting channel is unique per 220 // protocol instance. This can be achieved by prepending all 221 // messages by a unique instance ID. 222 Broadcast(data []byte) 223 // Disqualify flags that a participant is misbehaving and that it got 224 // disqualified from the protocol. Such behavior deserves 225 // disqualifying as it is flagged to all honest participants in 226 // the protocol. 227 // log describes the disqualification reason. 228 Disqualify(participant int, log string) 229 // FlagMisbehavior warns that a participant is misbehaving. 230 // Such behavior is not necessarily flagged to all participants and therefore 231 // the participant is not disqualified from the protocol. Other mechanisms 232 // outside DKG could be implemented to synchronize slashing the misbehaving 233 // participant by all participating participants, using the api `ForceDisqualify`. Failing to 234 // do so, the protocol can be broken. 235 // log describes the misbehavior. 236 FlagMisbehavior(participant int, log string) 237 }