Skip to content

Commit

Permalink
Merge branch 'main' into one-curve
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasz-zimnoch committed Oct 15, 2024
2 parents d288842 + b12f0f1 commit 915179b
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 2 deletions.
34 changes: 33 additions & 1 deletion frost/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,31 @@ package frost

import (
"errors"
"fmt"
"math/big"
)

// Coordinator represents a coordinator of the [FROST] signing protocol.
type Coordinator struct {
Participant
threshold int
groupSize int
}

// NewCoordinator creates a new [FROST] Coordinator instance.
func NewCoordinator(
ciphersuite Ciphersuite,
publicKey *Point,
threshold int,
groupSize int,
) *Coordinator {
return &Coordinator{
Participant: Participant{
ciphersuite: ciphersuite,
publicKey: publicKey,
},
threshold: threshold,
groupSize: groupSize,
}
}

Expand Down Expand Up @@ -64,7 +71,32 @@ func (c *Coordinator) Aggregate(
// - (R, z), a Schnorr signature consisting of an Element R and
// Scalar z.

// TODO: validate the number of signature shares
// MIN_PARTICIPANTS <= NUM_PARTICIPANTS
if len(signatureShares) < c.threshold {
return nil, fmt.Errorf(
"not enough shares; has [%d] for threshold [%d]",
len(signatureShares),
c.threshold,
)
}

// NUM_PARTICIPANTS <= MAX_PARTICIPANTS
if len(signatureShares) > c.groupSize {
return nil, fmt.Errorf(
"too many shares; has [%d] for group size [%d]",
len(signatureShares),
c.groupSize,
)
}

if len(commitments) != len(signatureShares) {
return nil, fmt.Errorf(
"the number of commitments and signature shares do not match; "+
"has [%d] commitments and [%d] signature shares",
len(commitments),
len(signatureShares),
)
}

validationErrors, _ := c.validateGroupCommitmentsBase(commitments)
if len(validationErrors) != 0 {
Expand Down
65 changes: 65 additions & 0 deletions frost/coordinator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package frost

import (
"math/big"
"testing"

"threshold.network/roast/internal/testutils"
)

// This test covers failure paths in the Aggregate function. The happy path is
// covered as a part of the roundtrip test in frost_test.go.
func TestAggregate_Failures(t *testing.T) {
message := []byte("For even the very wise cannot see all ends")

signers := createSigners(t)
publicKey := signers[0].publicKey

nonces, commitments := executeRound1(t, signers)
signatureShares := executeRound2(t, signers, message, nonces, commitments)

coordinator := NewCoordinator(ciphersuite, publicKey, threshold, groupSize)

tests := map[string]struct {
commitments []*NonceCommitment
signatureShares []*big.Int
expectedErr string
}{
"number of commitments and signature shares do not match": {
commitments: commitments[:groupSize],
signatureShares: signatureShares[:groupSize-1],
expectedErr: "the number of commitments and signature shares do not match; has [100] commitments and [99] signature shares",
},
"number of commitments and signature shares below threshold": {
commitments: commitments[:threshold-1],
signatureShares: signatureShares[:threshold-1],
expectedErr: "not enough shares; has [50] for threshold [51]",
},
"number of commitments and signatures above group size": {
commitments: append(commitments, commitments[0]),
signatureShares: append(signatureShares, signatureShares[0]),
expectedErr: "too many shares; has [101] for group size [100]",
},
}

for testName, test := range tests {
t.Run(testName, func(t *testing.T) {
signature, err := coordinator.Aggregate(
message,
test.commitments,
test.signatureShares,
)

testutils.AssertStringsEqual(
t,
"aggregate signature share error message",
test.expectedErr,
err.Error(),
)

if signature != nil {
t.Error("expected nil signature")
}
})
}
}
2 changes: 1 addition & 1 deletion frost/frost_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func TestFrostRoundtrip(t *testing.T) {
nonces, commitments := executeRound1(t, signers)
signatureShares := executeRound2(t, signers, message, nonces, commitments)

coordinator := NewCoordinator(ciphersuite, publicKey)
coordinator := NewCoordinator(ciphersuite, publicKey, threshold, groupSize)
signature, err := coordinator.Aggregate(message, commitments, signatureShares)
if err != nil {
t.Fatal(err)
Expand Down

0 comments on commit 915179b

Please sign in to comment.