{"id":18014311,"url":"https://github.com/stackoverflowexcept1on/frost-secp256k1-evm","last_synced_at":"2026-03-06T18:37:38.560Z","repository":{"id":258331405,"uuid":"866010138","full_name":"StackOverflowExcept1on/frost-secp256k1-evm","owner":"StackOverflowExcept1on","description":"Cheap threshold signature scheme for EVM","archived":false,"fork":false,"pushed_at":"2025-07-29T19:51:00.000Z","size":164,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-29T22:05:00.736Z","etag":null,"topics":["cryptography","elliptic-curves","schnorr","schnorr-signatures","solidity","threshold-cryptography","threshold-signature"],"latest_commit_sha":null,"homepage":"https://github.com/StackOverflowExcept1on/frost/tree/frost-secp256k1-evm-no-std/frost-secp256k1-evm","language":"Solidity","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/StackOverflowExcept1on.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-10-01T13:50:39.000Z","updated_at":"2025-07-29T19:51:03.000Z","dependencies_parsed_at":"2025-07-29T21:19:32.954Z","dependency_job_id":"2c41e8a4-4679-4846-9f3e-52501fce8c0f","html_url":"https://github.com/StackOverflowExcept1on/frost-secp256k1-evm","commit_stats":null,"previous_names":["stackoverflowexcept1on/frost-secp256k1-evm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/StackOverflowExcept1on/frost-secp256k1-evm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StackOverflowExcept1on%2Ffrost-secp256k1-evm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StackOverflowExcept1on%2Ffrost-secp256k1-evm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StackOverflowExcept1on%2Ffrost-secp256k1-evm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StackOverflowExcept1on%2Ffrost-secp256k1-evm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/StackOverflowExcept1on","download_url":"https://codeload.github.com/StackOverflowExcept1on/frost-secp256k1-evm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StackOverflowExcept1on%2Ffrost-secp256k1-evm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271083511,"owners_count":24696310,"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","status":"online","status_checked_at":"2025-08-18T02:00:08.743Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["cryptography","elliptic-curves","schnorr","schnorr-signatures","solidity","threshold-cryptography","threshold-signature"],"created_at":"2024-10-30T04:07:43.343Z","updated_at":"2026-03-06T18:37:38.545Z","avatar_url":"https://github.com/StackOverflowExcept1on.png","language":"Solidity","readme":"# frost-secp256k1-evm \u0026mdash; cheap threshold signature scheme for EVM\n\n[![Build Status](https://github.com/StackOverflowExcept1on/frost-secp256k1-evm/actions/workflows/ci.yml/badge.svg)](https://github.com/StackOverflowExcept1on/frost-secp256k1-evm/actions/workflows/ci.yml)\n[![Latest Version](https://img.shields.io/crates/v/frost-secp256k1-evm.svg)](https://crates.io/crates/frost-secp256k1-evm)\n\nThis is Solidity library that implements [FROST signature](https://github.com/ZcashFoundation/frost) verification for\nEVM applications. In addition to Solidity, there is also [Rust library](https://crates.io/crates/frost-secp256k1-evm)\nfor creating FROST signatures.\n\nFROST is threshold signature scheme with `n` participants and threshold `t`. Each of `n` participants has $\\frac{1}{n}$\nof group private key and participant's public key. The participants' public keys can be aggregated into group public\nkey (representing group of `n` participants with threshold `t`). The private key is generated by `n` participants\nthrough distributed key generation (DKG). In this case, private key never appears in memory completely in any of\nparticipants. Instead, each participant has only $\\frac{1}{n}$ of group private key. Alternatively, private key can be\ngenerated by a trusted dealer who distributes to each participant $\\frac{1}{n}$ of group private key via Shamir secret\nsharing scheme, but in this case dealer can know group private key and sign any messages. The trusted dealer scheme is\nintended only for tests or for cases when trusted dealer himself wants to split his key into parts (e.g., one part is\nstored on paper, second on flash drive, and third in safe deposit box). Participants can create FROST signature if at\nleast `t` (or more than `t`) of `n` participants sign message. The size of such signature will be 65 bytes in compressed\nform, and it can be verified in $O(1)$ time, and verification is done by group public key, message and signature.\n\nThis library can verify FROST signature `t` of `n` for $\\approx 4200$ gas on any EVM network. ECDSA signatures would\nrequire at least $3000 \\cdot t$ gas, i.e. $O(t)$ time instead of $O(1)$. Threshold signatures are suitable for creating\nmulti-signature wallets, decentralized orgs, oracles, and many other EVM applications. Since threshold signature scheme\nuses group public key, participants remain completely anonymous, and they can generate their signature in asynchronous\nnetwork using wrapper over FROST called [ROAST](https://github.com/StackOverflowExcept1on/roast). Only group public\nkey (64 bytes) needs to be stored onchain, signatures are created offchain in asynchronous network.\n\nLearn more about FROST signatures with [:book: ZF FROST Book](https://frost.zfnd.org/frost.html).\n\nFor usage examples, see [`test/examples/`](./test/examples).\n\nFor creating FROST signature, see [`offchain-signer/`](./offchain-signer) and [`FROSTOffchain`](#frostoffchain).\n\n## Installation\n\nInstall with [Foundry](https://getfoundry.sh):\n\n```bash\nforge install StackOverflowExcept1on/frost-secp256k1-evm\n```\n\n## Libraries\n\n```ml\nfrost-secp256k1-evm\n├─ FROST - \"Library for verifying `FROST-secp256k1-KECCAK256` signatures\"\n├─ FROSTOffchain - \"Library for creating `FROST-secp256k1-KECCAK256` signatures\"\n├─ TranspiledFROST - \"Transpiled library for verifying `FROST-secp256k1-KECCAK256` signatures\"\n└─ utils\n   ├─ cryptography\n   │  ├─ ChaChaRngOffchain - \"Library for interaction with pseudo-random number generator\"\n   │  ├─ ECDSA - \"Library for low-level ECDSA recovery\"\n   │  ├─ Hashes - \"Library for low-level interaction with standard hash functions\"\n   │  ├─ ModExp - \"Library for low-level modular exponentiation\"\n   │  ├─ Schnorr - \"Library for verifying Schnorr's signatures\"\n   │  ├─ Secp256k1 - \"Library for interaction with secp256k1 elliptic curve\"\n   │  └─ Secp256k1Arithmetic - \"Library for interaction with secp256k1 elliptic curve arithmetic\"\n   └─ Memory - \"Library for low-level memory interaction\"\n```\n\n### FROST\n\nLibrary for verifying `FROST-secp256k1-KECCAK256` signatures.\n\nIt's recommended to compile this library with the `--via-ir` flag (`via_ir = true` in `foundry.toml`) to avoid\npossible `\"Stack too deep\"` error and to reduce gas consumption.\n\nLibrary provides the following API:\n\n```solidity\nlibrary FROST {\n    function isValidPublicKey(uint256 publicKeyX, uint256 publicKeyY) internal pure returns (bool) { ... }\n\n    function verifySignature(\n        uint256 publicKeyX,\n        uint256 publicKeyY,\n        uint256 signatureCommitmentX,\n        uint256 signatureCommitmentY,\n        uint256 signatureZ,\n        bytes32 messageHash\n    ) internal view returns (bool) { ... }\n}\n```\n\n#### Example usage\n\nHere is an example `FROSTCounter` contract. This is same `Counter` contract that is usually written when learning\nSolidity, but with one difference: if at least `t` (or more than `t`) of `n` participants sign\n`setNumber(uint256 newNumber)`, then `setNumber` is executed. The group key of participants is also stored in contract.\n\n```solidity\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.33;\n\nimport {FROST} from \"frost-secp256k1-evm/FROST.sol\";\n\ncontract FROSTCounter {\n    uint256 public publicKeyX;\n    uint256 public publicKeyY;\n\n    uint256 public nonce;\n\n    uint256 public number;\n\n    constructor(uint256 _publicKeyX, uint256 _publicKeyY) {\n        require(FROST.isValidPublicKey(_publicKeyX, _publicKeyY));\n        publicKeyX = _publicKeyX;\n        publicKeyY = _publicKeyY;\n    }\n\n    function setNumber(\n        uint256 newNumber,\n        uint256 signatureCommitmentX,\n        uint256 signatureCommitmentY,\n        uint256 signatureZ\n    ) public {\n        /// forge-lint: disable-start(asm-keccak256)\n        bytes32 messageHash =\n            keccak256(abi.encodePacked(block.chainid, uint256(uint160(address(this))), nonce, newNumber));\n        /// forge-lint: disable-end(asm-keccak256)\n        nonce++;\n        // NOTE: `require(FROST.isValidPublicKey(...))` is checked in constructor\n        require(\n            FROST.verifySignature(\n                publicKeyX, publicKeyY, signatureCommitmentX, signatureCommitmentY, signatureZ, messageHash\n            )\n        );\n        number = newNumber;\n    }\n\n    function increment(uint256 signatureCommitmentX, uint256 signatureCommitmentY, uint256 signatureZ) public {\n        uint256 newNumber = number + 1;\n        setNumber(newNumber, signatureCommitmentX, signatureCommitmentY, signatureZ);\n    }\n}\n```\n\n### FROSTOffchain\n\nLibrary for creating `FROST-secp256k1-KECCAK256` signatures.\n\nThis is useful for testing contracts such as `FROSTCounter`. It allows generating `SigningKey`, which can then be split\ninto `n` participants with threshold `t` by function like [`frost_secp256k1_evm::keys::generate_with_dealer()`\n](https://docs.rs/frost-secp256k1-evm/latest/frost_secp256k1_evm/keys/fn.generate_with_dealer.html). However, when\n`SigningKey` is split via `frost_secp256k1_evm::keys::generate_with_dealer()`, it is removed (centralized dealer\nmust do this so as not to know group private key and not to affect value in `FROSTCounter` contract). In this library,\n`SigningKey` is not removed, and you can use group private key to create signature that will allow to change values in\n`FROSTCounter` contract.\n\n#### Example usage\n\n```solidity\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.33;\n\nimport {Test, Vm} from \"forge-std/Test.sol\";\nimport {FROST} from \"frost-secp256k1-evm/FROST.sol\";\nimport {SigningKey, FROSTOffchain} from \"frost-secp256k1-evm/FROSTOffchain.sol\";\n\ncontract MyContractTest is Test {\n    using FROSTOffchain for SigningKey;\n\n    function test_ExampleUsage() public {\n        SigningKey signingKey = FROSTOffchain.newSigningKey();\n\n        Vm.Wallet memory wallet = vm.createWallet(signingKey.asScalar());\n\n        uint256 publicKeyX = wallet.publicKeyX;\n        uint256 publicKeyY = wallet.publicKeyY;\n\n        /* set `publicKeyX` and `publicKeyY` in contract such as `FROSTCounter` */\n\n        bytes32 messageHash = 0x4141414141414141414141414141414141414141414141414141414141414141;\n        (uint256 signatureCommitmentX, uint256 signatureCommitmentY, uint256 signatureZ) =\n            signingKey.createSignature(messageHash);\n\n        /* pass `signatureCommitmentX`, `signatureCommitmentY`, `signatureZ` to contract such as `FROSTCounter` */\n\n        assertTrue(\n            FROST.verifySignature(\n                publicKeyX, publicKeyY, signatureCommitmentX, signatureCommitmentY, signatureZ, messageHash\n            )\n        );\n    }\n}\n```\n\n### TranspiledFROST\n\nTranspiled library for verifying `FROST-secp256k1-KECCAK256` signatures.\n\nUse `TranspiledFROST` instead of `FROST` if `--via-ir` is not available for some reason. It consists of inline\nassembly (language close to Ethereum Virtual Machine).\n\n#### Example usage\n\n```solidity\nimport {TranspiledFROST as FROST} from \"frost-secp256k1-evm/TranspiledFROST.sol\";\n```\n\n## Contributing\n\nThe project uses the Foundry toolchain. You can find installation instructions [here](https://getfoundry.sh).\n\nSetup:\n\n```bash\ngit clone https://github.com/StackOverflowExcept1on/frost-secp256k1-evm\ncd frost-secp256k1-evm\nforge install\n```\n\n## Safety\n\nThis is **experimental software** and is provided on an \"as is\" and \"as available\" basis.\n\nThere is currently no audit, but each file has comments explaining cryptography that is used to verify FROST signatures.\n\nKnown edge cases with FROST signature verification:\n\n- If `signatureZ = 0` or `challenge = 0`, then we cannot use math trick to verify signature via `ecrecover`.\n\n  :information_source: Your application must simply re-generate the signature (it's different each time).\n\n- If group public key has `X \u003e= Secp256k1.N`, then math trick with `ecrecover` will not work.\n\n  :warning: Before using `FROST.verifySignature(publicKeyX, publicKeyY, ...)`, check\n  `FROST.isValidPublicKey(publicKeyX, publicKeyY)`.\n\nBoth edge cases are very rare, but you should keep them in mind.\n\nWe **do not give any warranties** and **will not be liable for any loss** incurred through any use of this codebase.\n\n## License\n\nThis library is licensed under the [MIT LICENSE](./LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackoverflowexcept1on%2Ffrost-secp256k1-evm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstackoverflowexcept1on%2Ffrost-secp256k1-evm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackoverflowexcept1on%2Ffrost-secp256k1-evm/lists"}