Documentation
¶
Overview ¶
Package frost implements FROST, the Flexible Round-Optimized Schnorr Threshold (FROST) signing protocol.
Example (Coordinator) ¶
Example_coordinator shows how to aggregate signature shares produced by signers into the final signature and verify a final FROST signature.
package main import ( "fmt" "github.com/bytemare/secret-sharing/keys" "github.com/bytemare/frost" "github.com/bytemare/frost/debug" ) func main() { maxSigners := uint16(5) threshold := uint16(3) message := []byte("example message") ciphersuite := frost.Default // 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, verificationKey, _ := debug.TrustedDealerKeygen(ciphersuite, nil, threshold, maxSigners) participantSecretKeyShares := secretKeyShares[:threshold] participants := make([]*frost.Signer, threshold) // At key generation, each participant must send their public key share to the coordinator, and the collection must // be broadcast to every participant. publicKeyShares := make([]*keys.PublicKeyShare, len(secretKeyShares)) for i, sk := range secretKeyShares { publicKeyShares[i] = sk.Public() } // 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, VerificationKey: verificationKey, SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err != nil { panic(err) } // Create a participant on each instance for i, ks := range participantSecretKeyShares { signer, err := configuration.Signer(ks) if err != nil { panic(err) } participants[i] = signer } // Pre-commit commitments := make(frost.CommitmentList, threshold) for i, p := range participants { commitments[i] = p.Commit() } commitments.Sort() // Sign signatureShares := make([]*frost.SignatureShare, threshold) for i, p := range participants { var err error signatureShares[i], err = p.Sign(message, commitments) if err != nil { panic(err) } } // Everything above was a simulation of commitment and signing rounds to produce the signature shares. // The following shows how to aggregate these shares, and if verification fails, how to identify a misbehaving signer. // The coordinator assembles the shares. If the verify argument is set to true, AggregateSignatures will internally // verify each signature share and return an error on the first that is invalid. It will also verify whether the // output signature is valid. signature, err := configuration.AggregateSignatures(message, signatureShares, commitments, true) if err != nil { panic(err) } // 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, 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 { if err := configuration.VerifySignatureShare(signatureShare, message, commitments); err != nil { panic( fmt.Sprintf( "participant %v produced an invalid signature share: %s", signatureShare.SignerIdentifier, err, ), ) } } fmt.Println(err) panic("Signature verification failed.") } fmt.Println("Signature is valid.") }
Output: Signature is valid.
Example (Deserialize) ¶
Example_deserialize shows how to encode and decode a FROST messages.
package main import ( "bytes" "encoding/hex" "fmt" "github.com/bytemare/secret-sharing/keys" "github.com/bytemare/frost" ) func main() { verificationKeyHex := "74144431f64b052a173c2505e4224a6cc5f3e81d587d4f23369e1b2b1fd0d427" publicKeySharesHex := []string{ "010100000000003c5ff80cd593a3b7e9007fdbc2b8fe6caee380e7d23eb7ba35160a5b7a51cb08", "0102000000000002db540a823f17b975d9eb206ccfbcf3a7667a0365ec1918fa2c3bb69acb105c", "010300000000008cff0ae1ded90e77095b55218d3632cd90b669d05c888bca26093681e5250870", } g := frost.Default.Group() verificationKey := g.NewElement() if err := verificationKey.DecodeHex(verificationKeyHex); err != nil { fmt.Println(err) } publicKeyShares := make([]*keys.PublicKeyShare, len(publicKeySharesHex)) for i, p := range publicKeySharesHex { publicKeyShares[i] = new(keys.PublicKeyShare) if err := publicKeyShares[i].DecodeHex(p); err != nil { fmt.Println(err) } } // This is how to set up the Configuration for FROST, the same for every signer and the coordinator. // Note that every configuration setup for a Signer needs the public key shares of all other signers participating // in a signing session (at least for the Sign() step). configuration := &frost.Configuration{ Ciphersuite: frost.Default, Threshold: 2, MaxSigners: 3, VerificationKey: verificationKey, SignerPublicKeyShares: publicKeyShares, } // Decoding a commitment. commitment1Hex := "01963090de7d665c5101009073f1a30f4fb9a84275206002fc4394aea7a6cbaf944a7b2f0ae" + "9143f39fe62808704f776fccfc0080e90e59fdf9bf0156141732728d41fb15554b46a037a40" commitment2Hex := "017615b41957cca8d70200c2d3d3e8133d18daf95aee5371f397771118be5f3917058502637" + "0fa893828462400bfab522a542010e70b2b6d4eb388f92b47d6e01abbc16ea24aed5b4fb652" commitment1 := new(frost.Commitment) if err := commitment1.DecodeHex(commitment1Hex); err != nil { fmt.Println(err) } commitment2 := new(frost.Commitment) if err := commitment2.DecodeHex(commitment2Hex); err != nil { fmt.Println(err) } // You can individually check a commitment if err := configuration.ValidateCommitment(commitment1); err != nil { fmt.Println(err) } // You can then assemble these commitments to build a list. commitmentList := make(frost.CommitmentList, 2) commitmentList[0] = commitment1 commitmentList[1] = commitment2 encodedCommitmentListBytes := commitmentList.Encode() encodedCommitmentListHex := hex.EncodeToString(encodedCommitmentListBytes) // Note that the commitments are the same, but serializing using a CommitmentList is slightly different (3 bytes more) // since it has a length prefix header. commitmentListHex := "010200" + "01963090de7d665c5101009073f1a30f4fb9a84275206002fc4394aea7a6cbaf944a7b2f0ae" + "9143f39fe62808704f776fccfc0080e90e59fdf9bf0156141732728d41fb15554b46a037a40" + "017615b41957cca8d70200c2d3d3e8133d18daf95aee5371f397771118be5f3917058502637" + "0fa893828462400bfab522a542010e70b2b6d4eb388f92b47d6e01abbc16ea24aed5b4fb652" if commitmentListHex != encodedCommitmentListHex { fmt.Println( "something went wrong when re-encoding the first commitment list, which should yield the same output", ) } // Decoding a whole commitment list. decodedCommitmentList, err := frost.DecodeList(encodedCommitmentListBytes) if err != nil { fmt.Println(err) } reEncodedListBytes := decodedCommitmentList.Encode() if !bytes.Equal(reEncodedListBytes, encodedCommitmentListBytes) { fmt.Println( "something went wrong when re-encoding the second commitment list, which should yield the same output", ) } }
Output:
Example (Existing_keys) ¶
Example_existing_keys shows how to import existing keys in their canonical byte encoding.
package main import ( "encoding/hex" "fmt" "strings" "github.com/bytemare/frost" ) func main() { ciphersuite := frost.Ristretto255 id := 5 signerSecretKey := "941c0685dc7c567dd206a39bce556008367fdf633b56c010cde5561435f75b0e" signerPublicKey := "d4b9a3acda8acb133c1eff7b99838908c3f9271569c734591ac8f609f321d01a" verificationKey := "4400e5808c12c6ef9dc751135acf76edfa73780c08e766537bb6c49bea591872" fmt.Println("Decoding to key share:") fmt.Printf("- signer identifier: %d\n", id) fmt.Printf("- signer secret key: %s\n", signerSecretKey) fmt.Printf("- signer public key: %s\n", signerPublicKey) fmt.Printf("- global verification key: %s\n", verificationKey) // First, let's rebuilt a public key share. signerPublicKeyBytes, err := hex.DecodeString(signerPublicKey) if err != nil { fmt.Println(err) } signerPublicKeyShare, err := frost.NewPublicKeyShare(ciphersuite, uint16(id), signerPublicKeyBytes) if err != nil { fmt.Println(err) } encodedPublicKeyShare := hex.EncodeToString(signerPublicKeyShare.Encode()) fmt.Printf( "Decoded individual elements to a public key share, and re-encoded as a whole: %s\n", encodedPublicKeyShare, ) // Now, we rebuilt a private key share. signerSecretKeyBytes, err := hex.DecodeString(signerSecretKey) if err != nil { fmt.Println(err) } verificationKeyBytes, err := hex.DecodeString(verificationKey) if err != nil { fmt.Println(err) } signerKeyShare, err := frost.NewKeyShare( ciphersuite, uint16(id), signerSecretKeyBytes, signerPublicKeyBytes, verificationKeyBytes, ) if err != nil { fmt.Println(err) } encodedKeyShare := hex.EncodeToString(signerKeyShare.Encode()) fmt.Printf("Decoded individual elements to a secret key share, and re-encoded as a whole: %s\n", encodedKeyShare) if !strings.HasPrefix(encodedKeyShare, encodedPublicKeyShare) { fmt.Println( "Something went wrong when re-encoding: the public key share must be part of the private key share.", ) } }
Output: Decoding to key share: - signer identifier: 5 - signer secret key: 941c0685dc7c567dd206a39bce556008367fdf633b56c010cde5561435f75b0e - signer public key: d4b9a3acda8acb133c1eff7b99838908c3f9271569c734591ac8f609f321d01a - global verification key: 4400e5808c12c6ef9dc751135acf76edfa73780c08e766537bb6c49bea591872 Decoded individual elements to a public key share, and re-encoded as a whole: 01050000000000d4b9a3acda8acb133c1eff7b99838908c3f9271569c734591ac8f609f321d01a Decoded individual elements to a secret key share, and re-encoded as a whole: 01050000000000d4b9a3acda8acb133c1eff7b99838908c3f9271569c734591ac8f609f321d01a941c0685dc7c567dd206a39bce556008367fdf633b56c010cde5561435f75b0e4400e5808c12c6ef9dc751135acf76edfa73780c08e766537bb6c49bea591872
Example (Key_deserialization) ¶
Example_key_deserialization shows how to encode and decode scalars (e.g. secret keys) and elements (e.g. public keys). Note you must know the group beforehand.
package main import ( "bytes" "encoding/hex" "fmt" "github.com/bytemare/frost" ) func main() { ciphersuite := frost.Ristretto255 group := ciphersuite.Group() // Private keys and scalars. privateKeyHex := "941c0685dc7c567dd206a39bce556008367fdf633b56c010cde5561435f75b0e" privateKey := group.NewScalar() // You can directly decode a hex string to a scalar. if err := privateKey.DecodeHex(privateKeyHex); err != nil { fmt.Println(err) } // Or you can use byte slices. privateKeyBytes, err := hex.DecodeString(privateKeyHex) if err != nil { fmt.Println(err) } if err = privateKey.Decode(privateKeyBytes); err != nil { fmt.Println(err) } if privateKeyHex != privateKey.Hex() { fmt.Println("something went wrong re-encoding the scalar in hex, which should yield the same output") } if !bytes.Equal(privateKeyBytes, privateKey.Encode()) { fmt.Println("something went wrong re-encoding the scalar in bytes, which should yield the same output") } // Same thing for public keys and group elements. publicKeyHex := "d4b9a3acda8acb133c1eff7b99838908c3f9271569c734591ac8f609f321d01a" publicKey := group.NewElement() // You can directly decode a hex string to an element. if err = publicKey.DecodeHex(publicKeyHex); err != nil { panic(err) } // Or you can use byte slices. publicKeyBytes, err := hex.DecodeString(publicKeyHex) if err != nil { panic(err) } if err = publicKey.Decode(publicKeyBytes); err != nil { panic(err) } if publicKeyHex != publicKey.Hex() { fmt.Println("something went wrong re-encoding the element in hex, which should yield the same output") } if !bytes.Equal(publicKeyBytes, publicKey.Encode()) { fmt.Println("something went wrong re-encoding the element in bytes, which should yield the same output") } }
Output:
Example (Key_generation_centralised_trusted_dealer) ¶
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
package main import ( "fmt" "github.com/bytemare/ecc" "github.com/bytemare/frost" "github.com/bytemare/frost/debug" ) func main() { 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_decentralised) ¶
Example_key_generation shows how to create keys in a threshold setup with distributed key generation described in the original FROST paper.
package main import ( "fmt" ) func main() { fmt.Println("Visit github.com/bytemare/dkg for an example and documentation.") }
Output: Visit github.com/bytemare/dkg for an example and documentation.
Example (Signer) ¶
Example_signer shows the execution steps of a FROST participant.
package main import ( "fmt" "github.com/bytemare/secret-sharing/keys" "github.com/bytemare/frost" "github.com/bytemare/frost/debug" ) func main() { maxSigners := uint16(5) threshold := uint16(3) message := []byte("example message") ciphersuite := frost.Default // We assume you already have a pool of participants with distinct non-zero identifiers in [1:maxSingers] // 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, 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] // At key generation, each participant must send their public key share to the coordinator, and the collection must // be broadcast to every participant. publicKeyShares := make([]*keys.PublicKeyShare, len(secretKeyShares)) for i, sk := range secretKeyShares { publicKeyShares[i] = sk.Public() } // This is how to set up the Configuration for FROST, the same for every signer and the coordinator. // Note that every configuration setup for a Signer needs the public key shares of all other signers participating // in a signing session (at least for the Sign() step). configuration := &frost.Configuration{ Ciphersuite: ciphersuite, Threshold: threshold, MaxSigners: maxSigners, VerificationKey: verificationKey, SignerPublicKeyShares: publicKeyShares, } if err := configuration.Init(); err != nil { panic(err) } // Instantiate the participant using its secret share. // A participant (or Signer) can be backed up by serialization, and directly instantiated from that backup. participant, err := configuration.Signer(participantSecretKeyShare) if err != nil { panic(err) } // Step 1: call Commit() on each participant. This will return the participant's single-use commitment for a // signature (which is independent of the future message to sign). // Send this to the coordinator or all other participants (depending on your setup) over an authenticated // channel (confidentiality is not required). // A participant (or Signer) keeps an internal state during the protocol run across the two rounds. // A participant can pre-compute multiple commitments in advance: these commitments can be shared, but the // participant keeps an internal state of corresponding values, so it must the same instance or a backup of it using // the serialization functions. com := participant.Commit() // Step 2: collect the commitments from the other participants and coordinator-chosen message to sign, // and finalize by signing the message. commitments := make(frost.CommitmentList, threshold) commitments[0] = com // This is not part of a participant's flow, but we need to collect the commitments of the other participants for // the demo. { for i := uint16(1); i < threshold; i++ { signer, err := configuration.Signer(secretKeyShares[i]) if err != nil { panic(err) } commitments[i] = signer.Commit() } } // Step 3: The participant receives the commitments from the other signers and the message to sign. // Sign produces a signature share to be sent back to the coordinator. // Execution MUST be aborted upon errors. signatureShare, err := participant.Sign(message, commitments) if err != nil { panic(err) } // This shows how to verify a single signature share if err = configuration.VerifySignatureShare(signatureShare, message, commitments); err != nil { panic(fmt.Sprintf("signature share verification failed: %s", err)) } fmt.Println("Signing successful.") }
Output: Signing successful.
Index ¶
- Constants
- func NewKeyShare(c Ciphersuite, id uint16, secretShare, signerPublicKey, verificationKey []byte) (*keys.KeyShare, error)
- func NewPublicKeyShare(c Ciphersuite, id uint16, signerPublicKey []byte) (*keys.PublicKeyShare, error)
- func SchnorrChallenge(g ecc.Group, msg []byte, r, pk *ecc.Element) *ecc.Scalar
- func VerifySignature(c Ciphersuite, message []byte, signature *Signature, publicKey *ecc.Element) error
- type BindingFactors
- type Ciphersuite
- type Commitment
- type CommitmentList
- type Configuration
- func (c *Configuration) AggregateSignatures(message []byte, sigShares []*SignatureShare, commitments CommitmentList, ...) (*Signature, error)
- func (c *Configuration) Decode(data []byte) error
- func (c *Configuration) DecodeHex(h string) error
- func (c *Configuration) Encode() []byte
- func (c *Configuration) Hex() string
- func (c *Configuration) Init() error
- func (c *Configuration) Signer(keyShare *keys.KeyShare) (*Signer, error)
- func (c *Configuration) UnmarshalJSON(data []byte) error
- func (c *Configuration) ValidateCommitment(commitment *Commitment) error
- func (c *Configuration) ValidateCommitmentList(commitments CommitmentList) error
- func (c *Configuration) ValidateKeyShare(keyShare *keys.KeyShare) error
- func (c *Configuration) ValidatePublicKeyShare(pks *keys.PublicKeyShare) error
- func (c *Configuration) VerifySignatureShare(sigShare *SignatureShare, message []byte, commitments CommitmentList) error
- type Nonce
- type Signature
- type SignatureShare
- type Signer
- func (s *Signer) ClearNonceCommitment(commitmentID uint64)
- func (s *Signer) Commit() *Commitment
- func (s *Signer) Decode(data []byte) error
- func (s *Signer) DecodeHex(h string) error
- func (s *Signer) Encode() []byte
- func (s *Signer) Hex() string
- func (s *Signer) Identifier() uint16
- func (s *Signer) Sign(message []byte, commitments CommitmentList) (*SignatureShare, error)
- func (s *Signer) UnmarshalJSON(data []byte) error
- func (s *Signer) VerifyCommitmentList(commitments CommitmentList) error
Examples ¶
Constants ¶
const ( // Default and recommended ciphersuite for FROST. Default = Ristretto255 // Ristretto255 uses Ristretto255 and SHA-512. This ciphersuite is recommended. Ristretto255 = Ciphersuite(ecc.Ristretto255Sha512) // P256 uses P-256 and SHA-256. P256 = Ciphersuite(ecc.P256Sha256) // P384 uses P-384 and SHA-384. P384 = Ciphersuite(ecc.P384Sha384) // P521 uses P-521 and SHA-512. P521 = Ciphersuite(ecc.P521Sha512) // Ed25519 uses Edwards25519 and SHA-512, producing Ed25519-compliant signatures as specified in RFC8032. Ed25519 = Ciphersuite(ecc.Edwards25519Sha512) // Secp256k1 uses Secp256k1 and SHA-256. Secp256k1 = Ciphersuite(ecc.Secp256k1Sha256) )
Variables ¶
This section is empty.
Functions ¶
func NewKeyShare ¶
func NewKeyShare( c Ciphersuite, id uint16, secretShare, signerPublicKey, verificationKey []byte, ) (*keys.KeyShare, error)
NewKeyShare returns a KeyShare from separately encoded key material. To deserialize a byte string produced by the KeyShare.Encode() method, use the KeyShare.Decode() method.
func NewPublicKeyShare ¶
func NewPublicKeyShare(c Ciphersuite, id uint16, signerPublicKey []byte) (*keys.PublicKeyShare, error)
NewPublicKeyShare returns a PublicKeyShare from separately encoded key material. To deserialize a byte string produced by the PublicKeyShare.Encode() method, use the PublicKeyShare.Decode() method.
func SchnorrChallenge ¶
SchnorrChallenge computes the per-message SchnorrChallenge.
func VerifySignature ¶
func VerifySignature(c Ciphersuite, message []byte, signature *Signature, publicKey *ecc.Element) error
VerifySignature returns whether the signature of the message is valid under publicKey.
Types ¶
type BindingFactors ¶
BindingFactors is a map of participant identifiers to BindingFactors.
type Ciphersuite ¶
type Ciphersuite byte
Ciphersuite identifies the group and hash function to use for FROST.
func (Ciphersuite) Available ¶
func (c Ciphersuite) Available() bool
Available returns whether the selected ciphersuite is available.
func (Ciphersuite) Group ¶
func (c Ciphersuite) Group() ecc.Group
Group returns the elliptic curve group used in the ciphersuite.
type Commitment ¶
type Commitment struct { HidingNonceCommitment *ecc.Element `json:"hidingNonceCommitment"` BindingNonceCommitment *ecc.Element `json:"bindingNonceCommitment"` CommitmentID uint64 `json:"commitmentId"` SignerID uint16 `json:"signerId"` Group ecc.Group `json:"group"` }
Commitment is a participant's one-time commitment holding its identifier, and hiding and binding nonces.
func (*Commitment) Copy ¶
func (c *Commitment) Copy() *Commitment
Copy returns a new Commitment struct populated with the same values as the receiver.
func (*Commitment) Decode ¶
func (c *Commitment) Decode(data []byte) error
Decode attempts to deserialize the encoded commitment given as input, and to return it.
func (*Commitment) DecodeHex ¶
func (c *Commitment) DecodeHex(h string) error
DecodeHex sets s to the decoding of the hex encoded representation returned by Hex().
func (*Commitment) Encode ¶
func (c *Commitment) Encode() []byte
Encode returns the serialized byte encoding of a participant's commitment.
func (*Commitment) Hex ¶
func (c *Commitment) Hex() string
Hex returns the hexadecimal representation of the byte encoding returned by Encode().
func (*Commitment) UnmarshalJSON ¶
func (c *Commitment) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes data into c, or returns an error.
type CommitmentList ¶
type CommitmentList []*Commitment
CommitmentList is a sortable list of commitments with search functions.
func DecodeList ¶
func DecodeList(data []byte) (CommitmentList, error)
DecodeList decodes a byte string produced by the CommitmentList.Encode() method.
func (CommitmentList) Encode ¶
func (c CommitmentList) Encode() []byte
Encode serializes the CommitmentList into a compact byte encoding.
func (CommitmentList) Get ¶
func (c CommitmentList) Get(identifier uint16) *Commitment
Get returns the commitment of the participant with the corresponding identifier, or nil if it was not found.
func (CommitmentList) IsSorted ¶
func (c CommitmentList) IsSorted() bool
IsSorted returns whether the list is sorted in ascending order by identifier.
func (CommitmentList) Participants ¶
func (c CommitmentList) Participants() []uint16
Participants returns the uint64 list of participant identifiers in the list.
func (CommitmentList) ParticipantsScalar ¶
func (c CommitmentList) ParticipantsScalar() []*ecc.Scalar
ParticipantsScalar returns the ecc.Scalar list of participant identifier in the list.
func (CommitmentList) Sort ¶
func (c CommitmentList) Sort()
Sort sorts the list the ascending order of identifiers.
type Configuration ¶
type Configuration struct { VerificationKey *ecc.Element `json:"verificationKey"` Threshold uint16 `json:"threshold"` MaxSigners uint16 `json:"maxSigners"` Ciphersuite Ciphersuite `json:"ciphersuite"` // contains filtered or unexported fields }
Configuration holds the Configuration for a signing session.
func (*Configuration) AggregateSignatures ¶
func (c *Configuration) AggregateSignatures( message []byte, sigShares []*SignatureShare, commitments CommitmentList, verify bool, ) (*Signature, error)
AggregateSignatures enables a coordinator to produce the final signature given all signature shares.
Before aggregation, each signature share must be a valid, deserialized element. If that validation fails the coordinator must abort the protocol, as the resulting signature will be invalid. The CommitmentList must be sorted in ascending order by identifier.
The coordinator should verify this signature using the group public key before publishing or releasing the signature. This aggregate signature will verify if and only if all signature shares are valid. If an invalid share is identified a reasonable approach is to remove the signer from the set of allowed participants in future runs of FROST. If verify is set to true, AggregateSignatures will automatically verify the signature shares, and will return an error on the first encountered invalid signature share.
func (*Configuration) Decode ¶
func (c *Configuration) Decode(data []byte) error
Decode deserializes the input data into the Configuration, or returns an error.
func (*Configuration) DecodeHex ¶
func (c *Configuration) DecodeHex(h string) error
DecodeHex sets s to the decoding of the hex encoded representation returned by Hex().
func (*Configuration) Encode ¶
func (c *Configuration) Encode() []byte
Encode serializes the Configuration into a compact byte slice.
func (*Configuration) Hex ¶
func (c *Configuration) Hex() string
Hex returns the hexadecimal representation of the byte encoding returned by Encode().
func (*Configuration) Init ¶
func (c *Configuration) Init() error
Init verifies whether the configuration's components are valid, in which case it initializes internal values, or returns an error otherwise.
func (*Configuration) Signer ¶
func (c *Configuration) Signer(keyShare *keys.KeyShare) (*Signer, error)
Signer returns a new participant of the protocol instantiated from the Configuration and the signer's key share.
func (*Configuration) UnmarshalJSON ¶
func (c *Configuration) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes data into c, or returns an error.
func (*Configuration) ValidateCommitment ¶
func (c *Configuration) ValidateCommitment(commitment *Commitment) error
ValidateCommitment returns an error if the commitment is not valid.
func (*Configuration) ValidateCommitmentList ¶
func (c *Configuration) ValidateCommitmentList(commitments CommitmentList) error
ValidateCommitmentList returns an error if at least one of the following conditions is not met: - list length is within [threshold;max]. - no signer identifier in commitments is 0. - no singer identifier in commitments is > max signers. - no duplicated in signer identifiers. - all commitment signer identifiers are registered in the configuration.
func (*Configuration) ValidateKeyShare ¶
func (c *Configuration) ValidateKeyShare(keyShare *keys.KeyShare) error
ValidateKeyShare returns an error if they KeyShare has invalid components or properties that not compatible with the configuration.
func (*Configuration) ValidatePublicKeyShare ¶
func (c *Configuration) ValidatePublicKeyShare(pks *keys.PublicKeyShare) error
ValidatePublicKeyShare returns an error if they PublicKeyShare has invalid components or properties that not compatible with the configuration.
func (*Configuration) VerifySignatureShare ¶
func (c *Configuration) VerifySignatureShare( sigShare *SignatureShare, message []byte, commitments CommitmentList, ) error
VerifySignatureShare verifies a signature share. sigShare is the signer's signature share to be verified.
The CommitmentList must be sorted in ascending order by identifier.
type Nonce ¶
type Nonce struct { HidingNonce *ecc.Scalar `json:"hidingNonce"` BindingNonce *ecc.Scalar `json:"bindingNonce"` *Commitment `json:"commitment"` }
Nonce holds the signing nonces and their commitments. The Signer.Commit() method will generate and record a new nonce and return the Commitment to that nonce. That Commitment will be used in Signer.Sign() and the associated nonces to create a signature share. Note that nonces and their commitments are agnostic of the upcoming message to sign, and can therefore be pre-computed and the commitments shared before the signing session, saving a round-trip.
func (*Nonce) UnmarshalJSON ¶
UnmarshalJSON decodes data into n, or returns an error.
type Signature ¶
type Signature struct { R *ecc.Element `json:"r"` Z *ecc.Scalar `json:"z"` Group ecc.Group `json:"group"` }
Signature represents a Schnorr signature.
func (*Signature) Clear ¶
func (s *Signature) Clear()
Clear overwrites the original values with default ones.
func (*Signature) Decode ¶
Decode deserializes the compact encoding obtained from Encode(), or returns an error.
func (*Signature) DecodeHex ¶
DecodeHex sets s to the decoding of the hex encoded representation returned by Hex().
func (*Signature) Hex ¶
Hex returns the hexadecimal representation of the byte encoding returned by Encode().
func (*Signature) UnmarshalJSON ¶
UnmarshalJSON decodes data into s, or returns an error.
type SignatureShare ¶
type SignatureShare struct {}
SignatureShare represents a Signer's signature share and its identifier.
func (*SignatureShare) Decode ¶
func (s *SignatureShare) Decode(data []byte) error
Decode takes a byte string and attempts to decode it to return the signature share.
func (*SignatureShare) DecodeHex ¶
func (s *SignatureShare) DecodeHex(h string) error
DecodeHex sets s to the decoding of the hex encoded representation returned by Hex().
func (*SignatureShare) Encode ¶
func (s *SignatureShare) Encode() []byte
Encode returns a compact byte encoding of the signature share.
func (*SignatureShare) Hex ¶
func (s *SignatureShare) Hex() string
Hex returns the hexadecimal representation of the byte encoding returned by Encode().
func (*SignatureShare) UnmarshalJSON ¶
func (s *SignatureShare) UnmarshalJSON(data []byte) error
UnmarshalJSON decodes data into s, or returns an error.
type Signer ¶
type Signer struct { keys.KeyShare `json:"keyShare"` // LambdaRegistry records all interpolating values for the signers for different combinations of participant // groups. Each group makes up a unique polynomial defined by the participants' identifiers. A value will be // computed once for the first time a group is encountered, and kept across encodings and decodings of the signer, // accelerating subsequent signatures within the same group of signers. LambdaRegistry internal.LambdaRegistry `json:"lambdaRegistry"` // NonceCommitments maps Nonce and their NonceCommitments to their Commitment's identifier. NonceCommitments map[uint64]*Nonce `json:"nonceCommitments"` // Configuration is the core FROST setup configuration. Configuration *Configuration `json:"configuration"` // HidingRandom can be set to force the use its value for HidingNonce generation. This is only encouraged for vector // reproduction, but should be left to nil in any production deployments. HidingRandom []byte `json:"hidingRandom,omitempty"` // HidingRandom can be set to force the use its value for HidingNonce generation. This is only encouraged for vector // reproduction, but should be left to nil in any production deployments. BindingRandom []byte `json:"bindingRandom,omitempty"` }KeyShare *
Signer is a participant in a signing group.
func (*Signer) ClearNonceCommitment ¶
ClearNonceCommitment zeroes-out the nonces and their commitments, and unregisters the nonce record.
func (*Signer) Commit ¶
func (s *Signer) Commit() *Commitment
Commit generates a signer's nonces and commitment, to be used in the second FROST round. The internal nonce must be kept secret, and the returned commitment sent to the signature aggregator.
func (*Signer) DecodeHex ¶
DecodeHex sets s to the decoding of the hex encoded representation returned by Hex().
func (*Signer) Encode ¶
Encode serializes the client with its long term values, containing its secret share. This is useful for saving state and backup.
func (*Signer) Hex ¶
Hex returns the hexadecimal representation of the byte encoding returned by Encode().
func (*Signer) Identifier ¶
Identifier returns the Signer's identifier.
func (*Signer) Sign ¶
func (s *Signer) Sign(message []byte, commitments CommitmentList) (*SignatureShare, error)
Sign produces a participant's signature share of the message msg. The CommitmentList must contain a Commitment produced on a previous call to Commit(). Once the signature share with Sign() is produced, the internal commitment and nonces are cleared and another call to Sign() with the same Commitment will return an error.
func (*Signer) UnmarshalJSON ¶
UnmarshalJSON decodes data into s, or returns an error.
func (*Signer) VerifyCommitmentList ¶
func (s *Signer) VerifyCommitmentList(commitments CommitmentList) error
VerifyCommitmentList checks for the Commitment list integrity and the signer's commitment. This function must not return an error for Sign to succeed.
Directories
¶
Path | Synopsis |
---|---|
Package debug provides tools for key generation and verification for debugging purposes.
|
Package debug provides tools for key generation and verification for debugging purposes. |
Package internal provides values, structures, and functions to operate FROST that are not part of the public API.
|
Package internal provides values, structures, and functions to operate FROST that are not part of the public API. |