// // Copyright Coinbase, Inc. All Rights Reserved. // // SPDX-License-Identifier: Apache-2.0 // // Package frost is an implementation of t-of-n threshold signature of https://eprint.iacr.org/2020/852.pdf package frost import ( "fmt" "source.quilibrium.com/quilibrium/monorepo/nekryptology/internal" "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/dkg/frost" ) // Signer is a tSchnorr player performing the signing operation. type Signer struct { skShare curves.Scalar // secret signing share for this signer vkShare curves.Point // store verification key share verificationKey curves.Point // verification key id uint32 // The ID assigned to this signer's shamir share threshold uint32 curve *curves.Curve round uint lCoeffs map[uint32]curves.Scalar // lCoeffs are Lagrange coefficients of each cosigner. cosigners []uint32 state *state // Accumulated intermediate values associated with signing challengeDeriver ChallengeDerive } type state struct { // Round 1 capD, capE curves.Point // capD, capE are commitments this signer generates in signing round 1 smallD, smallE curves.Scalar // smallD, smallE are scalars this signer generates in signing round 1 // Round 2 commitments map[uint32]*Round1Bcast // Store commitments broadcast after signing round 1 msg []byte c curves.Scalar capRs map[uint32]curves.Point sumR curves.Point } // NewSigner create a signer from a dkg participant // Note that we can pre-assign Lagrange coefficients lcoeffs of each cosigner. This optimizes performance. // See paragraph 3 of section 3 in the draft - https://tools.ietf.org/pdf/draft-komlo-frost-00.pdf func NewSigner(info *frost.DkgParticipant, id, thresh uint32, lcoeffs map[uint32]curves.Scalar, cosigners []uint32, challengeDeriver ChallengeDerive) (*Signer, error) { if info == nil || len(cosigners) == 0 || len(lcoeffs) == 0 { return nil, internal.ErrNilArguments } if thresh > uint32(len(cosigners)) { return nil, fmt.Errorf("threshold is higher than number of signers") } if len(lcoeffs) != len(cosigners) { return nil, fmt.Errorf("expected coefficients to be equal to number of cosigners") } // Check if cosigners and lcoeffs contain the same IDs for i := 0; i < len(cosigners); i++ { id := cosigners[i] if _, ok := lcoeffs[id]; !ok { return nil, fmt.Errorf("lcoeffs and cosigners have inconsistent ID") } } return &Signer{ skShare: info.SkShare, vkShare: info.VkShare, verificationKey: info.VerificationKey, id: id, threshold: thresh, curve: info.Curve, round: 1, lCoeffs: lcoeffs, cosigners: cosigners, state: &state{}, challengeDeriver: challengeDeriver, }, nil }