{"id":20186183,"url":"https://github.com/bytemare/frost","last_synced_at":"2025-04-10T06:22:19.877Z","repository":{"id":114358660,"uuid":"582483188","full_name":"bytemare/frost","owner":"bytemare","description":"Go implementation of the FROST (Flexible Round-Optimized Schnorr Threshold) signing protocol.","archived":false,"fork":false,"pushed_at":"2024-10-08T22:56:34.000Z","size":239,"stargazers_count":15,"open_issues_count":2,"forks_count":7,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-12T17:44:50.977Z","etag":null,"topics":["ecc","frost","go","golang","schnorr","schnorr-signatures","threshold-cryptography","threshold-signature"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bytemare.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-27T01:28:08.000Z","updated_at":"2024-10-08T22:56:21.000Z","dependencies_parsed_at":"2023-11-27T03:26:54.193Z","dependency_job_id":"1b6d6e75-e974-42c2-87ae-7c330d9295a8","html_url":"https://github.com/bytemare/frost","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytemare%2Ffrost","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytemare%2Ffrost/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytemare%2Ffrost/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytemare%2Ffrost/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bytemare","download_url":"https://codeload.github.com/bytemare/frost/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224556867,"owners_count":17331088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ecc","frost","go","golang","schnorr","schnorr-signatures","threshold-cryptography","threshold-signature"],"created_at":"2024-11-14T03:16:19.418Z","updated_at":"2024-11-14T03:16:20.187Z","avatar_url":"https://github.com/bytemare.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# :snowflake: FROST\n\n[![frost](https://github.com/bytemare/frost/actions/workflows/code-scan.yml/badge.svg)](https://github.com/bytemare/frost/actions/workflows/code-scan.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/bytemare/frost.svg)](https://pkg.go.dev/github.com/bytemare/frost)\n[![codecov](https://codecov.io/gh/bytemare/frost/branch/main/graph/badge.svg?token=5bQfB0OctA)](https://codecov.io/gh/bytemare/frost)\n\n```\n  import \"github.com/bytemare/frost\"\n```\n\nThis package implements [RFC9591 - The FROST Flexible Round-Optimized Schnorr Threshold](https://datatracker.ietf.org/doc/rfc9591/) protocol.\nFROST provides Two-Round Threshold Schnorr Signatures.\n\nThe Ristretto255, Edwards25519, Secp256k1, and NIST elliptic curve groups are fully supported.\n\nThe [FROST Distributed Key Generation](https://github.com/bytemare/dkg) protocol produces compatible keys, as described\nin the [original work](https://eprint.iacr.org/2020/852.pdf).\n\n### Requirements\n\n- When communicating at protocol execution, network channels don't need to be confidential but *MUST* be authenticated. This\n  package verifies a lot of things with regard to the correctness to the protocol, but it assumes that signers and coordinators\n  really communicate with the relevant peer.\n- Long-term fixed configuration values *MUST* be known to all participant signers and coordinators (i.e. the ciphersuite,\n  threshold and maximum amount of signers, and the public key for signature verification)\n- For every signing session, at least the public key shares of all other participants *MUST* be known to all participant\n  signers and coordinators (which can be a subset t-among-n of the initial key generation setup)\n- Data provided to these functions (especially when received over the network) *MUST* be deserialized using the corresponding\n  decoding functions. If data deserialization/decoding fails for a signer, protocol execution must be aborted.\n- Identifiers (for participants/signers) *MUST* be between 1 and n, which is the maximum amount of participants defined at key generation.\n\n#### Supported Ciphersuites\n\n| ID | Name                       | Backend                       |\n|----|----------------------------|-------------------------------|\n| 1  | Ristretto255 (recommended) | github.com/gtank/ristretto255 |\n| 3  | P-256                      | filippo.io/nistec             |\n| 4  | P-384                      | filippo.io/nistec             |\n| 5  | P-521                      | filippo.io/nistec             |\n| 6  | Edwards25519               | filippo.io/edwards25519       |\n| 7  | Secp256k1                  | github.com/bytemare/secp256k1 |\n\nThe groups, scalars (secret keys and nonces), and group elements (public keys and commitments) are opaque objects that\nexpose all necessary cryptographic and serialization functions.\nIf you have existing cryptographic material in their canonical encodings, they can of course be imported.\n\n## Usage\n\nUsage examples and comments can be found in [examples_test.go](https://github.com/bytemare/frost/blob/main/examples_test.go).\n\n### Key Generation\n\nThe [FROST Distributed Key Generation](https://github.com/bytemare/dkg) is recommended to produce key material for all\nparticipants in the setup. This package also puts out KeyShares and PublicKeyShares ready to use with this FROST implementation.\nIt also ensures correct identifier generation compatible with FROST.\n\nIt is heavily recommended to use the same instances for distributed key generation and signing, as this will avoid that\nthe secret key material leaves that instance.\n\nFor testing and debugging _only_, the [debug package](https://github.com/bytemare/frost/debug) provides a centralised\nkey generation with a trusted dealer.\n\n### Key Management\n\nIf the [DKG](https://github.com/bytemare/dkg) package was used to generate keys, signers can use the produced KeyShare\nand must communicate their PublicKeyShare to the coordinator and other signers.\n\nIt is easy to encode and decode these key shares and public key shares for transmission and storage,\nusing the ```Encode()``` and ```Decode()``` methods (or hexadecimal or JSON marshalling).\n\n#### Import existing identifiers and keys\n\nExisting key material (e.g. identifiers, secret public, public keys) that has been generated otherwise (or transmitted or backed up)\nand encoded in their canonical byte representation can be imported.\n\nTo create a ```KeyShare``` and ```PublicKeyShare``` from individually encoded secret and public keys, use the\n```keys.NewKeyShare()``` and ```NewPublicKeyShare()``` functions, respectively.\nIf a ```KeyShare``` or ```PublicKeyShare``` have been encoded using their respective ```Encode()``` method, they can be\neasily recovered using the corresponding ```Decode()``` method. \n\nMore generally, to decode an element (or point) in the Ristretto255 group,\n```go\nimport (\n    \"https://github.com/bytemare/ecc\"\n)\n\nbytesPublicKey := []byte{1, 2, 3, ...}\n\ng := ecc.Ristretto255Sha512\n\npublicKey := g.NewElement()\nif err := publicKey.Decode(bytesPublicKey); err != nil {\n\treturn fmt.Errorf(\"can't decode public key: %w\", err)\n}\n```\n\nThe same goes for secret keys (or scalars),\n```go\nimport (\n    \"https://github.com/bytemare/ecc\"\n)\n\nbytesSecretKey := []byte{1, 2, 3, ...}\n\ng := ecc.Ristretto255Sha512\n\nsecretKey := g.NewScalar()\nif err := secretKey.Decode(bytesSecretKey); err != nil {\n\treturn fmt.Errorf(\"can't decode secret key: %w\", err)\n}\n```\n\nand any other byte or json encoded structure.\n\n### Setup\n\nBoth signers and coordinators must first instantiate a ```Configuration``` with the long-term fixed values as used at \nkey generation:\n- the ciphersuite (see the frost.Ciphersuite values for available ciphersuites)\n- threshold (t) and maximum amount of signers (n)\n- the global public key for signature verification (as put out at key generation)\n\nThen add the PublicKeyShares of the participants (or signers). For simplicity, it is recommended to add all PublicKeyShares\nof the all participants from the key generation step. It is sufficient, though, to only use the shares for the signers that\nwill participate in a signing session (which can be a subset _t among n_).\n\n```go\nconfiguration := \u0026frost.Configuration{\n\t\tCiphersuite:           ciphersuite,\n\t\tThreshold:             threshold,\n\t\tMaxSigners:            maxSigners,\n        VerificationKey:       verificationKey,\n\t\tSignerPublicKeyShares: publicKeyShares,\n\t}\n\nif err := configuration.Init(); err != nil {\n    return err\n}\n```\n\nThis configuration can be encoded for transmission and offline storage, and re-instantiated using its\n```Encode()``` and ```Decode()``` methods. This avoids having to store the parameters separately.\n\n#### Signers\n\nOnce the configuration is initialised, setting up a signer is straightforward, using the ```Signer()``` method\nand providing the signer's ```KeyShare```.\n\n### Protocol execution\n\nFROST is a two round signing protocol, in which the first round can be asynchronously pre-computed, so that signing can\nactually be done in one round when necessary.\n\n#### First Round: Signer commitment\n- Signers commit to internal nonces, by calling the ```commitment := signer.Commit()``` method, which returns one commitment\nand stores corresponding nonces internally. In this manner, signers can produce many commitments before signing sessions start.\nNote that a commitment is not function of the future message to sign, so a signer can produce them without knowing the message in advance.\n- Signers send these commitments to either a coordinator or all other signers.\n- The coordinator (or all other signers) collect these commitments, into a list. The coordinator can prepare such lists\nfor each future message to be signed, a list containing a single commitment from each signer. These commitments must\nnot be reused.\n\n#### Second Round: Signing\n- The coordinator broadcasts the message to be signed and a list of commitments, one from each signer, to each signer.\n- The signers sign the message ```sigShare, err := signer.Sign(message, commitmentList)```, each producing their signature share.\n- These signature shares must then be shared and aggregated to produce the final signature,\n```signature, err := configuration.AggregateSignatures(message, sigShares, commitmentList, true)```.\n\n#### Coordinator\n\nThe coordinator does not have any secret or private information, and must never have. It is also assumed to behave honestly.\n\nCommitments received by signers have an identifier, which allows for triage and registration. Commitments must only be\nused once. The coordinator may further hedge against nonce-reuse by tracking the nonce commitments used for a given group key.\n\nIf the ```verify``` argument in the ```AggregateSignatures()``` is set to ```true``` (which is recommended), signature shares are thoroughly verified.\nUpon error or invalid share, the error message indicates the first invalid share it encountered.\nA coordinator should always verify the signature after ```AggregateSignatures()``` if the ```verify``` argument has been set to ```false```.\n\nIf verification fails, the coordinator can then check signature shares individually to deter the misbehaving signer, leveraging the authenticated channel associated to them.\nThat signer can then be denied of further contributions.\n\n### Resumption and storage\n\nConfigurations, keys, commitments, commitment lists, and even signers can be serialized for transmission and storage,\nand re-instantiated from them. To decode, just create that object and use its ```Decode()``` method.\n\nFor example, to back up a signer with its private keys and commitments, use:\n```go\nbytes := signer.Encode()\n```\n\nTo re-instantiate that same signer from the byte string, do:\n```go\n// bytes := signer.Encode()\n\nsigner := new(frost.Signer)\nif err := signer.Decode(bytes); err != nil {\n\treturn err\n}\n```\n\nKeep in mind that signer encoding embeds the private key and secret nonces, and that they must be secured accordingly.\n\n## Notes\n\nSigners have local secret data and state, offline and during protocol execution:\n- the long term secret key\n- the internally stored commitment nonces, maintained between commitment and signature\n\n- FROST is _not robust_ by design.\n  - This means that there is a misbehaving participant if signature aggregation fails\n  (or if the output signature is not valid), in which case the protocol should be aborted and the problem investigated\n  (you shouldn't have a compromised or misbehaving participant in a sane infrastructure).\n  - Misbehaving signers can DOS the protocol by providing wrong sig shares or not contributing.\n- The coordinator may further hedge against nonce-reuse by tracking the nonce commitments used for a given group key\n- For message pre-hashing, see [RFC](https://datatracker.ietf.org/doc/rfc9591)\n\n## Documentation [![Go Reference](https://pkg.go.dev/badge/github.com/bytemare/frost.svg)](https://pkg.go.dev/github.com/bytemare/frost)\n\nYou can find the godoc documentation and usage examples in [the package doc](https://pkg.go.dev/github.com/bytemare/frost).\n\n## Versioning\n\n[SemVer](http://semver.org) is used for versioning. For the versions available, see the [tags on the repository](https://github.com/bytemare/frost/tags).\n\n## Contributing\n\nPlease read [CONTRIBUTING.md](.github/CONTRIBUTING.md) for details on the code of conduct, and the process for submitting pull requests.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytemare%2Ffrost","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbytemare%2Ffrost","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytemare%2Ffrost/lists"}