diff --git a/README.md b/README.md index 2814ac74..6a350c76 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/stellar/soroban-examples) -This repository contains example smart contracts for key Soroban features and concepts. The examples illustrate how to use the features, in their simplest form. +This repository contains example smart contracts for key Soroban features and concepts. The examples illustrate how to use the features, in their simplest form. > [!WARNING] > These implementations are educational examples, and have not been tested or audited. They are likely to have significant errors and security vulnerabilities. They should not be relied on for any purpose. Please refer to the license for more information. @@ -11,8 +11,8 @@ The examples in this repository: - **account**: This a basic multi-sig account contract that with a customizable per-token authorization policy - **alloc**: Allocates a temporary vector holding values (0..count), then computes and returns their sum -atomic_multiswap**: This contract performs a batch of atomic token swaps between multiple parties and does a simple price matching -- **atomic_swap**: This contract performs an atomic token swap between two parties that don't need to know each other + atomic_multiswap\*\*: This contract performs a batch of atomic token swaps between multiple parties and does a simple price matching +- **atomic_swap**: This contract performs an atomic token swap between two parties that don't need to know each other - **auth**: This contract demonstrates how to implement authorization using Soroban-managed auth framework for a simple case - **bls_signature**: This is a basic custom account contract that implements the FastAggregateVerify function in BLS Signatures - **cross_contract**: Demonstrates how to make cross contract calls @@ -21,8 +21,9 @@ atomic_multiswap**: This contract performs a batch of atomic token swaps between - **deployer**: This contract deploys another contract Wasm and after deployment it invokes the initialization function of the contract - **errors**: This contract demonstrates how to define and generate errors in a contract that invokers of the contract can understand and handle - **eth_abi**: Demonstrates how to decode contract specs in the Application Binary Interface format -- **events**: This contract demonstrates how to publish events from a contract +- **events**: This contract demonstrates how to publish events from a contract - **fuzzing**: This is the 'timelock' example modified slightly to demonstrate Soroban's fuzzing capabilities. +- **groth16_verifier**: Contract for verifying Groth16 ZK proofs on BLS12-381 and BN254 curves - **hello_world**: The simplest smart contract, it takes a parameter value and add it to a vector and returns it - **increment**: Demonstrates how to increment a stored value and returning the updated value - **liquidity_pool**: A minimalistic implementation of a liquidity pool and token swap @@ -40,7 +41,8 @@ atomic_multiswap**: This contract performs a batch of atomic token swaps between - **workspace**: This contract demonstrates how multiple smart contracts can be developed, tested, and built side-by-side in the same Rust workspace ## Get Started -The easiest way to get started experimenting with the example smart contracts, is to use Devcontainers. Run the smart + +The easiest way to get started experimenting with the example smart contracts, is to use Devcontainers. Run the smart contracts directly in a browser-based IDE or using a Devcontainer as your local VSCode backend, without any config or DevOps overhead. @@ -60,31 +62,35 @@ or DevOps overhead. **Learn more about how Devcontainers are used in this repo:** + - Running [Devcontainers Locally](./devcontainer.md) - Check out the [Devcontainer config](./.devcontainer/devcontainer.json) ## Installation -Stellar smart contracts are written in the [Rust](https://www.rust-lang.org/) programming language and can be deployed to the testnet or mainnet. + +Stellar smart contracts are written in the [Rust](https://www.rust-lang.org/) programming language and can be deployed to the testnet or mainnet. ### Prerequisites + To build and develop contracts you need only a couple prerequisites: - A [Rust](https://www.rust-lang.org/) toolchain - An editor that supports Rust - [Stellar CLI](https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup#install-the-stellar-cli) -See the [documentation](https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup) for more prerequisites installation instructions. +See the [documentation](https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup) for more prerequisites installation instructions. #### Create Identity -If an identity for signing transactions has already been created, this part can be skipped. -When deploying a smart contract to a network, an identity that will be used to sign the transactions must be specified. Let's configure an identity called alice. Any name can be used, but it might be convenient to have some named identities for testing, such as alice, bob, and carol. Notice that the account will be funded using [Friendbot](https://developers.stellar.org/docs/learn/fundamentals/networks#friendbot). +If an identity for signing transactions has already been created, this part can be skipped. + +When deploying a smart contract to a network, an identity that will be used to sign the transactions must be specified. Let's configure an identity called alice. Any name can be used, but it might be convenient to have some named identities for testing, such as alice, bob, and carol. Notice that the account will be funded using [Friendbot](https://developers.stellar.org/docs/learn/fundamentals/networks#friendbot). ``` stellar keys generate --global alice --network testnet --fund ``` -Get the public key of alice with this command: +Get the public key of alice with this command: ``` stellar keys address alice @@ -93,20 +99,23 @@ stellar keys address alice See the [documentation](https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup#configure-an-identity) for more information about identities. ### Clone Contracts + The example smart contracts don’t need installation, simply clone the repo: ``` git clone https://github.com/stellar/soroban-examples ``` -*Note all smart contract examples are cloned, not individual contracts.* +_Note all smart contract examples are cloned, not individual contracts._ ### Run Smart Contracts -*Note: The `increment` contract is used in these instructions, but the instructions are similar for the other contracts, except for how to invoke the contracts.* -The smart contracts can easily be run by deploying them to testnet. Choose a contract and follow these instructions. +_Note: The `increment` contract is used in these instructions, but the instructions are similar for the other contracts, except for how to invoke the contracts._ + +The smart contracts can easily be run by deploying them to testnet. Choose a contract and follow these instructions. #### Build + First the smart contract must be built with this command from the `increment` contract’s root folder: ``` @@ -117,6 +126,7 @@ stellar contract build A `.wasm` file will be outputted in the target directory, at `target/wasm32v1-none/release/soroban_increment_contract.wasm`. The `.wasm` file is the built contract. #### Deploy + The WASM file can now be deployed to the testnet by running this command: ``` @@ -130,6 +140,7 @@ stellar contract deploy \ When the smart contract has been successfully deployed, the command will return the contract’s ID (e.g. CACDYF3CYMJEJTIVFESQYZTN67GO2R5D5IUABTCUG3HXQSRXCSOROBAN). This ID can be used to invoke the contract, but since an alias is added, the alias can be used for invoking the contract as well. #### Invoke + Now the contract is on testnet, it can be invoked. For the increment contract there’s only one function to invoke, and that’s the increment() function. Look at the code for the other contracts to see which function to invoke as every example contract is different. Run this command to invoke the increment contract (the added alias is used as the contract ID): @@ -140,13 +151,14 @@ stellar contract invoke \ --source alice \ --network testnet \ -- \ - increment + increment ``` The contract will return 1 the first time it’s run, run it again and see the returned value is being incremented. ## Testing -Each of the example smart contracts also has a test file that has test cases for each of the features of the smart contracts. The test will just return a pass/fail result, but it’s a convenient way to check if the code works, without deploying and invoking the contract manually. + +Each of the example smart contracts also has a test file that has test cases for each of the features of the smart contracts. The test will just return a pass/fail result, but it’s a convenient way to check if the code works, without deploying and invoking the contract manually. From the root of the contract (e.g. `increment`) run this command: @@ -157,10 +169,12 @@ cargo test Some examples may contain multiple contracts and require contracts to be built before the test can be run. See the individual example contracts for details. ## Licence + The example smart contracts are licensed under the Apache 2.0 license. See the LICENSE file for details. ## Contributions -Contributions are welcome, please create a pull request with the following information: + +Contributions are welcome, please create a pull request with the following information: - Explain the changes/additions you made - Why are these changes/additions needed or relevant? @@ -168,8 +182,8 @@ Contributions are welcome, please create a pull request with the following infor - Have your changes/additions been thoroughly tested? ## Relevant Links: + - [Smart Contract Documentation](https://developers.stellar.org/docs/build) - [Getting Started Guide](https://developers.stellar.org/docs/build/smart-contracts/getting-started) - [Example descriptions in the documentation](https://developers.stellar.org/docs/build/smart-contracts/example-contracts) - [Stellar Developers Discord server](https://discord.gg/stellardev) - diff --git a/groth16_verifier/Cargo.lock b/groth16_verifier/Cargo.lock index 05923da8..c963e444 100644 --- a/groth16_verifier/Cargo.lock +++ b/groth16_verifier/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", @@ -15,10 +15,10 @@ dependencies = [ ] [[package]] -name = "android-tzdata" -version = "0.1.1" +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android_system_properties" @@ -44,10 +44,22 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" dependencies = [ - "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", ] [[package]] @@ -56,9 +68,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", ] [[package]] @@ -67,13 +90,34 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-poly 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", "hashbrown 0.13.2", - "itertools", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint", + "num-integer", "num-traits", "zeroize", ] @@ -84,13 +128,13 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", "digest", - "itertools", + "itertools 0.10.5", "num-bigint", "num-traits", "paste", @@ -98,6 +142,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.4.2" @@ -108,6 +172,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.115", +] + [[package]] name = "ark-ff-macros" version = "0.4.2" @@ -121,27 +195,68 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "ark-poly" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", "hashbrown 0.13.2", ] +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", +] + [[package]] name = "ark-serialize" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-serialize-derive", - "ark-std", + "ark-serialize-derive 0.4.2", + "ark-std 0.4.0", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", "digest", "num-bigint", ] @@ -157,6 +272,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "ark-std" version = "0.4.0" @@ -167,11 +293,39 @@ dependencies = [ "rand", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark_verifier" +version = "0.1.0" +dependencies = [ + "ark-bls12-381 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "serde", + "serde_json", + "soroban-sdk", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base16ct" @@ -187,9 +341,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "block-buffer" @@ -202,9 +356,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "byteorder" @@ -221,23 +375,24 @@ dependencies = [ "num-bigint", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] name = "cc" -version = "1.2.4" +version = "1.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_eval" @@ -247,20 +402,30 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ - "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets", + "windows-link", +] + +[[package]] +name = "circom_verifier" +version = "0.1.0" +dependencies = [ + "ark-bls12-381 0.5.0", + "ark-serialize 0.5.0", + "serde", + "serde_json", + "soroban-sdk", ] [[package]] @@ -277,9 +442,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -357,55 +522,90 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] name = "darling" -version = "0.20.10" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ - "darling_core", - "darling_macro", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.115", ] [[package]] name = "darling_core" -version = "0.20.10" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core", + "darling_core 0.20.11", "quote", - "syn 2.0.106", + "syn 2.0.115", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.115", ] [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "zeroize", @@ -413,12 +613,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -440,7 +640,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] @@ -507,9 +707,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", @@ -520,11 +720,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elliptic-curve" @@ -544,11 +756,31 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "escape-bytes" @@ -558,15 +790,15 @@ checksum = "2bfcf67fea2815c2fc3b90873fae90957be12ff417335dfadc7f52927feb03b2" [[package]] name = "ethnum" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" +checksum = "ca81e6b4777c89fd810c25a4be2b1bd93ea034fbe58e6a75216a34c6b82c539b" [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "rand_core", "subtle", @@ -578,6 +810,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "fnv" version = "1.0.7" @@ -586,9 +824,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -597,9 +835,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -608,6 +846,29 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gnark_bn254_verifier" +version = "0.1.0" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "serde", + "serde_json", + "soroban-sdk", +] + +[[package]] +name = "gnark_verifier" +version = "0.1.0" +dependencies = [ + "ark-bls12-381 0.5.0", + "ark-serialize 0.5.0", + "serde", + "serde_json", + "soroban-sdk", +] + [[package]] name = "group" version = "0.13.0" @@ -645,9 +906,18 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heapless" @@ -691,14 +961,15 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -731,13 +1002,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.16.1", "serde", + "serde_core", ] [[package]] @@ -755,17 +1027,26 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -794,21 +1075,21 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.168" +version = "0.2.181" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" [[package]] name = "libm" -version = "0.2.11" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "log" -version = "0.4.22" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "macro-string" @@ -818,14 +1099,14 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "num-bigint" @@ -839,9 +1120,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-derive" @@ -851,7 +1132,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] @@ -874,9 +1155,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "p256" @@ -914,21 +1195,21 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] @@ -942,18 +1223,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -990,22 +1271,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] @@ -1028,10 +1309,10 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.18" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "schemars" @@ -1058,9 +1339,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ "dyn-clone", "ref-cast", @@ -1083,58 +1364,68 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] name = "serde_with" -version = "3.14.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "base64", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.0", + "indexmap 2.13.0", "schemars 0.8.22", "schemars 0.9.0", - "schemars 1.0.4", - "serde", - "serde_derive", + "schemars 1.2.1", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -1142,14 +1433,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ - "darling", + "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] @@ -1191,9 +1482,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "soroban-builtin-sdk-macros" @@ -1201,10 +1492,10 @@ version = "25.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7192e3a5551a7aeee90d2110b11b615798e81951fd8c8293c87ea7f88b0168f5" dependencies = [ - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] @@ -1242,11 +1533,11 @@ version = "25.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43af5d53c57bc2f546e122adc0b1cca6f93942c718977379aa19ddd04f06fcec" dependencies = [ - "ark-bls12-381", - "ark-bn254", - "ark-ec", - "ark-ff", - "ark-serialize", + "ark-bls12-381 0.4.0", + "ark-bn254 0.4.0", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", "curve25519-dalek", "ecdsa", "ed25519-dalek", @@ -1279,24 +1570,13 @@ version = "25.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a989167512e3592d455b1e204d703cfe578a36672a77ed2f9e6f7e1bbfd9cc5c" dependencies = [ - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "serde", "serde_json", "stellar-xdr", - "syn 2.0.106", -] - -[[package]] -name = "soroban-groth16-verifier-contract" -version = "0.0.0" -dependencies = [ - "ark-bls12-381", - "ark-ec", - "ark-ff", - "ark-serialize", - "soroban-sdk", + "syn 2.0.115", ] [[package]] @@ -1343,9 +1623,9 @@ version = "25.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93b62c526917a1e77b6dce3cd841b6c271f0fff344ea93ad92a8c45afe8051b6" dependencies = [ - "darling", + "darling 0.20.11", "heck", - "itertools", + "itertools 0.10.5", "macro-string", "proc-macro2", "quote", @@ -1354,7 +1634,7 @@ dependencies = [ "soroban-spec", "soroban-spec-rust", "stellar-xdr", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] @@ -1381,7 +1661,7 @@ dependencies = [ "sha2", "soroban-spec", "stellar-xdr", - "syn 2.0.106", + "syn 2.0.115", "thiserror", ] @@ -1491,9 +1771,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" dependencies = [ "proc-macro2", "quote", @@ -1517,35 +1797,35 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] name = "time" -version = "0.3.37" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -1553,15 +1833,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "version_check" @@ -1577,45 +1857,33 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1623,22 +1891,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.115", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasmi_arena" @@ -1664,7 +1935,7 @@ version = "0.116.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.13.0", "semver", ] @@ -1679,114 +1950,105 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-targets", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" +name = "windows-interface" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] [[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.115", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/groth16_verifier/Cargo.toml b/groth16_verifier/Cargo.toml index 89b0c5bf..40f0e3b5 100644 --- a/groth16_verifier/Cargo.toml +++ b/groth16_verifier/Cargo.toml @@ -1,23 +1,16 @@ -[package] -name = "soroban-groth16-verifier-contract" -version = "0.0.0" -edition = "2021" -publish = false -rust-version = "1.89.0" +[workspace] +resolver = "2" +members = [ + "contracts/*", +] +exclude = [ + "data/arkworks/auxiliary", + "data/circom/**", + "data/gnark/**", +] -[lib] -crate-type = ["cdylib"] -doctest = false - -[dependencies] -soroban-sdk = { version = "25.1.0" } - -[dev-dependencies] -soroban-sdk = { version = "25.1.0", features = ["testutils"] } -ark-bls12-381 = { version = "0.4.0"} -ark-serialize = { version = "0.4.2"} -ark-ff = { version = "0.4.2"} -ark-ec = { version = "0.4.2"} +[workspace.dependencies] +soroban-sdk = "25" [profile.release] opt-level = "z" @@ -29,6 +22,7 @@ panic = "abort" codegen-units = 1 lto = true +# For more information about this profile see https://soroban.stellar.org/docs/basic-tutorials/logging#cargotoml-profile [profile.release-with-logs] inherits = "release" -debug-assertions = true +debug-assertions = true \ No newline at end of file diff --git a/groth16_verifier/Makefile b/groth16_verifier/Makefile deleted file mode 100644 index b9719346..00000000 --- a/groth16_verifier/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -default: build - -all: test - -test: build - cargo test - -build: - stellar contract build - @ls -l target/wasm32v1-none/release/*.wasm - -fmt: - cargo fmt --all - -clean: - cargo clean diff --git a/groth16_verifier/README b/groth16_verifier/README deleted file mode 100644 index bef4649f..00000000 --- a/groth16_verifier/README +++ /dev/null @@ -1,28 +0,0 @@ -# Groth16 Verifier Contract - -A demonstration of a Groth16 zero-knowledge proof verifier implemented as a Soroban smart contract. - -The proof and verification key are generated following the Circom2 (circom compiler 2.2.1) [getting-started guide](https://docs.circom.io/getting-started/installation/). - -The computation demonstrates a simple multiplication circuit: `a * b = c`, where: -- `a` and `b` are private inputs -- `c` is the public output - -The `./data` directory contains all input files (circuit definition, inputs) and generated outputs. For proof verification, three key files are required: -- [proof.json](./data/proof.json) - Contains the zero-knowledge proof -- [verification_key.json](./data/verification_key.json) - Contains the verification key -- [public.json](./data/public.json) - Contains the public inputs/outputs - -Other intermediate artifacts, including witness generation code and outputs from the "Powers of Tau" ceremony, are included in `./data/auxiliary` for reproducibility. - -The [contract implementation](./src/lib.rs) is translated from the auto-generated [Solidity contract](./data/multiplier2_js/verifier.sol). The [test suite](./src/test.rs) demonstrates off-chain parsing of the proof and verification key, along with successful contract execution. - -This example was presented at the [Stellar Developer Meeting - 12/19/2024](https://www.youtube.com/watch?v=51SitOUZySk&list=PLmr3tp_7-7Gg5IAsJ0VlgfMoh-aTmbQmh&index=4) to demonstrate the BLS12-381 features. - -## ⚠️ WARNING: Demonstration Use Only - -**This project is for demonstration purposes only.** -- It has **not** undergone security auditing -- It is **not** safe for use in production environments - -**Use at your own risk.** \ No newline at end of file diff --git a/groth16_verifier/README.md b/groth16_verifier/README.md new file mode 100644 index 00000000..ff486baa --- /dev/null +++ b/groth16_verifier/README.md @@ -0,0 +1,61 @@ +# Groth16 Verifier Contract + +Soroban smart contract that verifies Groth16 zero-knowledge proofs over BLS12-381 and BN254. + +This project demonstrates how Groth16 verifiers can be generated and executed on Stellar Soroban, using snarkjs-compatible JSON artifacts produced by multiple ZK toolchains. + +This example was presented at the [Stellar Developer Meeting - 12/19/2024](https://www.youtube.com/watch?v=51SitOUZySk&list=PLmr3tp_7-7Gg5IAsJ0VlgfMoh-aTmbQmh&index=4) + +## Supported Toolchains + +Proofs and verification keys generated by: + +- [Circom](https://docs.circom.io/) +- [Gnark (Go)](https://github.com/Consensys/gnark) +- [Arkworks (Rust)](https://github.com/arkworks-rs) +- [Noname](https://github.com/zksecurity/noname): [Article about integration with SnarkJS](https://blog.zksecurity.xyz/posts/noname-r1cs/) + +## Repository Structure + +The `./data/` directory is organized by ZK toolchain: e.g. `data/circom` (Circom/snarkjs), `data/gnark` (Go/gnark), `data/arkworks` (Rust/arkworks). Each subdirectory holds circuit definitions, inputs, and the generated proof artifacts for that toolchain. + +For proof verification, three key files are required per toolchain. **Example for Circom** (`data/circom/`): + +- [proof.json](./data/circom/proof.json) — zero-knowledge proof +- [verification_key.json](./data/circom/verification_key.json) — verification key +- [public.json](./data/circom/public.json) — public inputs/outputs + +Intermediate artifacts (witness code, Powers of Tau outputs, etc.) live under `./data/circom/auxiliary` (see [data/circom/README.md](./data/circom/README.md) for the Circom setup steps). + +For gnark BLS12-381, circuit definitions and setup code are in `./data/gnark/auxiliary` (see [data/gnark/README.md](./data/gnark/README.md)). + +For gnark BN254, circuit definitions and setup code are in `./data/gnark_bn254/auxiliary` (see [data/gnark_bn254/README.md](./data/gnark_bn254/README.md)). + +For arkworks, circuit definitions and setup code are in `./data/arkworks/auxiliary` (see [data/arkworks/README.md](./data/arkworks/README.md)). + +## Usage + +```sh +cd groth16_verifier + +cargo install soroban-verifier-gen + +# bls12-381 +soroban-verifier-gen --vk data/circom/verification_key.json --out contracts/circom_verifier --crate-name circom_verifier +soroban-verifier-gen --vk data/gnark/verification_key.json --out contracts/gnark_verifier --crate-name gnark_verifier +soroban-verifier-gen --vk data/arkworks/verification_key.json --out contracts/ark_verifier --crate-name ark_verifier + +# bn254 +soroban-verifier-gen --vk data/gnark_bn254/verification_key.json --out contracts/gnark_bn254_verifier --crate-name gnark_bn254_verifier --curve bn254 +``` + +--- + +## ⚠️ WARNING: Demonstration Use Only + +**This project is for demonstration purposes only.** + +- It has **not** undergone security auditing +- It is **not** safe for use in production environments + +**Use at your own risk.** diff --git a/groth16_verifier/contracts/ark_verifier/Cargo.toml b/groth16_verifier/contracts/ark_verifier/Cargo.toml new file mode 100644 index 00000000..f83bf7ff --- /dev/null +++ b/groth16_verifier/contracts/ark_verifier/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "ark_verifier" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +crate-type = ["lib", "cdylib"] +doctest = false + +[dependencies] +soroban-sdk = "25" + +[dev-dependencies] +soroban-sdk = { version = "25", features = ["testutils"] } +ark-bls12-381 = "0.5" +ark-ff = "0.5" +ark-serialize = "0.5" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/groth16_verifier/contracts/ark_verifier/src/lib.rs b/groth16_verifier/contracts/ark_verifier/src/lib.rs new file mode 100644 index 00000000..8b6ba8e0 --- /dev/null +++ b/groth16_verifier/contracts/ark_verifier/src/lib.rs @@ -0,0 +1,230 @@ +#![no_std] + +#[cfg(test)] +mod test; + +use soroban_sdk::{ + Env, Vec, contract, contracterror, contractimpl, contracttype, + crypto::bls12_381::{Fr, G1_SERIALIZED_SIZE, G1Affine, G2_SERIALIZED_SIZE, G2Affine}, +}; + +#[contracterror] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u32)] +pub enum Groth16Error { + MalformedVerifyingKey = 0, +} + +#[derive(Clone)] +#[contracttype] +pub struct VerificationKey { + pub alpha: G1Affine, + pub beta: G2Affine, + pub gamma: G2Affine, + pub delta: G2Affine, + pub ic: Vec, +} + +#[derive(Clone)] +#[contracttype] +pub struct Proof { + pub a: G1Affine, + pub b: G2Affine, + pub c: G1Affine, +} + +// AUTO-GENERATED VK BYTES (uncompressed). DO NOT EDIT. +const VK_ALPHA: [u8; G1_SERIALIZED_SIZE] = [ + 0x0d, 0xe2, 0x44, 0xed, 0x57, 0x6e, 0xbb, 0x28, 0x14, 0x21, 0x65, 0x6f, 0x8b, 0xda, 0xb5, 0x41, + 0x58, 0x12, 0x9a, 0x18, 0xa2, 0x5c, 0x17, 0x9e, 0x20, 0xdb, 0xad, 0x78, 0x04, 0x53, 0x49, 0xfa, + 0x8e, 0x63, 0x50, 0xd0, 0xdd, 0xb7, 0x10, 0xbe, 0x16, 0x23, 0x31, 0xa2, 0x5e, 0x47, 0xfb, 0x01, + 0x0c, 0xa8, 0x7c, 0x22, 0x36, 0x28, 0xac, 0xde, 0x30, 0x12, 0xb4, 0xfb, 0xf8, 0x43, 0x97, 0x53, + 0xa6, 0x89, 0x01, 0x7b, 0x46, 0xf9, 0xc2, 0xba, 0x2a, 0xfa, 0xf4, 0x1a, 0xa5, 0x83, 0x2d, 0x94, + 0xf3, 0x07, 0x86, 0xef, 0xfd, 0x93, 0xe6, 0xec, 0x62, 0xd0, 0x05, 0x82, 0xf7, 0xee, 0xf4, 0x53, +]; +const VK_BETA: [u8; G2_SERIALIZED_SIZE] = [ + 0x14, 0x19, 0x98, 0xfc, 0xb3, 0xf5, 0x62, 0xc2, 0x12, 0x18, 0x68, 0x6e, 0x18, 0x7b, 0x67, 0x1c, + 0x08, 0x02, 0x75, 0x08, 0x25, 0xd1, 0xf3, 0x46, 0x6f, 0x14, 0xaa, 0x81, 0x59, 0x65, 0x0a, 0x65, + 0x21, 0xac, 0x90, 0xb7, 0xd6, 0x99, 0xb2, 0xcc, 0x0c, 0x3f, 0x0d, 0xd7, 0x0e, 0xf3, 0x36, 0xb9, + 0x07, 0x4e, 0x0a, 0x8d, 0xc5, 0x35, 0x33, 0x42, 0x1a, 0x67, 0x32, 0x52, 0x5c, 0x80, 0x4f, 0x4e, + 0x48, 0xae, 0x6f, 0x39, 0x0a, 0x56, 0xdf, 0x1a, 0x91, 0x40, 0x4a, 0x51, 0x37, 0x14, 0x3a, 0x40, + 0x9a, 0x78, 0xd1, 0xec, 0x03, 0x23, 0x79, 0x15, 0xa3, 0x85, 0x6a, 0xfc, 0xb7, 0xf0, 0xf8, 0x3a, + 0x0a, 0xbc, 0x49, 0x02, 0x1c, 0x48, 0x98, 0xdf, 0xcb, 0x67, 0x15, 0xb6, 0x21, 0x1c, 0xd9, 0xd3, + 0x9b, 0x33, 0x7f, 0x33, 0xcb, 0x11, 0x84, 0xbd, 0x03, 0xe0, 0x3d, 0xd5, 0xcd, 0x7e, 0x2f, 0x8d, + 0xed, 0x72, 0xa5, 0xec, 0x29, 0x02, 0xd2, 0x68, 0x09, 0xc3, 0x07, 0x11, 0x61, 0xd8, 0x02, 0x5f, + 0x13, 0xb5, 0x9c, 0x45, 0x95, 0x04, 0xf1, 0x23, 0xb6, 0x4e, 0xbc, 0xab, 0x58, 0xf2, 0x58, 0x85, + 0xb0, 0x7b, 0xca, 0xd0, 0x6b, 0x71, 0xa2, 0xf1, 0x14, 0x2e, 0x45, 0xd6, 0x4f, 0x37, 0x4d, 0x9a, + 0x37, 0xee, 0x83, 0xdd, 0xad, 0x66, 0xb5, 0x1a, 0x19, 0xca, 0x9b, 0x73, 0xca, 0xdf, 0xa5, 0xf5, +]; +const VK_GAMMA: [u8; G2_SERIALIZED_SIZE] = [ + 0x0e, 0xab, 0x20, 0x45, 0x6a, 0x1c, 0x14, 0x51, 0x12, 0xa6, 0x0a, 0x88, 0x28, 0x0d, 0x3b, 0x48, + 0x06, 0x03, 0xd1, 0xe0, 0x4f, 0x8b, 0xf0, 0x38, 0x9f, 0x81, 0x26, 0xce, 0xf7, 0xdc, 0x49, 0xc2, + 0xa5, 0x8c, 0x08, 0x06, 0x0b, 0xb6, 0x82, 0x1a, 0xd7, 0x5e, 0x6a, 0x16, 0xb3, 0x8a, 0x6e, 0xf6, + 0x0e, 0xdf, 0x0c, 0xce, 0x00, 0x28, 0x9f, 0x6f, 0x22, 0x10, 0x7c, 0xd2, 0x99, 0x30, 0x00, 0x21, + 0x3f, 0xc7, 0x92, 0xd2, 0x27, 0xb6, 0x77, 0x72, 0x84, 0xc3, 0xef, 0xdd, 0xff, 0x64, 0xac, 0xe1, + 0x21, 0x53, 0x43, 0xf0, 0xfe, 0x14, 0xd1, 0x74, 0x03, 0xf4, 0xec, 0x2d, 0x87, 0xc5, 0x4d, 0xb6, + 0x0e, 0xd2, 0x0b, 0xfb, 0xf5, 0xe2, 0xc1, 0x65, 0xff, 0x66, 0xf7, 0x7d, 0x63, 0x9d, 0xda, 0x04, + 0xe1, 0xe3, 0x1e, 0x9d, 0x9e, 0xce, 0xb9, 0x53, 0x01, 0xcc, 0x36, 0x44, 0x7f, 0x1c, 0xc3, 0xe6, + 0xc5, 0x25, 0xf4, 0x8c, 0x57, 0x7c, 0xf1, 0xa0, 0xa1, 0x7d, 0x4a, 0x6a, 0xcd, 0xb7, 0x17, 0xec, + 0x0f, 0x43, 0xbf, 0x61, 0xb5, 0x81, 0x97, 0xb8, 0xdc, 0x2f, 0xe9, 0x59, 0xe0, 0x29, 0x7f, 0xc5, + 0xf7, 0x72, 0x69, 0x34, 0x0a, 0x5c, 0xa9, 0xbb, 0xe2, 0x8d, 0xd5, 0x1e, 0xf1, 0xcc, 0x41, 0xf1, + 0xbf, 0x18, 0x6a, 0xfd, 0xc6, 0x54, 0x2c, 0x11, 0xd7, 0x3e, 0x21, 0x5c, 0x72, 0x13, 0x3c, 0xe8, +]; +const VK_DELTA: [u8; G2_SERIALIZED_SIZE] = [ + 0x14, 0x38, 0x2e, 0xb0, 0xbb, 0x25, 0x00, 0x47, 0x4f, 0xd6, 0x88, 0x0b, 0xf2, 0x4b, 0xc0, 0x23, + 0xbd, 0x23, 0x4c, 0x96, 0x3c, 0x75, 0x15, 0xa1, 0xad, 0x62, 0xdc, 0xdc, 0x8d, 0x4b, 0x51, 0x00, + 0x79, 0x9f, 0x90, 0xbc, 0xd4, 0xd7, 0x56, 0xe0, 0xc9, 0xd1, 0x7a, 0xc1, 0x02, 0x97, 0x6d, 0xe1, + 0x10, 0x9f, 0xfa, 0x98, 0x67, 0x9b, 0x4a, 0x12, 0x04, 0xbf, 0xd2, 0x21, 0x97, 0x11, 0x10, 0x24, + 0xa6, 0x00, 0x3a, 0x9f, 0xf5, 0x78, 0x02, 0xc4, 0x89, 0x73, 0xd7, 0x7d, 0xc3, 0xca, 0xc2, 0xb2, + 0xe8, 0xe6, 0x71, 0xa9, 0x57, 0x84, 0x50, 0xfe, 0xdd, 0x82, 0x2f, 0xd1, 0xf1, 0x60, 0xd7, 0x0a, + 0x09, 0xbb, 0x77, 0x2c, 0xc3, 0x72, 0xfc, 0x8c, 0xa0, 0x2f, 0x0f, 0x50, 0xbd, 0xe9, 0x7f, 0xb8, + 0xe4, 0x79, 0x51, 0x72, 0x2a, 0x46, 0x2f, 0xcb, 0x55, 0x63, 0x87, 0x44, 0x7d, 0xfa, 0xc3, 0xfa, + 0xd8, 0xd8, 0x54, 0x5d, 0x63, 0x4c, 0x5a, 0xf4, 0x0c, 0xd2, 0xa4, 0xc2, 0x77, 0x7a, 0x64, 0xd8, + 0x15, 0x66, 0xe7, 0x92, 0xb8, 0xe8, 0x30, 0xc7, 0xc7, 0x7d, 0xdf, 0x11, 0x22, 0x9c, 0x4e, 0x8b, + 0x9a, 0x17, 0xff, 0x75, 0x15, 0x78, 0x25, 0x28, 0x4e, 0x57, 0xc5, 0x7c, 0xfe, 0xfd, 0xba, 0xc9, + 0x5b, 0x9a, 0xb8, 0x6a, 0xeb, 0xab, 0xdc, 0xcc, 0x5c, 0x00, 0xa6, 0xf0, 0x99, 0x3a, 0xe6, 0x02, +]; + +const VK_IC: [[u8; G1_SERIALIZED_SIZE]; 10] = [ + [ + 0x03, 0x5f, 0x4f, 0x75, 0xf8, 0x5d, 0xa1, 0x42, 0xb6, 0xa5, 0xc3, 0x17, 0xcf, 0x75, 0xd5, + 0x77, 0x43, 0xf4, 0xf8, 0x86, 0x75, 0x8c, 0x81, 0xe8, 0x76, 0x6a, 0xf9, 0x02, 0x2c, 0x30, + 0x27, 0x27, 0x61, 0xd7, 0x3f, 0x07, 0x5c, 0xc0, 0xa3, 0xbb, 0x4b, 0xde, 0xc9, 0xd1, 0xc9, + 0x04, 0x22, 0xaf, 0x0a, 0x2e, 0x82, 0x7a, 0xff, 0x91, 0x55, 0x67, 0x80, 0xe9, 0x6f, 0x50, + 0x78, 0x4f, 0xcb, 0x89, 0xc9, 0x7c, 0x11, 0xd1, 0x31, 0xcf, 0x5d, 0x37, 0xca, 0xff, 0x61, + 0x46, 0x33, 0x84, 0x21, 0xd1, 0x44, 0x88, 0x46, 0xf7, 0xf6, 0x3f, 0xc6, 0x30, 0x7a, 0xca, + 0xa2, 0xb6, 0xbd, 0x31, 0x00, 0x6b, + ], + [ + 0x0a, 0xf8, 0xe4, 0xab, 0x1e, 0xd3, 0x8a, 0xdc, 0x7f, 0x12, 0x09, 0x0e, 0xd5, 0xc8, 0xaa, + 0xbc, 0x41, 0xa9, 0xb6, 0xca, 0x9d, 0x0d, 0x80, 0xb1, 0x46, 0x8f, 0xd3, 0xd5, 0x65, 0x78, + 0x34, 0xb9, 0x83, 0x75, 0xbd, 0x08, 0x75, 0x2e, 0xf3, 0x85, 0xc5, 0xbf, 0x69, 0x18, 0xff, + 0xbf, 0x48, 0x7e, 0x16, 0xf3, 0xe5, 0xff, 0x02, 0xeb, 0xb1, 0xcc, 0xc7, 0xd0, 0x34, 0xc0, + 0xf9, 0x2c, 0x8b, 0xf7, 0x4d, 0x28, 0x9b, 0xef, 0x82, 0x64, 0x22, 0x40, 0xa9, 0xde, 0xef, + 0x4e, 0x66, 0xd2, 0x35, 0x48, 0x4c, 0x83, 0x0e, 0x4c, 0x3b, 0x69, 0xbe, 0x28, 0x0f, 0x23, + 0x64, 0x11, 0x02, 0x0f, 0x95, 0x02, + ], + [ + 0x0c, 0x3d, 0x35, 0xf4, 0x4f, 0x90, 0xa3, 0x62, 0xa6, 0xdf, 0x63, 0xd3, 0x9c, 0xf2, 0xe5, + 0x34, 0x59, 0x8e, 0xe6, 0xfd, 0xc3, 0x45, 0x03, 0x1c, 0xd6, 0x96, 0x7a, 0xa0, 0x34, 0x74, + 0x9b, 0xb0, 0x55, 0x8f, 0x2d, 0x8d, 0x7c, 0x3d, 0xef, 0x77, 0xe3, 0x1d, 0xa7, 0x86, 0xc9, + 0x31, 0x7e, 0x06, 0x14, 0xb3, 0x0a, 0x2b, 0x99, 0x57, 0x30, 0x4b, 0x45, 0x50, 0xc1, 0x2c, + 0xd4, 0xb0, 0xa9, 0x83, 0xc3, 0xef, 0x0f, 0x3f, 0x6f, 0x76, 0xa8, 0xed, 0xd2, 0x44, 0x27, + 0xc7, 0xf3, 0xcd, 0xcb, 0x88, 0xdd, 0x52, 0xea, 0xdd, 0xd5, 0x7f, 0x0b, 0xec, 0x69, 0x02, + 0xee, 0x87, 0x46, 0xd1, 0x6b, 0x59, + ], + [ + 0x14, 0xae, 0x49, 0x84, 0x4a, 0xe5, 0xd0, 0x8c, 0xdd, 0x6d, 0xa3, 0x0b, 0xad, 0xb6, 0x3d, + 0x9b, 0x4a, 0xe6, 0x46, 0x22, 0x1b, 0x4d, 0xe8, 0x05, 0x3a, 0x34, 0x2e, 0xef, 0x06, 0xcb, + 0x25, 0x26, 0x50, 0x96, 0xb5, 0xd6, 0x5d, 0x4a, 0x51, 0xa0, 0xb5, 0x48, 0x29, 0x60, 0x8a, + 0x58, 0xe3, 0xd1, 0x09, 0x51, 0x7e, 0x26, 0xd4, 0x2b, 0x17, 0x33, 0xc7, 0x12, 0x57, 0xef, + 0x86, 0x1b, 0x2a, 0x04, 0xc5, 0x4f, 0xc2, 0x15, 0xa7, 0xd1, 0x28, 0xb6, 0x56, 0x7f, 0xa1, + 0x34, 0x1c, 0x8c, 0xe7, 0x5b, 0x0c, 0x6f, 0x1c, 0x56, 0xc5, 0x06, 0x32, 0x97, 0xcc, 0x10, + 0x85, 0x8b, 0x2f, 0x7b, 0x2a, 0x5c, + ], + [ + 0x03, 0xd7, 0x09, 0x87, 0x72, 0x18, 0xe4, 0x8e, 0x63, 0x95, 0xdb, 0xff, 0x6e, 0x8d, 0x28, + 0x45, 0x5f, 0x68, 0x5d, 0xea, 0x17, 0x7d, 0x8e, 0xc0, 0xb5, 0x3e, 0x55, 0x91, 0xeb, 0xf3, + 0xa4, 0xe2, 0xe3, 0xf9, 0xa6, 0xce, 0x91, 0xaa, 0xcc, 0x79, 0x76, 0x97, 0x26, 0x6d, 0xba, + 0x79, 0x97, 0x65, 0x0c, 0x45, 0xa5, 0x19, 0xca, 0xa7, 0x00, 0xc7, 0x70, 0xe4, 0x75, 0xaf, + 0xa8, 0x3b, 0x98, 0xb5, 0xc0, 0x57, 0x00, 0x1c, 0xc9, 0xcf, 0xcb, 0xaa, 0xe0, 0xb0, 0x16, + 0x3f, 0x82, 0x47, 0x1c, 0x28, 0xe2, 0x76, 0x49, 0xfe, 0xa1, 0x8d, 0x70, 0x48, 0xf4, 0xd5, + 0x5c, 0xe2, 0x3e, 0xd7, 0x75, 0x9e, + ], + [ + 0x01, 0xf1, 0xcf, 0x66, 0x3b, 0x3f, 0xec, 0x6c, 0x32, 0x22, 0x06, 0xb7, 0xf1, 0x8c, 0x2f, + 0xdc, 0x90, 0x04, 0x26, 0x8e, 0x93, 0xc8, 0x19, 0xa3, 0xdf, 0x6e, 0x6b, 0x9b, 0x00, 0x47, + 0xda, 0x4d, 0x52, 0xa9, 0xc8, 0x82, 0xb2, 0xbc, 0x6d, 0xfa, 0x88, 0xfe, 0x40, 0xaf, 0x09, + 0xf3, 0xb6, 0x85, 0x19, 0x03, 0x6c, 0xe3, 0x84, 0x4f, 0xc4, 0x37, 0x54, 0xa8, 0xd1, 0xce, + 0x03, 0x8e, 0xf3, 0x9a, 0xfc, 0x54, 0xb7, 0x12, 0x34, 0xed, 0x87, 0x03, 0x6f, 0xed, 0x13, + 0xa2, 0x8e, 0x6c, 0xe0, 0xc4, 0x7c, 0x10, 0x0b, 0xa0, 0x94, 0x1a, 0x2b, 0xed, 0x7f, 0xfe, + 0x24, 0xbe, 0x74, 0xa8, 0xcf, 0x16, + ], + [ + 0x16, 0xc9, 0x36, 0x57, 0x72, 0x34, 0xe6, 0x05, 0x1a, 0x23, 0x3e, 0xf1, 0x51, 0x5c, 0xcb, + 0x0e, 0x6c, 0x98, 0xa8, 0xc8, 0x1f, 0x0b, 0x85, 0x1d, 0x85, 0x58, 0xab, 0x2f, 0x93, 0xe3, + 0xe1, 0xa2, 0xfe, 0x2c, 0x54, 0x72, 0x9b, 0x02, 0xbb, 0x45, 0x59, 0xbb, 0x17, 0x4e, 0xe7, + 0x54, 0xbd, 0x2c, 0x01, 0xf5, 0xa3, 0x29, 0x86, 0x13, 0x38, 0x54, 0x35, 0xad, 0x2b, 0x4c, + 0xd5, 0x3f, 0x08, 0xaf, 0xa8, 0x4e, 0x08, 0x18, 0x83, 0x44, 0xc1, 0x8f, 0xdc, 0x87, 0x56, + 0xec, 0xe4, 0x83, 0xec, 0x66, 0x3f, 0xfc, 0xee, 0xf5, 0x8e, 0x4b, 0xa3, 0x74, 0x04, 0x6e, + 0x12, 0x2b, 0x05, 0xd9, 0x34, 0x5d, + ], + [ + 0x03, 0x60, 0xac, 0xb4, 0x3c, 0xf0, 0xcd, 0xa2, 0x22, 0x53, 0x03, 0xe6, 0xa3, 0xfa, 0x09, + 0x30, 0xef, 0xaf, 0xeb, 0xa9, 0x26, 0x80, 0xc8, 0x02, 0xb6, 0xae, 0xd7, 0x01, 0xf5, 0x51, + 0x99, 0x1b, 0x08, 0xfb, 0x76, 0x19, 0x45, 0x7b, 0x90, 0x14, 0xa5, 0x42, 0x99, 0x62, 0x5a, + 0xb2, 0x7e, 0x0c, 0x03, 0x2b, 0xdd, 0x01, 0x69, 0xf4, 0x86, 0x18, 0x32, 0x72, 0x02, 0xfd, + 0x3b, 0xdf, 0xd2, 0x4e, 0x8d, 0x03, 0x4e, 0x52, 0x7c, 0xda, 0x1b, 0x1c, 0x11, 0xd6, 0x83, + 0xbc, 0x77, 0xb7, 0xd7, 0x04, 0xe1, 0x21, 0x29, 0xa4, 0x9b, 0x2d, 0x33, 0x35, 0x6b, 0xef, + 0xed, 0x38, 0xfb, 0xf0, 0x3d, 0xe9, + ], + [ + 0x19, 0x4c, 0x44, 0x49, 0x37, 0xfd, 0x7e, 0xec, 0xa0, 0x72, 0x8d, 0xbc, 0x33, 0x8a, 0xb1, + 0x0c, 0xdc, 0x61, 0x07, 0xb3, 0x8b, 0xe6, 0xa1, 0xb6, 0xe4, 0xe9, 0x48, 0x1f, 0xaf, 0xbe, + 0xcc, 0x82, 0xe9, 0x4d, 0xca, 0x21, 0x2e, 0x41, 0x88, 0x99, 0x68, 0x29, 0xe5, 0x78, 0x92, + 0xd3, 0x8b, 0x3c, 0x16, 0x1f, 0x8b, 0x6b, 0xf1, 0xda, 0x81, 0x66, 0x85, 0x7e, 0x17, 0x91, + 0xda, 0x93, 0x1b, 0x37, 0x04, 0x24, 0x34, 0x11, 0xe8, 0x58, 0x14, 0x41, 0x40, 0x34, 0x94, + 0xfe, 0xef, 0x5b, 0x42, 0xeb, 0x36, 0xba, 0x08, 0xb9, 0x5f, 0xa6, 0x46, 0xfa, 0xfc, 0xe7, + 0xd8, 0x85, 0x51, 0x35, 0x59, 0x1c, + ], + [ + 0x15, 0x86, 0x18, 0x2f, 0xca, 0x7e, 0x5b, 0x5b, 0x5f, 0x6c, 0x63, 0xea, 0x8c, 0xda, 0xd4, + 0x8b, 0xe3, 0xe4, 0x39, 0xf7, 0x7b, 0x4c, 0x79, 0x44, 0x36, 0x39, 0x55, 0xe6, 0xd1, 0xca, + 0x8e, 0x57, 0x28, 0xc3, 0xf9, 0x19, 0x32, 0xfc, 0x65, 0x21, 0x7f, 0xd9, 0xf9, 0x86, 0x41, + 0x83, 0x1c, 0xf6, 0x10, 0xa9, 0xc9, 0x28, 0x14, 0x14, 0xa0, 0x84, 0xe3, 0x1b, 0x2e, 0x0e, + 0x8c, 0x27, 0xaa, 0xda, 0x14, 0xbf, 0xf8, 0x89, 0x24, 0xc9, 0xa8, 0x8b, 0xe7, 0x65, 0x48, + 0xb5, 0x7f, 0xf0, 0x65, 0xe3, 0x69, 0x4a, 0x96, 0xb2, 0xcd, 0x90, 0x4d, 0x9e, 0xe6, 0x8d, + 0x47, 0xd1, 0x19, 0xa2, 0x4f, 0x53, + ], +]; + +fn vk(env: &Env) -> VerificationKey { + let alpha = G1Affine::from_array(env, &VK_ALPHA); + let beta = G2Affine::from_array(env, &VK_BETA); + let gamma = G2Affine::from_array(env, &VK_GAMMA); + let delta = G2Affine::from_array(env, &VK_DELTA); + + let mut ic = Vec::new(env); + for p in VK_IC.iter() { + ic.push_back(G1Affine::from_array(env, p)); + } + + VerificationKey { + alpha, + beta, + gamma, + delta, + ic, + } +} + +#[contract] +pub struct Groth16Verifier; + +#[contractimpl] +impl Groth16Verifier { + pub fn verify_proof( + env: Env, + proof: Proof, + pub_signals: Vec, + ) -> Result { + let bls = env.crypto().bls12_381(); + let vk = vk(&env); + + if pub_signals.len() + 1 != vk.ic.len() { + return Err(Groth16Error::MalformedVerifyingKey); + } + + let mut vk_x = vk.ic.get(0).unwrap(); + for (s, v) in pub_signals.iter().zip(vk.ic.iter().skip(1)) { + let prod = bls.g1_mul(&v, &s); + vk_x = bls.g1_add(&vk_x, &prod); + } + + let neg_a = -proof.a; + let vp1 = soroban_sdk::vec![&env, neg_a, vk.alpha, vk_x, proof.c]; + let vp2 = soroban_sdk::vec![&env, proof.b, vk.beta, vk.gamma, vk.delta]; + + Ok(bls.pairing_check(vp1, vp2)) + } +} diff --git a/groth16_verifier/contracts/ark_verifier/src/test.rs b/groth16_verifier/contracts/ark_verifier/src/test.rs new file mode 100644 index 00000000..1ee8cdb7 --- /dev/null +++ b/groth16_verifier/contracts/ark_verifier/src/test.rs @@ -0,0 +1,111 @@ +#![cfg(test)] + +extern crate std; + +use ark_bls12_381::{Fq, Fq2, Fr as ArkFr}; +use ark_ff::{BigInteger, PrimeField}; +use ark_serialize::CanonicalSerialize; +use core::str::FromStr; +use serde::Deserialize; +use soroban_sdk::{ + Bytes, Env, U256, Vec, + crypto::bls12_381::{Fr, G1_SERIALIZED_SIZE, G1Affine, G2_SERIALIZED_SIZE, G2Affine}, +}; +use std::vec::Vec as AllocVec; + +use crate::{Groth16Verifier, Groth16VerifierClient, Proof}; + +#[derive(Deserialize)] +struct ProofJson { + pi_a: [std::string::String; 3], + pi_b: [[std::string::String; 2]; 3], + pi_c: [std::string::String; 3], + #[serde(rename = "publicSignals")] + public_signals: AllocVec, +} + +fn g1_from_coords(env: &Env, x: &str, y: &str) -> G1Affine { + let ark_g1 = ark_bls12_381::G1Affine::new(Fq::from_str(x).unwrap(), Fq::from_str(y).unwrap()); + let mut buf = [0u8; G1_SERIALIZED_SIZE]; + ark_g1.serialize_uncompressed(&mut buf[..]).unwrap(); + G1Affine::from_array(env, &buf) +} + +fn g2_from_coords(env: &Env, x1: &str, x2: &str, y1: &str, y2: &str) -> G2Affine { + let x = Fq2::new(Fq::from_str(x1).unwrap(), Fq::from_str(x2).unwrap()); + let y = Fq2::new(Fq::from_str(y1).unwrap(), Fq::from_str(y2).unwrap()); + let ark_g2 = ark_bls12_381::G2Affine::new(x, y); + let mut buf = [0u8; G2_SERIALIZED_SIZE]; + ark_g2.serialize_uncompressed(&mut buf[..]).unwrap(); + G2Affine::from_array(env, &buf) +} + +fn create_client(e: &Env) -> Groth16VerifierClient<'_> { + let contract_id = e.register(Groth16Verifier {}, ()); + Groth16VerifierClient::new(e, &contract_id) +} + +fn fr_from_str(env: &Env, s: &str) -> Fr { + // Parse string -> arkworks Fr -> bytes -> Soroban Fr + let ark_fr = ArkFr::from_str(s).unwrap(); + let bigint = ark_fr.into_bigint(); + let bytes = bigint.to_bytes_le(); + let mut u256_bytes = [0u8; 32]; + u256_bytes[..bytes.len().min(32)].copy_from_slice(&bytes[..bytes.len().min(32)]); + u256_bytes.reverse(); // little-endian -> big-endian for U256 + let bytes_obj = Bytes::from_array(&env, &u256_bytes); + Fr::from_u256(U256::from_be_bytes(&env, &bytes_obj)) +} + +#[test] +fn test() { + // Initialize the test environment + let env = Env::default(); + + // Load proof from JSON file + let proof_json_str = include_str!("../../../data/arkworks/proof.json"); + let proof_json: ProofJson = serde_json::from_str(proof_json_str).unwrap(); + + // Extract proof components from JSON + let pi_ax = &proof_json.pi_a[0]; + let pi_ay = &proof_json.pi_a[1]; + let pi_bx1 = &proof_json.pi_b[0][0]; + let pi_bx2 = &proof_json.pi_b[0][1]; + let pi_by1 = &proof_json.pi_b[1][0]; + let pi_by2 = &proof_json.pi_b[1][1]; + let pi_cx = &proof_json.pi_c[0]; + let pi_cy = &proof_json.pi_c[1]; + + // Construct the proof from JSON data + let proof = Proof { + a: g1_from_coords(&env, pi_ax, pi_ay), + b: g2_from_coords(&env, pi_bx1, pi_bx2, pi_by1, pi_by2), + c: g1_from_coords(&env, pi_cx, pi_cy), + }; + + // Create the contract client + let client = create_client(&env); + + // Test Case 1: Verify the proof with all correct public signals from JSON + let mut public_signals = Vec::new(&env); + for signal_str in &proof_json.public_signals { + let fr = fr_from_str(&env, signal_str); + public_signals.push_back(fr); + } + let res = client.verify_proof(&proof, &public_signals); + assert_eq!(res, true); + + // Test Case 2: Verify the proof with incorrect public signals (change first signal) + let mut incorrect_signals = Vec::new(&env); + // Use incorrect value for first signal, keep others the same + incorrect_signals.push_back(fr_from_str( + &env, + "999999999999999999999999999999999999999999999999999999999999999999999", + )); + for signal_str in proof_json.public_signals.iter().skip(1) { + let fr = fr_from_str(&env, signal_str); + incorrect_signals.push_back(fr); + } + let res = client.verify_proof(&proof, &incorrect_signals); + assert_eq!(res, false); +} diff --git a/groth16_verifier/contracts/circom_verifier/Cargo.toml b/groth16_verifier/contracts/circom_verifier/Cargo.toml new file mode 100644 index 00000000..c17f93dd --- /dev/null +++ b/groth16_verifier/contracts/circom_verifier/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "circom_verifier" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +crate-type = ["lib", "cdylib"] +doctest = false + +[dependencies] +soroban-sdk = "25" + +[dev-dependencies] +soroban-sdk = { version = "25", features = ["testutils"] } +ark-bls12-381 = "0.5" +ark-serialize = "0.5" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" \ No newline at end of file diff --git a/groth16_verifier/contracts/circom_verifier/src/lib.rs b/groth16_verifier/contracts/circom_verifier/src/lib.rs new file mode 100644 index 00000000..bbf919a7 --- /dev/null +++ b/groth16_verifier/contracts/circom_verifier/src/lib.rs @@ -0,0 +1,159 @@ +#![no_std] + +#[cfg(test)] +mod test; + +use soroban_sdk::{ + contract, contracterror, contractimpl, contracttype, + crypto::bls12_381::{Fr, G1Affine, G2Affine, G1_SERIALIZED_SIZE, G2_SERIALIZED_SIZE}, + Env, Vec, +}; + +#[contracterror] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u32)] +pub enum Groth16Error { + MalformedVerifyingKey = 0, +} + +#[derive(Clone)] +#[contracttype] +pub struct VerificationKey { + pub alpha: G1Affine, + pub beta: G2Affine, + pub gamma: G2Affine, + pub delta: G2Affine, + pub ic: Vec, +} + +#[derive(Clone)] +#[contracttype] +pub struct Proof { + pub a: G1Affine, + pub b: G2Affine, + pub c: G1Affine, +} + +// AUTO-GENERATED VK BYTES (uncompressed). DO NOT EDIT. +const VK_ALPHA: [u8; G1_SERIALIZED_SIZE] = [ + 0x12, 0x90, 0x5a, 0x22, 0xf0, 0xd6, 0x27, 0xdd, 0x05, 0xab, 0xc9, 0x8a, 0xe1, 0x15, 0x50, 0xf7, + 0xc8, 0x2a, 0x8d, 0x8f, 0x32, 0xf8, 0x8f, 0xaa, 0xed, 0x11, 0xea, 0x1b, 0xaf, 0xcb, 0x04, 0x86, + 0x9e, 0x72, 0x81, 0xae, 0xf5, 0x89, 0x4a, 0x55, 0x4e, 0x1c, 0xf6, 0xfc, 0x7d, 0x6f, 0x91, 0xcf, + 0x17, 0x0a, 0x98, 0xa2, 0x1e, 0x0e, 0x9e, 0x64, 0xa9, 0x0d, 0x3a, 0x0b, 0x41, 0x7d, 0x6f, 0xd9, + 0x8d, 0xf3, 0x71, 0xc9, 0xd7, 0x4d, 0x2c, 0x86, 0x6b, 0xdb, 0x29, 0x3d, 0x97, 0x02, 0x62, 0xad, + 0x40, 0xf8, 0x03, 0x4a, 0xa3, 0x25, 0x0e, 0x8c, 0xae, 0xd3, 0xb8, 0xd9, 0x4a, 0x51, 0x40, 0x24, +]; +const VK_BETA: [u8; G2_SERIALIZED_SIZE] = [ + 0x18, 0x93, 0x6f, 0xc2, 0x55, 0xe4, 0xa3, 0x1d, 0x80, 0x29, 0x2d, 0x9e, 0x6a, 0x04, 0xeb, 0xdb, + 0x4c, 0x53, 0x3d, 0x15, 0x8e, 0x1a, 0x7d, 0x78, 0x5a, 0x29, 0x34, 0x9c, 0xb7, 0x11, 0x10, 0x41, + 0x65, 0x46, 0x91, 0x53, 0x43, 0x20, 0x14, 0x83, 0x03, 0xb3, 0x04, 0x06, 0x5c, 0xc4, 0xa4, 0xe3, + 0x06, 0xae, 0x97, 0xf3, 0x6d, 0x48, 0x8a, 0x13, 0x7e, 0x90, 0x21, 0x9f, 0x45, 0xae, 0xf5, 0xf2, + 0x61, 0x25, 0x75, 0x0c, 0xc4, 0xc1, 0x51, 0x60, 0x0a, 0x36, 0x91, 0x2d, 0xbe, 0xb4, 0x5c, 0x8f, + 0x49, 0x08, 0x84, 0x26, 0x41, 0xff, 0xe3, 0xf8, 0x3f, 0x11, 0x6f, 0x87, 0x42, 0xd3, 0xaa, 0x36, + 0x0d, 0xf5, 0xe7, 0x2a, 0xb4, 0x92, 0xfe, 0xbc, 0xc2, 0x48, 0xef, 0x71, 0x5f, 0xe3, 0xbf, 0x59, + 0x5d, 0x77, 0x5e, 0x1e, 0x35, 0xe0, 0x9f, 0xde, 0x89, 0x88, 0x08, 0x4c, 0x7d, 0x9a, 0xb4, 0xaa, + 0x1f, 0x73, 0x69, 0xa3, 0x73, 0x42, 0xb6, 0x59, 0x85, 0x7a, 0x8b, 0x37, 0x01, 0x62, 0x67, 0xc3, + 0x04, 0xd9, 0x19, 0x4d, 0x23, 0x67, 0x5f, 0x6f, 0x35, 0x88, 0x15, 0x95, 0x09, 0x2b, 0xaf, 0x51, + 0xb2, 0x37, 0x15, 0xe4, 0x4f, 0x9c, 0x7b, 0x67, 0x1a, 0x5e, 0xd4, 0x62, 0xe8, 0x17, 0x54, 0x57, + 0xad, 0x77, 0x9e, 0x9c, 0xe4, 0xb4, 0x2e, 0x0a, 0x89, 0x51, 0x55, 0xca, 0x40, 0x7e, 0x29, 0xc6, +]; +const VK_GAMMA: [u8; G2_SERIALIZED_SIZE] = [ + 0x13, 0xe0, 0x2b, 0x60, 0x52, 0x71, 0x9f, 0x60, 0x7d, 0xac, 0xd3, 0xa0, 0x88, 0x27, 0x4f, 0x65, + 0x59, 0x6b, 0xd0, 0xd0, 0x99, 0x20, 0xb6, 0x1a, 0xb5, 0xda, 0x61, 0xbb, 0xdc, 0x7f, 0x50, 0x49, + 0x33, 0x4c, 0xf1, 0x12, 0x13, 0x94, 0x5d, 0x57, 0xe5, 0xac, 0x7d, 0x05, 0x5d, 0x04, 0x2b, 0x7e, + 0x02, 0x4a, 0xa2, 0xb2, 0xf0, 0x8f, 0x0a, 0x91, 0x26, 0x08, 0x05, 0x27, 0x2d, 0xc5, 0x10, 0x51, + 0xc6, 0xe4, 0x7a, 0xd4, 0xfa, 0x40, 0x3b, 0x02, 0xb4, 0x51, 0x0b, 0x64, 0x7a, 0xe3, 0xd1, 0x77, + 0x0b, 0xac, 0x03, 0x26, 0xa8, 0x05, 0xbb, 0xef, 0xd4, 0x80, 0x56, 0xc8, 0xc1, 0x21, 0xbd, 0xb8, + 0x06, 0x06, 0xc4, 0xa0, 0x2e, 0xa7, 0x34, 0xcc, 0x32, 0xac, 0xd2, 0xb0, 0x2b, 0xc2, 0x8b, 0x99, + 0xcb, 0x3e, 0x28, 0x7e, 0x85, 0xa7, 0x63, 0xaf, 0x26, 0x74, 0x92, 0xab, 0x57, 0x2e, 0x99, 0xab, + 0x3f, 0x37, 0x0d, 0x27, 0x5c, 0xec, 0x1d, 0xa1, 0xaa, 0xa9, 0x07, 0x5f, 0xf0, 0x5f, 0x79, 0xbe, + 0x0c, 0xe5, 0xd5, 0x27, 0x72, 0x7d, 0x6e, 0x11, 0x8c, 0xc9, 0xcd, 0xc6, 0xda, 0x2e, 0x35, 0x1a, + 0xad, 0xfd, 0x9b, 0xaa, 0x8c, 0xbd, 0xd3, 0xa7, 0x6d, 0x42, 0x9a, 0x69, 0x51, 0x60, 0xd1, 0x2c, + 0x92, 0x3a, 0xc9, 0xcc, 0x3b, 0xac, 0xa2, 0x89, 0xe1, 0x93, 0x54, 0x86, 0x08, 0xb8, 0x28, 0x01, +]; +const VK_DELTA: [u8; G2_SERIALIZED_SIZE] = [ + 0x0f, 0x49, 0x68, 0x09, 0xac, 0x28, 0xd0, 0x39, 0x64, 0x39, 0x26, 0xec, 0xc9, 0x20, 0xc7, 0xd6, + 0x1b, 0x63, 0x31, 0xc0, 0xeb, 0xb9, 0xe4, 0x45, 0xa9, 0x38, 0xab, 0x4f, 0x47, 0xd1, 0x26, 0xce, + 0x2c, 0xa4, 0x3e, 0xd1, 0x8f, 0x6e, 0x55, 0x21, 0x98, 0x37, 0x5b, 0x32, 0x42, 0x86, 0xfe, 0xf8, + 0x0b, 0xac, 0xdf, 0xa7, 0xfb, 0xa6, 0xdd, 0x38, 0xdb, 0x6a, 0xa1, 0xd7, 0x7c, 0xec, 0xc8, 0x91, + 0x3d, 0xce, 0x42, 0xb2, 0x49, 0x3f, 0xa5, 0x75, 0x10, 0xee, 0x12, 0xf3, 0xd4, 0x71, 0x3f, 0xee, + 0xc2, 0xb6, 0x33, 0xae, 0xca, 0x12, 0x2c, 0xa7, 0x26, 0x16, 0x32, 0x53, 0x35, 0xb5, 0x63, 0xca, + 0x05, 0x05, 0xab, 0xa7, 0xb5, 0xf5, 0xf5, 0xb5, 0xa5, 0xbd, 0x13, 0x48, 0x37, 0x24, 0xbe, 0x8e, + 0x91, 0x5a, 0xdd, 0x0d, 0xf2, 0x3e, 0x68, 0xb0, 0xff, 0x07, 0x23, 0xb2, 0x77, 0x13, 0xf2, 0x29, + 0x23, 0x5e, 0xe4, 0xeb, 0xc0, 0xe8, 0xa9, 0xd4, 0x5d, 0xbe, 0xee, 0x33, 0x95, 0x9c, 0x63, 0x1e, + 0x17, 0x81, 0x28, 0xa1, 0x60, 0x6a, 0xf6, 0x9d, 0xf9, 0x82, 0xfe, 0x2c, 0x5a, 0xef, 0xa6, 0x31, + 0xa1, 0xc7, 0x21, 0x35, 0x85, 0xa9, 0x64, 0x89, 0xd8, 0xb6, 0xb5, 0x65, 0x72, 0x1c, 0x49, 0xe0, + 0x8c, 0x9d, 0x56, 0x68, 0xfa, 0xa1, 0x03, 0x53, 0xa8, 0x33, 0xed, 0x07, 0x29, 0x1c, 0xc3, 0x1a, +]; + +const VK_IC: [[u8; G1_SERIALIZED_SIZE]; 2] = [ + [ + 0x06, 0x77, 0xc4, 0x0c, 0x42, 0xbc, 0x40, 0x76, 0x1f, 0x70, 0xb7, 0x38, 0xaf, 0x19, 0xe1, + 0x8a, 0x22, 0x9e, 0x1f, 0x81, 0x3d, 0x85, 0x3d, 0xe8, 0x70, 0x07, 0xea, 0xd0, 0x15, 0x2e, + 0xe9, 0xa9, 0xd1, 0xc2, 0x1c, 0x2f, 0x59, 0xd3, 0x27, 0xcf, 0x47, 0x5f, 0x7d, 0x09, 0x99, + 0xb9, 0x67, 0x77, 0x15, 0x27, 0x21, 0xd1, 0xa4, 0x69, 0x38, 0x36, 0x0b, 0xf5, 0xbc, 0xa4, + 0xe0, 0xf0, 0x64, 0xbc, 0x57, 0x23, 0x9a, 0x29, 0x94, 0x2e, 0x58, 0x2a, 0x53, 0xde, 0xd8, + 0xf8, 0xde, 0x3f, 0x3b, 0x89, 0x18, 0x39, 0x22, 0x1b, 0xdf, 0x54, 0x4a, 0x57, 0x13, 0x0e, + 0xee, 0x05, 0x86, 0x62, 0x16, 0x5e, + ], + [ + 0x09, 0xf1, 0xda, 0x6c, 0xb4, 0x07, 0x7d, 0x77, 0x45, 0x9a, 0xd2, 0xa1, 0x64, 0xee, 0x3b, + 0x77, 0xfa, 0x07, 0xb4, 0x66, 0x03, 0xba, 0x16, 0xc1, 0xfe, 0x1e, 0xe7, 0x52, 0x9d, 0x39, + 0xa9, 0x3d, 0xe3, 0xfb, 0x72, 0x02, 0xe8, 0x32, 0x37, 0x71, 0xac, 0x74, 0x69, 0x2a, 0xcd, + 0x05, 0x7a, 0x1a, 0x12, 0x27, 0x7b, 0xfd, 0x10, 0x21, 0x1a, 0x08, 0x8d, 0x11, 0x96, 0xca, + 0x22, 0x40, 0xc8, 0x37, 0x48, 0xac, 0x43, 0x5d, 0x1b, 0xba, 0x92, 0xe8, 0xa9, 0xdf, 0x93, + 0x58, 0xc8, 0x51, 0xce, 0xaf, 0x33, 0xc0, 0xd8, 0xd3, 0xf6, 0x21, 0x98, 0x9e, 0xaf, 0x44, + 0x7e, 0xba, 0x31, 0x5f, 0x99, 0xf1, + ], +]; + +fn vk(env: &Env) -> VerificationKey { + let alpha = G1Affine::from_array(env, &VK_ALPHA); + let beta = G2Affine::from_array(env, &VK_BETA); + let gamma = G2Affine::from_array(env, &VK_GAMMA); + let delta = G2Affine::from_array(env, &VK_DELTA); + + let mut ic = Vec::new(env); + for p in VK_IC.iter() { + ic.push_back(G1Affine::from_array(env, p)); + } + + VerificationKey { + alpha, + beta, + gamma, + delta, + ic, + } +} + +#[contract] +pub struct Groth16Verifier; + +#[contractimpl] +impl Groth16Verifier { + pub fn verify_proof( + env: Env, + proof: Proof, + pub_signals: Vec, + ) -> Result { + let bls = env.crypto().bls12_381(); + let vk = vk(&env); + + if pub_signals.len() + 1 != vk.ic.len() { + return Err(Groth16Error::MalformedVerifyingKey); + } + + let mut vk_x = vk.ic.get(0).unwrap(); + for (s, v) in pub_signals.iter().zip(vk.ic.iter().skip(1)) { + let prod = bls.g1_mul(&v, &s); + vk_x = bls.g1_add(&vk_x, &prod); + } + + let neg_a = -proof.a; + let vp1 = soroban_sdk::vec![&env, neg_a, vk.alpha, vk_x, proof.c]; + let vp2 = soroban_sdk::vec![&env, proof.b, vk.beta, vk.gamma, vk.delta]; + + Ok(bls.pairing_check(vp1, vp2)) + } +} diff --git a/groth16_verifier/contracts/circom_verifier/src/test.rs b/groth16_verifier/contracts/circom_verifier/src/test.rs new file mode 100644 index 00000000..f481a8be --- /dev/null +++ b/groth16_verifier/contracts/circom_verifier/src/test.rs @@ -0,0 +1,86 @@ +#![cfg(test)] + +extern crate std; + +use ark_bls12_381::{Fq, Fq2}; +use ark_serialize::CanonicalSerialize; +use core::str::FromStr; +use serde::Deserialize; +use soroban_sdk::{ + Env, U256, Vec, + crypto::bls12_381::{Fr, G1_SERIALIZED_SIZE, G1Affine, G2_SERIALIZED_SIZE, G2Affine}, +}; + +use crate::{Groth16Verifier, Groth16VerifierClient, Proof}; + +#[derive(Deserialize)] +struct ProofJson { + pi_a: [std::string::String; 3], + pi_b: [[std::string::String; 2]; 3], + pi_c: [std::string::String; 3], +} + +fn g1_from_coords(env: &Env, x: &str, y: &str) -> G1Affine { + let ark_g1 = ark_bls12_381::G1Affine::new(Fq::from_str(x).unwrap(), Fq::from_str(y).unwrap()); + let mut buf = [0u8; G1_SERIALIZED_SIZE]; + ark_g1.serialize_uncompressed(&mut buf[..]).unwrap(); + G1Affine::from_array(env, &buf) +} + +fn g2_from_coords(env: &Env, x1: &str, x2: &str, y1: &str, y2: &str) -> G2Affine { + let x = Fq2::new(Fq::from_str(x1).unwrap(), Fq::from_str(x2).unwrap()); + let y = Fq2::new(Fq::from_str(y1).unwrap(), Fq::from_str(y2).unwrap()); + let ark_g2 = ark_bls12_381::G2Affine::new(x, y); + let mut buf = [0u8; G2_SERIALIZED_SIZE]; + ark_g2.serialize_uncompressed(&mut buf[..]).unwrap(); + G2Affine::from_array(env, &buf) +} + +fn create_client(e: &Env) -> Groth16VerifierClient<'_> { + let contract_id = e.register(Groth16Verifier {}, ()); + Groth16VerifierClient::new(e, &contract_id) +} + +#[test] +fn test() { + // Initialize the test environment + let env = Env::default(); + + // Load proof from JSON file + let proof_json_str = include_str!("../../../data/circom/proof.json"); + let proof_json: ProofJson = serde_json::from_str(proof_json_str).unwrap(); + + // Extract proof components from JSON + let pi_ax = &proof_json.pi_a[0]; + let pi_ay = &proof_json.pi_a[1]; + let pi_bx1 = &proof_json.pi_b[0][0]; + let pi_bx2 = &proof_json.pi_b[0][1]; + let pi_by1 = &proof_json.pi_b[1][0]; + let pi_by2 = &proof_json.pi_b[1][1]; + let pi_cx = &proof_json.pi_c[0]; + let pi_cy = &proof_json.pi_c[1]; + + // Construct the proof from JSON data + let proof = Proof { + a: g1_from_coords(&env, pi_ax, pi_ay), + b: g2_from_coords(&env, pi_bx1, pi_bx2, pi_by1, pi_by2), + c: g1_from_coords(&env, pi_cx, pi_cy), + }; + + // Create the contract client + let client = create_client(&env); + + // // Test Case 1: Verify the proof with the correct public output loaded from `data/circom/public.json` + let public_json_str = include_str!("../../../data/circom/public.json"); + let public_signals: std::vec::Vec = + serde_json::from_str(public_json_str).unwrap(); + let expected_output: u32 = public_signals[0].parse().unwrap(); + let output = Vec::from_array(&env, [Fr::from_u256(U256::from_u32(&env, expected_output))]); + let res = client.verify_proof(&proof, &output); + assert_eq!(res, true); + + // Test Case 2: Verify the proof with an incorrect public output + let output = Vec::from_array(&env, [Fr::from_u256(U256::from_u32(&env, 22))]); + let res = client.verify_proof(&proof, &output); + assert_eq!(res, false); +} diff --git a/groth16_verifier/contracts/gnark_bn254_verifier/Cargo.toml b/groth16_verifier/contracts/gnark_bn254_verifier/Cargo.toml new file mode 100644 index 00000000..cba393a0 --- /dev/null +++ b/groth16_verifier/contracts/gnark_bn254_verifier/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "gnark_bn254_verifier" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +crate-type = ["lib", "cdylib"] +doctest = false + +[dependencies] +soroban-sdk = "25" + +[dev-dependencies] +soroban-sdk = { version = "25", features = ["testutils"] } +ark-bn254 = "0.5" +ark-serialize = "0.5" +ark-ff = "0.5" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" \ No newline at end of file diff --git a/groth16_verifier/contracts/gnark_bn254_verifier/src/lib.rs b/groth16_verifier/contracts/gnark_bn254_verifier/src/lib.rs new file mode 100644 index 00000000..615f0d5c --- /dev/null +++ b/groth16_verifier/contracts/gnark_bn254_verifier/src/lib.rs @@ -0,0 +1,142 @@ +#![no_std] + +#[cfg(test)] +mod test; + +use soroban_sdk::{ + Env, Vec, contract, contracterror, contractimpl, contracttype, + crypto::bn254::{ + BN254_G1_SERIALIZED_SIZE, BN254_G2_SERIALIZED_SIZE, Bn254G1Affine, Bn254G2Affine, Fr, + }, +}; + +#[contracterror] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u32)] +pub enum Groth16Error { + MalformedVerifyingKey = 0, +} + +#[derive(Clone)] +#[contracttype] +pub struct VerificationKey { + pub alpha: Bn254G1Affine, + pub beta: Bn254G2Affine, + pub gamma: Bn254G2Affine, + pub delta: Bn254G2Affine, + pub ic: Vec, +} + +#[derive(Clone)] +#[contracttype] +pub struct Proof { + pub a: Bn254G1Affine, + pub b: Bn254G2Affine, + pub c: Bn254G1Affine, +} + +// AUTO-GENERATED VK BYTES (uncompressed). DO NOT EDIT. +const VK_ALPHA: [u8; BN254_G1_SERIALIZED_SIZE] = [ + 0x25, 0xf0, 0xb8, 0x9e, 0x3b, 0xbf, 0xd5, 0x99, 0x65, 0x06, 0x9c, 0x98, 0xf3, 0xdb, 0x43, 0x84, + 0x50, 0x58, 0x4b, 0x6e, 0x73, 0x43, 0xe8, 0x3c, 0xdf, 0xb2, 0xb2, 0x57, 0xfc, 0x25, 0x18, 0xbf, + 0x17, 0x83, 0xaf, 0x17, 0x79, 0xb7, 0xb1, 0x4c, 0xbf, 0xe4, 0x47, 0x89, 0x38, 0xbd, 0xd9, 0xbe, + 0x22, 0x21, 0x6e, 0x42, 0x9d, 0xeb, 0xc7, 0x69, 0x9b, 0x26, 0xd0, 0xaa, 0xd5, 0x82, 0x43, 0x57, +]; +const VK_BETA: [u8; BN254_G2_SERIALIZED_SIZE] = [ + 0x21, 0x18, 0x47, 0x55, 0x97, 0xb3, 0x1a, 0x2a, 0x4e, 0x5b, 0xd4, 0x4d, 0x9e, 0x1f, 0x2f, 0xd5, + 0x10, 0x85, 0x12, 0x33, 0x70, 0x5f, 0xc2, 0xea, 0x2e, 0x35, 0x63, 0xd6, 0xfd, 0xc3, 0x50, 0x66, + 0x18, 0x9c, 0xfb, 0xaf, 0xc2, 0x08, 0x36, 0xea, 0xe4, 0x34, 0x93, 0x76, 0x49, 0xdd, 0xfb, 0x04, + 0xf2, 0x85, 0xf6, 0x6a, 0xc2, 0x8a, 0x5c, 0x59, 0xc0, 0xfe, 0x2a, 0xa8, 0x0e, 0x56, 0xcc, 0x67, + 0x1d, 0xbb, 0x1e, 0xae, 0xa3, 0xb7, 0xae, 0x66, 0x7c, 0x29, 0xc1, 0x16, 0xbe, 0x40, 0x04, 0x9a, + 0x2e, 0xf7, 0x20, 0x71, 0xd7, 0x3b, 0x8a, 0x6c, 0x5a, 0x0c, 0x4d, 0xd4, 0x84, 0x64, 0xff, 0x1a, + 0x2c, 0x9f, 0xb5, 0xd3, 0x4e, 0x65, 0x49, 0xd0, 0x53, 0x1b, 0x30, 0xe0, 0xea, 0x01, 0x38, 0x63, + 0xa4, 0xb8, 0x36, 0xdf, 0x70, 0x03, 0xe0, 0x81, 0xa1, 0x8e, 0xba, 0x0d, 0x40, 0xfe, 0x34, 0x5e, +]; +const VK_GAMMA: [u8; BN254_G2_SERIALIZED_SIZE] = [ + 0x04, 0x1e, 0x0c, 0x1a, 0xc5, 0x28, 0x83, 0xa4, 0xd6, 0x95, 0x1e, 0x73, 0x51, 0x27, 0xcb, 0xab, + 0x19, 0xda, 0x83, 0x83, 0xcf, 0x10, 0xe8, 0x0e, 0xce, 0x67, 0x0f, 0x51, 0xcd, 0x3e, 0xd5, 0xe1, + 0x0f, 0x31, 0x08, 0x68, 0xf9, 0xe1, 0x6f, 0x0f, 0xd9, 0x18, 0x37, 0x5c, 0xd6, 0xc9, 0x40, 0x92, + 0x34, 0xef, 0x6d, 0x44, 0x88, 0x87, 0x78, 0x1e, 0xcf, 0x6c, 0x2c, 0x70, 0x77, 0x9b, 0x17, 0xae, + 0x1c, 0x8f, 0x35, 0x1b, 0xa2, 0xee, 0x10, 0x38, 0x81, 0xbc, 0x83, 0xc3, 0xb8, 0x3c, 0x8b, 0xda, + 0xcb, 0xbe, 0xa2, 0x67, 0x7f, 0x18, 0x28, 0x8e, 0xa6, 0x88, 0xf3, 0xeb, 0x60, 0x34, 0x73, 0x8e, + 0x18, 0x93, 0x65, 0x7b, 0x22, 0xe6, 0x84, 0x72, 0x24, 0x0d, 0x81, 0xe6, 0xba, 0xa2, 0xe1, 0x03, + 0xa1, 0x34, 0x47, 0x10, 0xeb, 0x33, 0xa1, 0x9d, 0x4f, 0xf4, 0x58, 0xf3, 0x62, 0x85, 0x54, 0xd4, +]; +const VK_DELTA: [u8; BN254_G2_SERIALIZED_SIZE] = [ + 0x02, 0xc2, 0xce, 0x28, 0xff, 0xf2, 0xf3, 0xbe, 0x1e, 0x9e, 0x99, 0x69, 0xad, 0x0f, 0xb1, 0xd5, + 0x28, 0x91, 0xef, 0x5f, 0x01, 0x37, 0xb7, 0xd8, 0xd8, 0xc1, 0xc8, 0x4b, 0xc1, 0x05, 0x19, 0x91, + 0x26, 0x8a, 0xef, 0xb5, 0x46, 0x3e, 0xee, 0x0a, 0xcf, 0x48, 0x56, 0xaf, 0xaa, 0x53, 0xb4, 0xa1, + 0x0d, 0x30, 0xde, 0x5c, 0xf4, 0x86, 0xfe, 0x72, 0x8a, 0x4b, 0x74, 0x05, 0x31, 0x11, 0xc7, 0x54, + 0x1f, 0x7c, 0xf1, 0xf2, 0x23, 0xa8, 0x14, 0x32, 0xad, 0x60, 0x63, 0x39, 0xc6, 0xfe, 0x2b, 0xb9, + 0x9c, 0x82, 0x91, 0x81, 0x32, 0x73, 0x11, 0xc6, 0xcd, 0x8a, 0x06, 0x6f, 0x26, 0xc1, 0x3d, 0xcb, + 0x25, 0x0e, 0x0d, 0xf1, 0x61, 0xf7, 0xeb, 0x48, 0x0a, 0x57, 0x8a, 0xd2, 0x35, 0x1d, 0x35, 0x6b, + 0xda, 0xfe, 0xdf, 0x41, 0xc7, 0x85, 0xea, 0xec, 0x94, 0x23, 0x87, 0x99, 0xb5, 0xc9, 0xaa, 0x17, +]; + +const VK_IC: [[u8; BN254_G1_SERIALIZED_SIZE]; 2] = [ + [ + 0x27, 0xec, 0x4e, 0x58, 0xb2, 0x43, 0xef, 0xd3, 0x08, 0xd0, 0xc8, 0x9d, 0xac, 0xd0, 0x9c, + 0xd6, 0xa3, 0xc2, 0x47, 0xee, 0xa9, 0xdb, 0x7e, 0x85, 0x46, 0x8d, 0x87, 0xc2, 0x02, 0x0b, + 0xff, 0x5f, 0x0f, 0x38, 0x7f, 0x2a, 0xde, 0x6f, 0xfe, 0xcd, 0xe7, 0x77, 0xaf, 0xca, 0x23, + 0xb6, 0x9f, 0x9a, 0x12, 0xc6, 0x1a, 0xd5, 0x2c, 0x0f, 0xfb, 0x51, 0x3f, 0x6f, 0x52, 0xb2, + 0xb0, 0x5c, 0x12, 0x69, + ], + [ + 0x14, 0x18, 0xe6, 0xfb, 0xc7, 0x03, 0x3e, 0x20, 0xe9, 0x35, 0x67, 0xf2, 0x99, 0x31, 0x9b, + 0x32, 0x40, 0x21, 0x6c, 0xf7, 0xbf, 0x7e, 0xb3, 0xb5, 0xeb, 0x06, 0x36, 0xce, 0xd7, 0xc4, + 0xc7, 0xaa, 0x24, 0x64, 0xd7, 0xee, 0x1c, 0x64, 0x97, 0xb1, 0xb1, 0x5e, 0xcd, 0x00, 0xaf, + 0xb1, 0xdd, 0x6b, 0x6a, 0x2a, 0xe1, 0x1e, 0x61, 0xb9, 0x8c, 0xb0, 0x64, 0xd7, 0x12, 0x05, + 0x69, 0x44, 0xbd, 0xb6, + ], +]; + +fn vk(env: &Env) -> VerificationKey { + let alpha = Bn254G1Affine::from_array(env, &VK_ALPHA); + let beta = Bn254G2Affine::from_array(env, &VK_BETA); + let gamma = Bn254G2Affine::from_array(env, &VK_GAMMA); + let delta = Bn254G2Affine::from_array(env, &VK_DELTA); + + let mut ic = Vec::new(env); + for p in VK_IC.iter() { + ic.push_back(Bn254G1Affine::from_array(env, p)); + } + + VerificationKey { + alpha, + beta, + gamma, + delta, + ic, + } +} + +#[contract] +pub struct Groth16Verifier; + +#[contractimpl] +impl Groth16Verifier { + pub fn verify_proof( + env: Env, + proof: Proof, + pub_signals: Vec, + ) -> Result { + let bn = env.crypto().bn254(); + let vk = vk(&env); + + if pub_signals.len() + 1 != vk.ic.len() { + return Err(Groth16Error::MalformedVerifyingKey); + } + + let mut vk_x = vk.ic.get(0).unwrap(); + for (s, v) in pub_signals.iter().zip(vk.ic.iter().skip(1)) { + let prod = bn.g1_mul(&v, &s); + vk_x = bn.g1_add(&vk_x, &prod); + } + + let neg_a = -proof.a; + let vp1 = soroban_sdk::vec![&env, neg_a, vk.alpha, vk_x, proof.c]; + let vp2 = soroban_sdk::vec![&env, proof.b, vk.beta, vk.gamma, vk.delta]; + + Ok(bn.pairing_check(vp1, vp2)) + } +} diff --git a/groth16_verifier/contracts/gnark_bn254_verifier/src/test.rs b/groth16_verifier/contracts/gnark_bn254_verifier/src/test.rs new file mode 100644 index 00000000..52baccbc --- /dev/null +++ b/groth16_verifier/contracts/gnark_bn254_verifier/src/test.rs @@ -0,0 +1,92 @@ +#![cfg(test)] + +extern crate std; + +use ark_bn254::{Fq, Fq2}; +use ark_ff::{BigInteger, PrimeField}; +use core::str::FromStr; +use serde::Deserialize; +use soroban_sdk::{ + Env, U256, Vec, + crypto::bn254::{ + BN254_G1_SERIALIZED_SIZE, BN254_G2_SERIALIZED_SIZE, Bn254G1Affine, Bn254G2Affine, Fr, + }, +}; + +use crate::{Groth16Verifier, Groth16VerifierClient, Proof}; + +#[derive(Deserialize)] +struct ProofJson { + pi_a: [std::string::String; 3], + pi_b: [[std::string::String; 2]; 3], + pi_c: [std::string::String; 3], + #[serde(rename = "publicSignals")] + public_signals: std::vec::Vec, +} + +fn fq_to_bytes_be(fq: &Fq) -> [u8; 32] { + let bytes = fq.into_bigint().to_bytes_be(); + let mut out = [0u8; 32]; + let start = out.len().saturating_sub(bytes.len()); + out[start..].copy_from_slice(&bytes); + out +} + +fn g1_from_coords(env: &Env, x: &str, y: &str) -> Bn254G1Affine { + let ark_g1 = ark_bn254::G1Affine::new(Fq::from_str(x).unwrap(), Fq::from_str(y).unwrap()); + let mut buf = [0u8; BN254_G1_SERIALIZED_SIZE]; + buf[..32].copy_from_slice(&fq_to_bytes_be(&ark_g1.x)); + buf[32..].copy_from_slice(&fq_to_bytes_be(&ark_g1.y)); + Bn254G1Affine::from_array(env, &buf) +} + +fn g2_from_coords(env: &Env, x1: &str, x2: &str, y1: &str, y2: &str) -> Bn254G2Affine { + let x = Fq2::new(Fq::from_str(x1).unwrap(), Fq::from_str(x2).unwrap()); + let y = Fq2::new(Fq::from_str(y1).unwrap(), Fq::from_str(y2).unwrap()); + let ark_g2 = ark_bn254::G2Affine::new(x, y); + let mut buf = [0u8; BN254_G2_SERIALIZED_SIZE]; + buf[0..32].copy_from_slice(&fq_to_bytes_be(&ark_g2.x.c1)); + buf[32..64].copy_from_slice(&fq_to_bytes_be(&ark_g2.x.c0)); + buf[64..96].copy_from_slice(&fq_to_bytes_be(&ark_g2.y.c1)); + buf[96..128].copy_from_slice(&fq_to_bytes_be(&ark_g2.y.c0)); + Bn254G2Affine::from_array(env, &buf) +} + +fn create_client(e: &Env) -> Groth16VerifierClient<'_> { + let contract_id = e.register(Groth16Verifier {}, ()); + Groth16VerifierClient::new(e, &contract_id) +} + +#[test] +fn test() { + let env = Env::default(); + + let proof_json_str = include_str!("../../../data/gnark_bn254/proof.json"); + let proof_json: ProofJson = serde_json::from_str(proof_json_str).unwrap(); + + let proof = Proof { + a: g1_from_coords(&env, &proof_json.pi_a[0], &proof_json.pi_a[1]), + b: g2_from_coords( + &env, + &proof_json.pi_b[0][0], + &proof_json.pi_b[0][1], + &proof_json.pi_b[1][0], + &proof_json.pi_b[1][1], + ), + c: g1_from_coords(&env, &proof_json.pi_c[0], &proof_json.pi_c[1]), + }; + + let client = create_client(&env); + + let mut output = Vec::new(&env); + for s in &proof_json.public_signals { + let val: u32 = s.parse().unwrap(); + output.push_back(Fr::from_u256(U256::from_u32(&env, val))); + } + let res = client.verify_proof(&proof, &output); + assert_eq!(res, true); + + let output = Vec::from_array(&env, [Fr::from_u256(U256::from_u32(&env, 22))]); + let res = client.verify_proof(&proof, &output); + assert_eq!(res, false); +} diff --git a/groth16_verifier/contracts/gnark_verifier/Cargo.toml b/groth16_verifier/contracts/gnark_verifier/Cargo.toml new file mode 100644 index 00000000..5bb621f1 --- /dev/null +++ b/groth16_verifier/contracts/gnark_verifier/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "gnark_verifier" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +crate-type = ["lib", "cdylib"] +doctest = false + +[dependencies] +soroban-sdk = "25" + +[dev-dependencies] +soroban-sdk = { version = "25", features = ["testutils"] } +ark-bls12-381 = "0.5" +ark-serialize = "0.5" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/groth16_verifier/contracts/gnark_verifier/src/lib.rs b/groth16_verifier/contracts/gnark_verifier/src/lib.rs new file mode 100644 index 00000000..e6582e4a --- /dev/null +++ b/groth16_verifier/contracts/gnark_verifier/src/lib.rs @@ -0,0 +1,158 @@ +#![no_std] + +#[cfg(test)] +mod test; + +use soroban_sdk::{ + Env, Vec, contract, contracterror, contractimpl, contracttype, + crypto::bls12_381::{Fr, G1_SERIALIZED_SIZE, G1Affine, G2_SERIALIZED_SIZE, G2Affine}, +}; + +#[contracterror] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +#[repr(u32)] +pub enum Groth16Error { + MalformedVerifyingKey = 0, +} + +#[derive(Clone)] +#[contracttype] +pub struct VerificationKey { + pub alpha: G1Affine, + pub beta: G2Affine, + pub gamma: G2Affine, + pub delta: G2Affine, + pub ic: Vec, +} + +#[derive(Clone)] +#[contracttype] +pub struct Proof { + pub a: G1Affine, + pub b: G2Affine, + pub c: G1Affine, +} + +// AUTO-GENERATED VK BYTES (uncompressed). DO NOT EDIT. +const VK_ALPHA: [u8; G1_SERIALIZED_SIZE] = [ + 0x0d, 0x4b, 0xb1, 0x9e, 0x5d, 0x80, 0x84, 0x88, 0x7e, 0x9f, 0x4b, 0xeb, 0xf9, 0xb8, 0xe4, 0xa3, + 0x95, 0x4e, 0x0f, 0x28, 0x2a, 0xb1, 0x32, 0x28, 0x1b, 0x19, 0x3b, 0x2f, 0x3d, 0x01, 0xd5, 0x3e, + 0x22, 0x2a, 0x97, 0x80, 0x33, 0xf2, 0xe8, 0x79, 0xa5, 0xe0, 0xb9, 0x3e, 0x7d, 0x65, 0x0d, 0x14, + 0x09, 0x72, 0x40, 0x7d, 0x26, 0x84, 0x18, 0xa4, 0x0b, 0x03, 0x9d, 0x61, 0xe8, 0xed, 0x4f, 0x62, + 0xd9, 0x30, 0xfd, 0xf1, 0x37, 0xaf, 0x76, 0x8b, 0xcd, 0x3c, 0xe5, 0xdb, 0x3f, 0x3d, 0x9a, 0x70, + 0xe0, 0x84, 0x5d, 0x01, 0x3c, 0x27, 0x4c, 0xc6, 0xbc, 0x36, 0x81, 0x67, 0x3c, 0x9b, 0x00, 0xbf, +]; +const VK_BETA: [u8; G2_SERIALIZED_SIZE] = [ + 0x0d, 0xb4, 0x60, 0x41, 0x3d, 0xe6, 0x67, 0xa3, 0xdf, 0x89, 0x89, 0x9f, 0x91, 0x6e, 0xc0, 0xad, + 0x5c, 0x03, 0x3d, 0x50, 0x97, 0xf9, 0x80, 0x3f, 0xae, 0xea, 0x46, 0x87, 0x1f, 0x20, 0x68, 0x3c, + 0x19, 0xeb, 0x82, 0xa9, 0x53, 0x7e, 0x9f, 0x55, 0xc3, 0x4e, 0x5a, 0x47, 0x47, 0xd5, 0x85, 0x1a, + 0x16, 0x96, 0x3e, 0xa8, 0x86, 0x8e, 0x59, 0x20, 0xeb, 0x3d, 0x48, 0xc6, 0xec, 0x1d, 0xe8, 0xc7, + 0xf6, 0xef, 0x7c, 0x00, 0x6c, 0x3c, 0xfb, 0xd8, 0xfe, 0x94, 0x61, 0xa5, 0xeb, 0xa4, 0x2e, 0xd9, + 0x1e, 0xa9, 0xe7, 0x87, 0x80, 0xd4, 0xb3, 0x99, 0xd8, 0xef, 0x87, 0x22, 0xb0, 0x39, 0xd7, 0x56, + 0x04, 0x05, 0xd1, 0x5f, 0xcb, 0xc3, 0xf7, 0x70, 0xe0, 0x03, 0xfa, 0x3a, 0x90, 0x84, 0xf4, 0x83, + 0x71, 0x20, 0xd4, 0x4f, 0xb1, 0xa8, 0x44, 0x14, 0xe6, 0xd7, 0x3e, 0x1b, 0xc6, 0xec, 0x52, 0xd5, + 0x4f, 0xa2, 0x03, 0x0a, 0xd8, 0x3a, 0x7e, 0x68, 0xbe, 0x48, 0xc4, 0x7f, 0xfe, 0xae, 0x23, 0x34, + 0x16, 0x6b, 0x09, 0x42, 0x91, 0x45, 0x0f, 0x5b, 0xd4, 0xe6, 0xb7, 0xc1, 0x23, 0xd8, 0x94, 0x5a, + 0xfb, 0x0f, 0x43, 0xd1, 0x22, 0xb3, 0x7c, 0xec, 0x1d, 0x0e, 0x52, 0xbb, 0x57, 0xc5, 0xb3, 0xae, + 0x89, 0x4c, 0xaa, 0x2a, 0x06, 0x5f, 0x0e, 0x79, 0x9d, 0xc5, 0xf4, 0xd9, 0x11, 0x28, 0xae, 0xe6, +]; +const VK_GAMMA: [u8; G2_SERIALIZED_SIZE] = [ + 0x0e, 0xfc, 0x36, 0xda, 0x93, 0x67, 0xe6, 0x57, 0x7e, 0x00, 0xf4, 0xcb, 0x0f, 0xbd, 0x68, 0x8a, + 0xe9, 0x6e, 0x95, 0xad, 0x22, 0x45, 0x67, 0xf8, 0x82, 0xa0, 0x8f, 0x2f, 0x6d, 0x35, 0x46, 0xc4, + 0x3b, 0x9d, 0xac, 0xa6, 0x4f, 0x52, 0xdb, 0x9b, 0x7a, 0xc3, 0x44, 0x82, 0xa8, 0x30, 0xfc, 0x16, + 0x02, 0x8e, 0xc7, 0x1d, 0xe7, 0xf0, 0x36, 0xea, 0x27, 0xfc, 0x43, 0x81, 0x7e, 0xb8, 0x4c, 0x42, + 0xfe, 0xd3, 0x58, 0xb6, 0xdb, 0x55, 0x8a, 0x72, 0x1c, 0x29, 0xbb, 0xc6, 0xdd, 0x2a, 0xe1, 0x1d, + 0x87, 0xad, 0xe1, 0x35, 0xcc, 0x1c, 0x6b, 0xbe, 0xfa, 0xdd, 0x52, 0x96, 0xf5, 0x43, 0xeb, 0xde, + 0x05, 0xd8, 0xb3, 0x14, 0x8a, 0x11, 0x5c, 0x3f, 0xbf, 0x77, 0x1e, 0xf2, 0xd2, 0xf0, 0x3f, 0x95, + 0x98, 0x2b, 0x29, 0x78, 0x16, 0x99, 0x35, 0x1f, 0x76, 0x84, 0x2a, 0x88, 0x2f, 0x7c, 0x4a, 0x84, + 0x4a, 0x40, 0x2d, 0x61, 0x04, 0x98, 0x0a, 0x15, 0x4a, 0x05, 0xd4, 0xe2, 0xfe, 0xc8, 0x30, 0xd9, + 0x12, 0x96, 0xce, 0xf2, 0x20, 0x84, 0x03, 0xa6, 0x1f, 0xd3, 0x1d, 0x09, 0xa4, 0x79, 0xb4, 0x6f, + 0xcc, 0x66, 0x2a, 0x4c, 0x70, 0xa2, 0x66, 0x58, 0x07, 0xc6, 0x2f, 0xf8, 0x81, 0x7d, 0x63, 0x32, + 0xe4, 0x0c, 0x67, 0xe1, 0x43, 0x45, 0x7d, 0x9c, 0xa7, 0xd0, 0xda, 0x10, 0xb1, 0x96, 0x98, 0x90, +]; +const VK_DELTA: [u8; G2_SERIALIZED_SIZE] = [ + 0x10, 0x63, 0x84, 0x26, 0xc8, 0x2a, 0x30, 0x9a, 0x09, 0x9f, 0x26, 0x7c, 0x44, 0x4b, 0xf5, 0x95, + 0x78, 0x33, 0x9d, 0xa9, 0x47, 0x6b, 0xbd, 0x24, 0x20, 0xeb, 0x1f, 0xca, 0x40, 0xa0, 0x6c, 0x0d, + 0xe9, 0xd9, 0xcc, 0x92, 0x9a, 0x7d, 0x30, 0xda, 0xd7, 0xbe, 0xc0, 0x2a, 0x3d, 0x16, 0x30, 0x5c, + 0x15, 0x59, 0xc7, 0xef, 0x00, 0x3a, 0x9d, 0xb8, 0x15, 0x11, 0x5e, 0x1a, 0x83, 0xde, 0xc8, 0x70, + 0x1a, 0xfa, 0xc6, 0x10, 0xe5, 0x44, 0xcd, 0x2c, 0xea, 0x14, 0x4c, 0x3c, 0x3c, 0x79, 0x78, 0xfd, + 0x51, 0x23, 0x3c, 0xe6, 0x06, 0x58, 0xa1, 0x5a, 0x99, 0x34, 0xc7, 0xb6, 0x12, 0x29, 0x1c, 0xac, + 0x02, 0x82, 0xdd, 0x82, 0x61, 0xb0, 0x5b, 0x94, 0x72, 0x9e, 0xd9, 0x0e, 0xdf, 0x63, 0xb7, 0x98, + 0x79, 0xed, 0xb3, 0x72, 0xf6, 0xb7, 0x76, 0x1f, 0x58, 0x7e, 0x59, 0x09, 0xca, 0x72, 0x43, 0xc8, + 0xa4, 0xe1, 0x75, 0xc2, 0xa2, 0xa2, 0x8c, 0x14, 0x79, 0xe2, 0xc1, 0xc4, 0x5c, 0xe5, 0x23, 0x17, + 0x0a, 0x9e, 0x44, 0x89, 0xca, 0xcb, 0x2d, 0xd6, 0xf0, 0x89, 0x77, 0xac, 0x6a, 0x20, 0x90, 0xb1, + 0x94, 0x92, 0x88, 0x74, 0x62, 0xcd, 0x00, 0x7b, 0x81, 0xbc, 0xda, 0xbb, 0x08, 0xe3, 0x66, 0x99, + 0x8d, 0xd5, 0xac, 0x6e, 0x04, 0x3e, 0xc6, 0xed, 0x07, 0x13, 0xd6, 0x30, 0xf9, 0x3a, 0x4e, 0x56, +]; + +const VK_IC: [[u8; G1_SERIALIZED_SIZE]; 2] = [ + [ + 0x19, 0x56, 0x87, 0xf1, 0xfb, 0xdd, 0x9c, 0x51, 0x78, 0xd1, 0xbe, 0x8f, 0x62, 0xa6, 0x7d, + 0x79, 0x1d, 0x03, 0x76, 0xf4, 0x78, 0xdd, 0x83, 0x88, 0x53, 0xb5, 0x40, 0xa7, 0x28, 0x1a, + 0x4b, 0x00, 0x41, 0xec, 0x67, 0xdd, 0x2d, 0x9e, 0xf0, 0xaf, 0x28, 0x88, 0xdf, 0x13, 0x43, + 0x17, 0x66, 0xc9, 0x03, 0x29, 0xe6, 0xdb, 0xf4, 0xe7, 0x98, 0x0c, 0xe3, 0x36, 0x8e, 0xe8, + 0x0c, 0xda, 0x11, 0x9f, 0x5f, 0x55, 0xf2, 0xad, 0x6f, 0x0e, 0xdd, 0xe0, 0x29, 0x86, 0x18, + 0x30, 0xde, 0x6d, 0xbd, 0xd5, 0xf3, 0x41, 0xe7, 0xa4, 0x07, 0x9d, 0xc9, 0xa1, 0x03, 0x5a, + 0x57, 0x42, 0x3f, 0x9a, 0x37, 0x16, + ], + [ + 0x09, 0x6d, 0x93, 0x45, 0x4f, 0x8a, 0x01, 0x4c, 0xff, 0xdc, 0x44, 0xca, 0xc1, 0x00, 0x2c, + 0x0e, 0xdb, 0x40, 0x8a, 0xfd, 0xbf, 0x5f, 0xd7, 0x13, 0xc8, 0xae, 0xa7, 0x07, 0x65, 0x6f, + 0xfd, 0x4f, 0xa4, 0x13, 0xdb, 0xdb, 0x66, 0xad, 0xee, 0x34, 0xe3, 0xbe, 0x94, 0x5b, 0x2a, + 0x87, 0xbf, 0x8d, 0x01, 0x3a, 0x71, 0x2e, 0x6a, 0xdd, 0x16, 0x29, 0x2d, 0xee, 0xa6, 0xb2, + 0xcd, 0xa8, 0x6c, 0x7a, 0x0f, 0xf2, 0x5f, 0x70, 0xa7, 0xf4, 0x32, 0xf0, 0x99, 0x79, 0xb8, + 0xfd, 0x54, 0xbe, 0x77, 0x57, 0xff, 0xa2, 0xf2, 0x73, 0xbb, 0xc6, 0xce, 0xe5, 0x36, 0x7a, + 0xbe, 0xfe, 0x3c, 0xd3, 0x66, 0x8a, + ], +]; + +fn vk(env: &Env) -> VerificationKey { + let alpha = G1Affine::from_array(env, &VK_ALPHA); + let beta = G2Affine::from_array(env, &VK_BETA); + let gamma = G2Affine::from_array(env, &VK_GAMMA); + let delta = G2Affine::from_array(env, &VK_DELTA); + + let mut ic = Vec::new(env); + for p in VK_IC.iter() { + ic.push_back(G1Affine::from_array(env, p)); + } + + VerificationKey { + alpha, + beta, + gamma, + delta, + ic, + } +} + +#[contract] +pub struct Groth16Verifier; + +#[contractimpl] +impl Groth16Verifier { + pub fn verify_proof( + env: Env, + proof: Proof, + pub_signals: Vec, + ) -> Result { + let bls = env.crypto().bls12_381(); + let vk = vk(&env); + + if pub_signals.len() + 1 != vk.ic.len() { + return Err(Groth16Error::MalformedVerifyingKey); + } + + let mut vk_x = vk.ic.get(0).unwrap(); + for (s, v) in pub_signals.iter().zip(vk.ic.iter().skip(1)) { + let prod = bls.g1_mul(&v, &s); + vk_x = bls.g1_add(&vk_x, &prod); + } + + let neg_a = -proof.a; + let vp1 = soroban_sdk::vec![&env, neg_a, vk.alpha, vk_x, proof.c]; + let vp2 = soroban_sdk::vec![&env, proof.b, vk.beta, vk.gamma, vk.delta]; + + Ok(bls.pairing_check(vp1, vp2)) + } +} diff --git a/groth16_verifier/contracts/gnark_verifier/src/test.rs b/groth16_verifier/contracts/gnark_verifier/src/test.rs new file mode 100644 index 00000000..7a10b3cf --- /dev/null +++ b/groth16_verifier/contracts/gnark_verifier/src/test.rs @@ -0,0 +1,86 @@ +#![cfg(test)] + +extern crate std; + +use ark_bls12_381::{Fq, Fq2}; +use ark_serialize::CanonicalSerialize; +use core::str::FromStr; +use serde::Deserialize; +use soroban_sdk::{ + Env, U256, Vec, + crypto::bls12_381::{Fr, G1_SERIALIZED_SIZE, G1Affine, G2_SERIALIZED_SIZE, G2Affine}, +}; +use std::vec::Vec as AllocVec; + +use crate::{Groth16Verifier, Groth16VerifierClient, Proof}; + +#[derive(Deserialize)] +struct ProofJson { + pi_a: [std::string::String; 3], + pi_b: [[std::string::String; 2]; 3], + pi_c: [std::string::String; 3], + #[serde(rename = "publicSignals")] + public_signals: AllocVec, +} + +fn g1_from_coords(env: &Env, x: &str, y: &str) -> G1Affine { + let ark_g1 = ark_bls12_381::G1Affine::new(Fq::from_str(x).unwrap(), Fq::from_str(y).unwrap()); + let mut buf = [0u8; G1_SERIALIZED_SIZE]; + ark_g1.serialize_uncompressed(&mut buf[..]).unwrap(); + G1Affine::from_array(env, &buf) +} + +fn g2_from_coords(env: &Env, x1: &str, x2: &str, y1: &str, y2: &str) -> G2Affine { + let x = Fq2::new(Fq::from_str(x1).unwrap(), Fq::from_str(x2).unwrap()); + let y = Fq2::new(Fq::from_str(y1).unwrap(), Fq::from_str(y2).unwrap()); + let ark_g2 = ark_bls12_381::G2Affine::new(x, y); + let mut buf = [0u8; G2_SERIALIZED_SIZE]; + ark_g2.serialize_uncompressed(&mut buf[..]).unwrap(); + G2Affine::from_array(env, &buf) +} + +fn create_client(e: &Env) -> Groth16VerifierClient<'_> { + let contract_id = e.register(Groth16Verifier {}, ()); + Groth16VerifierClient::new(e, &contract_id) +} + +#[test] +fn test() { + // Initialize the test environment + let env = Env::default(); + + // Load proof from JSON file + let proof_json_str = include_str!("../../../data/gnark/proof.json"); + let proof_json: ProofJson = serde_json::from_str(proof_json_str).unwrap(); + + // Extract proof components from JSON + let pi_ax = &proof_json.pi_a[0]; + let pi_ay = &proof_json.pi_a[1]; + let pi_bx1 = &proof_json.pi_b[0][0]; + let pi_bx2 = &proof_json.pi_b[0][1]; + let pi_by1 = &proof_json.pi_b[1][0]; + let pi_by2 = &proof_json.pi_b[1][1]; + let pi_cx = &proof_json.pi_c[0]; + let pi_cy = &proof_json.pi_c[1]; + + // Construct the proof from JSON data + let proof = Proof { + a: g1_from_coords(&env, pi_ax, pi_ay), + b: g2_from_coords(&env, pi_bx1, pi_bx2, pi_by1, pi_by2), + c: g1_from_coords(&env, pi_cx, pi_cy), + }; + + // Create the contract client + let client = create_client(&env); + + // Test Case 1: Verify the proof with the correct public output from JSON + let public_signal: u32 = proof_json.public_signals[0].parse().unwrap(); + let output = Vec::from_array(&env, [Fr::from_u256(U256::from_u32(&env, public_signal))]); + let res = client.verify_proof(&proof, &output); + assert_eq!(res, true); + + // Test Case 2: Verify the proof with an incorrect public output + let output = Vec::from_array(&env, [Fr::from_u256(U256::from_u32(&env, 23))]); + let res = client.verify_proof(&proof, &output); + assert_eq!(res, false); +} diff --git a/groth16_verifier/data/arkworks/README.md b/groth16_verifier/data/arkworks/README.md new file mode 100644 index 00000000..0be1ec52 --- /dev/null +++ b/groth16_verifier/data/arkworks/README.md @@ -0,0 +1,25 @@ +# Arkworks example + +The proof and verification key are generated using [arkworks](https://github.com/arkworks-rs) (a Rust ecosystem for zero-knowledge cryptography) with the BLS12-381 curve. + +The computation demonstrates a **Merkle tree membership verification** circuit: given a Merkle tree root and an authentication path, prove that a specific leaf value exists in the tree without revealing the entire tree structure. + +In this example: + +- A Merkle tree is constructed from 8 leaf values: `[1, 2, 3, 10, 9, 17, 70, 45]` +- The proof demonstrates membership of leaf `9` (at index 4) +- The circuit verifies the authentication path against the public root + +The [contract implementation](../../contracts/ark_verifier/src/lib.rs) is **auto-generated** from `verification_key.json` using [soroban-verifier-gen](https://github.com/mysteryon88/soroban-verifier-gen) (Groth16 verifier generator for Soroban). The [test suite](../../contracts/ark_verifier/src/test.rs) demonstrates off-chain parsing of the proof and verification key, along with successful contract execution. + +--- + +Step-by-step arkworks circuit setup and generation of keys/proof for the `ark_verifier` contract. Run the commands in order. + +```sh +cd data/arkworks/auxiliary + +# Run the integration test: compiles circuit, generates keys, creates proof, and exports to JSON +# Outputs: ../proof.json and ../verification_key.json +cargo test merkle_tree -- --nocapture +``` diff --git a/groth16_verifier/data/arkworks/auxiliary/Cargo.lock b/groth16_verifier/data/arkworks/auxiliary/Cargo.lock new file mode 100644 index 00000000..e0c81a1a --- /dev/null +++ b/groth16_verifier/data/arkworks/auxiliary/Cargo.lock @@ -0,0 +1,952 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0c292754729c8a190e50414fd1a37093c786c709899f29c9f7daccecfa855e" +dependencies = [ + "ahash", + "ark-crypto-primitives-macros", + "ark-ec", + "ark-ff", + "ark-r1cs-std", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "blake2", + "derivative", + "digest", + "fnv", + "hashbrown 0.14.5", + "merlin", + "rayon", + "sha2", + "tracing", +] + +[[package]] +name = "ark-crypto-primitives-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools", + "num-bigint", + "num-integer", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ed-on-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba93ca6e75e5f589c139e5a41ebd783ebf2153de0025cd2b00da2963929c92ec" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-r1cs-std", + "ark-std", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "arrayvec", + "digest", + "educe", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.114", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "ark-groth16" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f1d0f3a534bb54188b8dcc104307db6c56cdae574ddc3212aec0625740fc7e" +dependencies = [ + "ark-crypto-primitives", + "ark-ec", + "ark-ff", + "ark-poly", + "ark-relations", + "ark-serialize", + "ark-std", + "rayon", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.5", + "rayon", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-relations", + "ark-std", + "educe", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", + "tracing-subscriber 0.2.25", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "arrayvec", + "digest", + "num-bigint", + "rayon", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "ark-snark" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d368e2848c2d4c129ce7679a7d0d2d612b6a274d3ea6a13bad4445d61b381b88" +dependencies = [ + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-snarkjs" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a36a14cb04e5a4e61c3e8e45f790a8cc94cab9aa6b60900363552fd1aba8dbb1" +dependencies = [ + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-groth16", + "ark-std", + "num-bigint", + "serde", + "serde_json", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand", + "rayon", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "merkle" +version = "0.1.0" +dependencies = [ + "ark-bls12-381", + "ark-crypto-primitives", + "ark-ec", + "ark-ed-on-bls12-381", + "ark-ff", + "ark-groth16", + "ark-r1cs-std", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-snarkjs", + "ark-std", + "tracing", + "tracing-subscriber 0.3.22", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zerocopy" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zmij" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" diff --git a/groth16_verifier/data/arkworks/auxiliary/Cargo.toml b/groth16_verifier/data/arkworks/auxiliary/Cargo.toml new file mode 100644 index 00000000..a2319d89 --- /dev/null +++ b/groth16_verifier/data/arkworks/auxiliary/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "merkle" +version = "0.1.0" +edition = "2024" + +[dependencies] +ark-ff = "0.5.0" +ark-ec = "0.5.0" +ark-std = { version = "0.5.0", features = ["getrandom"] } +ark-relations = "0.5.0" +ark-r1cs-std = "0.5.0" +ark-snark = "0.5.0" +ark-serialize = "0.5.0" + +ark-bls12-381 = "0.5.0" +ark-ed-on-bls12-381 = { version = "0.5.0", features = ["r1cs"] } +ark-groth16 = "0.5.0" + +ark-crypto-primitives = { version = "0.5.0", default-features = false, features = ["std", "crh", "r1cs", "merkle_tree"] } + +tracing-subscriber = "0.3.22" +tracing = { version = "0.1.44", features = ["attributes"] } +ark-snarkjs = "0.1.4" diff --git a/groth16_verifier/data/arkworks/auxiliary/src/circuit.rs b/groth16_verifier/data/arkworks/auxiliary/src/circuit.rs new file mode 100644 index 00000000..a5940257 --- /dev/null +++ b/groth16_verifier/data/arkworks/auxiliary/src/circuit.rs @@ -0,0 +1,97 @@ +use crate::common::*; +use crate::{MerkleConfig, Root, SimplePath}; + +use ark_crypto_primitives::crh::constraints::{CRHSchemeGadget, TwoToOneCRHSchemeGadget}; +use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; +use ark_crypto_primitives::merkle_tree::constraints::{ConfigGadget, PathVar}; + +use ark_r1cs_std::prelude::*; +use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; + +/// Merkle tree gadget config: binds hash gadgets + digest types to the MerkleConfig. +pub struct MerkleConfigGadget; + +impl ConfigGadget for MerkleConfigGadget { + /// Leaf in-circuit is a byte-slice (`&[u8]` off-circuit). + type Leaf = [UInt8]; + + /// Digest variables produced by the leaf hash gadget and the two-to-one hash gadget. + type LeafDigest = >::OutputVar; + type InnerDigest = + >::OutputVar; + + /// Hash gadgets used by the Merkle path gadget. + type LeafHash = LeafHashGadget; + type TwoToOneHash = TwoToOneHashGadget; + + /// Converts leaf digest var into bytes for feeding into the two-to-one hash gadget. + /// (Required for many arkworks versions when leaf and inner digests differ in representation.) + type LeafInnerConverter = + ark_crypto_primitives::merkle_tree::constraints::BytesVarDigestConverter< + Self::LeafDigest, + ConstraintF, + >; +} + +/// The R1CS equivalent of the Merkle tree root. +pub type RootVar = + >::OutputVar; + +/// The R1CS equivalent of the Merkle tree authentication path. +pub type SimplePathVar = PathVar; + +//////////////////////////////////////////////////////////////////////////////// + +#[derive(Clone)] +pub struct MerkleTreeVerification { + /// Public inputs + pub root: Root, + pub leaf: u8, + + /// Private witness + pub authentication_path: Option, + /// Constants embedded into the circuit + pub leaf_crh_params: Option<::Parameters>, + pub two_to_one_crh_params: Option<::Parameters>, +} + +impl ConstraintSynthesizer for MerkleTreeVerification { + fn generate_constraints( + self, + cs: ConstraintSystemRef, + ) -> Result<(), SynthesisError> { + // --- Public inputs --- + let root = RootVar::new_input(ark_relations::ns!(cs, "root_var"), || Ok(&self.root))?; + let leaf = UInt8::new_input(ark_relations::ns!(cs, "leaf_var"), || Ok(&self.leaf))?; + + // --- Constant params --- + let leaf_crh_params = LeafHashParamsVar::new_constant( + cs.clone(), + self.leaf_crh_params + .as_ref() + .expect("leaf_crh_params must be Some"), + )?; + let two_to_one_crh_params = TwoToOneHashParamsVar::new_constant( + cs.clone(), + self.two_to_one_crh_params + .as_ref() + .expect("two_to_one_crh_params must be Some"), + )?; + + // --- Private witness (path) --- + let path = SimplePathVar::new_witness(ark_relations::ns!(cs, "path_var"), || { + self.authentication_path + .as_ref() + .ok_or(SynthesisError::AssignmentMissing) + })?; + + // Leaf as bytes (your leaf is a single u8) + let leaf_bytes = vec![leaf.clone()]; + + // Enforce membership == true + path.verify_membership(&leaf_crh_params, &two_to_one_crh_params, &root, &leaf_bytes)? + .enforce_equal(&Boolean::TRUE)?; + + Ok(()) + } +} diff --git a/groth16_verifier/data/arkworks/auxiliary/src/common.rs b/groth16_verifier/data/arkworks/auxiliary/src/common.rs new file mode 100644 index 00000000..519cc3ec --- /dev/null +++ b/groth16_verifier/data/arkworks/auxiliary/src/common.rs @@ -0,0 +1,54 @@ +use ark_crypto_primitives::crh::constraints::{CRHSchemeGadget, TwoToOneCRHSchemeGadget}; +use ark_crypto_primitives::crh::injective_map::constraints::{ + PedersenCRHCompressorGadget, PedersenTwoToOneCRHCompressorGadget, TECompressorGadget, +}; +use ark_crypto_primitives::crh::{ + injective_map::{PedersenCRHCompressor, PedersenTwoToOneCRHCompressor, TECompressor}, + pedersen, +}; +use ark_ed_on_bls12_381::{EdwardsProjective, constraints::EdwardsVar}; + +pub type TwoToOneHash = + PedersenTwoToOneCRHCompressor; +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct TwoToOneWindow; + +// `WINDOW_SIZE * NUM_WINDOWS` = 2 * 256 bits = enough for hashing two outputs. +impl pedersen::Window for TwoToOneWindow { + const WINDOW_SIZE: usize = 4; + const NUM_WINDOWS: usize = 128; +} + +pub type LeafHash = PedersenCRHCompressor; + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct LeafWindow; + +// `WINDOW_SIZE * NUM_WINDOWS` = 2 * 256 bits = enough for hashing two outputs. +impl pedersen::Window for LeafWindow { + const WINDOW_SIZE: usize = 4; + const NUM_WINDOWS: usize = 144; +} + +pub type LeafHashGadget = PedersenCRHCompressorGadget< + EdwardsProjective, + TECompressor, + LeafWindow, + EdwardsVar, + TECompressorGadget, +>; + +pub type TwoToOneHashGadget = PedersenTwoToOneCRHCompressorGadget< + EdwardsProjective, + TECompressor, + TwoToOneWindow, + EdwardsVar, + TECompressorGadget, +>; + +pub type LeafHashParamsVar = + >::ParametersVar; +pub type TwoToOneHashParamsVar = + >::ParametersVar; + +pub type ConstraintF = ark_ed_on_bls12_381::Fq; diff --git a/groth16_verifier/data/arkworks/auxiliary/src/lib.rs b/groth16_verifier/data/arkworks/auxiliary/src/lib.rs new file mode 100644 index 00000000..cd47540b --- /dev/null +++ b/groth16_verifier/data/arkworks/auxiliary/src/lib.rs @@ -0,0 +1,42 @@ +use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; +use ark_crypto_primitives::merkle_tree::{ByteDigestConverter, Config, MerkleTree, Path}; + +pub mod circuit; +pub mod common; + +use common::*; + +/// Merkle tree configuration for byte-slice leaves. +/// +/// This Merkle tree uses: +/// - `LeafHash` to hash raw leaves (`&[u8]`) +/// - `TwoToOneHash` to hash pairs of child digests for internal nodes +#[derive(Clone)] +pub struct MerkleConfig; + +impl Config for MerkleConfig { + /// Hash function used for leaf hashing. + type LeafHash = LeafHash; + /// Hash function used for hashing pairs of child digests at internal nodes. + type TwoToOneHash = TwoToOneHash; + + /// A leaf is a raw byte slice. Ark's Merkle tree APIs operate on `&Self::Leaf`, + /// so this becomes `&[u8]` in practice. + type Leaf = [u8]; + + /// Digest type produced by `LeafHash`. + type LeafDigest = ::Output; + /// Digest type produced by `TwoToOneHash`. + type InnerDigest = ::Output; + + /// Converts a leaf digest into bytes so it can be used as input to the two-to-one hash + /// when building/verifying inner nodes. + type LeafInnerDigestConverter = ByteDigestConverter; +} + +/// A simple Merkle tree over raw byte-slice leaves. +pub type SimpleMerkleTree = MerkleTree; +/// The root digest of the Merkle tree (an output of the two-to-one hash). +pub type Root = ::Output; +/// A Merkle membership proof for a leaf. +pub type SimplePath = Path; diff --git a/groth16_verifier/data/arkworks/auxiliary/tests/integration_tests.rs b/groth16_verifier/data/arkworks/auxiliary/tests/integration_tests.rs new file mode 100644 index 00000000..b0f655c4 --- /dev/null +++ b/groth16_verifier/data/arkworks/auxiliary/tests/integration_tests.rs @@ -0,0 +1,111 @@ +use ark_bls12_381::{Bls12_381, Fr}; +use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; +use ark_groth16::Groth16; +use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; +use ark_snark::SNARK; +use ark_snarkjs::{export_proof, export_vk}; +use ark_std::rand::rngs::OsRng; +use merkle::circuit::MerkleTreeVerification; +use merkle::common::{LeafHash, TwoToOneHash}; +use merkle::*; +use std::fs; + +// cargo test merkle_tree -- --nocapture + +#[test] +fn merkle_tree() { + let mut rng = OsRng; + + // Sample public parameters for the hash functions. + let leaf_crh_params = ::setup(&mut rng).unwrap(); + let two_to_one_crh_params = ::setup(&mut rng).unwrap(); + + // Construct the tree. + let tree = SimpleMerkleTree::new( + &leaf_crh_params, + &two_to_one_crh_params, + &[ + &[1u8], + &[2u8], + &[3u8], + &[10u8], + &[9u8], + &[17u8], + &[70u8], + &[45u8], + ], + ) + .unwrap(); + + // Generate membership proof for leaf == 9 (index 4). + let proof = tree.generate_proof(4).unwrap(); + let root = tree.root(); + + // Create circuit instance for parameter generation + // We reuse the actual leaf value and clone the authentication path + let dummy_circuit = MerkleTreeVerification { + leaf_crh_params: Some(leaf_crh_params.clone()), + two_to_one_crh_params: Some(two_to_one_crh_params.clone()), + root, + leaf: 9u8, // Use the actual leaf value + authentication_path: Some(proof.clone()), // Use a clone of the proof + }; + + // Generate Groth16 parameters + let groth_params = + Groth16::::generate_random_parameters_with_reduction(dummy_circuit, &mut rng) + .unwrap(); + + // Create circuit with witness for actual proof generation + let circuit = MerkleTreeVerification { + leaf_crh_params: Some(leaf_crh_params.clone()), + two_to_one_crh_params: Some(two_to_one_crh_params.clone()), + root, + leaf: 9u8, + authentication_path: Some(proof.clone()), + }; + + // Get public inputs from the constraint system + // We need to build a constraint system to extract the actual public inputs + let cs_for_inputs = ConstraintSystem::new_ref(); + let circuit_for_inputs = MerkleTreeVerification { + leaf_crh_params: Some(leaf_crh_params.clone()), + two_to_one_crh_params: Some(two_to_one_crh_params.clone()), + root, + leaf: 9u8, + authentication_path: Some(proof.clone()), + }; + circuit_for_inputs + .generate_constraints(cs_for_inputs.clone()) + .unwrap(); + + // Extract public inputs from the constraint system + // instance_assignment[0] is always 1 (the constant one), so we skip it + let public_inputs: Vec = cs_for_inputs.borrow().unwrap().instance_assignment[1..].to_vec(); + + eprintln!("Total public inputs count: {}", public_inputs.len()); + eprintln!("Public inputs: {:?}", public_inputs); + + // Generate proof using the original circuit + let groth_proof = Groth16::::prove(&groth_params, circuit, &mut rng).unwrap(); + + eprintln!("Groth proof: {:?}", groth_proof); + eprintln!("Groth parameters: {:?}", groth_params.vk); + eprintln!("Public inputs: {:?}", public_inputs); + + // Verify proof before export + let verified = + Groth16::::verify(&groth_params.vk, &public_inputs, &groth_proof).unwrap(); + assert!(verified, "Proof verification failed"); + + // Export to JSON + export_proof::(&groth_proof, &public_inputs, "../proof.json").unwrap(); + + // Use the number of public inputs (verified to match VK) + export_vk::( + &groth_params.vk, + public_inputs.len(), + "../verification_key.json", + ) + .unwrap(); +} diff --git a/groth16_verifier/data/arkworks/proof.json b/groth16_verifier/data/arkworks/proof.json new file mode 100644 index 00000000..de82e1e8 --- /dev/null +++ b/groth16_verifier/data/arkworks/proof.json @@ -0,0 +1,39 @@ +{ + "protocol": "groth16", + "curve": "bls12381", + "pi_a": [ + "463442673288626976318730223483022924216746367865659198031625943136393219592312210082405659993012556488905991384792", + "2555518816576651365142062979897966041501114948576940389142512737831320682146248465445760558108986295357838624382173", + "1" + ], + "pi_b": [ + [ + "315032386211310299779443477220446942285991921050068995795893646988875303895491723708625518580754012520497060965110", + "2051479785402457295228179973164002904407637936689260130614552509591447894687935004342606238299285807469941140187374" + ], + [ + "3933318198445117752169405267448071998712771161914450699616745224044732744932349082013939221473580383897959613349127", + "3144158053233370018395970035400001216698065121769503149795484990393529968163660549718429153034512575363290938252893" + ], + [ + "1", + "0" + ] + ], + "pi_c": [ + "387381385559694400356556303822014674644805385147090902398559570029756576048241200870814564292797959503937594718754", + "2419318070228501970449547644178908727710294248812448923485233166579267991617465924065751981964968685114016084800399", + "1" + ], + "publicSignals": [ + "42276951836222677314430747432886445723349414438748189320502556399897340668040", + "1", + "0", + "0", + "1", + "0", + "0", + "0", + "0" + ] +} \ No newline at end of file diff --git a/groth16_verifier/data/arkworks/verification_key.json b/groth16_verifier/data/arkworks/verification_key.json new file mode 100644 index 00000000..fe41614c --- /dev/null +++ b/groth16_verifier/data/arkworks/verification_key.json @@ -0,0 +1,104 @@ +{ + "protocol": "groth16", + "curve": "bls12381", + "nPublic": 9, + "vk_alpha_1": [ + "2136922285095161887771411650360458188078381976436156407276710561880115338298749752142067607016164650333280355744513", + "1948266692992837307979096930830917266422865021615489277796977007718403395473433067622753915186873726387164420174931", + "1" + ], + "vk_beta_2": [ + [ + "1124319091251659210032951422232922366433232204408917304605339733642429791010070647477270261676191653354899900528698", + "3093671703391236796897568732625788780257818379388864572664334131794119791671970455335199714075814994322542000551609" + ], + [ + "3033556727492835081401373591283185604449574124771953349629328619620706285536908068021760226193760451914353837319669", + "1652342987440497896952960890503870447267362831679545173647512569798249819152895901112670414069775269386452272153183" + ], + [ + "1", + "0" + ] + ], + "vk_gamma_2": [ + [ + "2288900885190255077503463688523575643516800469992174475684974856546333802196208036337696408938929244906473155546550", + "2257682804139634926685168796052140338285033462000494996683755748014712757832001997736800743441982616206554971139830" + ], + [ + "2349442970964940289067888900308368963221708009629776535366883260117231916873613549042821701138126109156832863010024", + "2281083008567806858983567610484342320688493194045611789249956169102431455531159546166584972951786180961930684340204" + ], + [ + "1", + "0" + ] + ], + "vk_delta_2": [ + [ + "2558808998369570403670575535766684277756989342418587072196855182313894635195219273505993790478508634355928345401098", + "3112060094848293445586650993690294383584465700660060631554210368691969657780064447500327114598262788351025185517025" + ], + [ + "3294064824085498943273970321751388019770269773562495156206506943609842356127969980743880446727097607641111971161602", + "1497936098091748728552053159344552664152359820353899592580632071843283542233555197558633894049058198285117489308888" + ], + [ + "1", + "0" + ] + ], + "IC": [ + [ + "519045432848862676165846250139585261372013738720492875957634629235131573803144700783040398712186736754913326670511", + "1567103743422992140767395454604403930664521521733964138050839064159958055841349697334680609818699251739430231277675", + "1" + ], + [ + "1688782176108420280546976460197435803157029686574219474189908649151460327400140960773384330863310038893308365719678", + "3532748200216553998331442706409284927439971798436051748189599488705464966083262274400944205492352089752350613280002", + "1" + ], + [ + "1883770595491408010211619743719980711811428650339928877492524315637747001707283508942717187447320759248289497447942", + "3185925234809036659591615322476169028185621629189046762573806224132810067437374791777481620571870756551895444187993", + "1" + ], + [ + "3183067872160236207630147754943551026024924718416393979459652348078818304729258456352148442634391393465649510015953", + "1434222431918856915847500212206593711196899743120673099514217565130511305722285266199571800779898793148660879927900", + "1" + ], + [ + "591028423331146187547563146488266448342144976005062940020008889365390148266605440446822384539551613493432553150309", + "1888841442776360253171277322207961977437869945640528662377688739817329969470691093481463974994385603866297363821982", + "1" + ], + [ + "299296856076817167114012581888603040961895254725546444184726961926001246428929973476069989385231690977004330661509", + "3849911578157408486081888491732980522333966666367753312860428525367360082054887773890574978420450242924910247202582", + "1" + ], + [ + "3507084138171548429377791078253503724202924195010364706177300716012344910204758938454595827927132534717259158175020", + "301597870875709137155533556750311998977232908908425983980078384746994361482644106003417386057628197892028672586845", + "1" + ], + [ + "519865645455351707383487739247969211103246004642096400096992120476569075009041656241216543679520554367175825194508", + "488114057746960239305944608329730155431662201511709966686669522161756346481309533495286661278999996732679706918377", + "1" + ], + [ + "3893705784710781290297971491939293550521510825796345647375797045759390643975757365092413247231611785570660646095676", + "3405075379142999910141203748262019942167557698059612800245559268650137632341387091208574880025066414317859033667868", + "1" + ], + [ + "3312817029013727527751005938065465136070541557791746713938409840320754463399731504213652481075258365207312800619766", + "2564705158314303942727903420571454673307767136605638605136182561677008996868203811712984171166928122135459540389715", + "1" + ] + ] +} \ No newline at end of file diff --git a/groth16_verifier/data/auxiliary/input.json b/groth16_verifier/data/auxiliary/input.json deleted file mode 100644 index c7e0fc65..00000000 --- a/groth16_verifier/data/auxiliary/input.json +++ /dev/null @@ -1 +0,0 @@ -{"a": 3, "b": 11} diff --git a/groth16_verifier/data/auxiliary/multiplier2_0000.zkey b/groth16_verifier/data/auxiliary/multiplier2_0000.zkey deleted file mode 100644 index 7d9b5b09..00000000 Binary files a/groth16_verifier/data/auxiliary/multiplier2_0000.zkey and /dev/null differ diff --git a/groth16_verifier/data/auxiliary/multiplier2_0001.zkey b/groth16_verifier/data/auxiliary/multiplier2_0001.zkey deleted file mode 100644 index 2be0729a..00000000 Binary files a/groth16_verifier/data/auxiliary/multiplier2_0001.zkey and /dev/null differ diff --git a/groth16_verifier/data/auxiliary/pot12_0000.ptau b/groth16_verifier/data/auxiliary/pot12_0000.ptau deleted file mode 100644 index a7bd6041..00000000 Binary files a/groth16_verifier/data/auxiliary/pot12_0000.ptau and /dev/null differ diff --git a/groth16_verifier/data/auxiliary/pot12_0001.ptau b/groth16_verifier/data/auxiliary/pot12_0001.ptau deleted file mode 100644 index 262ae1b4..00000000 Binary files a/groth16_verifier/data/auxiliary/pot12_0001.ptau and /dev/null differ diff --git a/groth16_verifier/data/auxiliary/pot12_final.ptau b/groth16_verifier/data/auxiliary/pot12_final.ptau deleted file mode 100644 index 5b6df58d..00000000 Binary files a/groth16_verifier/data/auxiliary/pot12_final.ptau and /dev/null differ diff --git a/groth16_verifier/data/auxiliary/witness.wtns b/groth16_verifier/data/auxiliary/witness.wtns deleted file mode 100644 index 4b6d58cf..00000000 Binary files a/groth16_verifier/data/auxiliary/witness.wtns and /dev/null differ diff --git a/groth16_verifier/data/circom/README.md b/groth16_verifier/data/circom/README.md new file mode 100644 index 00000000..0cd47b8c --- /dev/null +++ b/groth16_verifier/data/circom/README.md @@ -0,0 +1,40 @@ +# Circom example + +The proof and verification key are generated following the Circom (circom compiler 2.2.2) [getting-started guide](https://docs.circom.io/getting-started/installation/). + +The computation demonstrates a simple multiplication circuit: `a * b = c`, where: + +- `a` and `b` are private inputs +- `c` is the public output + +The [contract implementation](../../contracts/circom_verifier/src/lib.rs) is **auto-generated** from `verification_key.json` using [soroban-verifier-gen](https://github.com/mysteryon88/soroban-verifier-gen) (Groth16 verifier generator for Soroban). The [test suite](../../contracts/circom_verifier/src/test.rs) demonstrates off-chain parsing of the proof and verification key, along with successful contract execution. + +--- + +Step-by-step Circom circuit setup and generation of keys/proof for the `circom_verifier` contract. Run the commands in order. + +```sh +cd ./data/circom/auxiliary/ + +# Compile the circuit: R1CS, WASM build, and debug symbols; BLS12-381 curve (same as Soroban) +circom multiplier2.circom --r1cs --wasm --prime bls12381 + +# --- Trusted setup (Phase 1: Powers of Tau) --- +snarkjs powersoftau new bls12-381 5 pot5_0000.ptau -v +snarkjs powersoftau contribute pot5_0000.ptau pot5_0001.ptau --name="First contribution" -v -e="some random text" +snarkjs powersoftau prepare phase2 pot5_0001.ptau pot5_final.ptau -v + +# Phase 2: circuit + ptau → initial zkey, then contribution +snarkjs groth16 setup Multiplier2.r1cs pot5_final.ptau Multiplier2_0000.zkey +snarkjs zkey contribute Multiplier2_0000.zkey Multiplier2_final.zkey --name="1st Contributor Name" -v -e="some random text" + +# Export verification key (used by the contract) +snarkjs zkey export verificationkey Multiplier2_final.zkey ../verification_key.json + +# Generate proof: inputs → proof + public signals (output in ../proof.json and ../public.json) +snarkjs groth16 fullprove input.json Multiplier2_js/Multiplier2.wasm Multiplier2_final.zkey ../proof.json ../public.json + +cd ../../.. +``` + +After running, `data/circom/` will contain `verification_key.json`, `proof.json`, and `public.json` — use them to update the contract and tests. diff --git a/groth16_verifier/data/circom/auxiliary/Multiplier2.r1cs b/groth16_verifier/data/circom/auxiliary/Multiplier2.r1cs new file mode 100644 index 00000000..1d90b62b Binary files /dev/null and b/groth16_verifier/data/circom/auxiliary/Multiplier2.r1cs differ diff --git a/groth16_verifier/data/circom/auxiliary/Multiplier2_final.zkey b/groth16_verifier/data/circom/auxiliary/Multiplier2_final.zkey new file mode 100644 index 00000000..2be66072 Binary files /dev/null and b/groth16_verifier/data/circom/auxiliary/Multiplier2_final.zkey differ diff --git a/groth16_verifier/data/circom/auxiliary/Multiplier2_js/Multiplier2.wasm b/groth16_verifier/data/circom/auxiliary/Multiplier2_js/Multiplier2.wasm new file mode 100644 index 00000000..ca4632b3 Binary files /dev/null and b/groth16_verifier/data/circom/auxiliary/Multiplier2_js/Multiplier2.wasm differ diff --git a/groth16_verifier/data/circom/auxiliary/Multiplier2_js/generate_witness.js b/groth16_verifier/data/circom/auxiliary/Multiplier2_js/generate_witness.js new file mode 100644 index 00000000..2c6656d6 --- /dev/null +++ b/groth16_verifier/data/circom/auxiliary/Multiplier2_js/generate_witness.js @@ -0,0 +1,21 @@ +const wc = require("./witness_calculator.js"); +const { readFileSync, writeFile } = require("fs"); + +if (process.argv.length != 5) { + console.log("Usage: node generate_witness.js "); +} else { + const input = JSON.parse(readFileSync(process.argv[3], "utf8")); + + const buffer = readFileSync(process.argv[2]); + wc(buffer).then(async witnessCalculator => { + const w= await witnessCalculator.calculateWitness(input,0); + /* + for (let i=0; i< w.length; i++){ + console.log(w[i]); + }*/ + const buff= await witnessCalculator.calculateWTNSBin(input,0); + writeFile(process.argv[4], buff, function(err) { + if (err) throw err; + }); + }); +} diff --git a/groth16_verifier/data/circom/auxiliary/Multiplier2_js/witness_calculator.js b/groth16_verifier/data/circom/auxiliary/Multiplier2_js/witness_calculator.js new file mode 100644 index 00000000..206df493 --- /dev/null +++ b/groth16_verifier/data/circom/auxiliary/Multiplier2_js/witness_calculator.js @@ -0,0 +1,381 @@ +module.exports = async function builder(code, options) { + + options = options || {}; + + let wasmModule; + try { + wasmModule = await WebAssembly.compile(code); + } catch (err) { + console.log(err); + console.log("\nTry to run circom --c in order to generate c++ code instead\n"); + throw new Error(err); + } + + let wc; + + let errStr = ""; + let msgStr = ""; + + const instance = await WebAssembly.instantiate(wasmModule, { + runtime: { + exceptionHandler : function(code) { + let err; + if (code == 1) { + err = "Signal not found.\n"; + } else if (code == 2) { + err = "Too many signals set.\n"; + } else if (code == 3) { + err = "Signal already set.\n"; + } else if (code == 4) { + err = "Assert Failed.\n"; + } else if (code == 5) { + err = "Not enough memory.\n"; + } else if (code == 6) { + err = "Input signal array access exceeds the size.\n"; + } else { + err = "Unknown error.\n"; + } + throw new Error(err + errStr); + }, + printErrorMessage : function() { + errStr += getMessage() + "\n"; + // console.error(getMessage()); + }, + writeBufferMessage : function() { + const msg = getMessage(); + // Any calls to `log()` will always end with a `\n`, so that's when we print and reset + if (msg === "\n") { + console.log(msgStr); + msgStr = ""; + } else { + // If we've buffered other content, put a space in between the items + if (msgStr !== "") { + msgStr += " " + } + // Then append the message to the message we are creating + msgStr += msg; + } + }, + showSharedRWMemory : function() { + printSharedRWMemory (); + } + + } + }); + + const sanityCheck = + options +// options && +// ( +// options.sanityCheck || +// options.logGetSignal || +// options.logSetSignal || +// options.logStartComponent || +// options.logFinishComponent +// ); + + + wc = new WitnessCalculator(instance, sanityCheck); + return wc; + + function getMessage() { + var message = ""; + var c = instance.exports.getMessageChar(); + while ( c != 0 ) { + message += String.fromCharCode(c); + c = instance.exports.getMessageChar(); + } + return message; + } + + function printSharedRWMemory () { + const shared_rw_memory_size = instance.exports.getFieldNumLen32(); + const arr = new Uint32Array(shared_rw_memory_size); + for (let j=0; j { + const h = fnvHash(k); + const hMSB = parseInt(h.slice(0,8), 16); + const hLSB = parseInt(h.slice(8,16), 16); + const fArr = flatArray(input[k]); + let signalSize = this.instance.exports.getInputSignalSize(hMSB, hLSB); + if (signalSize < 0){ + throw new Error(`Signal ${k} not found\n`); + } + if (fArr.length < signalSize) { + throw new Error(`Not enough values for input signal ${k}\n`); + } + if (fArr.length > signalSize) { + throw new Error(`Too many values for input signal ${k}\n`); + } + for (let i=0; i 0) { + let t = typeof a[0]; + for (let i = 1; i { + let new_prefix = prefix == ""? k : prefix + "." + k; + qualify_input(new_prefix,input[k],input1); + }); + } else { + input1[prefix] = input; + } +} + +function toArray32(rem,size) { + const res = []; //new Uint32Array(size); //has no unshift + const radix = BigInt(0x100000000); + while (rem) { + res.unshift( Number(rem % radix)); + rem = rem / radix; + } + if (size) { + var i = size - res.length; + while (i>0) { + res.unshift(0); + i--; + } + } + return res; +} + +function fromArray32(arr) { //returns a BigInt + var res = BigInt(0); + const radix = BigInt(0x100000000); + for (let i = 0; i known to the prover only +// - public part --> known to the prover and the verifier +type Circuit struct { + X frontend.Variable `gnark:"x"` // x --> secret visibility (default) + Y frontend.Variable `gnark:",public"` // Y --> public visibility +} + +// Define declares the circuit logic. The compiler then produces a list of constraints +// which must be satisfied (valid witness) in order to create a valid zk-SNARK +func (circuit *Circuit) Define(api frontend.API) error { + // compute x**3 and store it in the local variable x3. + x3 := api.Mul(circuit.X, circuit.X, circuit.X) + + // compute x**3 + x + 5 and store it in the local variable res + res := api.Add(x3, circuit.X, 5) + + // assert that the statement x**3 + x + 5 == y is true. + api.AssertIsEqual(circuit.Y, res) + return nil +} diff --git a/groth16_verifier/data/gnark/auxiliary/go.mod b/groth16_verifier/data/gnark/auxiliary/go.mod new file mode 100644 index 00000000..a8f41e90 --- /dev/null +++ b/groth16_verifier/data/gnark/auxiliary/go.mod @@ -0,0 +1,25 @@ +module gnark_example + +go 1.25.0 + +require ( + github.com/consensys/gnark v0.14.0 + github.com/consensys/gnark-crypto v0.19.0 + github.com/mysteryon88/gnark-to-snarkjs v1.0.2 +) + +require ( + github.com/bits-and-blooms/bitset v1.24.0 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 // indirect + github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ronanh/intcomp v1.1.1 // indirect + github.com/rs/zerolog v1.34.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect +) diff --git a/groth16_verifier/data/gnark/auxiliary/go.sum b/groth16_verifier/data/gnark/auxiliary/go.sum new file mode 100644 index 00000000..7edb38e7 --- /dev/null +++ b/groth16_verifier/data/gnark/auxiliary/go.sum @@ -0,0 +1,58 @@ +github.com/bits-and-blooms/bitset v1.24.0 h1:H4x4TuulnokZKvHLfzVRTHJfFfnHEeSYJizujEZvmAM= +github.com/bits-and-blooms/bitset v1.24.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/consensys/gnark v0.14.0 h1:RG+8WxRanFSFBSlmCDRJnYMYYKpH3Ncs5SMzg24B5HQ= +github.com/consensys/gnark v0.14.0/go.mod h1:1IBpDPB/Rdyh55bQRR4b0z1WvfHQN1e0020jCvKP2Gk= +github.com/consensys/gnark-crypto v0.19.0 h1:zXCqeY2txSaMl6G5wFpZzMWJU9HPNh8qxPnYJ1BL9vA= +github.com/consensys/gnark-crypto v0.19.0/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY= +github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= +github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2 h1:B+aWVgAx+GlFLhtYjIaF0uGjU3rzpl99Wf9wZWt+Mq8= +github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2/go.mod h1:CH/cwcr21pPWH+9GtK/PFaa4OGTv4CtfkCKro6GpbRE= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mysteryon88/gnark-to-snarkjs v1.0.2 h1:tcn72yevI0JOsBhxVSmSTpqoHZxxSZB7GeoDkot27sg= +github.com/mysteryon88/gnark-to-snarkjs v1.0.2/go.mod h1:pqCKRvPoi7jZZ1Xa1gczcVGr85FxynEf3xgDIZuFvFQ= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ronanh/intcomp v1.1.1 h1:+1bGV/wEBiHI0FvzS7RHgzqOpfbBJzLIxkqMJ9e6yxY= +github.com/ronanh/intcomp v1.1.1/go.mod h1:7FOLy3P3Zj3er/kVrU/pl+Ql7JFZj7bwliMGketo0IU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0= +golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/groth16_verifier/data/gnark/auxiliary/main.go b/groth16_verifier/data/gnark/auxiliary/main.go new file mode 100644 index 00000000..5ae7e8e5 --- /dev/null +++ b/groth16_verifier/data/gnark/auxiliary/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "os" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + gnarktosnarkjs "github.com/mysteryon88/gnark-to-snarkjs" +) + +const ( + ProofPath = "../proof.json" + VKeyPath = "../verification_key.json" +) + +func main() { + + scalarField := ecc.BLS12_381.ScalarField() + + circuit := Circuit{} + + // Compile the circuit into an R1CS + r1cs, err := frontend.Compile(scalarField, r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } + + // Setup the proving and verifying keys + pk, vk, err := groth16.Setup(r1cs) + if err != nil { + panic(err) + } + + // Set the witness values + circuit.X = 3 + circuit.Y = 35 + + // Create a witness for the circuit + witnessFull, err := frontend.NewWitness(&circuit, scalarField) + if err != nil { + panic(err) + } + + // Create a witness for the public inputs + witnessPublic, err := frontend.NewWitness(&circuit, scalarField, frontend.PublicOnly()) + if err != nil { + panic(err) + } + + // Prove the circuit + proof, err := groth16.Prove(r1cs, pk, witnessFull) + if err != nil { + panic(err) + } + + // Verify the proof + err = groth16.Verify(proof, vk, witnessPublic) + if err != nil { + panic(err) + } + + // Export the proof + { + + proof_out, err := os.Create(ProofPath) + if err != nil { + panic(err) + } + + defer proof_out.Close() + + err = gnarktosnarkjs.ExportProof(proof, []string{"35"}, proof_out) + if err != nil { + panic(err) + } + } + + // Export the verification key + { + out, err := os.Create(VKeyPath) + if err != nil { + panic(err) + } + defer out.Close() + err = gnarktosnarkjs.ExportVerifyingKey(vk, out) + if err != nil { + panic(err) + } + } + +} diff --git a/groth16_verifier/data/gnark/proof.json b/groth16_verifier/data/gnark/proof.json new file mode 100644 index 00000000..2a4c1fa3 --- /dev/null +++ b/groth16_verifier/data/gnark/proof.json @@ -0,0 +1,31 @@ +{ + "curve": "bls12381", + "pi_a": [ + "1205269832026320883846162572057574550937034601892601637567069205556602173631055801824996442159007077452719031016169", + "509653811413329128158380693716147097497310486377372411385942265956090919916641176407924906500259048453635102634224", + "1" + ], + "pi_b": [ + [ + "3760454423640472031967423300101998357826013959433117347316664968143518915247509915411847824050579542279293379327554", + "206764999358480385126695487691712747213218414414674027463783733897168141034963129168691765255595264237752390499461" + ], + [ + "569471031769228065112530884674267338359998036890224342945289008168524139264043267786881607557100897925677425747971", + "87251390152593321390221579372956629021025779994532869135344132440883455822697323749910970170960749870692506475563" + ], + [ + "1", + "0" + ] + ], + "pi_c": [ + "889569667264426183474215150300740792288501438598305892512586802930599632114663089282450387614998929372623783192476", + "2752720791882609984979576664599376073985209506890055886367444046727092996929286028635862746742141426855779989042463", + "1" + ], + "protocol": "groth16", + "publicSignals": [ + "35" + ] +} \ No newline at end of file diff --git a/groth16_verifier/data/gnark/verification_key.json b/groth16_verifier/data/gnark/verification_key.json new file mode 100644 index 00000000..3fce7dfe --- /dev/null +++ b/groth16_verifier/data/gnark/verification_key.json @@ -0,0 +1,94 @@ +{ + "protocol": "groth16", + "curve": "bls12381", + "nPublic": 1, + "vk_alpha_1": [ + "2046392289628921624803202637007764965974908680234303859321061752704246194662280282915576471646720198711042638155028", + "1453918101932526650356945279067802053438118947034072243680144120829299414281553920214421435844463025012093904158911", + "1" + ], + "vk_beta_2": [ + [ + "3476441098374306874703389587163754936465123030949715712723109981888424521136610175664650673690184702614090863466326", + "2109330027990705698819683204041742869776126763880103989975384208967460229552124356361215962404124640841439200511258" + ], + [ + "3450462933502746082356078437111177209921700023899639262128712364420123366780618930403253913697780426695554913316582", + "619154205556011167066083581090595661392423465852956752393413834557531943105818459724947100809889434084059896488756" + ], + [ + "1", + "0" + ] + ], + "vk_gamma_2": [ + [ + "393670027709860468268022353012629533069341341342464029691887001316786344379193666102948050552457699275492603194334", + "2306435219477915485634629885494277675330991546503161297574309753117560391606194703738761960188520990918616328240150" + ], + [ + "2861123616906442900993924135418440372609532657604026051097735625101935813223193106257646879991153765180092093733008", + "899856021730383912086252787389655460142379099790193412560110985065738204306742775228055507951047236855551664599257" + ], + [ + "1", + "0" + ] + ], + "vk_delta_2": [ + [ + "3286174567570757835945954664743344043076281818350651882246005683724658003434074668564167650876873308460390728408236", + "2522457213898279837520193730103923284150964867785831463051857642690752549918481743713171254809605239248594096500828" + ], + [ + "1634295682434862367663900423140054213001784758005147688701465576284008786324203602845887594004651714852355986574934", + "386507894594889479710978627378161142941389995503427611604636314096171796108650635015154343114767541370073551020823" + ], + [ + "1", + "0" + ] + ], + "vk_alphabeta_12": [ + [ + [ + "1848234587010346614538850265740091186762093234139935038515189125432668769847777332768579401872008608666093304110213", + "438274384751933783506340840887842567101586615181132441800049826021021765126615481247197637421863169586692016494413" + ], + [ + "3718107815807696274384805038280951971126539492753968110901339977962154420454689824574228568221546000019116465467821", + "2319450866703000970846441589732584516959810328830042543929263784435153991595306130519953189453662622841400133819672" + ], + [ + "2103285112016708956460022812265916003164953594461614629334763710439886658253379313271387474236700342412967877181769", + "2823055407372805356162065318329489693972187954132407383256279357451724336373731632280438243956947646917752276157811" + ] + ], + [ + [ + "2260323016325063409697291383221527784419184328699475957290416294880224868740860437061130585377665534375975097543189", + "2577867979051528972076830489156555494668510890208299475143519157186786885607836089591600195855580177850915658956556" + ], + [ + "1346470369862547041868654715160311909649255708674451190858665275111051409102331937379512034642147817320301914463142", + "1654120778075858027911265661863366476941150400938621643296634784693785818780991077834536972555279185575852125531971" + ], + [ + "2630381072123343039553843023619204612966827806951131490179138514473873922505055388466398251290927094720435538887233", + "3528080389758811088532041013732275879863348461235047015039595507862049118315367605606786922922361432675226756617305" + ] + ] + ], + "IC": [ + [ + "3899876954326174190472731197130129404590025633942370865200519141648727364299923012328153117334070341629256993826505", + "486934745738000477006405560633844719755118274492211521743004537912638803941021078840562556667842479841742092384022", + "1" + ], + [ + "1451106384187356082738496498966262053575386480702350206518007790169255013870670106439378293905157531543563038867341", + "189051058118846270341164024404610169172235789047137523937181165157239608783807845439332650709905685282598547580554", + "1" + ] + ] +} \ No newline at end of file diff --git a/groth16_verifier/data/gnark_bn254/README.md b/groth16_verifier/data/gnark_bn254/README.md new file mode 100644 index 00000000..0ff09ef2 --- /dev/null +++ b/groth16_verifier/data/gnark_bn254/README.md @@ -0,0 +1,31 @@ +# Gnark example + +The proof and verification key are generated using [gnark](https://github.com/consensys/gnark) (a zk-SNARK library written in Go) with the BN254 curve. + +The computation demonstrates a polynomial circuit: `x³ + x + 5 = y`, where: + +- `x` is a private input (secret witness) +- `y` is the public output + +In this example, `x = 3` and `y = 35` (since 3³ + 3 + 5 = 27 + 3 + 5 = 35). + +The [contract implementation](../../contracts/gnark_bn254_verifier/src/lib.rs) is **auto-generated** from `verification_key.json` using [soroban-verifier-gen](https://github.com/mysteryon88/soroban-verifier-gen) (Groth16 verifier generator for Soroban). The [test suite](../../contracts/gnark_bn254_verifier/src/test.rs) demonstrates off-chain parsing of the proof and verification key, along with successful contract execution. + +Exports proof and verification key to snarkjs-compatible JSON format using [gnark-to-snarkjs](https://github.com/mysteryon88/gnark-to-snarkjs) + +--- + +Step-by-step gnark circuit setup and generation of keys/proof for the `gnark_bn254_verifier` contract. Run the commands in order. + +```sh +cd data/gnark_bn254/auxiliary + +# Install dependencies +go mod tidy + +# Run the setup: compiles circuit, generates keys, creates proof, and exports to JSON +# Outputs: ../proof.json and ../verification_key.json +go run . + +cd ../../.. +``` diff --git a/groth16_verifier/data/gnark_bn254/auxiliary/circuit.go b/groth16_verifier/data/gnark_bn254/auxiliary/circuit.go new file mode 100644 index 00000000..9aae35ee --- /dev/null +++ b/groth16_verifier/data/gnark_bn254/auxiliary/circuit.go @@ -0,0 +1,30 @@ +// https://play.gnark.io/ + +// Welcome to the gnark playground! +package main + +import "github.com/consensys/gnark/frontend" + +// gnark is a zk-SNARK library written in Go. Circuits are regular structs. +// The inputs must be of type frontend.Variable and make up the witness. +// The witness has a +// - secret part --> known to the prover only +// - public part --> known to the prover and the verifier +type Circuit struct { + X frontend.Variable `gnark:"x"` // x --> secret visibility (default) + Y frontend.Variable `gnark:",public"` // Y --> public visibility +} + +// Define declares the circuit logic. The compiler then produces a list of constraints +// which must be satisfied (valid witness) in order to create a valid zk-SNARK +func (circuit *Circuit) Define(api frontend.API) error { + // compute x**3 and store it in the local variable x3. + x3 := api.Mul(circuit.X, circuit.X, circuit.X) + + // compute x**3 + x + 5 and store it in the local variable res + res := api.Add(x3, circuit.X, 5) + + // assert that the statement x**3 + x + 5 == y is true. + api.AssertIsEqual(circuit.Y, res) + return nil +} diff --git a/groth16_verifier/data/gnark_bn254/auxiliary/go.mod b/groth16_verifier/data/gnark_bn254/auxiliary/go.mod new file mode 100644 index 00000000..a8f41e90 --- /dev/null +++ b/groth16_verifier/data/gnark_bn254/auxiliary/go.mod @@ -0,0 +1,25 @@ +module gnark_example + +go 1.25.0 + +require ( + github.com/consensys/gnark v0.14.0 + github.com/consensys/gnark-crypto v0.19.0 + github.com/mysteryon88/gnark-to-snarkjs v1.0.2 +) + +require ( + github.com/bits-and-blooms/bitset v1.24.0 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 // indirect + github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ronanh/intcomp v1.1.1 // indirect + github.com/rs/zerolog v1.34.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect +) diff --git a/groth16_verifier/data/gnark_bn254/auxiliary/go.sum b/groth16_verifier/data/gnark_bn254/auxiliary/go.sum new file mode 100644 index 00000000..7edb38e7 --- /dev/null +++ b/groth16_verifier/data/gnark_bn254/auxiliary/go.sum @@ -0,0 +1,58 @@ +github.com/bits-and-blooms/bitset v1.24.0 h1:H4x4TuulnokZKvHLfzVRTHJfFfnHEeSYJizujEZvmAM= +github.com/bits-and-blooms/bitset v1.24.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/consensys/gnark v0.14.0 h1:RG+8WxRanFSFBSlmCDRJnYMYYKpH3Ncs5SMzg24B5HQ= +github.com/consensys/gnark v0.14.0/go.mod h1:1IBpDPB/Rdyh55bQRR4b0z1WvfHQN1e0020jCvKP2Gk= +github.com/consensys/gnark-crypto v0.19.0 h1:zXCqeY2txSaMl6G5wFpZzMWJU9HPNh8qxPnYJ1BL9vA= +github.com/consensys/gnark-crypto v0.19.0/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY= +github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= +github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2 h1:B+aWVgAx+GlFLhtYjIaF0uGjU3rzpl99Wf9wZWt+Mq8= +github.com/ingonyama-zk/icicle-gnark/v3 v3.2.2/go.mod h1:CH/cwcr21pPWH+9GtK/PFaa4OGTv4CtfkCKro6GpbRE= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mysteryon88/gnark-to-snarkjs v1.0.2 h1:tcn72yevI0JOsBhxVSmSTpqoHZxxSZB7GeoDkot27sg= +github.com/mysteryon88/gnark-to-snarkjs v1.0.2/go.mod h1:pqCKRvPoi7jZZ1Xa1gczcVGr85FxynEf3xgDIZuFvFQ= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ronanh/intcomp v1.1.1 h1:+1bGV/wEBiHI0FvzS7RHgzqOpfbBJzLIxkqMJ9e6yxY= +github.com/ronanh/intcomp v1.1.1/go.mod h1:7FOLy3P3Zj3er/kVrU/pl+Ql7JFZj7bwliMGketo0IU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0= +golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/groth16_verifier/data/gnark_bn254/auxiliary/main.go b/groth16_verifier/data/gnark_bn254/auxiliary/main.go new file mode 100644 index 00000000..0cf1754f --- /dev/null +++ b/groth16_verifier/data/gnark_bn254/auxiliary/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "os" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + gnarktosnarkjs "github.com/mysteryon88/gnark-to-snarkjs" +) + +const ( + ProofPath = "../proof.json" + VKeyPath = "../verification_key.json" +) + +func main() { + + scalarField := ecc.BN254.ScalarField() + + circuit := Circuit{} + + // Compile the circuit into an R1CS + r1cs, err := frontend.Compile(scalarField, r1cs.NewBuilder, &circuit) + if err != nil { + panic(err) + } + + // Setup the proving and verifying keys + pk, vk, err := groth16.Setup(r1cs) + if err != nil { + panic(err) + } + + // Set the witness values + circuit.X = 3 + circuit.Y = 35 + + // Create a witness for the circuit + witnessFull, err := frontend.NewWitness(&circuit, scalarField) + if err != nil { + panic(err) + } + + // Create a witness for the public inputs + witnessPublic, err := frontend.NewWitness(&circuit, scalarField, frontend.PublicOnly()) + if err != nil { + panic(err) + } + + // Prove the circuit + proof, err := groth16.Prove(r1cs, pk, witnessFull) + if err != nil { + panic(err) + } + + // Verify the proof + err = groth16.Verify(proof, vk, witnessPublic) + if err != nil { + panic(err) + } + + // Export the proof + { + + proof_out, err := os.Create(ProofPath) + if err != nil { + panic(err) + } + + defer proof_out.Close() + + err = gnarktosnarkjs.ExportProof(proof, []string{"35"}, proof_out) + if err != nil { + panic(err) + } + } + + // Export the verification key + { + out, err := os.Create(VKeyPath) + if err != nil { + panic(err) + } + defer out.Close() + err = gnarktosnarkjs.ExportVerifyingKey(vk, out) + if err != nil { + panic(err) + } + } + +} diff --git a/groth16_verifier/data/gnark_bn254/proof.json b/groth16_verifier/data/gnark_bn254/proof.json new file mode 100644 index 00000000..82a0b28a --- /dev/null +++ b/groth16_verifier/data/gnark_bn254/proof.json @@ -0,0 +1,31 @@ +{ + "curve": "bn254", + "pi_a": [ + "10598850184003840763161362781678097562587216932439357734732219474573915897532", + "20927195754446888305180777787483281534446762458928359718199788147414355519889", + "1" + ], + "pi_b": [ + [ + "16328246674332551327886799707513482669533795248885577419730431344937245578701", + "6715299278813991292072009238722873121824241571877064580637739995041839068717" + ], + [ + "2926654788909971882315137611857838373428912489602490211974601762143783436672", + "792155186453170309799771964160462497494052237872978686140432855975854848213" + ], + [ + "1", + "0" + ] + ], + "pi_c": [ + "21472647602435116638622527462157688896853045540421733317237784966229773860037", + "8192862309059005289732917876825819686897152084682143073788634555894287168398", + "1" + ], + "protocol": "groth16", + "publicSignals": [ + "35" + ] +} diff --git a/groth16_verifier/data/gnark_bn254/verification_key.json b/groth16_verifier/data/gnark_bn254/verification_key.json new file mode 100644 index 00000000..391b0747 --- /dev/null +++ b/groth16_verifier/data/gnark_bn254/verification_key.json @@ -0,0 +1,94 @@ +{ + "protocol": "groth16", + "curve": "bn254", + "nPublic": 1, + "vk_alpha_1": [ + "17160892880419392774185061232400090990827596346413287671506157471369546504383", + "10635860921408911008080985713278969196581349225038585898100560515097474253655", + "1" + ], + "vk_beta_2": [ + [ + "11132873584861496301153896658263136317554331102286032051706067686649889213543", + "14969220664364395294904019557860830321864102496704052736041988821689531846758" + ], + [ + "20183948933857026412032501050398875210227692592453194989660422446309275743326", + "13447684770690872559584239690842918338115200388112402552845246691203273260826" + ], + [ + "1", + "0" + ] + ], + "vk_gamma_2": [ + [ + "6871326279043863092348922185004361202123144101478725043729586351061291702190", + "1862340348954379963931887304766613873027063325411339893600137790290315367905" + ], + [ + "11115935280650728984952115133516406276126318243993625382880283082553156785364", + "12917785428228232583705904773986960034435495112858768582953727058946773250958" + ], + [ + "1", + "0" + ] + ], + "vk_delta_2": [ + [ + "17433367545628517751225399534207449159030793523592307600712738319715296986964", + "1248816892833423959396500265161993147649529757868498602793114605728995547537" + ], + [ + "16760407486854689091970528822171471843558323189726462822252526577998642129431", + "14242457191045521529443123834006685671324573194647929480957389142363121728971" + ], + [ + "1", + "0" + ] + ], + "vk_alphabeta_12": [ + [ + [ + "14497539175042492142072626630100573681924135642781617485419155390252893186909", + "18240963135080995784765209127003771505918109908988392219656041272159218434379" + ], + [ + "17362253251580575947034996209714643639622484717110610668032319594638811168356", + "12654626878978723618701453440087701862762095864758777496819450382068938247449" + ], + [ + "16272147662425838058042178843320755056798829965828388686180266919325884781801", + "12322848290682767597599755331403203239851565618843751449458286476955448422998" + ] + ], + [ + [ + "12256614163346471293507641959121816531985335776502504608536858826169873009173", + "2757795301978121908033135617518167498098961195756695134784539999071416332732" + ], + [ + "16863657275098726665813278370678780732223492075743055133893190567440788844798", + "2092422268602512524055684976322258837665734429926255472767032165639375621021" + ], + [ + "13491501198799573917485358815497047499770535307310580350541559518126754848848", + "18647149794271857853494226563586718992490212682168472384887037259655139149882" + ] + ] + ], + "IC": [ + [ + "18057717729498979722788532728536490219609882989833214173191596618304837123935", + "6884513841905788726614426330636785910076400865992059027956215914696472793705", + "1" + ], + [ + "9090255490784864283063310105539158323614601248659946585772390216342371092394", + "16461437550397420711157998253394441579370272813842713706414839918543193292214", + "1" + ] + ] +} diff --git a/groth16_verifier/data/proof.json b/groth16_verifier/data/proof.json deleted file mode 100644 index 2f5f720b..00000000 --- a/groth16_verifier/data/proof.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "pi_a": [ - "314442236668110257304682488877371582255161413673331360366570443799415414639292047869143313601702131653514009114222", - "2384632327855835824635705027009217874826122107057894594162233214798350178691568018290025994699762298534539543934607", - "1" - ], - "pi_b": [ - [ - "428844167033934720609657613212495751617651348480870890908850335525890280786532876634895457032623422366474694342656", - "3083139526360252775789959298805261067575555607578161553873977966165446991459924053189383038704105379290158793353905" - ], - [ - "1590919422794657666432683000821892403620510405626533455397042191265963587891653562867091397248216891852168698286910", - "3617931039814164588401589536353142503544155307022467123698224064329647390280346725086550997337076315487486714327146" - ], - [ - "1", - "0" - ] - ], - "pi_c": [ - "3052934797502613468327963344215392478880720823583493172692775426011388142569325036386650708808320216973179639719187", - "2028185281516938724429867827057869371578022471499780916652824405212207527699373814371051328341613972789943854539597", - "1" - ], - "protocol": "groth16", - "curve": "bls12381" -} \ No newline at end of file diff --git a/groth16_verifier/data/public.json b/groth16_verifier/data/public.json deleted file mode 100644 index bf203097..00000000 --- a/groth16_verifier/data/public.json +++ /dev/null @@ -1,3 +0,0 @@ -[ - "33" -] \ No newline at end of file diff --git a/groth16_verifier/data/verification_key.json b/groth16_verifier/data/verification_key.json deleted file mode 100644 index e778e4cc..00000000 --- a/groth16_verifier/data/verification_key.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "protocol": "groth16", - "curve": "bls12381", - "nPublic": 1, - "vk_alpha_1": [ - "851850525556173310373115880154698084608631105506432893865500290442025919078535925294035153152030470398262539759609", - "2637289349983507610125993281171282870664683328789064436670091381805667870657250691837988574635646688089951719927247", - "1" - ], - "vk_beta_2": [ - [ - "1312620381151154625549413690218290437739613987001512553647554932245743783919690104921577716179019375920325686841943", - "1853421227732662200477195678252233549930451033531229987959164216695698667330234953033341200627605777603511819497457" - ], - [ - "3215807833988244618006117550809420301978856703407297742347804415291049013404133666905173282837707341742014140541018", - "812366606879346135498483310623227330050424196838294715759414425317592599094348477520229174120664109186562798527696" - ], - [ - "1", - "0" - ] - ], - "vk_gamma_2": [ - [ - "352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160", - "3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758" - ], - [ - "1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905", - "927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582" - ], - [ - "1", - "0" - ] - ], - "vk_delta_2": [ - [ - "2981843938988033214458466658185878126396080429969635248100956025957789319926032198626745120548947333202362392267114", - "2236695112259305382987038341098587500598216646308901956168137697892380899086228863246537938263638056666003066263342" - ], - [ - "717163810166643254871951856655865822196000925757284470845197358532703820821048809982340614428800986999944933231635", - "3496058064578305387608803828034117220735807855182872031001942587835768203820179263722136810383631418598310938506798" - ], - [ - "1", - "0" - ] - ], - "vk_alphabeta_12": [ - [ - [ - "986314345434602723285761114714540815165948174207594366788880385445737871991742175366408675245262651703330249336130", - "326977788325290192027797763473385602198956814735567144445960526834466398305728141416506007314903111972816830478089" - ], - [ - "2566972005765663057117355569821288484662616312199992221569222108527565285637706226450975712288567676826211052009828", - "3699434258626382601224687161724795332821272399478014444888824853489335102533827344776496756934365201558496458450771" - ], - [ - "2791301291086490268194308427815002039220388356530337362551865917357667624852630484089067561323027336067266533847617", - "2525898105055075876710827163715065053410720193292753626174136502545194475866793819259204836400779184493881266645914" - ] - ], - [ - [ - "480299570814332158054387851962628719327276307648582608402834899543072822075592318735491209978693496772033004010886", - "2621205732128367220198749961294220375809850215113980318702173439822645663565392552757606784904531795766602126547186" - ], - [ - "595095377653192119804154024995457838213848090311176688409443538615730480845851619856290554780504041637921591536463", - "3453759709483545713747202263396993637467503312851899108221558283493344243439629223186561135905026261100343232562575" - ], - [ - "2939220041151334342625680543852621747013170638890028810335805818305055266895856524675501328053529188293569824477394", - "1312330610224137073804595761443475470236611771864535096449446987267281424279024152773977719507281348207744015092239" - ] - ] - ], - "IC": [ - [ - "829685638389803071404995253486571779300247099942205634643821309129201420207693030476756893332812706176564514055395", - "3455508165409829148751617737772894557887792278044850553785496869183933597103951941805834639972489587640583544390358", - "1" - ], - [ - "2645559270376031734407122278942646687260452979296081924477586893972449945444985371392950465676350735694002713633589", - "2241039659097418315097403108596818813895651201896886552939297756980670248638746432560267634304593609165964274111037", - "1" - ] - ] -} \ No newline at end of file diff --git a/groth16_verifier/rust-toolchain.toml b/groth16_verifier/rust-toolchain.toml deleted file mode 100644 index 1d3de4b2..00000000 --- a/groth16_verifier/rust-toolchain.toml +++ /dev/null @@ -1,4 +0,0 @@ -[toolchain] -channel = "1.89.0" -targets = ["wasm32v1-none"] -components = ["rustc", "cargo", "rustfmt", "clippy", "rust-src"] \ No newline at end of file diff --git a/groth16_verifier/src/lib.rs b/groth16_verifier/src/lib.rs deleted file mode 100644 index 80697e68..00000000 --- a/groth16_verifier/src/lib.rs +++ /dev/null @@ -1,67 +0,0 @@ -#![no_std] -use soroban_sdk::{ - contract, contracterror, contractimpl, contracttype, - crypto::bls12_381::{Fr, G1Affine, G2Affine}, - vec, Env, Vec, -}; - -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -#[repr(u32)] -pub enum Groth16Error { - MalformedVerifyingKey = 0, -} - -#[derive(Clone)] -#[contracttype] -pub struct VerificationKey { - pub alpha: G1Affine, - pub beta: G2Affine, - pub gamma: G2Affine, - pub delta: G2Affine, - pub ic: Vec, -} - -#[derive(Clone)] -#[contracttype] -pub struct Proof { - pub a: G1Affine, - pub b: G2Affine, - pub c: G1Affine, -} - -#[contract] -pub struct Groth16Verifier; - -#[contractimpl] -impl Groth16Verifier { - pub fn verify_proof( - env: Env, - vk: VerificationKey, - proof: Proof, - pub_signals: Vec, - ) -> Result { - let bls = env.crypto().bls12_381(); - - // Prepare proof inputs: - // Compute vk_x = ic[0] + sum(pub_signals[i] * ic[i+1]) - if pub_signals.len() + 1 != vk.ic.len() { - return Err(Groth16Error::MalformedVerifyingKey); - } - let mut vk_x = vk.ic.get(0).unwrap(); - for (s, v) in pub_signals.iter().zip(vk.ic.iter().skip(1)) { - let prod = bls.g1_mul(&v, &s); - vk_x = bls.g1_add(&vk_x, &prod); - } - - // Compute the pairing: - // e(-A, B) * e(alpha, beta) * e(vk_x, gamma) * e(C, delta) == 1 - let neg_a = -proof.a; - let vp1 = vec![&env, neg_a, vk.alpha, vk_x, proof.c]; - let vp2 = vec![&env, proof.b, vk.beta, vk.gamma, vk.delta]; - - Ok(bls.pairing_check(vp1, vp2)) - } -} - -mod test; diff --git a/groth16_verifier/src/test.rs b/groth16_verifier/src/test.rs deleted file mode 100644 index 02100185..00000000 --- a/groth16_verifier/src/test.rs +++ /dev/null @@ -1,139 +0,0 @@ -#![cfg(test)] -extern crate std; - -use ark_bls12_381::{Fq, Fq2}; -use ark_serialize::CanonicalSerialize; -use core::str::FromStr; -use soroban_sdk::{ - crypto::bls12_381::{Fr, G1Affine, G2Affine, G1_SERIALIZED_SIZE, G2_SERIALIZED_SIZE}, - Env, Vec, U256, -}; - -use crate::{Groth16Verifier, Groth16VerifierClient, Proof, VerificationKey}; - -fn g1_from_coords(env: &Env, x: &str, y: &str) -> G1Affine { - let ark_g1 = ark_bls12_381::G1Affine::new(Fq::from_str(x).unwrap(), Fq::from_str(y).unwrap()); - let mut buf = [0u8; G1_SERIALIZED_SIZE]; - ark_g1.serialize_uncompressed(&mut buf[..]).unwrap(); - G1Affine::from_array(env, &buf) -} - -fn g2_from_coords(env: &Env, x1: &str, x2: &str, y1: &str, y2: &str) -> G2Affine { - let x = Fq2::new(Fq::from_str(x1).unwrap(), Fq::from_str(x2).unwrap()); - let y = Fq2::new(Fq::from_str(y1).unwrap(), Fq::from_str(y2).unwrap()); - let ark_g2 = ark_bls12_381::G2Affine::new(x, y); - let mut buf = [0u8; G2_SERIALIZED_SIZE]; - ark_g2.serialize_uncompressed(&mut buf[..]).unwrap(); - G2Affine::from_array(env, &buf) -} - -fn create_client(e: &Env) -> Groth16VerifierClient<'_> { - Groth16VerifierClient::new(e, &e.register(Groth16Verifier {}, ())) -} - -#[test] -fn test() { - // Initialize the test environment - let env = Env::default(); - - // Load verification key components (copied from `data/verification_key.json`) - // These values are pre-computed for the circuit that verifies a*b = c - // where a=3, b=11, c=33 and only c is public. - let alphax = "851850525556173310373115880154698084608631105506432893865500290442025919078535925294035153152030470398262539759609"; - let alphay = "2637289349983507610125993281171282870664683328789064436670091381805667870657250691837988574635646688089951719927247"; - - let betax1 = "1312620381151154625549413690218290437739613987001512553647554932245743783919690104921577716179019375920325686841943"; - let betax2 = "1853421227732662200477195678252233549930451033531229987959164216695698667330234953033341200627605777603511819497457"; - let betay1 = "3215807833988244618006117550809420301978856703407297742347804415291049013404133666905173282837707341742014140541018"; - let betay2 = "812366606879346135498483310623227330050424196838294715759414425317592599094348477520229174120664109186562798527696"; - - let gammax1 = "352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160"; - let gammax2 = "3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758"; - let gammay1 = "1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905"; - let gammay2 = "927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582"; - - let deltax1 = "2981843938988033214458466658185878126396080429969635248100956025957789319926032198626745120548947333202362392267114"; - let deltax2 = "2236695112259305382987038341098587500598216646308901956168137697892380899086228863246537938263638056666003066263342"; - let deltay1 = "717163810166643254871951856655865822196000925757284470845197358532703820821048809982340614428800986999944933231635"; - let deltay2 = "3496058064578305387608803828034117220735807855182872031001942587835768203820179263722136810383631418598310938506798"; - - let ic0x = "829685638389803071404995253486571779300247099942205634643821309129201420207693030476756893332812706176564514055395"; - let ic0y = "3455508165409829148751617737772894557887792278044850553785496869183933597103951941805834639972489587640583544390358"; - - let ic1x = "2645559270376031734407122278942646687260452979296081924477586893972449945444985371392950465676350735694002713633589"; - let ic1y = "2241039659097418315097403108596818813895651201896886552939297756980670248638746432560267634304593609165964274111037"; - - // Construct the verification key from the pre-computed components - let vk = VerificationKey { - alpha: g1_from_coords(&env, alphax, alphay), - beta: g2_from_coords(&env, betax1, betax2, betay1, betay2), - gamma: g2_from_coords(&env, gammax1, gammax2, gammay1, gammay2), - delta: g2_from_coords(&env, deltax1, deltax2, deltay1, deltay2), - ic: Vec::from_array( - &env, - [ - g1_from_coords(&env, ic0x, ic0y), - g1_from_coords(&env, ic1x, ic1y), - ], - ), - }; - - // Load proof components (copied from `data/proof.json`) - let pi_ax = "314442236668110257304682488877371582255161413673331360366570443799415414639292047869143313601702131653514009114222"; - let pi_ay = "2384632327855835824635705027009217874826122107057894594162233214798350178691568018290025994699762298534539543934607"; - let pi_bx1 = "428844167033934720609657613212495751617651348480870890908850335525890280786532876634895457032623422366474694342656"; - let pi_bx2 = "3083139526360252775789959298805261067575555607578161553873977966165446991459924053189383038704105379290158793353905"; - let pi_by1 = "1590919422794657666432683000821892403620510405626533455397042191265963587891653562867091397248216891852168698286910"; - let pi_by2 = "3617931039814164588401589536353142503544155307022467123698224064329647390280346725086550997337076315487486714327146"; - let pi_cx = "3052934797502613468327963344215392478880720823583493172692775426011388142569325036386650708808320216973179639719187"; - let pi_cy = "2028185281516938724429867827057869371578022471499780916652824405212207527699373814371051328341613972789943854539597"; - - // Construct the proof from the pre-computed components - let proof = Proof { - a: g1_from_coords(&env, &pi_ax, &pi_ay), - b: g2_from_coords(&env, &pi_bx1, &pi_bx2, &pi_by1, &pi_by2), - c: g1_from_coords(&env, &pi_cx, &pi_cy), - }; - - // Create the contract client - let client = create_client(&env); - - // Test Case 1: Verify the proof with the correct public output (33, copied from `data/public.json`) - let output = Vec::from_array(&env, [Fr::from_u256(U256::from_u32(&env, 33))]); - let res = client.verify_proof(&vk, &proof, &output); - assert_eq!(res, true); - - // Print out the budget report showing CPU and memory cost breakdown for - // different operations (zero-value operations omitted for brevity) - env.cost_estimate().budget().print(); - /* - ================================================================= - Cpu limit: 100000000; used: 40968821 - Mem limit: 41943040; used: 297494 - ================================================================= - CostType cpu_insns mem_bytes - MemAlloc 12089 3401 - MemCpy 3091 0 - MemCmp 928 0 - VisitObject 5917 0 - ComputeSha256Hash 3738 0 - Bls12381EncodeFp 2644 0 - Bls12381DecodeFp 29550 0 - Bls12381G1CheckPointOnCurve 13538 0 - Bls12381G1CheckPointInSubgroup 3652550 0 - Bls12381G2CheckPointOnCurve 23684 0 - Bls12381G2CheckPointInSubgroup 4231288 0 - Bls12381G1ProjectiveToAffine 185284 0 - Bls12381G1Add 7689 0 - Bls12381G1Mul 2458985 0 - Bls12381Pairing 30335852 294093 - Bls12381FrFromU256 1994 0 - // ... zero-value rows omitted ... - ================================================================= - */ - - // Test Case 2: Verify the proof with an incorrect public output (22) - let output = Vec::from_array(&env, [Fr::from_u256(U256::from_u32(&env, 22))]); - let res = client.verify_proof(&vk, &proof, &output); - assert_eq!(res, false); -}