github.com/onflow/flow-go/crypto@v0.24.8/dkg_feldmanvss.go (about)

     1  //go:build relic
     2  // +build relic
     3  
     4  package crypto
     5  
     6  // #cgo CFLAGS: -g -Wall -std=c99
     7  // #include "dkg_include.h"
     8  import "C"
     9  
    10  import (
    11  	"fmt"
    12  )
    13  
    14  // Implements Feldman Verifiable Secret Sharing using
    15  // the BLS set up on the BLS12-381 curve.
    16  
    17  // The secret is a BLS private key generated by a single dealer.
    18  // (and hence this is a centralized generation).
    19  // The  generates key shares for a BLS-based
    20  // threshold signature scheme and distributes the shares over the (n)
    21  // partcipants including itself. The particpants validate their shares
    22  // using a public verifiaction vector shared by the .
    23  
    24  // Private keys are scalar in Zr, where r is the group order of G1/G2
    25  // Public keys are in G2.
    26  
    27  // feldman VSS protocol, implements DKGState
    28  type feldmanVSSstate struct {
    29  	// common DKG state
    30  	*dkgCommon
    31  	// participant  index
    32  	dealerIndex index
    33  	// Polynomial P = a_0 + a_1*x + .. + a_t*x^t  in Zr[X], the vector size is (t+1)
    34  	// a_0 is the group private key
    35  	a []scalar
    36  	// Public vector of the group, the vector size is (t+1)
    37  	// A_0 is the group public key
    38  	vA         []pointG2
    39  	vAReceived bool
    40  	// Private share of the current participant
    41  	x         scalar
    42  	xReceived bool
    43  	// Public keys of the group participants, the vector size is (n)
    44  	y []pointG2
    45  	// true if the private share is valid
    46  	validKey bool
    47  }
    48  
    49  // NewFeldmanVSS creates a new instance of Feldman VSS protocol.
    50  //
    51  // An instance is run by a single participant and is usable for only one protocol.
    52  // In order to run the protocol again, a new instance needs to be created
    53  //
    54  // The function returns:
    55  // - (nil, InvalidInputsError) if:
    56  //   - size if not in [DKGMinSize, DKGMaxSize]
    57  //   - threshold is not in [MinimumThreshold, size-1]
    58  //   - myIndex is not in [0, size-1]
    59  //   - dealerIndex is not in [0, size-1]
    60  //
    61  // - (dkgInstance, nil) otherwise
    62  func NewFeldmanVSS(size int, threshold int, myIndex int,
    63  	processor DKGProcessor, dealerIndex int) (DKGState, error) {
    64  
    65  	common, err := newDKGCommon(size, threshold, myIndex, processor, dealerIndex)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	fvss := &feldmanVSSstate{
    71  		dkgCommon:   common,
    72  		dealerIndex: index(dealerIndex),
    73  	}
    74  	fvss.init()
    75  	return fvss, nil
    76  }
    77  
    78  func (s *feldmanVSSstate) init() {
    79  	// set the bls context
    80  	blsInstance.reInit()
    81  	s.running = false
    82  	s.y = nil
    83  	s.xReceived = false
    84  	s.vAReceived = false
    85  	C.bn_new_wrapper((*C.bn_st)(&s.x))
    86  }
    87  
    88  // Start triggers the protocol start for the current participant.
    89  // If the current participant is the dealer, then the seed is used
    90  // to generate the secret polynomial (including the group private key).
    91  // If the current participant is not the dealer, the seed is ignored.
    92  //
    93  // The function returns:
    94  // - dkgInvalidStateTransitionError if the DKG instance is already running.
    95  // - error if an unexpected exception occurs
    96  // - nil otherwise
    97  func (s *feldmanVSSstate) Start(seed []byte) error {
    98  	if s.running {
    99  		return dkgInvalidStateTransitionErrorf("dkg is already running")
   100  	}
   101  
   102  	s.running = true
   103  	// Generate shares if necessary
   104  	if s.dealerIndex == s.myIndex {
   105  		return s.generateShares(seed)
   106  	}
   107  	return nil
   108  }
   109  
   110  // End finalizes the protocol in the current node.
   111  // It returns the finalized public data and participants private key share.
   112  // - the group public key corresponding to the group secret key
   113  // - all the public key shares corresponding to the participants private
   114  // key shares.
   115  // - the finalized private key which is the current participant's own private key share
   116  //
   117  // The returned erorr is :
   118  //   - dkgInvalidStateTransitionError if the DKG instance was not running.
   119  //   - dkgFailureError if the private key and vector are inconsistent.
   120  //   - dkgFailureError if the public key share or group public key is identity.
   121  //   - nil otherwise.
   122  func (s *feldmanVSSstate) End() (PrivateKey, PublicKey, []PublicKey, error) {
   123  	if !s.running {
   124  		return nil, nil, nil, dkgInvalidStateTransitionErrorf("dkg is not running")
   125  	}
   126  	s.running = false
   127  	if !s.validKey {
   128  		return nil, nil, nil, dkgFailureErrorf("received private key is invalid")
   129  	}
   130  	// private key of the current participant
   131  	x := newPrKeyBLSBLS12381(&s.x)
   132  
   133  	// Group public key
   134  	Y := newPubKeyBLSBLS12381(&s.vA[0])
   135  
   136  	// The participants public keys
   137  	y := make([]PublicKey, s.size)
   138  	for i, p := range s.y {
   139  		y[i] = newPubKeyBLSBLS12381(&p)
   140  	}
   141  
   142  	// check if current public key share or group public key is identity.
   143  	// In that case all signatures generated by the key are invalid (as stated by the BLS IETF draft)
   144  	// to avoid equivocation issues.
   145  	if (&s.x).isZero() {
   146  		return nil, nil, nil, dkgFailureErrorf("received private key is identity and is therefore invalid")
   147  	}
   148  	if Y.isIdentity {
   149  		return nil, nil, nil, dkgFailureErrorf("group private key is identity and is therefore invalid")
   150  	}
   151  	return x, Y, y, nil
   152  }
   153  
   154  const (
   155  	shareSize = PrKeyLenBLSBLS12381
   156  	// the actual verifVectorSize depends on the state and is:
   157  	// PubKeyLenBLSBLS12381*(t+1)
   158  	verifVectorSize = PubKeyLenBLSBLS12381
   159  )
   160  
   161  // HandleBroadcastMsg processes a new broadcasted message received by the current participant.
   162  // `orig` is the message origin index.
   163  //
   164  // The function returns:
   165  //   - dkgInvalidStateTransitionError if the instance is not running
   166  //   - invalidInputsError if `orig` is not valid (in [0, size-1])
   167  //   - nil otherwise
   168  func (s *feldmanVSSstate) HandleBroadcastMsg(orig int, msg []byte) error {
   169  	if !s.running {
   170  		return dkgInvalidStateTransitionErrorf("dkg is not running")
   171  	}
   172  	if orig >= s.Size() || orig < 0 {
   173  		return invalidInputsErrorf(
   174  			"wrong origin input, should be less than %d, got %d",
   175  			s.Size(),
   176  			orig)
   177  	}
   178  
   179  	// In case a message is received by the origin participant,
   180  	// the message is just ignored
   181  	if s.myIndex == index(orig) {
   182  		return nil
   183  	}
   184  
   185  	if len(msg) == 0 {
   186  		s.processor.Disqualify(orig, "the received broadcast is empty")
   187  		return nil
   188  	}
   189  
   190  	// msg = |tag| Data |
   191  	if dkgMsgTag(msg[0]) == feldmanVSSVerifVec {
   192  		s.receiveVerifVector(index(orig), msg[1:])
   193  	} else {
   194  		s.processor.Disqualify(orig,
   195  			fmt.Sprintf("the broadcast header is invalid, got %d",
   196  				dkgMsgTag(msg[0])))
   197  	}
   198  	return nil
   199  }
   200  
   201  // HandlePrivateMsg processes a new private message received by the current participant.
   202  // `orig` is the message origin index.
   203  //
   204  // The function returns:
   205  //   - dkgInvalidStateTransitionError if the instance is not running
   206  //   - invalidInputsError if `orig` is not valid (in [0, size-1])
   207  //   - nil otherwise
   208  func (s *feldmanVSSstate) HandlePrivateMsg(orig int, msg []byte) error {
   209  	if !s.running {
   210  		return dkgInvalidStateTransitionErrorf("dkg is not running")
   211  	}
   212  
   213  	if orig >= s.Size() || orig < 0 {
   214  		return invalidInputsErrorf(
   215  			"wrong origin, should be positive less than %d, got %d",
   216  			s.Size(),
   217  			orig)
   218  	}
   219  
   220  	// In case a private message is received by the origin participant,
   221  	// the message is just ignored
   222  	if s.myIndex == index(orig) {
   223  		return nil
   224  	}
   225  
   226  	// forward received message to receiveShare because private messages
   227  	// can only be private shares
   228  	// msg = |tag| Data |
   229  	s.receiveShare(index(orig), msg)
   230  
   231  	return nil
   232  }
   233  
   234  // ForceDisqualify forces a participant to get disqualified
   235  // for a reason outside of the DKG protocol
   236  // The caller should make sure all honest participants call this function,
   237  // otherwise, the protocol can be broken.
   238  //
   239  // The function returns:
   240  //   - dkgInvalidStateTransitionError if the instance is not running
   241  //   - invalidInputsError if `orig` is not valid (in [0, size-1])
   242  //   - nil otherwise
   243  func (s *feldmanVSSstate) ForceDisqualify(participant int) error {
   244  	if !s.running {
   245  		return dkgInvalidStateTransitionErrorf("dkg is not running")
   246  	}
   247  	if participant >= s.Size() || participant < 0 {
   248  		return invalidInputsErrorf(
   249  			"wrong origin input, should be less than %d, got %d",
   250  			s.Size(),
   251  			participant)
   252  	}
   253  	if index(participant) == s.dealerIndex {
   254  		s.validKey = false
   255  	}
   256  	return nil
   257  }
   258  
   259  // generateShares is used by the dealer to generate secret polynomial from the input seed
   260  // and derive all private shares and public data.
   261  func (s *feldmanVSSstate) generateShares(seed []byte) error {
   262  	err := seedRelic(seed)
   263  	if err != nil {
   264  		return fmt.Errorf("generating shares failed: %w", err)
   265  	}
   266  
   267  	// Generate a polyomial P in Zr[X] of degree t
   268  	s.a = make([]scalar, s.threshold+1)
   269  	s.vA = make([]pointG2, s.threshold+1)
   270  	s.y = make([]pointG2, s.size)
   271  	// non-zero a[0] - group private key is not zero
   272  	randZrStar(&s.a[0])
   273  	generatorScalarMultG2(&s.vA[0], &s.a[0])
   274  	if s.threshold > 0 {
   275  		for i := 1; i < s.threshold; i++ {
   276  			C.bn_new_wrapper((*C.bn_st)(&s.a[i]))
   277  			randZr(&s.a[i])
   278  			generatorScalarMultG2(&s.vA[i], &s.a[i])
   279  		}
   280  		// non-zero a[t] to enforce the polynomial degree
   281  		randZrStar(&s.a[s.threshold])
   282  		generatorScalarMultG2(&s.vA[s.threshold], &s.a[s.threshold])
   283  	}
   284  
   285  	// compute the shares
   286  	for i := index(1); int(i) <= s.size; i++ {
   287  		// the dealer's own share
   288  		if i-1 == s.myIndex {
   289  			xdata := make([]byte, shareSize)
   290  			zrPolynomialImage(xdata, s.a, i, &s.y[i-1])
   291  			C.bn_read_bin((*C.bn_st)(&s.x),
   292  				(*C.uchar)(&xdata[0]),
   293  				PrKeyLenBLSBLS12381,
   294  			)
   295  			continue
   296  		}
   297  		// the-other-participant shares
   298  		data := make([]byte, shareSize+1)
   299  		data[0] = byte(feldmanVSSShare)
   300  		zrPolynomialImage(data[1:], s.a, i, &s.y[i-1])
   301  		s.processor.PrivateSend(int(i-1), data)
   302  	}
   303  	// broadcast the vector
   304  	vectorSize := verifVectorSize * (s.threshold + 1)
   305  	data := make([]byte, vectorSize+1)
   306  	data[0] = byte(feldmanVSSVerifVec)
   307  	writeVerifVector(data[1:], s.vA)
   308  	s.processor.Broadcast(data)
   309  
   310  	s.vAReceived = true
   311  	s.xReceived = true
   312  	s.validKey = true
   313  	return nil
   314  }
   315  
   316  // receives a private share from the
   317  func (s *feldmanVSSstate) receiveShare(origin index, data []byte) {
   318  	// only accept private shares from the .
   319  	if origin != s.dealerIndex {
   320  		return
   321  	}
   322  
   323  	if s.xReceived {
   324  		s.processor.FlagMisbehavior(int(origin), "private share was already received")
   325  		return
   326  	}
   327  
   328  	// at this point, tag the private message as received
   329  	s.xReceived = true
   330  
   331  	// private message general check
   332  	// msg = |tag| Data |
   333  	if len(data) == 0 || dkgMsgTag(data[0]) != feldmanVSSShare {
   334  		s.validKey = false
   335  		s.processor.FlagMisbehavior(int(origin),
   336  			fmt.Sprintf("private share should be non-empty and first byte should be %d, received %#x",
   337  				feldmanVSSShare, data))
   338  		return
   339  	}
   340  
   341  	// consider the remaining data from message
   342  	data = data[1:]
   343  
   344  	if (len(data)) != shareSize {
   345  		s.validKey = false
   346  		s.processor.FlagMisbehavior(int(origin),
   347  			fmt.Sprintf("invalid share size, expects %d, got %d",
   348  				shareSize, len(data)))
   349  		return
   350  	}
   351  
   352  	// read the participant private share
   353  	if C.bn_read_Zr_bin((*C.bn_st)(&s.x),
   354  		(*C.uchar)(&data[0]),
   355  		PrKeyLenBLSBLS12381,
   356  	) != valid {
   357  		s.validKey = false
   358  		s.processor.FlagMisbehavior(int(origin),
   359  			fmt.Sprintf("invalid share value %x", data))
   360  		return
   361  	}
   362  
   363  	if s.vAReceived {
   364  		s.validKey = s.verifyShare()
   365  	}
   366  }
   367  
   368  // receives the public vector from the
   369  func (s *feldmanVSSstate) receiveVerifVector(origin index, data []byte) {
   370  	// only accept the verification vector from the .
   371  	if origin != s.dealerIndex {
   372  		return
   373  	}
   374  
   375  	if s.vAReceived {
   376  		s.processor.FlagMisbehavior(int(origin),
   377  			"verification vector was already received")
   378  		return
   379  	}
   380  
   381  	if verifVectorSize*(s.threshold+1) != len(data) {
   382  		s.vAReceived = true
   383  		s.validKey = false
   384  		s.processor.Disqualify(int(origin),
   385  			fmt.Sprintf("invalid verification vector size, expects %d, got %d",
   386  				verifVectorSize*(s.threshold+1), len(data)))
   387  		return
   388  	}
   389  	// read the verification vector
   390  	s.vA = make([]pointG2, s.threshold+1)
   391  	err := readVerifVector(s.vA, data)
   392  	if err != nil {
   393  		s.vAReceived = true
   394  		s.validKey = false
   395  		s.processor.Disqualify(int(origin),
   396  			fmt.Sprintf("reading the verification vector failed: %s", err))
   397  	}
   398  
   399  	s.y = make([]pointG2, s.size)
   400  	s.computePublicKeys()
   401  
   402  	s.vAReceived = true
   403  	if s.xReceived {
   404  		s.validKey = s.verifyShare()
   405  	}
   406  }
   407  
   408  // zrPolynomialImage computes P(x) = a_0 + a_1*x + .. + a_n*x^n (mod r) in Z/Zr
   409  // r being the order of G1
   410  // P(x) is written in dest, while g2^P(x) is written in y
   411  // x being a small integer
   412  func zrPolynomialImage(dest []byte, a []scalar, x index, y *pointG2) {
   413  	C.Zr_polynomialImage_export((*C.uchar)(&dest[0]),
   414  		(*C.ep2_st)(y),
   415  		(*C.bn_st)(&a[0]), (C.int)(len(a)),
   416  		(C.uint8_t)(x),
   417  	)
   418  }
   419  
   420  // writeVerifVector exports a vector A into an array of bytes
   421  // assuming the array length matches the vector length
   422  func writeVerifVector(dest []byte, A []pointG2) {
   423  	C.ep2_vector_write_bin((*C.uchar)(&dest[0]),
   424  		(*C.ep2_st)(&A[0]),
   425  		(C.int)(len(A)),
   426  	)
   427  }
   428  
   429  // readVerifVector imports A vector from an array of bytes,
   430  // assuming the slice length matches the vector length
   431  func readVerifVector(A []pointG2, src []byte) error {
   432  	read := C.ep2_vector_read_bin((*C.ep2_st)(&A[0]),
   433  		(*C.uchar)(&src[0]),
   434  		(C.int)(len(A)))
   435  	if read == valid {
   436  		return nil
   437  	}
   438  	// invalid A vector
   439  	return invalidInputsErrorf("the verifcation vector does not serialize G2 points")
   440  }
   441  
   442  func (s *feldmanVSSstate) verifyShare() bool {
   443  	// check y[current] == x.G2
   444  	return C.verifyshare((*C.bn_st)(&s.x),
   445  		(*C.ep2_st)(&s.y[s.myIndex])) == 1
   446  }
   447  
   448  // computePublicKeys extracts the participants public keys from the verification vector
   449  // y[i] = Q(i+1) for all participants i, with:
   450  //
   451  //	Q(x) = A_0 + A_1*x + ... +  A_n*x^n  in G2
   452  func (s *feldmanVSSstate) computePublicKeys() {
   453  	C.G2_polynomialImages(
   454  		(*C.ep2_st)(&s.y[0]), (C.int)(len(s.y)),
   455  		(*C.ep2_st)(&s.vA[0]), (C.int)(len(s.vA)),
   456  	)
   457  }