From 63b1d102d15413f1d0a08212715e1565e1454b2a Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Mon, 7 Oct 2024 18:33:41 -0700 Subject: [PATCH] remove evm --- .github/workflows/foundry-test.yml | 40 ------- .gitmodules | 10 -- Cargo.lock | 4 +- Cargo.toml | 1 - README.md | 34 +----- contracts/.gitignore | 15 --- contracts/README.md | 61 ---------- contracts/foundry.toml | 7 -- contracts/lib/forge-std | 1 - contracts/lib/sp1-contracts | 1 - contracts/remappings.txt | 1 - contracts/src/Fibonacci.sol | 44 ------- contracts/src/fixtures/groth16-fixture.json | 8 -- contracts/src/fixtures/plonk-fixture.json | 8 -- contracts/test/Fibonacci.t.sol | 58 --------- elf/riscv32im-succinct-zkvm-elf | Bin 130760 -> 131812 bytes lib/Cargo.toml | 2 +- lib/src/lib.rs | 15 ++- program/Cargo.toml | 1 - program/src/main.rs | 5 +- script/Cargo.toml | 5 - script/src/bin/evm.rs | 126 -------------------- script/src/bin/main.rs | 5 +- 23 files changed, 15 insertions(+), 437 deletions(-) delete mode 100644 .github/workflows/foundry-test.yml delete mode 100644 .gitmodules delete mode 100644 contracts/.gitignore delete mode 100644 contracts/README.md delete mode 100644 contracts/foundry.toml delete mode 160000 contracts/lib/forge-std delete mode 160000 contracts/lib/sp1-contracts delete mode 100644 contracts/remappings.txt delete mode 100644 contracts/src/Fibonacci.sol delete mode 100644 contracts/src/fixtures/groth16-fixture.json delete mode 100644 contracts/src/fixtures/plonk-fixture.json delete mode 100644 contracts/test/Fibonacci.t.sol delete mode 100644 script/src/bin/evm.rs diff --git a/.github/workflows/foundry-test.yml b/.github/workflows/foundry-test.yml deleted file mode 100644 index f00e456..0000000 --- a/.github/workflows/foundry-test.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Foundry Test - -on: - workflow_dispatch: - push: - branches: [ main ] - pull_request: - -env: - FOUNDRY_PROFILE: ci - -jobs: - check: - strategy: - fail-fast: true - - name: Foundry project - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Run Forge build - run: | - cd contracts - forge --version - forge build --sizes - id: build - - - name: Run Forge tests - run: | - cd contracts - forge test -vvv - id: test diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 9219300..0000000 --- a/.gitmodules +++ /dev/null @@ -1,10 +0,0 @@ -[submodule "contracts/lib/forge-std"] - path = contracts/lib/forge-std - url = https://github.com/foundry-rs/forge-std - tag = v1.8.2 - shallow = true -[submodule "contracts/lib/sp1-contracts"] - path = contracts/lib/sp1-contracts - url = https://github.com/succinctlabs/sp1-contracts - tag = v2.0.0 - shallow = true diff --git a/Cargo.lock b/Cargo.lock index 45ffb36..2e6ff2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1729,14 +1729,13 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" name = "fibonacci-lib" version = "0.1.0" dependencies = [ - "alloy-sol-types", + "serde", ] [[package]] name = "fibonacci-program" version = "0.1.0" dependencies = [ - "alloy-sol-types", "fibonacci-lib", "sp1-zkvm", ] @@ -1745,7 +1744,6 @@ dependencies = [ name = "fibonacci-script" version = "0.1.0" dependencies = [ - "alloy-sol-types", "clap", "fibonacci-lib", "hex", diff --git a/Cargo.toml b/Cargo.toml index 2f463f7..b55e454 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ resolver = "2" sp1-sdk = "2.0.0" sp1-zkvm = "2.0.0" sp1-helper = "2.0.0" -alloy-sol-types = "0.7.7" serde_json = { version = "1.0", default-features = false, features = ["alloc"] } serde = { version = "1.0", default-features = false, features = ["derive"] } clap = { version = "4.0", features = ["derive", "env"] } diff --git a/README.md b/README.md index 9fbeaec..8da7129 100644 --- a/README.md +++ b/README.md @@ -37,35 +37,6 @@ cd script cargo run --release -- --prove ``` -### Generate an EVM-Compatible Proof - -> [!WARNING] -> You will need at least 128GB RAM to generate a Groth16 or PLONK proof. - -To generate a proof that is small enough to be verified on-chain and verifiable by the EVM: - -```sh -cd script -cargo run --release --bin evm -- --system groth16 -``` - -this will generate a Groth16 proof. If you want to generate a PLONK proof, run the following command: - -```sh -cargo run --release --bin evm -- --system plonk -``` - -These commands will also generate fixtures that can be used to test the verification of SP1 zkVM proofs -inside Solidity. - -### Retrieve the Verification Key - -To retrieve your `programVKey` for your on-chain contract, run the following command: - -```sh -cargo prove vkey --elf elf/riscv32im-succinct-zkvm-elf -``` - ## Using the Prover Network We highly recommend using the Succinct prover network for any non-trivial programs or benchmarking purposes. For more information, see the [setup guide](https://docs.succinct.xyz/generating-proofs/prover-network.html). @@ -79,9 +50,8 @@ cp .env.example .env Then, set the `SP1_PROVER` environment variable to `network` and set the `SP1_PRIVATE_KEY` environment variable to your whitelisted private key. -For example, to generate an EVM-compatible proof using the prover network, run the following -command: +To generate a proof, run the following command: ```sh -SP1_PROVER=network SP1_PRIVATE_KEY=... cargo run --release --bin evm +SP1_PROVER=network SP1_PRIVATE_KEY=... cargo run --release ``` diff --git a/contracts/.gitignore b/contracts/.gitignore deleted file mode 100644 index 59ae5b1..0000000 --- a/contracts/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# Compiler files -cache/ -out/ - -# Ignores development broadcast logs -/broadcast -/broadcast/*/11155111/ -/broadcast/*/31337/ -/broadcast/**/dry-run/ - -# Docs -docs/ - -# Dotenv file -.env diff --git a/contracts/README.md b/contracts/README.md deleted file mode 100644 index 02f860a..0000000 --- a/contracts/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# SP1 Project Template Contracts - -This is a template for writing a contract that uses verification of [SP1](https://github.com/succinctlabs/sp1) PlonK proofs onchain using the [SP1VerifierGateway](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/SP1VerifierGateway.sol). - -## Requirements - -- [Foundry](https://book.getfoundry.sh/getting-started/installation) - -## Test - -```sh -forge test -v -``` - -## Deployment - -#### Step 1: Set the `VERIFIER` environment variable - -Find the address of the `verifer` to use from the [deployments](https://github.com/succinctlabs/sp1-contracts/tree/main/contracts/deployments) list for the chain you are deploying to. Set it to the `VERIFIER` environment variable, for example: - -```sh -VERIFIER=0x3B6041173B80E77f038f3F2C0f9744f04837185e -``` - -Note: you can use either the [SP1VerifierGateway](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/SP1VerifierGateway.sol) or a specific version, but it is highly recommended to use the gateway as this will allow you to use different versions of SP1. - -#### Step 2: Set the `PROGRAM_VKEY` environment variable - -Find your program verification key by going into the `../script` directory and running `RUST_LOG=info cargo run --package fibonacci-script --bin vkey --release`, which will print an output like: - -> Program Verification Key: 0x00620892344c310c32a74bf0807a5c043964264e4f37c96a10ad12b5c9214e0e - -Then set the `PROGRAM_VKEY` environment variable to the output of that command, for example: - -```sh -PROGRAM_VKEY=0x00620892344c310c32a74bf0807a5c043964264e4f37c96a10ad12b5c9214e0e -``` - -#### Step 3: Deploy the contract - -Fill out the rest of the details needed for deployment: - -```sh -RPC_URL=... -``` - -```sh -PRIVATE_KEY=... -``` - -Then deploy the contract to the chain: - -```sh -forge create src/Fibonacci.sol:Fibonacci --rpc-url $RPC_URL --private-key $PRIVATE_KEY --constructor-args $VERIFIER $PROGRAM_VKEY -``` - -It can also be a good idea to verify the contract when you deploy, in which case you would also need to set `ETHERSCAN_API_KEY`: - -```sh -forge create src/Fibonacci.sol:Fibonacci --rpc-url $RPC_URL --private-key $PRIVATE_KEY --constructor-args $VERIFIER $PROGRAM_VKEY --verify --verifier etherscan --etherscan-api-key $ETHERSCAN_API_KEY -``` diff --git a/contracts/foundry.toml b/contracts/foundry.toml deleted file mode 100644 index 9430db1..0000000 --- a/contracts/foundry.toml +++ /dev/null @@ -1,7 +0,0 @@ -[profile.default] -src = "src" -out = "out" -libs = ["lib"] -fs_permissions = [{ access = "read-write", path = "./" }] - -# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/contracts/lib/forge-std b/contracts/lib/forge-std deleted file mode 160000 index c28115d..0000000 --- a/contracts/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c28115db8d90ebffb41953cf83aac63130f4bd40 diff --git a/contracts/lib/sp1-contracts b/contracts/lib/sp1-contracts deleted file mode 160000 index af1ae09..0000000 --- a/contracts/lib/sp1-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit af1ae093ef8a8f68b022aa8f0f7ad9ffd94aa6fb diff --git a/contracts/remappings.txt b/contracts/remappings.txt deleted file mode 100644 index 4483f06..0000000 --- a/contracts/remappings.txt +++ /dev/null @@ -1 +0,0 @@ -@sp1-contracts/=./lib/sp1-contracts/contracts/src/ \ No newline at end of file diff --git a/contracts/src/Fibonacci.sol b/contracts/src/Fibonacci.sol deleted file mode 100644 index f66a01f..0000000 --- a/contracts/src/Fibonacci.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol"; - -struct PublicValuesStruct { - uint32 n; - uint32 a; - uint32 b; -} - -/// @title Fibonacci. -/// @author Succinct Labs -/// @notice This contract implements a simple example of verifying the proof of a computing a -/// fibonacci number. -contract Fibonacci { - /// @notice The address of the SP1 verifier contract. - /// @dev This can either be a specific SP1Verifier for a specific version, or the - /// SP1VerifierGateway which can be used to verify proofs for any version of SP1. - /// For the list of supported verifiers on each chain, see: - /// https://github.com/succinctlabs/sp1-contracts/tree/main/contracts/deployments - address public verifier; - - /// @notice The verification key for the fibonacci program. - bytes32 public fibonacciProgramVKey; - - constructor(address _verifier, bytes32 _fibonacciProgramVKey) { - verifier = _verifier; - fibonacciProgramVKey = _fibonacciProgramVKey; - } - - /// @notice The entrypoint for verifying the proof of a fibonacci number. - /// @param _proofBytes The encoded proof. - /// @param _publicValues The encoded public values. - function verifyFibonacciProof(bytes calldata _publicValues, bytes calldata _proofBytes) - public - view - returns (uint32, uint32, uint32) - { - ISP1Verifier(verifier).verifyProof(fibonacciProgramVKey, _publicValues, _proofBytes); - PublicValuesStruct memory publicValues = abi.decode(_publicValues, (PublicValuesStruct)); - return (publicValues.n, publicValues.a, publicValues.b); - } -} diff --git a/contracts/src/fixtures/groth16-fixture.json b/contracts/src/fixtures/groth16-fixture.json deleted file mode 100644 index fd07864..0000000 --- a/contracts/src/fixtures/groth16-fixture.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "a": 6765, - "b": 10946, - "n": 20, - "vkey": "0x00a22fd3af2b4ec77de39ec50023cf6c2b64984d0156a3df1984262984ef71bf", - "publicValues": "0x00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000001a6d0000000000000000000000000000000000000000000000000000000000002ac2", - "proof": "0x6a2906ac23e4480564d34dfcf7005e26d0cc0d530a1b5029dfc2152f14b97841cbcb738a03a407d4104ced929ce6474501da24e7e1e5267ea0e1b2ace137c28a053febcf1fa039f5f964c2ed7f82ca582574f761af8c2541a6991d85190450c02131539f03747b06260cd8bff401728a923fc6f980c7fa8bed4a9de3c9821f62328c243e003d00cd3b8eb153f1df4e5e9f7fbfa9b81ac4f03d3bbbfdb8204ec9e25b520016d69ba1c93b90d86da73111123388195d65ed14c8241cf8a4390c416bdabffd165b92debad53ca3db689e06e533131364e1d9652aba537d689321fac966d32e1d2e7714067217b2cd5a3d1df81ece476eec70bf682164102de5e8d652221d3d" -} \ No newline at end of file diff --git a/contracts/src/fixtures/plonk-fixture.json b/contracts/src/fixtures/plonk-fixture.json deleted file mode 100644 index 0d381e7..0000000 --- a/contracts/src/fixtures/plonk-fixture.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "a": 6765, - "b": 10946, - "n": 20, - "vkey": "0x00a22fd3af2b4ec77de39ec50023cf6c2b64984d0156a3df1984262984ef71bf", - "publicValues": "0x00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000001a6d0000000000000000000000000000000000000000000000000000000000002ac2", - "proof": "0x4aca240a10e48d547d454301bd5384e07852d60e6ba0f115f65a60f4443c4cee1348b695086b30d01c43bbd73a4026a1e2085b206e16f2e996ea101e35e116501fbe8c70003cef43831a390fc7d551058c6b186bb29597eb5d4981d72453a1c48c9ef3b90f1571cc98e55ebac36e5fecb14f7840419de70cd9a4c5c9692ab35b7222203c0f146200c674ffde1bb21feded6250d54d1bbbae633d1c4d070ce21384187ee60e87d43ed7a580181615ca48a5dfa0704ed429f690e0cb8f4382a16fc911d24623dc90465ed642716ffcb0cd53ff149273f5c511129f029f4072371572cf3bcc1e53ace42dbd6890319597f31401c96287eac3300c5930cfc150e9d81bf1ee740e5b7e8ed8e8e592d9f779f35e2be0208e209ff9b728ff3825b1a9b7aef826a525f9d755f96ec2e68a88b4da246b425ebd4af4c3041ea12c5e4c44ed9e83a4ad069f674517a08ec7bcda9c7672978a2fd056956c5f48e9b8f348028335aee6db1c105a306b0d03f309f406ceb824c72133f186a615849b950ab9baec61bff812034bb448565d0b789adeaaead1e5c07b9224d081a9c42dbe3bf0d66889dda3d11fc11c3465d952f797cf9a26341edbfb868de65bb51cc3e4445ca084e120c4b406f30b78f720ff785e6592ad218f71b4382cd6cfbb4d653a64efea019e5c705e1e15f9034b85b02b5c65d5c4a79143982b596bb1dc49d2799c581906686042780ca366da2fed051649bfa7fd0a350bd5953db403e2b638d992288cf2df85adba29442fd8f5fe7db31bd22002ba1e9bf59d5fe848dc66242191c070ddc1ba6e9d16affcb406d1b765024293ee018e48a79b81dc26c3219a7c76a91071fc1abb67096561ba7cb68c5c7f0eb82c3aed59c413abb7cad01a2ad2c6a3cbc87700f01716ecb7c7b42f6d5cb2dd20c5ec528236fa0220500e07daf5138a8ede04ee206f02912f9571ef693a699811a9bcbe544a5ab6e97e61dcff677e631f50126868460715fda230220afce3ca030a8b561a0863d2a1e926f8b07c4846e858690f593a1713eb06cf21f1a3962ab2a9086c4d8761dcf0d8c2c7dcbc35ade5b7be2848ff1861e824799ace0e4ea39031ff336e2005373d35a9549e5d9cc4191f337f407f0fc4ce65a7484686747f6de7914eef3bdca97cf4ca0013c3af4097e7d768146a1bfa12db65d818ecae20612f5e14d71f608bd19da830794b7ca09ff5e00b0722" -} \ No newline at end of file diff --git a/contracts/test/Fibonacci.t.sol b/contracts/test/Fibonacci.t.sol deleted file mode 100644 index 9e065f1..0000000 --- a/contracts/test/Fibonacci.t.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Test, console} from "forge-std/Test.sol"; -import {stdJson} from "forge-std/StdJson.sol"; -import {Fibonacci} from "../src/Fibonacci.sol"; -import {SP1VerifierGateway} from "@sp1-contracts/SP1VerifierGateway.sol"; - -struct SP1ProofFixtureJson { - uint32 a; - uint32 b; - uint32 n; - bytes proof; - bytes publicValues; - bytes32 vkey; -} - -contract FibonacciTest is Test { - using stdJson for string; - - address verifier; - Fibonacci public fibonacci; - - function loadFixture() public view returns (SP1ProofFixtureJson memory) { - string memory root = vm.projectRoot(); - string memory path = string.concat(root, "/src/fixtures/plonk-fixture.json"); - string memory json = vm.readFile(path); - bytes memory jsonBytes = json.parseRaw("."); - return abi.decode(jsonBytes, (SP1ProofFixtureJson)); - } - - function setUp() public { - SP1ProofFixtureJson memory fixture = loadFixture(); - - verifier = address(new SP1VerifierGateway(address(1))); - fibonacci = new Fibonacci(verifier, fixture.vkey); - } - - function test_ValidFibonacciProof() public { - SP1ProofFixtureJson memory fixture = loadFixture(); - - vm.mockCall(verifier, abi.encodeWithSelector(SP1VerifierGateway.verifyProof.selector), abi.encode(true)); - - (uint32 n, uint32 a, uint32 b) = fibonacci.verifyFibonacciProof(fixture.publicValues, fixture.proof); - assert(n == fixture.n); - assert(a == fixture.a); - assert(b == fixture.b); - } - - function testFail_InvalidFibonacciProof() public view { - SP1ProofFixtureJson memory fixture = loadFixture(); - - // Create a fake proof. - bytes memory fakeProof = new bytes(fixture.proof.length); - - fibonacci.verifyFibonacciProof(fixture.publicValues, fakeProof); - } -} diff --git a/elf/riscv32im-succinct-zkvm-elf b/elf/riscv32im-succinct-zkvm-elf index 92b2fb30c48a4ff8e04c0097eea4dde89caf9565..9818e60f0f6c4d83dfc5293bdb9ae60ea5922656 100755 GIT binary patch delta 37855 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 C+xB7r delta 37173 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 j6s$GMIOz^9HqCf* client.prove(&pk, stdin).plonk().run(), - ProofSystem::Groth16 => client.prove(&pk, stdin).groth16().run(), - } - .expect("failed to generate proof"); - - create_proof_fixture(&proof, &vk, args.system); -} - -/// Create a fixture for the given proof. -fn create_proof_fixture( - proof: &SP1ProofWithPublicValues, - vk: &SP1VerifyingKey, - system: ProofSystem, -) { - // Deserialize the public values. - let bytes = proof.public_values.as_slice(); - let PublicValuesStruct { n, a, b } = PublicValuesStruct::abi_decode(bytes, false).unwrap(); - - // Create the testing fixture so we can test things end-to-end. - let fixture = SP1FibonacciProofFixture { - a, - b, - n, - vkey: vk.bytes32().to_string(), - public_values: format!("0x{}", hex::encode(bytes)), - proof: format!("0x{}", hex::encode(proof.bytes())), - }; - - // The verification key is used to verify that the proof corresponds to the execution of the - // program on the given input. - // - // Note that the verification key stays the same regardless of the input. - println!("Verification Key: {}", fixture.vkey); - - // The public values are the values which are publicly committed to by the zkVM. - // - // If you need to expose the inputs or outputs of your program, you should commit them in - // the public values. - println!("Public Values: {}", fixture.public_values); - - // The proof proves to the verifier that the program was executed with some inputs that led to - // the give public values. - println!("Proof Bytes: {}", fixture.proof); - - // Save the fixture to a file. - let fixture_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../contracts/src/fixtures"); - std::fs::create_dir_all(&fixture_path).expect("failed to create fixture path"); - std::fs::write( - fixture_path.join(format!("{:?}-fixture.json", system).to_lowercase()), - serde_json::to_string_pretty(&fixture).unwrap(), - ) - .expect("failed to write fixture"); -} diff --git a/script/src/bin/main.rs b/script/src/bin/main.rs index 33089b1..2b9e0fd 100644 --- a/script/src/bin/main.rs +++ b/script/src/bin/main.rs @@ -10,7 +10,6 @@ //! RUST_LOG=info cargo run --release -- --prove //! ``` -use alloy_sol_types::SolType; use clap::Parser; use fibonacci_lib::PublicValuesStruct; use sp1_sdk::{ProverClient, SP1Stdin}; @@ -55,11 +54,11 @@ fn main() { if args.execute { // Execute the program - let (output, report) = client.execute(FIBONACCI_ELF, stdin).run().unwrap(); + let (mut output, report) = client.execute(FIBONACCI_ELF, stdin).run().unwrap(); println!("Program executed successfully."); // Read the output. - let decoded = PublicValuesStruct::abi_decode(output.as_slice(), true).unwrap(); + let decoded = output.read::(); let PublicValuesStruct { n, a, b } = decoded; println!("n: {}", n); println!("a: {}", a);