diff --git a/Cargo.lock b/Cargo.lock index 5ffacb584b..0a3a548194 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6492,6 +6492,7 @@ dependencies = [ "hashbrown 0.14.5", "hex", "indicatif", + "itertools 0.13.0", "log", "num-bigint 0.4.6", "p3-baby-bear", diff --git a/book/developers/common-issues.md b/book/developers/common-issues.md index 06556b82dd..f26f3ba0ae 100644 --- a/book/developers/common-issues.md +++ b/book/developers/common-issues.md @@ -22,7 +22,7 @@ This is likely due to two different versions of `alloy_sol_types` being used. To ```toml [dependencies] -sp1-sdk = { version = "1.1.0", default-features = false } +sp1-sdk = { version = "2.0.0", default-features = false } ``` This will configure out the `network` feature which will remove the dependency on `alloy_sol_types` and configure out the `NetworkProver`. @@ -100,7 +100,7 @@ C++ toolchain be setting this variable manually: export CC_riscv32im_succinct_zkvm_elf=/path/to/toolchain ``` -## Compilation Errors with [`sp1-lib::syscall_verify_sp1_proof`](https://docs.rs/sp1-lib/latest/sp1_lib/fn.syscall_verify_sp1_proof.html) +## Compilation Errors with [`sp1-lib::syscall_verify_sp1_proof`](https://docs.rs/sp1-lib/latest/sp1_lib/fn.syscall_verify_sp1_proof.html) If you are using the [`sp1-lib::syscall_verify_sp1_proof`](https://docs.rs/sp1-lib/latest/sp1_lib/fn.syscall_verify_sp1_proof.html) function, you may encounter compilation errors when building your program. @@ -108,14 +108,15 @@ If you are using the [`sp1-lib::syscall_verify_sp1_proof`](https://docs.rs/sp1-l [sp1] = note: rust-lld: error: undefined symbol: syscall_verify_sp1_proof [sp1] >>> referenced by sp1_lib.b593533d149f0f6e-cgu.0 [sp1] >>> sp1_lib-8f5deb4c47d01871.sp1_lib.b593533d149f0f6e-cgu.0.rcgu.o:(sp1_lib::verify::verify_sp1_proof::h5c1bb38f11b3fe71) in ... - [sp1] - [sp1] + [sp1] + [sp1] [sp1] error: could not compile `package-name` (bin "package-name") due to 1 previous error - ``` +``` + +To resolve this, ensure that you're importing both `sp1-lib` and `sp1-zkvm` with the verify feature enabled. - To resolve this, ensure that you're importing both `sp1-lib` and `sp1-zkvm` with the verify feature enabled. - ```toml - [dependencies] - sp1-lib = { version = "", features = ["verify"] } - sp1-zkvm = { version = "", features = ["verify"] } - ``` \ No newline at end of file +```toml +[dependencies] +sp1-lib = { version = "", features = ["verify"] } +sp1-zkvm = { version = "", features = ["verify"] } +``` diff --git a/book/generating-proofs/advanced.md b/book/generating-proofs/advanced.md index 2d17439012..4b1f30c544 100644 --- a/book/generating-proofs/advanced.md +++ b/book/generating-proofs/advanced.md @@ -48,7 +48,7 @@ RUSTFLAGS='-C target-cpu=native' cargo run --release Currently there is support for AVX512 and NEON SIMD instructions. For NEON, you must also enable the `sp1-sdk` feature `neon` in your script crate's `Cargo.toml` file. ```toml -sp1-sdk = { version = "1.1.0", features = ["neon"] } +sp1-sdk = { version = "2.0.0", features = ["neon"] } ``` ## Performance diff --git a/book/generating-proofs/proof-types.md b/book/generating-proofs/proof-types.md index 70513f8faa..dd11a2b618 100644 --- a/book/generating-proofs/proof-types.md +++ b/book/generating-proofs/proof-types.md @@ -4,12 +4,12 @@ There are a few different types of proofs that can be generated by the SP1 zkVM. The `ProverClient` follows a "builder" pattern that allows you to configure the proof type and other options after creating a `ProverClient` and calling `prove` on it. -For a full list of options, see the following [docs](https://docs.rs/sp1-sdk/1.1.0/sp1_sdk/action/struct.Prove.html). +For a full list of options, see the following [docs](https://docs.rs/sp1-sdk/1.2.0/sp1_sdk/action/struct.Prove.html). ## Core (Default) The default prover mode generates a list of STARK proofs that in aggregate have size proportional to - the size of the execution. Use this in settings where you don't care about **verification cost / proof size**. +the size of the execution. Use this in settings where you don't care about **verification cost / proof size**. ```rust,noplayground let client = ProverClient::new(); @@ -19,7 +19,7 @@ client.prove(&pk, stdin).run().unwrap(); ## Compressed The compressed prover mode generates STARK proofs that have constant size. Use this in settings where you -care about **verification cost / proof size**. This is useful for applications where you want to recursively verify SP1 proofs within SP1 (see the [proof aggregation](../writing-programs/proof-aggregation.md) section). +care about **verification cost / proof size**. This is useful for applications where you want to recursively verify SP1 proofs within SP1 (see the [proof aggregation](../writing-programs/proof-aggregation.md) section). ```rust,noplayground let client = ProverClient::new(); @@ -32,7 +32,6 @@ client.prove(&pk, stdin).compressed().run().unwrap(); WARNING: The PLONK prover requires around 64GB of RAM and is only guaranteed to work on official releases of SP1. We recommend using the prover network to generate PLONK proofs. - The PLONK prover mode generates a SNARK proof with extremely small proof size and low verification cost. This mode is necessary for generating proofs that can be verified onchain for around ~300k gas. diff --git a/book/generating-proofs/prover-network.md b/book/generating-proofs/prover-network.md index 593a9f41aa..da457bfffe 100644 --- a/book/generating-proofs/prover-network.md +++ b/book/generating-proofs/prover-network.md @@ -1,8 +1,9 @@ # Prover Network Beta -> **Currently, the supported version of SP1 on the prover network is `v1.1.0`.** +> **Currently, the supported version of SP1 on the prover network is `v2.0.0`.** Succinct [has been building](https://blog.succinct.xyz/succinct-network/) the Succinct Prover Network, a distributed network of provers that can generate proofs of any size quickly and reliably. It's currently in private beta, but you can get access by following the steps below. To get started, **[FILL OUT THIS FORM](https://forms.gle/rTUvhstS8PFfv9B3A)** to gain access to the Succinct -Network. Completing this form requires you to complete the [key setup](./prover-network/key-setup.md) steps below. \ No newline at end of file +Network. Completing this form requires you to complete the [key +setup](./prover-network/key-setup.md) steps below. diff --git a/book/generating-proofs/prover-network/usage.md b/book/generating-proofs/prover-network/usage.md index c334228d4c..4a8d7bee86 100644 --- a/book/generating-proofs/prover-network/usage.md +++ b/book/generating-proofs/prover-network/usage.md @@ -1,6 +1,6 @@ # Prover Network: Usage -> **Currently, the supported version of SP1 on the prover network is `v1.1.0`.** +> **See [Supported Versions](../versions.md) for the currently supported versions of SP1 on the Prover Network.** ## Sending a proof request diff --git a/book/generating-proofs/prover-network/versions.md b/book/generating-proofs/prover-network/versions.md index 633fbe6e24..271a09078b 100644 --- a/book/generating-proofs/prover-network/versions.md +++ b/book/generating-proofs/prover-network/versions.md @@ -2,13 +2,14 @@ The prover network currently only supports specific versions of SP1: -| Environment | RPC URL | Supported Version | -| ----------- | -------------------------- | ----------------- | -| Production | `https://rpc.succinct.xyz` | `v1.2.X` | +| Version | Description | +| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| v2.X.X | Audited, production ready version. | +| v3.X.X | Pre-release version with enhanced performance, currently being audited. **Recommended for benchmarking or testing, not recommended for production use.** | -Where `X` denotes that any patch version is supported (e.g. `v1.2.0`, `v1.2.1`). +`X` denotes that any minor and patch version is supported (e.g. `v2.1.0`, `v2.1.1`). -If you submit a proof request to the prover network and your are not using the supported version, you will receive an error message. +If you submit a proof request to the prover network and you are not using a supported version, you will receive an error message. ## Changing versions @@ -16,14 +17,14 @@ You must switch to a supported version before submitting a proof. To do so, repl ```toml [dependencies] -sp1-zkvm = "1.1.0" +sp1-zkvm = "2.0.0" ``` replace the `sp1-sdk` version in your script's `Cargo.toml`: ```toml [dependencies] -sp1-sdk = "1.1.0" +sp1-sdk = "2.0.0" ``` Re-build your program and script, and then try again. diff --git a/book/generating-proofs/setup.md b/book/generating-proofs/setup.md index 9a8561cea0..88db15fb8e 100644 --- a/book/generating-proofs/setup.md +++ b/book/generating-proofs/setup.md @@ -32,7 +32,7 @@ name = "script" edition = "2021" [dependencies] -sp1-sdk = "1.1.0" +sp1-sdk = "2.0.0" ``` The `sp1-sdk` crate includes the necessary utilities to generate, save, and verify proofs. diff --git a/book/onchain-verification/getting-started.md b/book/onchain-verification/getting-started.md index 110553e7e8..34f707837d 100644 --- a/book/onchain-verification/getting-started.md +++ b/book/onchain-verification/getting-started.md @@ -27,5 +27,5 @@ You can run the above script with `RUST_LOG=info cargo run --bin plonk_bn254 --r If you would like to run the PLONK prover directly without Docker, you must have Go 1.22 installed and enable the `native-plonk` feature in `sp1-sdk`. This path is not recommended and may require additional native dependencies. ```toml -sp1-sdk = { version = "1.1.0", features = ["native-plonk"] } +sp1-sdk = { version = "2.0.0", features = ["native-plonk"] } ``` diff --git a/book/writing-programs/compiling.md b/book/writing-programs/compiling.md index 29a33cedd7..f1acd49b0d 100644 --- a/book/writing-programs/compiling.md +++ b/book/writing-programs/compiling.md @@ -34,7 +34,6 @@ Under the hood, this CLI command calls `cargo build` with the `riscv32im-succinc You can pass additional arguments to the `cargo prove build` command to customize the build process, like configuring what features are enabled, customizing the output directory and more. To see all available options, run `cargo prove build --help`. Many of these options mirror the options available in the `cargo build` command. - ## Production Builds For production builds of programs, you can build your program inside a Docker container which will generate a **reproducible ELF** on all platforms. To do so, just use the `--docker` flag and optionally the `--tag` flag with the release version you want to use (defaults to `latest`). For example: @@ -62,12 +61,12 @@ The path passed in to `build_program` should point to the directory containing t ```toml [build-dependencies] -sp1-build = "1.2.0" +sp1-build = "2.0.0" ``` You will see output like the following from the build script if the program has changed, indicating that the program was rebuilt: -```` +``` [fibonacci-script 0.1.0] cargo:rerun-if-changed=../program/src [fibonacci-script 0.1.0] cargo:rerun-if-changed=../program/Cargo.toml [fibonacci-script 0.1.0] cargo:rerun-if-changed=../program/Cargo.lock @@ -75,11 +74,10 @@ You will see output like the following from the build script if the program has [fibonacci-script 0.1.0] [sp1] Compiling fibonacci-program v0.1.0 (/Users/umaroy/Documents/fibonacci/program) [fibonacci-script 0.1.0] [sp1] Finished release [optimized] target(s) in 0.15s warning: fibonacci-script@0.1.0: fibonacci-program built at 2024-03-02 22:01:26 -```` +``` The above output was generated by running `RUST_LOG=info cargo run --release -vv` for the `script` folder of the Fibonacci example. - ### Advanced Build Options To configure the build process when using the `sp1-build` crate, you can pass a [`BuildArgs`](https://docs.rs/sp1-build/1.2.0/sp1_build/struct.BuildArgs.html) struct to to the [`build_program_with_args`](https://docs.rs/sp1-build/1.2.0/sp1_build/fn.build_program_with_args.html) function. The build arguments are the same as the ones available from the `cargo prove build` command. @@ -99,4 +97,4 @@ fn main() { } ``` -**Note:** If you want reproducible builds with the `build.rs` approach, you should use the `docker` flag and the `build_program_with_args` function, as shown in the example above. \ No newline at end of file +**Note:** If you want reproducible builds with the `build.rs` approach, you should use the `docker` flag and the `build_program_with_args` function, as shown in the example above. diff --git a/book/writing-programs/cycle-tracking.md b/book/writing-programs/cycle-tracking.md index 176249b45e..c560f28ae5 100644 --- a/book/writing-programs/cycle-tracking.md +++ b/book/writing-programs/cycle-tracking.md @@ -14,7 +14,7 @@ Note that to use the macro, you must add the `sp1-derive` crate to your dependen ```toml [dependencies] -sp1-derive = "1.1.0" +sp1-derive = "2.0.0" ``` In the script for proof generation, setup the logger with `utils::setup_logger()` and run the script with `RUST_LOG=info cargo run --release`. You should see the following output: @@ -43,6 +43,7 @@ stdout: result: 2940 Note that we elegantly handle nested cycle tracking, as you can see above. ### Get Tracked Cycle Counts + To include tracked cycle counts in the `ExecutionReport` when using `ProverClient::execute`, use the following annotations: ```rust,noplayground @@ -65,8 +66,7 @@ First, we need to generate a trace file of the program counter at each cycle whi TRACE_FILE=trace.log RUST_LOG=info cargo run --release ``` -When the `TRACE_FILE` environment variable is set, as SP1's RISC-V runtime is executing, it will write a log of the program counter to the file specified by `TRACE_FILE`. - +When the `TRACE_FILE` environment variable is set, as SP1's RISC-V runtime is executing, it will write a log of the program counter to the file specified by `TRACE_FILE`. Next, we can use the `cargo prove` CLI with the `trace` command to analyze the trace file and generate a table of instruction counts. This can be done with the following command: diff --git a/book/writing-programs/setup.md b/book/writing-programs/setup.md index 0346b3b7ad..aa3f4a2cca 100644 --- a/book/writing-programs/setup.md +++ b/book/writing-programs/setup.md @@ -32,7 +32,7 @@ name = "program" edition = "2021" [dependencies] -sp1-zkvm = "1.1.0" +sp1-zkvm = "2.0.0" ``` The `sp1-zkvm` crate includes necessary utilities for your program, including handling inputs and outputs, diff --git a/crates/core/machine/src/io.rs b/crates/core/machine/src/io.rs index ee6c652f73..6f5475cf22 100644 --- a/crates/core/machine/src/io.rs +++ b/crates/core/machine/src/io.rs @@ -113,13 +113,20 @@ impl SP1PublicValues { self.buffer.write_slice(slice); } + /// Hash the public values. + pub fn hash(&self) -> Vec { + let mut hasher = Sha256::new(); + hasher.update(self.buffer.data.as_slice()); + hasher.finalize().to_vec() + } + /// Hash the public values, mask the top 3 bits and return a BigUint. Matches the implementation /// of `hashPublicValues` in the Solidity verifier. /// /// ```solidity /// sha256(publicValues) & bytes32(uint256((1 << 253) - 1)); /// ``` - pub fn hash(&self) -> BigUint { + pub fn hash_bn254(&self) -> BigUint { // Hash the public values. let mut hasher = Sha256::new(); hasher.update(self.buffer.data.as_slice()); @@ -188,7 +195,7 @@ mod tests { let mut public_values = SP1PublicValues::new(); public_values.write_slice(&test_bytes); - let hash = public_values.hash(); + let hash = public_values.hash_bn254(); let expected_hash = "1ce987d0a7fcc2636fe87e69295ba12b1cc46c256b369ae7401c51b805ee91bd"; let expected_hash_biguint = BigUint::from_bytes_be(&hex::decode(expected_hash).unwrap()); diff --git a/crates/prover/src/verify.rs b/crates/prover/src/verify.rs index f9c0817ca3..99cf818d01 100644 --- a/crates/prover/src/verify.rs +++ b/crates/prover/src/verify.rs @@ -441,7 +441,7 @@ pub fn verify_plonk_bn254_public_inputs( return Err(PlonkVerificationError::InvalidVerificationKey.into()); } - let public_values_hash = public_values.hash(); + let public_values_hash = public_values.hash_bn254(); if public_values_hash != expected_public_values_hash { return Err(PlonkVerificationError::InvalidPublicValues.into()); } @@ -464,7 +464,7 @@ pub fn verify_groth16_bn254_public_inputs( return Err(Groth16VerificationError::InvalidVerificationKey.into()); } - let public_values_hash = public_values.hash(); + let public_values_hash = public_values.hash_bn254(); if public_values_hash != expected_public_values_hash { return Err(Groth16VerificationError::InvalidPublicValues.into()); } diff --git a/crates/recursion/gnark-ffi/assets/SP1VerifierGroth16.txt b/crates/recursion/gnark-ffi/assets/SP1VerifierGroth16.txt new file mode 100644 index 0000000000..b0d4b5953b --- /dev/null +++ b/crates/recursion/gnark-ffi/assets/SP1VerifierGroth16.txt @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol"; +import {Groth16Verifier} from "./Groth16Verifier.sol"; + +/// @title SP1 Verifier +/// @author Succinct Labs +/// @notice This contracts implements a solidity verifier for SP1. +contract SP1Verifier is Groth16Verifier, ISP1VerifierWithHash { + /// @notice Thrown when the verifier selector from this proof does not match the one in this + /// verifier. This indicates that this proof was sent to the wrong verifier. + /// @param received The verifier selector from the first 4 bytes of the proof. + /// @param expected The verifier selector from the first 4 bytes of the VERIFIER_HASH(). + error WrongVerifierSelector(bytes4 received, bytes4 expected); + + /// @notice Thrown when the proof is invalid. + error InvalidProof(); + + function VERSION() external pure returns (string memory) { + return "{SP1_CIRCUIT_VERSION}"; + } + + /// @inheritdoc ISP1VerifierWithHash + function VERIFIER_HASH() public pure returns (bytes32) { + return {VERIFIER_HASH}; + } + + /// @notice Hashes the public values to a field elements inside Bn254. + /// @param publicValues The public values. + function hashPublicValues( + bytes calldata publicValues + ) public pure returns (bytes32) { + return sha256(publicValues) & bytes32(uint256((1 << 253) - 1)); + } + + /// @notice Verifies a proof with given public values and vkey. + /// @param programVKey The verification key for the RISC-V program. + /// @param publicValues The public values encoded as bytes. + /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes. + function verifyProof( + bytes32 programVKey, + bytes calldata publicValues, + bytes calldata proofBytes + ) external view { + bytes4 receivedSelector = bytes4(proofBytes[:4]); + bytes4 expectedSelector = bytes4(VERIFIER_HASH()); + if (receivedSelector != expectedSelector) { + revert WrongVerifierSelector(receivedSelector, expectedSelector); + } + + bytes32 publicValuesDigest = hashPublicValues(publicValues); + uint256[2] memory inputs; + inputs[0] = uint256(programVKey); + inputs[1] = uint256(publicValuesDigest); + uint256[8] memory proof = abi.decode(proofBytes[4:], (uint256[8])); + this.Verify(proof, inputs); + } +} \ No newline at end of file diff --git a/crates/recursion/gnark-ffi/assets/SP1Verifier.txt b/crates/recursion/gnark-ffi/assets/SP1VerifierPlonk.txt similarity index 94% rename from crates/recursion/gnark-ffi/assets/SP1Verifier.txt rename to crates/recursion/gnark-ffi/assets/SP1VerifierPlonk.txt index a18f01b819..3c464708e7 100644 --- a/crates/recursion/gnark-ffi/assets/SP1Verifier.txt +++ b/crates/recursion/gnark-ffi/assets/SP1VerifierPlonk.txt @@ -2,12 +2,12 @@ pragma solidity ^0.8.20; import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol"; -import {{PROOF_SYSTEM}Verifier} from "./{PROOF_SYSTEM}Verifier.sol"; +import {PlonkVerifier} from "./PlonkVerifier.sol"; /// @title SP1 Verifier /// @author Succinct Labs /// @notice This contracts implements a solidity verifier for SP1. -contract SP1Verifier is {PROOF_SYSTEM}Verifier, ISP1VerifierWithHash { +contract SP1Verifier is PlonkVerifier, ISP1VerifierWithHash { /// @notice Thrown when the verifier selector from this proof does not match the one in this /// verifier. This indicates that this proof was sent to the wrong verifier. /// @param received The verifier selector from the first 4 bytes of the proof. diff --git a/crates/recursion/gnark-ffi/src/groth16_bn254.rs b/crates/recursion/gnark-ffi/src/groth16_bn254.rs index 2ea1f299f0..063ca25ccd 100644 --- a/crates/recursion/gnark-ffi/src/groth16_bn254.rs +++ b/crates/recursion/gnark-ffi/src/groth16_bn254.rs @@ -1,6 +1,6 @@ use std::{ fs::File, - io::Write, + io::{Read, Write}, path::{Path, PathBuf}, }; @@ -76,12 +76,15 @@ impl Groth16Bn254Prover { // Write the corresponding asset files to the build dir. let sp1_verifier_path = build_dir.join("SP1VerifierGroth16.sol"); let vkey_hash = Self::get_vkey_hash(&build_dir); - let sp1_verifier_str = include_str!("../assets/SP1Verifier.txt") + let sp1_verifier_str = include_str!("../assets/SP1VerifierGroth16.txt") .replace("{SP1_CIRCUIT_VERSION}", SP1_CIRCUIT_VERSION) .replace("{VERIFIER_HASH}", format!("0x{}", hex::encode(vkey_hash)).as_str()) .replace("{PROOF_SYSTEM}", "Groth16"); let mut sp1_verifier_file = File::create(sp1_verifier_path).unwrap(); sp1_verifier_file.write_all(sp1_verifier_str.as_bytes()).unwrap(); + + let groth16_verifier_path = build_dir.join("Groth16Verifier.sol"); + Self::modify_groth16_verifier(&groth16_verifier_path); } /// Generates a Groth16 proof given a witness. @@ -120,6 +123,20 @@ impl Groth16Bn254Prover { ) .expect("failed to verify proof") } + + /// Modify the Groth16Verifier so that it works with the SP1Verifier. + fn modify_groth16_verifier(file_path: &Path) { + let mut content = String::new(); + File::open(file_path).unwrap().read_to_string(&mut content).unwrap(); + + content = content + .replace("pragma solidity ^0.8.0;", "pragma solidity ^0.8.20;") + .replace("contract Verifier {", "contract Groth16Verifier {") + .replace("function verifyProof(", "function Verify("); + + let mut file = File::create(file_path).unwrap(); + file.write_all(content.as_bytes()).unwrap(); + } } impl Default for Groth16Bn254Prover { diff --git a/crates/recursion/gnark-ffi/src/plonk_bn254.rs b/crates/recursion/gnark-ffi/src/plonk_bn254.rs index d719d1ae80..b901eecc05 100644 --- a/crates/recursion/gnark-ffi/src/plonk_bn254.rs +++ b/crates/recursion/gnark-ffi/src/plonk_bn254.rs @@ -1,6 +1,6 @@ use std::{ fs::File, - io::Write, + io::{Read, Write}, path::{Path, PathBuf}, }; @@ -75,12 +75,15 @@ impl PlonkBn254Prover { // Write the corresponding asset files to the build dir. let sp1_verifier_path = build_dir.join("SP1VerifierPlonk.sol"); let vkey_hash = Self::get_vkey_hash(&build_dir); - let sp1_verifier_str = include_str!("../assets/SP1Verifier.txt") + let sp1_verifier_str = include_str!("../assets/SP1VerifierPlonk.txt") .replace("{SP1_CIRCUIT_VERSION}", SP1_CIRCUIT_VERSION) .replace("{VERIFIER_HASH}", format!("0x{}", hex::encode(vkey_hash)).as_str()) .replace("{PROOF_SYSTEM}", "Plonk"); let mut sp1_verifier_file = File::create(sp1_verifier_path).unwrap(); sp1_verifier_file.write_all(sp1_verifier_str.as_bytes()).unwrap(); + + let plonk_verifier_path = build_dir.join("PlonkVerifier.sol"); + Self::modify_plonk_verifier(&plonk_verifier_path); } /// Generates a PLONK proof given a witness. @@ -119,6 +122,17 @@ impl PlonkBn254Prover { ) .expect("failed to verify proof") } + + /// Modify the PlonkVerifier so that it works with the SP1Verifier. + fn modify_plonk_verifier(file_path: &Path) { + let mut content = String::new(); + File::open(file_path).unwrap().read_to_string(&mut content).unwrap(); + + content = content.replace("pragma solidity ^0.8.19;", "pragma solidity ^0.8.20;"); + + let mut file = File::create(file_path).unwrap(); + file.write_all(content.as_bytes()).unwrap(); + } } impl Default for PlonkBn254Prover { diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index 1d296f94bf..ada8973cea 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -53,6 +53,7 @@ sysinfo = "0.30.13" sp1-core-executor = { workspace = true } sp1-stark = { workspace = true } getrandom = { version = "0.2.15", features = ["custom", "js"] } +itertools = "0.13.0" [features] default = ["network"] diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index da73835c01..e4721a0efa 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -39,7 +39,9 @@ use {std::future::Future, tokio::task::block_in_place}; pub use provers::{CpuProver, MockProver, Prover}; pub use sp1_core_executor::{ExecutionReport, HookEnv, SP1Context, SP1ContextBuilder}; -pub use sp1_core_machine::{io::SP1Stdin, riscv::cost::CostEstimator, SP1_CIRCUIT_VERSION}; +pub use sp1_core_machine::{ + io::SP1PublicValues, io::SP1Stdin, riscv::cost::CostEstimator, SP1_CIRCUIT_VERSION, +}; pub use sp1_prover::{ CoreSC, HashableKey, InnerSC, OuterSC, PlonkBn254Proof, SP1Prover, SP1ProvingKey, SP1VerifyingKey, @@ -291,6 +293,8 @@ pub fn block_on(fut: impl Future) -> T { #[cfg(test)] mod tests { + use sp1_prover::init::SP1PublicValues; + use crate::{utils, CostEstimator, ProverClient, SP1Stdin}; #[test] @@ -327,6 +331,48 @@ mod tests { client.execute(elf, stdin).max_cycles(1).run().unwrap(); } + #[test] + fn test_e2e_core() { + utils::setup_logger(); + let client = ProverClient::local(); + let elf = + include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + let (pk, vk) = client.setup(elf); + let mut stdin = SP1Stdin::new(); + stdin.write(&10usize); + + // Generate proof & verify. + let mut proof = client.prove(&pk, stdin).run().unwrap(); + client.verify(&proof, &vk).unwrap(); + + // Test invalid public values. + proof.public_values = SP1PublicValues::from(&[255, 4, 84]); + if client.verify(&proof, &vk).is_ok() { + panic!("verified proof with invalid public values") + } + } + + #[test] + fn test_e2e_compressed() { + utils::setup_logger(); + let client = ProverClient::local(); + let elf = + include_bytes!("../../../examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf"); + let (pk, vk) = client.setup(elf); + let mut stdin = SP1Stdin::new(); + stdin.write(&10usize); + + // Generate proof & verify. + let mut proof = client.prove(&pk, stdin).compressed().run().unwrap(); + client.verify(&proof, &vk).unwrap(); + + // Test invalid public values. + proof.public_values = SP1PublicValues::from(&[255, 4, 84]); + if client.verify(&proof, &vk).is_ok() { + panic!("verified proof with invalid public values") + } + } + #[test] fn test_e2e_prove_plonk() { utils::setup_logger(); @@ -336,8 +382,16 @@ mod tests { let (pk, vk) = client.setup(elf); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); - let proof = client.prove(&pk, stdin).plonk().run().unwrap(); + + // Generate proof & verify. + let mut proof = client.prove(&pk, stdin).plonk().run().unwrap(); client.verify(&proof, &vk).unwrap(); + + // Test invalid public values. + proof.public_values = SP1PublicValues::from(&[255, 4, 84]); + if client.verify(&proof, &vk).is_ok() { + panic!("verified proof with invalid public values") + } } #[test] diff --git a/crates/sdk/src/provers/mock.rs b/crates/sdk/src/provers/mock.rs index d4d2467045..b774cd005b 100644 --- a/crates/sdk/src/provers/mock.rs +++ b/crates/sdk/src/provers/mock.rs @@ -97,7 +97,7 @@ impl Prover for MockProver { proof: SP1Proof::Plonk(PlonkBn254Proof { public_inputs: [ pk.vk.hash_bn254().as_canonical_biguint().to_string(), - public_values.hash().to_string(), + public_values.hash_bn254().to_string(), ], encoded_proof: "".to_string(), raw_proof: "".to_string(), @@ -114,7 +114,7 @@ impl Prover for MockProver { proof: SP1Proof::Groth16(Groth16Bn254Proof { public_inputs: [ pk.vk.hash_bn254().as_canonical_biguint().to_string(), - public_values.hash().to_string(), + public_values.hash_bn254().to_string(), ], encoded_proof: "".to_string(), raw_proof: "".to_string(), diff --git a/crates/sdk/src/provers/mod.rs b/crates/sdk/src/provers/mod.rs index 34152d8460..ecc62ff4ce 100644 --- a/crates/sdk/src/provers/mod.rs +++ b/crates/sdk/src/provers/mod.rs @@ -8,6 +8,11 @@ pub use cpu::CpuProver; pub use cuda::CudaProver; pub use mock::MockProver; +use itertools::Itertools; +use p3_field::PrimeField32; +use std::borrow::Borrow; +use std::time::Duration; + use anyhow::Result; use sp1_core_executor::SP1Context; use sp1_core_machine::{io::SP1Stdin, SP1_CIRCUIT_VERSION}; @@ -15,8 +20,7 @@ use sp1_prover::{ components::SP1ProverComponents, CoreSC, InnerSC, SP1CoreProofData, SP1Prover, SP1ProvingKey, SP1ReduceProof, SP1VerifyingKey, }; -use sp1_stark::{MachineVerificationError, SP1ProverOpts}; -use std::time::Duration; +use sp1_stark::{air::PublicValues, MachineVerificationError, SP1ProverOpts, Word}; use strum_macros::EnumString; use thiserror::Error; @@ -44,6 +48,8 @@ pub struct ProofOpts { #[derive(Error, Debug)] pub enum SP1VerificationError { + #[error("Invalid public values")] + InvalidPublicValues, #[error("Version mismatch")] VersionMismatch(String), #[error("Core machine verification error: {0}")] @@ -90,14 +96,53 @@ pub trait Prover: Send + Sync { return Err(SP1VerificationError::VersionMismatch(bundle.sp1_version.clone())); } match &bundle.proof { - SP1Proof::Core(proof) => self - .sp1_prover() - .verify(&SP1CoreProofData(proof.clone()), vkey) - .map_err(SP1VerificationError::Core), - SP1Proof::Compressed(proof) => self - .sp1_prover() - .verify_compressed(&SP1ReduceProof { proof: proof.clone() }, vkey) - .map_err(SP1VerificationError::Recursion), + SP1Proof::Core(proof) => { + let public_values: &PublicValues, _> = + proof.last().unwrap().public_values.as_slice().borrow(); + + // Get the commited value digest bytes. + let commited_value_digest_bytes = public_values + .committed_value_digest + .iter() + .flat_map(|w| w.0.iter().map(|x| x.as_canonical_u32() as u8)) + .collect_vec(); + + // Make sure the commited value digest matches the public values hash. + for (a, b) in commited_value_digest_bytes.iter().zip_eq(bundle.public_values.hash()) + { + if *a != b { + return Err(SP1VerificationError::InvalidPublicValues); + } + } + + // Verify the core proof. + self.sp1_prover() + .verify(&SP1CoreProofData(proof.clone()), vkey) + .map_err(SP1VerificationError::Core) + } + SP1Proof::Compressed(proof) => { + let public_values: &PublicValues, _> = + proof.public_values.as_slice().borrow(); + + // Get the commited value digest bytes. + let commited_value_digest_bytes = public_values + .committed_value_digest + .iter() + .flat_map(|w| w.0.iter().map(|x| x.as_canonical_u32() as u8)) + .collect_vec(); + + // Make sure the commited value digest matches the public values hash. + for (a, b) in commited_value_digest_bytes.iter().zip_eq(bundle.public_values.hash()) + { + if *a != b { + return Err(SP1VerificationError::InvalidPublicValues); + } + } + + self.sp1_prover() + .verify_compressed(&SP1ReduceProof { proof: proof.clone() }, vkey) + .map_err(SP1VerificationError::Recursion) + } SP1Proof::Plonk(proof) => self .sp1_prover() .verify_plonk_bn254( diff --git a/examples/Cargo.lock b/examples/Cargo.lock index cc23acea9c..ac3fe60b6d 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -1472,6 +1472,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", + "serde", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.75", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -4965,6 +4986,7 @@ dependencies = [ "bincode", "bytemuck", "elf", + "enum-map", "eyre", "generic-array 1.1.0", "hashbrown 0.14.5", diff --git a/examples/fibonacci/program/Cargo.lock b/examples/fibonacci/program/Cargo.lock index c3079154b8..bf06ad227b 100644 --- a/examples/fibonacci/program/Cargo.lock +++ b/examples/fibonacci/program/Cargo.lock @@ -335,7 +335,7 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "1.2.0-rc1" +version = "1.2.0" dependencies = [ "anyhow", "bincode", @@ -347,7 +347,7 @@ dependencies = [ [[package]] name = "sp1-zkvm" -version = "1.2.0-rc1" +version = "1.2.0" dependencies = [ "bincode", "cfg-if", diff --git a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf index 41b281e4ae..017feaa1a2 100755 Binary files a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf and b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/rsa/program/Cargo.lock b/examples/rsa/program/Cargo.lock index 4cbf5f0f88..c5fdebb49f 100644 --- a/examples/rsa/program/Cargo.lock +++ b/examples/rsa/program/Cargo.lock @@ -35,15 +35,6 @@ dependencies = [ "serde", ] -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -73,9 +64,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const-oid" -version = "0.7.1" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cpufeatures" @@ -86,16 +77,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -108,13 +89,13 @@ dependencies = [ [[package]] name = "der" -version = "0.5.1" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", - "crypto-bigint", "pem-rfc7468", + "zeroize", ] [[package]] @@ -128,22 +109,14 @@ dependencies = [ "syn 2.0.60", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", + "const-oid", "crypto-common", ] @@ -287,12 +260,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "parity-scale-codec" version = "3.6.12" @@ -319,33 +286,32 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "0.3.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01de5d978f34aa4b2296576379fcc416034702fd94117c56ffd8a1a767cefb30" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ "base64ct", ] [[package]] name = "pkcs1" -version = "0.3.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78f66c04ccc83dd4486fd46c33896f4e17b24a7a3a6400dedc48ed0ddd72320" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ "der", "pkcs8", - "zeroize", + "spki", ] [[package]] name = "pkcs8" -version = "0.8.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", - "zeroize", ] [[package]] @@ -413,20 +379,19 @@ dependencies = [ [[package]] name = "rsa" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf22754c49613d2b3b119f0e5d46e34a2c628a937e3024b8762de4e7d8c710b" +version = "0.9.6" dependencies = [ - "byteorder", - "digest 0.10.7", + "const-oid", + "digest", "num-bigint-dig", "num-integer", - "num-iter", "num-traits", "pkcs1", "pkcs8", "rand_core", - "smallvec", + "signature", + "sp1-derive", + "spki", "subtle", "zeroize", ] @@ -435,10 +400,10 @@ dependencies = [ name = "rsa-program" version = "1.1.0" dependencies = [ - "digest 0.10.7", + "digest", "rand", "rsa", - "sha2 0.9.8", + "sha2", "sp1-zkvm", ] @@ -488,25 +453,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.8" -source = "git+https://github.com/succinctbot/RustCrypto-hashes.git?branch=v0.9.8#0b578688db61bb53e15353f5beaa2c11ad93f037" +version = "0.10.8" +source = "git+https://github.com/sp1-patches/RustCrypto-hashes?branch=patch-sha2-v0.10.8#1f224388fdede7cef649bce0d63876d1a9e3f515" dependencies = [ - "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "digest", ] [[package]] -name = "sha2" -version = "0.10.8" +name = "signature" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "digest", + "rand_core", ] [[package]] @@ -525,9 +487,20 @@ dependencies = [ "scale-info", ] +[[package]] +name = "sp1-derive" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d06fdae1dc74a9085b155d12180825653e530983262b8ad2e57fe15551d17a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "sp1-lib" -version = "1.1.1" +version = "1.2.0" dependencies = [ "anyhow", "bincode", @@ -539,7 +512,7 @@ dependencies = [ [[package]] name = "sp1-zkvm" -version = "1.1.1" +version = "1.2.0" dependencies = [ "bincode", "cfg-if", @@ -549,7 +522,7 @@ dependencies = [ "once_cell", "rand", "serde", - "sha2 0.10.8", + "sha2", "sp1-lib", ] @@ -561,9 +534,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" -version = "0.5.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -649,6 +622,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/examples/rsa/program/Cargo.toml b/examples/rsa/program/Cargo.toml index 9a9db9e814..2d54b00181 100644 --- a/examples/rsa/program/Cargo.toml +++ b/examples/rsa/program/Cargo.toml @@ -9,9 +9,10 @@ publish = false sp1-zkvm = { path = "../../../crates/zkvm/entrypoint" } digest = "0.10.7" rand = "0.8.5" -rsa = "0.6" # Check for the latest version -sha2 = "0.9.8" # Check for the latest version +rsa = "0.9.6" # Check for the latest version +sha2 = {version = "0.10.8",package = "sha2", features = ["oid"]} # Check for the latest version [patch.crates-io] # Patch sha2 so we can use sha precompiles -sha2 = { git = "https://github.com/succinctbot/RustCrypto-hashes.git", package = "sha2", branch = "v0.9.8" } +sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8"} + diff --git a/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf b/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf index 2ab2c15058..3fde9f4d1d 100755 Binary files a/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf and b/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf differ diff --git a/examples/rsa/program/src/main.rs b/examples/rsa/program/src/main.rs index 67c21cd146..b1326eb778 100644 --- a/examples/rsa/program/src/main.rs +++ b/examples/rsa/program/src/main.rs @@ -1,11 +1,9 @@ #![no_main] sp1_zkvm::entrypoint!(main); -use rsa::PaddingScheme; -use rsa::PublicKey; +use rsa::Pkcs1v15Sign; use rsa::{pkcs8::DecodePublicKey, RsaPublicKey}; -use sha2::Digest; -use sha2::Sha256; +use sha2::{Digest, Sha256}; // Ensure this is imported for the Digest trait to work pub fn main() { // Read an input to the program. @@ -21,8 +19,7 @@ pub fn main() { hasher.update(message); let hashed_msg = hasher.finalize(); - let padding = PaddingScheme::new_pkcs1v15_sign(Some(rsa::hash::Hash::SHA2_256)); - let verification = public_key.verify(padding, &hashed_msg, &signature); + let verification = public_key.verify(Pkcs1v15Sign::new::(), &hashed_msg, &signature); let verified = match verification { Ok(_) => { diff --git a/examples/rsa/script/proof-with-pis b/examples/rsa/script/proof-with-pis new file mode 100644 index 0000000000..123d1dc2b9 Binary files /dev/null and b/examples/rsa/script/proof-with-pis differ