Skip to content

Commit

Permalink
rename groupublickey to verificationkey, add tests
Browse files Browse the repository at this point in the history
Signed-off-by: bytemare <[email protected]>
  • Loading branch information
bytemare committed Oct 8, 2024
1 parent 4f1004e commit 8050e3a
Show file tree
Hide file tree
Showing 19 changed files with 227 additions and 153 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ configuration := &frost.Configuration{
Ciphersuite: ciphersuite,
Threshold: threshold,
MaxSigners: maxSigners,
GroupPublicKey: groupPublicKey,
VerificationKey: verificationKey,
SignerPublicKeyShares: publicKeyShares,
}

Expand Down
2 changes: 1 addition & 1 deletion coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (c *Configuration) prepareSignatureShareVerification(message []byte,
return nil, nil, nil, fmt.Errorf("invalid list of commitments: %w", err)
}

groupCommitment, bindingFactors := commitments.groupCommitmentAndBindingFactors(c.GroupPublicKey, message)
groupCommitment, bindingFactors := commitments.groupCommitmentAndBindingFactors(c.VerificationKey, message)
participants := commitments.ParticipantsScalar()

return groupCommitment, bindingFactors, participants, nil
Expand Down
4 changes: 2 additions & 2 deletions debug/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ func TrustedDealerKeygen(
shares := make([]*keys.KeyShare, maxSigners)
for i, k := range privateKeyShares {
shares[i] = &keys.KeyShare{
Secret: k.Secret,
GroupPublicKey: coms[0],
Secret: k.Secret,
VerificationKey: coms[0],
PublicKeyShare: keys.PublicKeyShare{
PublicKey: g.Base().Multiply(k.Secret),
VssCommitment: coms,
Expand Down
22 changes: 11 additions & 11 deletions encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func (c *Configuration) Encode() []byte {
binary.LittleEndian.PutUint16(out[3:5], c.MaxSigners)
binary.LittleEndian.PutUint16(out[5:7], uint16(len(c.SignerPublicKeyShares)))

out = append(out, c.GroupPublicKey.Encode()...)
out = append(out, c.VerificationKey.Encode()...)

for _, pk := range c.SignerPublicKeyShares {
out = append(out, pk.Encode()...)
Expand Down Expand Up @@ -165,7 +165,7 @@ func (c *Configuration) decode(header *confHeader, data []byte) error {
Ciphersuite: Ciphersuite(header.g),
Threshold: uint16(header.t),
MaxSigners: uint16(header.n),
GroupPublicKey: gpk,
VerificationKey: gpk,
SignerPublicKeyShares: pks,
group: header.g,
verified: false,
Expand Down Expand Up @@ -198,7 +198,7 @@ func (c *Configuration) decode(header *confHeader, data []byte) error {
c.Ciphersuite = conf.Ciphersuite
c.Threshold = conf.Threshold
c.MaxSigners = conf.MaxSigners
c.GroupPublicKey = gpk
c.VerificationKey = gpk
c.SignerPublicKeyShares = pks
c.group = ecc.Group(conf.Ciphersuite)
c.verified = true
Expand Down Expand Up @@ -364,9 +364,9 @@ func (s *Signer) Decode(data []byte) error {
nLambdas := int(binary.LittleEndian.Uint16(data[header.length+4 : header.length+6]))
g := conf.group
_, nLen := encodedLength(encNonceCommitment, g)
_, lLem := encodedLength(encLambda, g)
_, llen := encodedLength(encLambda, g)

_, length := encodedLength(encSigner, g, header.length, ksLen, nCommitments*nLen, nLambdas*lLem)
_, length := encodedLength(encSigner, g, header.length, ksLen, nCommitments*nLen, nLambdas*llen)
if len(data) != length {
return fmt.Errorf(errFmt, errDecodeSignerPrefix, errInvalidLength)
}
Expand All @@ -383,9 +383,9 @@ func (s *Signer) Decode(data []byte) error {
}

offset += ksLen
stop := offset + nLambdas*lLem
stop := offset + nLambdas*llen

lambdaRegistry := make(internal.LambdaRegistry, lLem)
lambdaRegistry := make(internal.LambdaRegistry, llen)
if err = lambdaRegistry.Decode(g, data[offset:stop]); err != nil {
return fmt.Errorf("%w: failed to decode lambda registry in signer: %w", errDecodeSignerPrefix, err)
}
Expand Down Expand Up @@ -692,15 +692,15 @@ type shadowInit interface {
type configurationShadow Configuration

func (c *configurationShadow) init(g ecc.Group) {
c.GroupPublicKey = g.NewElement()
c.VerificationKey = g.NewElement()
}

type signerShadow Signer

func (s *signerShadow) init(g ecc.Group) {
s.KeyShare = &keys.KeyShare{
Secret: g.NewScalar(),
GroupPublicKey: g.NewElement(),
Secret: g.NewScalar(),
VerificationKey: g.NewElement(),
PublicKeyShare: keys.PublicKeyShare{
PublicKey: g.NewElement(),
VssCommitment: nil,
Expand All @@ -709,7 +709,7 @@ func (s *signerShadow) init(g ecc.Group) {
},
}
s.Configuration = &Configuration{
GroupPublicKey: g.NewElement(),
VerificationKey: g.NewElement(),
SignerPublicKeyShares: nil,
Threshold: 0,
MaxSigners: 0,
Expand Down
42 changes: 31 additions & 11 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"
"strings"

"github.com/bytemare/ecc"
"github.com/bytemare/secret-sharing/keys"

"github.com/bytemare/frost"
Expand All @@ -31,7 +32,7 @@ func Example_signer() {
// and their signing share.
// This example uses a centralised trusted dealer, but it is strongly recommended to use distributed key generation,
// e.g. from github.com/bytemare/dkg, which is compatible with FROST.
secretKeyShares, groupPublicKey, _ := debug.TrustedDealerKeygen(ciphersuite, nil, threshold, maxSigners)
secretKeyShares, verificationKey, _ := debug.TrustedDealerKeygen(ciphersuite, nil, threshold, maxSigners)

// Since we used a centralised key generation, we only take the first key share for our participant.
participantSecretKeyShare := secretKeyShares[0]
Expand All @@ -50,7 +51,7 @@ func Example_signer() {
Ciphersuite: ciphersuite,
Threshold: threshold,
MaxSigners: maxSigners,
GroupPublicKey: groupPublicKey,
VerificationKey: verificationKey,
SignerPublicKeyShares: publicKeyShares,
}

Expand Down Expand Up @@ -123,7 +124,7 @@ func Example_coordinator() {
// We assume you already have a pool of participants with distinct non-zero identifiers and their signing share.
// The following block uses a centralised trusted dealer to do this, but it is strongly recommended to use
// distributed key generation, e.g. from github.com/bytemare/dkg, which is compatible with FROST.
secretKeyShares, groupPublicKey, _ := debug.TrustedDealerKeygen(ciphersuite, nil, threshold, maxSigners)
secretKeyShares, verificationKey, _ := debug.TrustedDealerKeygen(ciphersuite, nil, threshold, maxSigners)
participantSecretKeyShares := secretKeyShares[:threshold]
participants := make([]*frost.Signer, threshold)

Expand All @@ -139,7 +140,7 @@ func Example_coordinator() {
Ciphersuite: ciphersuite,
Threshold: threshold,
MaxSigners: maxSigners,
GroupPublicKey: groupPublicKey,
VerificationKey: verificationKey,
SignerPublicKeyShares: publicKeyShares,
}

Expand Down Expand Up @@ -189,7 +190,7 @@ func Example_coordinator() {
// Verify the signature and identify potential foul players. Note that since we set verify to true when calling
// AggregateSignatures, the following is redundant.
// Anyone can verify the signature given the ciphersuite parameter, message, and the group public key.
if err = frost.VerifySignature(ciphersuite, message, signature, groupPublicKey); err != nil {
if err = frost.VerifySignature(ciphersuite, message, signature, verificationKey); err != nil {
// At this point one should try to identify which participant's signature share is invalid and act on it.
// This verification is done as follows:
for _, signatureShare := range signatureShares {
Expand All @@ -216,13 +217,32 @@ func Example_coordinator() {
// Example_key_generation shows how to create keys in a threshold setup with a centralized trusted dealer.
// - a decentralised protocol described in the original FROST paper
func Example_key_generation_centralised_trusted_dealer() {
panic(nil)
maxSigners := uint16(5)
threshold := uint16(3)
ciphersuite := frost.Default

optionnalSecretKey := ciphersuite.Group().NewScalar().Random()
keyShares, verificationKey, vssCommitment := debug.TrustedDealerKeygen(
ciphersuite,
optionnalSecretKey,
threshold,
maxSigners,
)

fmt.Printf("Created %d key shares with %d vss commitments and %d verification key.",
len(keyShares),
len(vssCommitment),
len([]*ecc.Element{verificationKey}), // yes that line is ugly but it's pretext to use the variable produced.
)

// Output: Created 5 key shares with 3 vss commitments and 1 verification key.
}

// Example_key_generation shows how to create keys in a threshold setup with distributed key generation described in
// the original FROST paper.
func Example_key_generation_decentralised() {
panic(nil)
fmt.Println("Visit github.com/bytemare/dkg for an example and documentation.")
// Output: Visit github.com/bytemare/dkg for an example and documentation.
}

// Example_existing_keys shows how to import existing keys in their canonical byte encoding.
Expand Down Expand Up @@ -361,16 +381,16 @@ func Example_key_deserialization() {

// Example_deserialize shows how to encode and decode a FROST messages.
func Example_deserialize() {
groupPublicKeyHex := "74144431f64b052a173c2505e4224a6cc5f3e81d587d4f23369e1b2b1fd0d427"
verificationKeyHex := "74144431f64b052a173c2505e4224a6cc5f3e81d587d4f23369e1b2b1fd0d427"
publicKeySharesHex := []string{
"010100000000003c5ff80cd593a3b7e9007fdbc2b8fe6caee380e7d23eb7ba35160a5b7a51cb08",
"0102000000000002db540a823f17b975d9eb206ccfbcf3a7667a0365ec1918fa2c3bb69acb105c",
"010300000000008cff0ae1ded90e77095b55218d3632cd90b669d05c888bca26093681e5250870",
}

g := frost.Default.Group()
groupPublicKey := g.NewElement()
if err := groupPublicKey.DecodeHex(groupPublicKeyHex); err != nil {
verificationKey := g.NewElement()
if err := verificationKey.DecodeHex(verificationKeyHex); err != nil {
fmt.Println(err)
}

Expand All @@ -389,7 +409,7 @@ func Example_deserialize() {
Ciphersuite: frost.Default,
Threshold: 2,
MaxSigners: 3,
GroupPublicKey: groupPublicKey,
VerificationKey: verificationKey,
SignerPublicKeyShares: publicKeyShares,
}

Expand Down
18 changes: 9 additions & 9 deletions frost.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (c Ciphersuite) Group() ecc.Group {

// Configuration holds the Configuration for a signing session.
type Configuration struct {
GroupPublicKey *ecc.Element `json:"groupPublicKey"`
VerificationKey *ecc.Element `json:"verificationKey"`
SignerPublicKeyShares []*keys.PublicKeyShare `json:"signerPublicKeyShares"`
Threshold uint16 `json:"threshold"`
MaxSigners uint16 `json:"maxSigners"`
Expand Down Expand Up @@ -184,7 +184,7 @@ func (c *Configuration) ValidateKeyShare(keyShare *keys.KeyShare) error {
return err
}

if !c.GroupPublicKey.Equal(keyShare.GroupPublicKey) {
if !c.VerificationKey.Equal(keyShare.VerificationKey) {
return errKeyShareNotMatch
}

Expand Down Expand Up @@ -277,7 +277,7 @@ func (c *Configuration) verifyConfiguration() error {
return errInvalidMaxSignersOrder

Check warning on line 277 in frost.go

View check run for this annotation

Codecov / codecov/patch

frost.go#L277

Added line #L277 was not covered by tests
}

if err := c.validateGroupElement(c.GroupPublicKey); err != nil {
if err := c.validateGroupElement(c.VerificationKey); err != nil {
return fmt.Errorf("invalid group public key, the key %w", err)
}

Expand Down Expand Up @@ -322,7 +322,7 @@ func (c *Configuration) validateGroupElement(e *ecc.Element) error {
}

func (c *Configuration) challenge(lambda *ecc.Scalar, message []byte, groupCommitment *ecc.Element) *ecc.Scalar {
chall := SchnorrChallenge(c.group, message, groupCommitment, c.GroupPublicKey)
chall := SchnorrChallenge(c.group, message, groupCommitment, c.VerificationKey)
return chall.Multiply(lambda)
}

Expand Down Expand Up @@ -387,7 +387,7 @@ func NewPublicKeyShare(c Ciphersuite, id uint16, signerPublicKey []byte) (*keys.
func NewKeyShare(
c Ciphersuite,
id uint16,
secretShare, signerPublicKey, groupPublicKey []byte,
secretShare, signerPublicKey, verificationKey []byte,
) (*keys.KeyShare, error) {
pks, err := NewPublicKeyShare(c, id, signerPublicKey)
if err != nil {
Expand All @@ -407,13 +407,13 @@ func NewKeyShare(
}

gpk := g.NewElement()
if err = gpk.Decode(groupPublicKey); err != nil {
if err = gpk.Decode(verificationKey); err != nil {
return nil, fmt.Errorf("could not decode the group public key: %w", err)
}

return &keys.KeyShare{
Secret: s,
GroupPublicKey: gpk,
PublicKeyShare: *pks,
Secret: s,
VerificationKey: gpk,
PublicKeyShare: *pks,
}, nil
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ go 1.23.1

require (
filippo.io/edwards25519 v1.1.0
github.com/bytemare/dkg v0.0.0-20241004153610-04af7b423593
github.com/bytemare/dkg v0.0.0-20241007182121-23ea4d549880
github.com/bytemare/ecc v0.8.2
github.com/bytemare/hash v0.3.0
github.com/bytemare/secret-sharing v0.6.0
github.com/bytemare/secret-sharing v0.7.0
github.com/gtank/ristretto255 v0.1.2
)

Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
filippo.io/nistec v0.0.3 h1:h336Je2jRDZdBCLy2fLDUd9E2unG32JLwcJi0JQE9Cw=
filippo.io/nistec v0.0.3/go.mod h1:84fxC9mi+MhC2AERXI4LSa8cmSVOzrFikg6hZ4IfCyw=
github.com/bytemare/dkg v0.0.0-20241004153610-04af7b423593 h1:pIVaRXwCFangFes/2adBWxQskwWbWU5DlgO/i1f0Q0w=
github.com/bytemare/dkg v0.0.0-20241004153610-04af7b423593/go.mod h1:uu0zK5IObiwEexMegqZe/wLyK+HZTstGnrz47ZdDkiI=
github.com/bytemare/dkg v0.0.0-20241007182121-23ea4d549880 h1:KoEDglTZoJx0EaWdmYkvdrPNxAr/Hkc1WgWvH2b/XCw=
github.com/bytemare/dkg v0.0.0-20241007182121-23ea4d549880/go.mod h1:szhmKyIBs11r5IPo/jGqwxfmnpELmbj8okgdKxA+QVs=
github.com/bytemare/ecc v0.8.2 h1:MN+Ah48hApFpzJgIMa1xOrK7/R5uwCV06dtJyuHAi3Y=
github.com/bytemare/ecc v0.8.2/go.mod h1:dvkSikSCejw8YaTdJs6lZSN4qz9B4PC5PtGq+CRDmHk=
github.com/bytemare/hash v0.3.0 h1:RqFMt3mqpF7UxLdjBrsOZm/2cz0cQiAOnYc9gDLopWE=
Expand All @@ -12,8 +12,8 @@ github.com/bytemare/hash2curve v0.3.0 h1:41Npcbc+u/E252A5aCMtxDcz7JPkkX1QzShneTF
github.com/bytemare/hash2curve v0.3.0/go.mod h1:itj45U8uqvCtWC0eCswIHVHswXcEHkpFui7gfJdPSfQ=
github.com/bytemare/secp256k1 v0.1.6 h1:5pOA84UBBTPTUmCkjtH6jHrbvZSh2kyxG0mW/OjSih0=
github.com/bytemare/secp256k1 v0.1.6/go.mod h1:Zr7o3YCog5jKx5JwgYbj984gRIqVioTDZMSDo1y0zgE=
github.com/bytemare/secret-sharing v0.6.0 h1:/gQhsC3BY2pn7nIl+1sQDtI4c9IfkjuTbBXsvh922UM=
github.com/bytemare/secret-sharing v0.6.0/go.mod h1:CQ7ALe5CIbvnEGhcF50LKu9brAki7efQPT3d/UUhzQQ=
github.com/bytemare/secret-sharing v0.7.0 h1:ayJWEhwQzeChtavB4WrqufRJPnG5u2IePe1MEeJJEgs=
github.com/bytemare/secret-sharing v0.7.0/go.mod h1:Qzrf83Sk36D2NGJpk1/0H6YJx0SnsiOtrS6zaiISL2o=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
Expand Down
11 changes: 9 additions & 2 deletions internal/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
)

// ComputeLambda derives the interpolating value for id in the polynomial made by the participant identifiers.
// This function assumes that:
// This function is not public to protect its usage, as the following conditions MUST be met.
// - id is non-nil and != 0.
// - every scalar in participants is non-nil and != 0.
// - there are no duplicates in participants.
Expand All @@ -43,8 +43,11 @@ func ComputeLambda(g ecc.Group, id uint16, participants []*ecc.Scalar) *ecc.Scal

// A Lambda is the interpolating value for a given id in the polynomial made by the participant identifiers.
type Lambda struct {
// Value is the actual Lambda value.
Value *ecc.Scalar `json:"value"`
Group ecc.Group `json:"group"`

// Group is necessary so the Value scalar can reliably be decoded in the right group.
Group ecc.Group `json:"group"`
}

type lambdaShadow Lambda
Expand Down Expand Up @@ -110,6 +113,10 @@ func (l LambdaRegistry) Get(participants []uint16) *ecc.Scalar {

// GetOrNew returns the recorded Lambda for the list of participants, or created, records, and returns a new one if
// it wasn't found.
// This function assumes that:
// - id is non-nil and != 0.
// - every scalar in participants is non-nil and != 0.
// - there are no duplicates in participants.
func (l LambdaRegistry) GetOrNew(g ecc.Group, id uint16, participants []uint16) *ecc.Scalar {
lambda := l.Get(participants)
if lambda == nil {
Expand Down
2 changes: 1 addition & 1 deletion signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func (s *Signer) Sign(message []byte, commitments CommitmentList) (*SignatureSha
}

groupCommitment, bindingFactors := commitments.groupCommitmentAndBindingFactors(
s.Configuration.GroupPublicKey,
s.Configuration.VerificationKey,
message,
)

Expand Down
4 changes: 2 additions & 2 deletions tests/commitment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestCommitment_Validate_InvalidConfiguration(t *testing.T) {
Ciphersuite: tt.Ciphersuite,
Threshold: tt.threshold,
MaxSigners: tt.maxSigners,
GroupPublicKey: nil,
VerificationKey: nil,
SignerPublicKeyShares: nil,
}

Expand Down Expand Up @@ -269,7 +269,7 @@ func TestCommitmentList_Validate_InvalidConfiguration(t *testing.T) {
Ciphersuite: tt.Ciphersuite,
Threshold: tt.threshold,
MaxSigners: tt.maxSigners,
GroupPublicKey: nil,
VerificationKey: nil,
SignerPublicKeyShares: nil,
}

Expand Down
Loading

0 comments on commit 8050e3a

Please sign in to comment.