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  }