diff --git a/commitment.go b/commitment.go index b190a02..76da4d9 100644 --- a/commitment.go +++ b/commitment.go @@ -6,7 +6,6 @@ // LICENSE file in the root directory of this source tree or at // https://spdx.org/licenses/MIT.html -// Package commitment defines the FROST Signer commitment. package frost import ( @@ -238,7 +237,7 @@ func (c CommitmentList) groupCommitment(bf BindingFactors) *group.Element { } func (c *Configuration) isSignerRegistered(sid uint64) bool { - for _, peer := range c.SignerPublicKeys { + for _, peer := range c.SignerPublicKeyShares { if peer.ID == sid { return true } @@ -249,6 +248,12 @@ func (c *Configuration) isSignerRegistered(sid uint64) bool { // ValidateCommitment returns an error if the commitment is not valid. func (c *Configuration) ValidateCommitment(commitment *Commitment) error { + if !c.verified || !c.keysVerified { + if err := c.Init(); err != nil { + return err + } + } + if commitment == nil { return fmt.Errorf("the commitment list has a nil commitment") } @@ -322,6 +327,12 @@ func (c *Configuration) validateCommitmentListLength(commitments CommitmentList) // - no duplicated in signer identifiers // - all commitment signer identifiers are registered in the configuration func (c *Configuration) ValidateCommitmentList(commitments CommitmentList) error { + if !c.verified || !c.keysVerified { + if err := c.Init(); err != nil { + return err + } + } + if err := c.validateCommitmentListLength(commitments); err != nil { return err } diff --git a/coordinator.go b/coordinator.go index 975b3f7..82fd9da 100644 --- a/coordinator.go +++ b/coordinator.go @@ -42,6 +42,12 @@ func (c *Configuration) AggregateSignatures( commitments CommitmentList, verify bool, ) (*Signature, error) { + if !c.verified || !c.keysVerified { + if err := c.Init(); err != nil { + return nil, err + } + } + groupCommitment, bindingFactors, participants, err := c.prepareSignatureShareVerification(message, commitments) if err != nil { return nil, err @@ -89,6 +95,12 @@ func (c *Configuration) VerifySignatureShare( message []byte, commitments CommitmentList, ) error { + if !c.verified || !c.keysVerified { + if err := c.Init(); err != nil { + return err + } + } + groupCommitment, bindingFactors, participants, err := c.prepareSignatureShareVerification(message, commitments) if err != nil { return err @@ -100,12 +112,6 @@ func (c *Configuration) VerifySignatureShare( func (c *Configuration) prepareSignatureShareVerification(message []byte, commitments CommitmentList, ) (*group.Element, BindingFactors, []*group.Scalar, error) { - if !c.verified { - if err := c.verify(); err != nil { - return nil, nil, nil, err - } - } - commitments.Sort() // Validate general consistency of the commitment list. diff --git a/encoding.go b/encoding.go index 1315e1b..77d9598 100644 --- a/encoding.go +++ b/encoding.go @@ -68,16 +68,16 @@ func encodedLength(encID byte, g group.Group, other ...uint64) uint64 { func (c *Configuration) Encode() []byte { g := group.Group(c.Ciphersuite) pksLen := encodedLength(encPubKeyShare, g, c.Threshold*uint64(g.ElementLength())) - size := encodedLength(encConf, g, uint64(len(c.SignerPublicKeys))*pksLen) + size := encodedLength(encConf, g, uint64(len(c.SignerPublicKeyShares))*pksLen) out := make([]byte, 25, size) out[0] = byte(g) binary.LittleEndian.PutUint64(out[1:9], c.Threshold) binary.LittleEndian.PutUint64(out[9:17], c.MaxSigners) - binary.LittleEndian.PutUint64(out[17:25], uint64(len(c.SignerPublicKeys))) + binary.LittleEndian.PutUint64(out[17:25], uint64(len(c.SignerPublicKeyShares))) out = append(out, c.GroupPublicKey.Encode()...) - for _, pk := range c.SignerPublicKeys { + for _, pk := range c.SignerPublicKeyShares { out = append(out, pk.Encode()...) } @@ -106,7 +106,7 @@ func (c *Configuration) decodeHeader(data []byte) (*confHeader, error) { pksLen := encodedLength(encPubKeyShare, g, t*uint64(g.ElementLength())) length := encodedLength(encConf, g, nPks*pksLen) - if t > n { + if t == 0 || t > n { return nil, errInvalidConfigEncoding } @@ -135,12 +135,15 @@ func (c *Configuration) decode(header *confHeader, data []byte) error { pks := make([]*PublicKeyShare, header.nPks) conf := &Configuration{ - Ciphersuite: Ciphersuite(header.g), - Threshold: header.t, - MaxSigners: header.n, - GroupPublicKey: gpk, - SignerPublicKeys: pks, - group: header.g, + Ciphersuite: Ciphersuite(header.g), + Threshold: header.t, + MaxSigners: header.n, + GroupPublicKey: gpk, + SignerPublicKeyShares: pks, + } + + if err := conf.verifyConfiguration(); err != nil { + return err } for j := range header.nPks { @@ -149,15 +152,11 @@ func (c *Configuration) decode(header *confHeader, data []byte) error { return fmt.Errorf("could not decode signer public key share for signer %d: %w", j, err) } - if err := conf.validatePublicKeyShare(pk); err != nil { - return err - } - offset += pksLen pks[j] = pk } - if err := conf.verify(); err != nil { + if err := conf.verifySignerPublicKeyShares(); err != nil { return err } @@ -165,9 +164,10 @@ func (c *Configuration) decode(header *confHeader, data []byte) error { c.Threshold = conf.Threshold c.MaxSigners = conf.MaxSigners c.GroupPublicKey = gpk - c.SignerPublicKeys = pks + c.SignerPublicKeyShares = pks c.group = group.Group(conf.Ciphersuite) c.verified = true + c.keysVerified = true return nil } diff --git a/examples_test.go b/examples_test.go index 087d670..bc95aab 100644 --- a/examples_test.go +++ b/examples_test.go @@ -39,11 +39,11 @@ func Example_signer() { // This is how to set up the Configuration for FROST, the same for every signer and the coordinator. configuration := &frost.Configuration{ - Ciphersuite: ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err != nil { @@ -126,11 +126,11 @@ func Example_coordinator() { // This is how to set up the Configuration for FROST, the same for every signer and the coordinator. configuration := &frost.Configuration{ - Ciphersuite: ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err != nil { diff --git a/frost.go b/frost.go index 99e68f5..0c0719d 100644 --- a/frost.go +++ b/frost.go @@ -113,15 +113,16 @@ func (c Ciphersuite) ECGroup() group.Group { return group.Group(c) } -// Configuration holds long term Configuration information. +// Configuration holds the Configuration for a signing session. type Configuration struct { - GroupPublicKey *group.Element - SignerPublicKeys []*PublicKeyShare - Threshold uint64 - MaxSigners uint64 - Ciphersuite Ciphersuite - group group.Group - verified bool + GroupPublicKey *group.Element + SignerPublicKeyShares []*PublicKeyShare + Threshold uint64 + MaxSigners uint64 + Ciphersuite Ciphersuite + group group.Group + verified bool + keysVerified bool } var ( @@ -130,13 +131,57 @@ var ( errInvalidNumberOfPublicKeys = errors.New("invalid number of public keys (lower than threshold or above maximum)") ) -func (c *Configuration) validatePublicKeyShare(pks *PublicKeyShare) error { +func (c *Configuration) Init() error { + if !c.verified { + if err := c.verifyConfiguration(); err != nil { + return err + } + } + + if !c.keysVerified { + if err := c.verifySignerPublicKeyShares(); err != nil { + return err + } + } + + return nil +} + +// Signer returns a new participant of the protocol instantiated from the Configuration and the signer's key share. +func (c *Configuration) Signer(keyShare *KeyShare) (*Signer, error) { + if !c.verified || !c.keysVerified { + if err := c.Init(); err != nil { + return nil, err + } + } + + if err := c.ValidateKeyShare(keyShare); err != nil { + return nil, err + } + + return &Signer{ + KeyShare: keyShare, + LambdaRegistry: make(internal.LambdaRegistry), + NonceCommitments: make(map[uint64]*Nonce), + HidingRandom: nil, + BindingRandom: nil, + Configuration: c, + }, nil +} + +func (c *Configuration) ValidatePublicKeyShare(pks *PublicKeyShare) error { + if !c.verified { + if err := c.verifyConfiguration(); err != nil { + return err + } + } + if pks == nil { return errors.New("public key share is nil") } if pks.Group != c.group { - return fmt.Errorf("key share has invalid group parameter, want %s got %s", c.group, pks.Group) + return fmt.Errorf("key share has invalid group parameter, want %s got %d", c.group, pks.Group) } if err := c.validateIdentifier(pks.ID); err != nil { @@ -150,22 +195,65 @@ func (c *Configuration) validatePublicKeyShare(pks *PublicKeyShare) error { return nil } -func (c *Configuration) verifySignerPublicKeys() error { - length := uint64(len(c.SignerPublicKeys)) +func (c *Configuration) ValidateKeyShare(keyShare *KeyShare) error { + if !c.verified || !c.keysVerified { + if err := c.Init(); err != nil { + return err + } + } + + if keyShare == nil { + return errors.New("provided key share is nil") + } + + if err := c.ValidatePublicKeyShare(keyShare.Public()); err != nil { + return err + } + + if c.GroupPublicKey.Equal(keyShare.GroupPublicKey) != 1 { + return errors.New( + "the key share's group public key does not match the one in the configuration", + ) + } + + if keyShare.Secret == nil || keyShare.Secret.IsZero() { + return errors.New("provided key share has invalid secret key") + } + + if c.group.Base().Multiply(keyShare.Secret).Equal(keyShare.PublicKey) != 1 { + return errors.New("provided key share has non-matching secret and public keys") + } + + pk := c.getSignerPubKey(keyShare.ID) + if pk == nil { + return errors.New("provided key share has no registered signer identifier in the configuration") + } + + if pk.Equal(keyShare.PublicKey) != 1 { + return errors.New( + "provided key share has a different public key than the one registered for that signer in the configuration", + ) + } + + return nil +} + +func (c *Configuration) verifySignerPublicKeyShares() error { + length := uint64(len(c.SignerPublicKeyShares)) if length < c.Threshold || length > c.MaxSigners { return errInvalidNumberOfPublicKeys } // Sets to detect duplicates. - pkSet := make(map[string]uint64, len(c.SignerPublicKeys)) - idSet := make(map[uint64]struct{}, len(c.SignerPublicKeys)) + pkSet := make(map[string]uint64, len(c.SignerPublicKeyShares)) + idSet := make(map[uint64]struct{}, len(c.SignerPublicKeyShares)) - for i, pks := range c.SignerPublicKeys { + for i, pks := range c.SignerPublicKeyShares { if pks == nil { return fmt.Errorf("empty public key share at index %d", i) } - if err := c.validatePublicKeyShare(pks); err != nil { + if err := c.ValidatePublicKeyShare(pks); err != nil { return err } @@ -184,19 +272,23 @@ func (c *Configuration) verifySignerPublicKeys() error { idSet[pks.ID] = struct{}{} } + c.keysVerified = true + return nil } -func (c *Configuration) verify() error { +func (c *Configuration) verifyConfiguration() error { if !c.Ciphersuite.Available() { return internal.ErrInvalidCiphersuite } + g := group.Group(c.Ciphersuite) + if c.Threshold == 0 || c.Threshold > c.MaxSigners { return errInvalidThresholdParameter } - order, _ := new(big.Int).SetString(group.Group(c.Ciphersuite).Order(), 0) + order, _ := new(big.Int).SetString(g.Order(), 0) if order == nil { panic("can't set group order number") } @@ -212,27 +304,14 @@ func (c *Configuration) verify() error { return fmt.Errorf("invalid group public key, the key %w", err) } - if err := c.verifySignerPublicKeys(); err != nil { - return err - } - - return nil -} - -func (c *Configuration) Init() error { - c.group = group.Group(c.Ciphersuite) - - if err := c.verify(); err != nil { - return err - } - + c.group = g c.verified = true return nil } func (c *Configuration) getSignerPubKey(id uint64) *group.Element { - for _, pks := range c.SignerPublicKeys { + for _, pks := range c.SignerPublicKeyShares { if pks.ID == id { return pks.PublicKey } @@ -241,49 +320,6 @@ func (c *Configuration) getSignerPubKey(id uint64) *group.Element { return nil } -func (c *Configuration) ValidateKeyShare(keyShare *KeyShare) error { - if !c.verified { - if err := c.Init(); err != nil { - return err - } - } - - if keyShare == nil { - return errors.New("provided key share is nil") - } - - if err := c.validatePublicKeyShare(keyShare.Public()); err != nil { - return err - } - - if c.GroupPublicKey.Equal(keyShare.GroupPublicKey) != 1 { - return errors.New( - "the key share's group public key does not match the one in the configuration", - ) - } - - if keyShare.Secret == nil || keyShare.Secret.IsZero() { - return errors.New("provided key share has invalid secret key") - } - - if c.group.Base().Multiply(keyShare.Secret).Equal(keyShare.PublicKey) != 1 { - return errors.New("provided key share has non-matching secret and public keys") - } - - pk := c.getSignerPubKey(keyShare.ID) - if pk == nil { - return errors.New("provided key share has no registered signer identifier in the configuration") - } - - if pk.Equal(keyShare.PublicKey) != 1 { - return errors.New( - "provided key share has a different public key than the one registered for that signer in the configuration", - ) - } - - return nil -} - func (c *Configuration) validateIdentifier(id uint64) error { switch { case id == 0: @@ -301,35 +337,13 @@ func (c *Configuration) validateGroupElement(e *group.Element) error { return errors.New("is nil") case e.IsIdentity(): return errors.New("is the identity element") - case c.group.Base().Equal(e) == 1: + case group.Group(c.Ciphersuite).Base().Equal(e) == 1: return errors.New("is the group generator (base element)") } return nil } -// Signer returns a new participant of the protocol instantiated from the Configuration and the signer's key share. -func (c *Configuration) Signer(keyShare *KeyShare) (*Signer, error) { - if !c.verified { - if err := c.Init(); err != nil { - return nil, err - } - } - - if err := c.ValidateKeyShare(keyShare); err != nil { - return nil, err - } - - return &Signer{ - KeyShare: keyShare, - LambdaRegistry: make(internal.LambdaRegistry), - NonceCommitments: make(map[uint64]*Nonce), - HidingRandom: nil, - BindingRandom: nil, - Configuration: c, - }, nil -} - func (c *Configuration) challenge(lambda *group.Scalar, message []byte, groupCommitment *group.Element) *group.Scalar { chall := SchnorrChallenge(c.group, message, groupCommitment, c.GroupPublicKey) return chall.Multiply(lambda) diff --git a/tests/commitment_test.go b/tests/commitment_test.go index bfed5be..0add67e 100644 --- a/tests/commitment_test.go +++ b/tests/commitment_test.go @@ -380,7 +380,7 @@ func TestCommitmentList_Validate_UnregisteredKey(t *testing.T) { coms[i] = s.Commit() } - configuration.SignerPublicKeys = slices.Delete(configuration.SignerPublicKeys, 1, 2) + configuration.SignerPublicKeyShares = slices.Delete(configuration.SignerPublicKeyShares, 1, 2) expectedErrorPrefix := fmt.Sprintf( "signer identifier %d for commitment %d is not registered in the configuration", coms[1].SignerID, diff --git a/tests/configuration_test.go b/tests/configuration_test.go index 4105cbc..f63c7f0 100644 --- a/tests/configuration_test.go +++ b/tests/configuration_test.go @@ -14,6 +14,8 @@ import ( "strings" "testing" + secretsharing "github.com/bytemare/secret-sharing" + "github.com/bytemare/frost" "github.com/bytemare/frost/debug" "github.com/bytemare/frost/internal" @@ -32,11 +34,11 @@ func TestConfiguration_Verify_InvalidCiphersuite(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: 2, - Threshold: test.threshold, - MaxSigners: test.maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: 2, + Threshold: test.threshold, + MaxSigners: test.maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix.Error()) { @@ -58,11 +60,11 @@ func TestConfiguration_Verify_Threshold_0(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: test.Ciphersuite, - Threshold: 0, - MaxSigners: test.maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: test.Ciphersuite, + Threshold: 0, + MaxSigners: test.maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { @@ -84,11 +86,11 @@ func TestConfiguration_Verify_Threshold_Max(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: test.Ciphersuite, - Threshold: test.maxSigners + 1, - MaxSigners: test.maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: test.Ciphersuite, + Threshold: test.maxSigners + 1, + MaxSigners: test.maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { @@ -105,11 +107,11 @@ func TestConfiguration_Verify_GroupPublicKey_Nil(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: test.Ciphersuite, - Threshold: test.threshold, - MaxSigners: test.maxSigners, - GroupPublicKey: nil, - SignerPublicKeys: publicKeyShares, + Ciphersuite: test.Ciphersuite, + Threshold: test.threshold, + MaxSigners: test.maxSigners, + GroupPublicKey: nil, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { @@ -126,11 +128,11 @@ func TestConfiguration_Verify_GroupPublicKey_Identity(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: test.Ciphersuite, - Threshold: test.threshold, - MaxSigners: test.maxSigners, - GroupPublicKey: test.ECGroup().NewElement(), - SignerPublicKeys: publicKeyShares, + Ciphersuite: test.Ciphersuite, + Threshold: test.threshold, + MaxSigners: test.maxSigners, + GroupPublicKey: test.ECGroup().NewElement(), + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { @@ -147,11 +149,11 @@ func TestConfiguration_Verify_GroupPublicKey_Generator(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: test.Ciphersuite, - Threshold: test.threshold, - MaxSigners: test.maxSigners, - GroupPublicKey: test.ECGroup().Base(), - SignerPublicKeys: publicKeyShares, + Ciphersuite: test.Ciphersuite, + Threshold: test.threshold, + MaxSigners: test.maxSigners, + GroupPublicKey: test.ECGroup().Base(), + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { @@ -172,11 +174,11 @@ func TestConfiguration_VerifySignerPublicKeys_InvalidNumber(t *testing.T) { // nil configuration := &frost.Configuration{ - Ciphersuite: ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: nil, + Ciphersuite: ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: nil, } if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { @@ -184,21 +186,21 @@ func TestConfiguration_VerifySignerPublicKeys_InvalidNumber(t *testing.T) { } // empty - configuration.SignerPublicKeys = []*frost.PublicKeyShare{} + configuration.SignerPublicKeyShares = []*frost.PublicKeyShare{} if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) } // too few - configuration.SignerPublicKeys = publicKeyShares[:threshold-1] + configuration.SignerPublicKeyShares = publicKeyShares[:threshold-1] if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) } // too many - configuration.SignerPublicKeys = append(publicKeyShares, &frost.PublicKeyShare{}) + configuration.SignerPublicKeyShares = append(publicKeyShares, &frost.PublicKeyShare{}) if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) @@ -217,11 +219,11 @@ func TestConfiguration_VerifySignerPublicKeys_Nil(t *testing.T) { publicKeyShares[threshold-1] = nil configuration := &frost.Configuration{ - Ciphersuite: ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { @@ -238,19 +240,19 @@ func TestConfiguration_VerifySignerPublicKeys_BadPublicKey(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } // nil pk expectedErrorPrefix := fmt.Sprintf( "invalid public key for participant %d, the key is nil", - configuration.SignerPublicKeys[threshold-1].ID, + configuration.SignerPublicKeyShares[threshold-1].ID, ) - configuration.SignerPublicKeys[threshold-1].PublicKey = nil + configuration.SignerPublicKeyShares[threshold-1].PublicKey = nil if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) @@ -259,9 +261,9 @@ func TestConfiguration_VerifySignerPublicKeys_BadPublicKey(t *testing.T) { // identity expectedErrorPrefix = fmt.Sprintf( "invalid public key for participant %d, the key is the identity element", - configuration.SignerPublicKeys[threshold-1].ID, + configuration.SignerPublicKeyShares[threshold-1].ID, ) - configuration.SignerPublicKeys[threshold-1].PublicKey = ciphersuite.ECGroup().NewElement() + configuration.SignerPublicKeyShares[threshold-1].PublicKey = ciphersuite.ECGroup().NewElement() if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) @@ -270,9 +272,9 @@ func TestConfiguration_VerifySignerPublicKeys_BadPublicKey(t *testing.T) { // generator expectedErrorPrefix = fmt.Sprintf( "invalid public key for participant %d, the key is the group generator (base element)", - configuration.SignerPublicKeys[threshold-1].ID, + configuration.SignerPublicKeyShares[threshold-1].ID, ) - configuration.SignerPublicKeys[threshold-1].PublicKey = ciphersuite.ECGroup().Base() + configuration.SignerPublicKeyShares[threshold-1].PublicKey = ciphersuite.ECGroup().Base() if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) @@ -290,16 +292,16 @@ func TestConfiguration_VerifySignerPublicKeys_Duplicate_Identifiers(t *testing.T publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } // duplicate id - id1 := configuration.SignerPublicKeys[0].ID - configuration.SignerPublicKeys[1].ID = id1 + id1 := configuration.SignerPublicKeyShares[0].ID + configuration.SignerPublicKeyShares[1].ID = id1 if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) @@ -317,22 +319,112 @@ func TestConfiguration_VerifySignerPublicKeys_Duplicate_PublicKeys(t *testing.T) publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } // duplicate id - pk1 := configuration.SignerPublicKeys[0].PublicKey.Copy() - configuration.SignerPublicKeys[1].PublicKey = pk1 + pk1 := configuration.SignerPublicKeyShares[0].PublicKey.Copy() + configuration.SignerPublicKeyShares[1].PublicKey = pk1 if err := configuration.Init(); err == nil || !strings.HasPrefix(err.Error(), expectedErrorPrefix) { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) } } +func TestConfiguration_ValidatePublicKeyShare_Nil(t *testing.T) { + expectedErrorPrefix := "public key share is nil" + tt := &tableTest{ + Ciphersuite: frost.Ristretto255, + threshold: 2, + maxSigners: 3, + } + configuration, _ := makeConfAndShares(t, tt) + + if err := configuration.ValidatePublicKeyShare(nil); err == nil || err.Error() != expectedErrorPrefix { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } +} + +func TestConfiguration_ValidatePublicKeyShare_WrongGroup(t *testing.T) { + expectedErrorPrefix := "key share has invalid group parameter, want ristretto255_XMD:SHA-512_R255MAP_RO_ got 0" + tt := &tableTest{ + Ciphersuite: frost.Ristretto255, + threshold: 2, + maxSigners: 3, + } + configuration, _ := makeConfAndShares(t, tt) + + pks := &frost.PublicKeyShare{ + Group: 0, + } + + if err := configuration.ValidatePublicKeyShare(pks); err == nil || err.Error() != expectedErrorPrefix { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } +} + +func TestConfiguration_ValidatePublicKeyShare_ID0(t *testing.T) { + expectedErrorPrefix := "invalid identifier for public key share, the identifier is 0" + tt := &tableTest{ + Ciphersuite: frost.Ristretto255, + threshold: 2, + maxSigners: 3, + } + configuration, _ := makeConfAndShares(t, tt) + + pks := &frost.PublicKeyShare{ + Group: tt.ECGroup(), + ID: 0, + } + + if err := configuration.ValidatePublicKeyShare(pks); err == nil || err.Error() != expectedErrorPrefix { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } +} + +func TestConfiguration_ValidatePublicKeyShare_InvalidID(t *testing.T) { + expectedErrorPrefix := "invalid identifier for public key share, the identifier 4 is above authorized range [1:3]" + tt := &tableTest{ + Ciphersuite: frost.Ristretto255, + threshold: 2, + maxSigners: 3, + } + configuration, _ := makeConfAndShares(t, tt) + + pks := &frost.PublicKeyShare{ + Group: tt.ECGroup(), + ID: tt.maxSigners + 1, + } + + if err := configuration.ValidatePublicKeyShare(pks); err == nil || err.Error() != expectedErrorPrefix { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } +} + +func TestConfiguration_ValidatePublicKeyShare_InvalidPublicKey(t *testing.T) { + expectedErrorPrefix := "invalid public key for participant 1, the key is the group generator (base element)" + tt := &tableTest{ + Ciphersuite: frost.Ristretto255, + threshold: 2, + maxSigners: 3, + } + configuration, _ := makeConfAndShares(t, tt) + + pks := &frost.PublicKeyShare{ + Group: tt.ECGroup(), + ID: 1, + PublicKey: tt.ECGroup().Base(), + } + + if err := configuration.ValidatePublicKeyShare(pks); err == nil || err.Error() != expectedErrorPrefix { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } +} + func TestConfiguration_ValidateKeyShare_InvalidConf(t *testing.T) { expectedErrorPrefix := internal.ErrInvalidCiphersuite tt := &tableTest{ @@ -344,11 +436,11 @@ func TestConfiguration_ValidateKeyShare_InvalidConf(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: 2, - Threshold: tt.threshold, - MaxSigners: tt.maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: 2, + Threshold: tt.threshold, + MaxSigners: tt.maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.ValidateKeyShare(nil); err == nil || err.Error() != expectedErrorPrefix.Error() { @@ -384,10 +476,20 @@ func TestConfiguration_ValidateKeyShare_InvalidGroupPublicKey(t *testing.T) { if err := configuration.ValidateKeyShare(keyShare); err == nil || err.Error() != expectedErrorPrefix { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) } + + keyShare.GroupPublicKey = tt.ECGroup().NewElement() + if err := configuration.ValidateKeyShare(keyShare); err == nil || err.Error() != expectedErrorPrefix { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } + + keyShare.GroupPublicKey.Base() + if err := configuration.ValidateKeyShare(keyShare); err == nil || err.Error() != expectedErrorPrefix { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } } -func TestConfiguration_ValidateKeyShare_WrongPublicKeyShare(t *testing.T) { - expectedErrorPrefix := "the key share's group public key does not match the one in the configuration" +func TestConfiguration_ValidateKeyShare_BadPublicKeyShare(t *testing.T) { + expectedErrorPrefix := "invalid public key for participant 1, the key is nil" tt := &tableTest{ Ciphersuite: frost.Ristretto255, threshold: 2, @@ -396,8 +498,7 @@ func TestConfiguration_ValidateKeyShare_WrongPublicKeyShare(t *testing.T) { configuration, keyShares := makeConfAndShares(t, tt) keyShare := keyShares[0] - random := tt.ECGroup().NewScalar().Random() - keyShare.GroupPublicKey = tt.ECGroup().Base().Multiply(random) + keyShare.PublicKey = nil if err := configuration.ValidateKeyShare(keyShare); err == nil || err.Error() != expectedErrorPrefix { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) } @@ -441,7 +542,7 @@ func TestConfiguration_ValidateKeyShare_KeysNotMatching(t *testing.T) { } } -func TestConfiguration_ValidateKeyShare_NotRegistered(t *testing.T) { +func TestConfiguration_ValidateKeyShare_SignerIDNotRegistered(t *testing.T) { expectedErrorPrefix := "provided key share has no registered signer identifier in the configuration" tt := &tableTest{ Ciphersuite: frost.Ristretto255, @@ -455,13 +556,38 @@ func TestConfiguration_ValidateKeyShare_NotRegistered(t *testing.T) { pks[i] = ks.Public() } - configuration.SignerPublicKeys = pks + configuration.SignerPublicKeyShares = pks if err := configuration.ValidateKeyShare(keyShares[0]); err == nil || err.Error() != expectedErrorPrefix { t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) } } +func TestConfiguration_ValidateKeyShare_WrongPublicKey(t *testing.T) { + expectedErrorPrefix := "provided key share has a different public key than the one registered for that signer in the configuration" + tt := &tableTest{ + Ciphersuite: frost.Ristretto255, + threshold: 2, + maxSigners: 3, + } + configuration, keyShares := makeConfAndShares(t, tt) + + random := tt.ECGroup().NewScalar().Random() + keyShare := &frost.KeyShare{ + Secret: random, + GroupPublicKey: keyShares[0].GroupPublicKey, + PublicKeyShare: secretsharing.PublicKeyShare{ + PublicKey: tt.ECGroup().Base().Multiply(random), + ID: keyShares[0].ID, + Group: keyShares[0].Group, + }, + } + + if err := configuration.ValidateKeyShare(keyShare); err == nil || err.Error() != expectedErrorPrefix { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } +} + func TestConfiguration_Signer_NotVerified(t *testing.T) { ciphersuite := frost.Ristretto255 threshold := uint64(2) @@ -471,11 +597,11 @@ func TestConfiguration_Signer_NotVerified(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if _, err := configuration.Signer(keyShares[0]); err != nil { @@ -493,11 +619,11 @@ func TestConfiguration_Signer_BadConfig(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: 2, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: 2, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if _, err := configuration.Signer(keyShares[0]); err == nil || @@ -506,6 +632,22 @@ func TestConfiguration_Signer_BadConfig(t *testing.T) { } } +func TestConfiguration_Singer_BadKeyShare(t *testing.T) { + expectedErrorPrefix := "provided key share is nil" + tt := &tableTest{ + Ciphersuite: frost.Ristretto255, + threshold: 2, + maxSigners: 3, + } + + configuration := makeConf(t, tt) + + if _, err := configuration.Signer(nil); err == nil || + !strings.HasPrefix(err.Error(), expectedErrorPrefix) { + t.Fatalf("expected %q, got %q", expectedErrorPrefix, err) + } +} + func TestConfiguration_VerifySignatureShare_BadPrep(t *testing.T) { expectedErrorPrefix := internal.ErrInvalidCiphersuite @@ -517,11 +659,11 @@ func TestConfiguration_VerifySignatureShare_BadPrep(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: 2, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: 2, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.VerifySignatureShare(nil, nil, nil); err == nil || @@ -659,7 +801,7 @@ func TestConfiguration_VerifySignatureShare_MissingPublicKey(t *testing.T) { t.Fatal(err) } - configuration.SignerPublicKeys = slices.Delete(configuration.SignerPublicKeys, 0, 1) + configuration.SignerPublicKeyShares = slices.Delete(configuration.SignerPublicKeyShares, 0, 1) expectedErrorPrefix := fmt.Sprintf("no public key registered for signer 1") if err := configuration.VerifySignatureShare(sigShare, message, coms[1:]); err == nil || diff --git a/tests/encoding_test.go b/tests/encoding_test.go index adc2b80..cc07ef1 100644 --- a/tests/encoding_test.go +++ b/tests/encoding_test.go @@ -29,11 +29,11 @@ func makeConfAndShares(t *testing.T, test *tableTest) (*frost.Configuration, []* publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: test.Ciphersuite, - Threshold: test.threshold, - MaxSigners: test.maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: test.Ciphersuite, + Threshold: test.threshold, + MaxSigners: test.maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err != nil { @@ -100,16 +100,16 @@ func compareConfigurations(t *testing.T, c1, c2 *frost.Configuration, expectedMa t.Fatalf("expected matching GroupPublicKey: %q / %q", c1.Ciphersuite, c2.Ciphersuite) } - if len(c1.SignerPublicKeys) != len(c2.SignerPublicKeys) { + if len(c1.SignerPublicKeyShares) != len(c2.SignerPublicKeyShares) { t.Fatalf( - "expected matching SignerPublicKeys lengths: %q / %q", - len(c1.SignerPublicKeys), - len(c2.SignerPublicKeys), + "expected matching SignerPublicKeyShares lengths: %q / %q", + len(c1.SignerPublicKeyShares), + len(c2.SignerPublicKeyShares), ) } - for i, p1 := range c1.SignerPublicKeys { - p2 := c2.SignerPublicKeys[i] + for i, p1 := range c1.SignerPublicKeyShares { + p2 := c2.SignerPublicKeyShares[i] if err := comparePublicKeyShare(p1, p2); !expectedMatch && err != nil { t.Fatal(err) } @@ -387,11 +387,11 @@ func TestEncoding_Configuration_InvalidPublicKeyShare(t *testing.T) { publicKeyShares := getPublicKeyShares(keyShares) configuration := &frost.Configuration{ - Ciphersuite: test.Ciphersuite, - Threshold: test.threshold, - MaxSigners: test.maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: test.Ciphersuite, + Threshold: test.threshold, + MaxSigners: test.maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } g := group.Group(test.Ciphersuite) pksSize := len(publicKeyShares[0].Encode()) diff --git a/tests/frost_test.go b/tests/frost_test.go index 9877d61..3543595 100644 --- a/tests/frost_test.go +++ b/tests/frost_test.go @@ -59,11 +59,11 @@ func runFrost( // Set up configuration. configuration := &frost.Configuration{ - Ciphersuite: test.Ciphersuite, - Threshold: threshold, - MaxSigners: maxSigners, - GroupPublicKey: groupPublicKey, - SignerPublicKeys: publicKeyShares, + Ciphersuite: test.Ciphersuite, + Threshold: threshold, + MaxSigners: maxSigners, + GroupPublicKey: groupPublicKey, + SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err != nil { diff --git a/tests/vector_utils_test.go b/tests/vector_utils_test.go index 597a1f6..36005d9 100644 --- a/tests/vector_utils_test.go +++ b/tests/vector_utils_test.go @@ -205,11 +205,11 @@ type testRoundTwoOutputs struct { func makeFrostConfig(c frost.Ciphersuite, threshold, maxSigners uint) *frost.Configuration { return &frost.Configuration{ - Ciphersuite: c, - Threshold: uint64(threshold), - MaxSigners: uint64(maxSigners), - GroupPublicKey: nil, - SignerPublicKeys: nil, + Ciphersuite: c, + Threshold: uint64(threshold), + MaxSigners: uint64(maxSigners), + GroupPublicKey: nil, + SignerPublicKeyShares: nil, } } @@ -313,10 +313,10 @@ func (v testVector) decode(t *testing.T) *test { inputs := v.Inputs.decode(t, conf.Ciphersuite.ECGroup()) conf.GroupPublicKey = inputs.GroupPublicKey - conf.SignerPublicKeys = make([]*frost.PublicKeyShare, len(inputs.Participants)) + conf.SignerPublicKeyShares = make([]*frost.PublicKeyShare, len(inputs.Participants)) for i, ks := range inputs.Participants { - conf.SignerPublicKeys[i] = ks.Public() + conf.SignerPublicKeyShares[i] = ks.Public() } if err := conf.Configuration.Init(); err != nil {