From 9d322d54af6f416cff71ad27c767222f4350a5d2 Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Fri, 2 Feb 2024 12:28:46 -0800 Subject: [PATCH 01/10] initial round of edits --- Cargo.lock | 20 +-- Cargo.toml | 14 +- README.md | 139 ++++++++++-------- cli/src/{guest_interface.rs => interface.rs} | 0 cli/src/main.rs | 6 +- methods/guest/Cargo.toml | 2 +- sdk/src/snark.rs | 2 +- .../{BonsaiStarter.t.sol => EvenNumber.t.sol} | 0 8 files changed, 98 insertions(+), 85 deletions(-) rename cli/src/{guest_interface.rs => interface.rs} (100%) rename tests/{BonsaiStarter.t.sol => EvenNumber.t.sol} (100%) diff --git a/Cargo.lock b/Cargo.lock index b3f02399..c30e35a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3089,9 +3089,9 @@ dependencies = [ [[package]] name = "risc0-binfmt" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66ad9a127fd4810fc42430353dc9d297d26cc10f3e4eb66cc44730b4625b3abe" +checksum = "9d263c6370d7714d2a634b6d88deb3871d0fad1f9486a9da6d48139c1ac85b26" dependencies = [ "anyhow", "elf", @@ -3103,9 +3103,9 @@ dependencies = [ [[package]] name = "risc0-build" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef0c264c77fb8989c9a5eec6d6c8c9fdd24af9eeae8bedede06c30cccd645b53" +checksum = "a636849a58335ebece68161006a53d5590a6698092c3ca8e8a40a7c0aa8a20fb" dependencies = [ "anyhow", "cargo-platform", @@ -3148,9 +3148,9 @@ dependencies = [ [[package]] name = "risc0-core" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fadfa2c4f1cb3a7bf7385f2dd8ca03ca6f8520e1310ea1eb8d73492f67d3a1b" +checksum = "be79c89bcd18886b376073e3da22f8b7963247a42dce7b49cf3d09853f51641e" dependencies = [ "bytemuck", "rand_core", @@ -3179,9 +3179,9 @@ dependencies = [ [[package]] name = "risc0-zkp" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e53bb3c714aec9a82faf9df504feb80c93d4cd62666569d413f0088ed9e7b8b" +checksum = "e20a57e04840a5afadebb5d232546245f4fd8bd0e774bd69bf4bf25f8ab90c04" dependencies = [ "anyhow", "blake2", @@ -3235,9 +3235,9 @@ dependencies = [ [[package]] name = "risc0-zkvm-platform" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bbe8ee216df9a6ed5b82a8de0dc80007b540d13cd13422bcaf6788a534ee966" +checksum = "cc5819c0c3bfd8f20b1226c9d4ca1f342eb3d8385e71211a9383a879643d1dde" dependencies = [ "bytemuck", "getrandom", diff --git a/Cargo.toml b/Cargo.toml index 3043b035..89974923 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,21 +14,11 @@ bincode = { version = "1.3" } bonsai-sdk = { version = "0.6.0" } bytemuck = { version = "1.14" } methods = { path = "./methods", package = "bonsai-starter-methods" } -risc0-build = { version = "0.20.0", features = ["guest-list"] } +risc0-build = { version = "0.20", features = ["guest-list"] } risc0-ethereum-sdk = { version = "0.1.0", path = "sdk" } -risc0-zkvm = { version = "0.20.0", default-features = false } +risc0-zkvm = { version = "0.20", default-features = false } serde = { version = "1.0", features = ["derive"] } -# Always optimize; building and running the guest takes much longer without optimization. -[profile.dev] -opt-level = 3 - -[profile.dev.build-override] -opt-level = 3 - [profile.release] debug = 1 lto = true - -[profile.release.build-override] -opt-level = 3 diff --git a/README.md b/README.md index 28388bba..83a3af34 100644 --- a/README.md +++ b/README.md @@ -2,65 +2,101 @@ > **Note: This software is not production ready. Do not use in production.** -Starter template for writing an application using [Bonsai]. +Starter template for writing an application using [RISC Zero] and Ethereum. -This repository implements an application on Ethereum utilizing Bonsai as a [coprocessor] to the smart contract application. -It provides a starting point for building powerful new applications on Ethereum that offload computationally intensive, or difficult to implement, tasks to be proven by the [RISC Zero zkVM], with verifiable results sent to your Ethereum contract. +This repository implements an application on Ethereum utilizing [Bonsai] as a [coprocessor] to the smart contract application. +It provides a starting point for building powerful new applications on Ethereum that offload computationally intensive (i.e. gas expensive), or difficult to implement, tasks to be proven by the [RISC Zero zkVM]. +Verifiable results are sent to your Ethereum contract. + +[RISC Zero]: https://www.risczero.com/ +[Bonsai]: https://dev.bonsai.xyz/ +[coprocessor]: https://twitter.com/RiscZero/status/1677316664772132864 +[RISC Zero zkVM]: https://dev.risczero.com/zkvm ## Overview -The picture below shows a simplified overview of how users can integrate Bonsai into their Ethereum smart contracts: +The picture below shows a simplified overview of how users can integrate [Bonsai] into their Ethereum smart contracts: ![Bonsai Foundry Template Diagram](images/bonsai-foundry-template.png) -1. Delegate your smart contract's logic to the [RISC Zero zkVM] simply using a Command Line Interface (CLI) to initiate an off-chain proof request, which is sent to the Bonsai proving service. -2. Bonsai generates a SNARK proof and its result, encapsulated in a journal. +1. Run your application logic in the [RISC Zero zkVM]. The provided Command Line Interface (CLI) sends an off-chain proof request to the Bonsai proving service. +2. Bonsai generates the computation result, written to the [journal], and a SNARK proof of its correctness. 3. The CLI submits this proof and journal on-chain to your app contract for validation. -4. Your app contract calls the RISC Zero Verifier to validate the proof. If the verification is successful, the journal is deemed trustworthy and can be safely used. +4. Your app contract calls the [RISC Zero Verifier] to validate the proof. If the verification is successful, the journal is deemed trustworthy and can be safely used. + +[journal]: https://dev.risczero.com/terminology#journal +[RISC Zero Verifier]: https://github.com/risc0/risc0/blob/release-0.20/bonsai/ethereum/contracts/IRiscZeroVerifier.sol ## Dependencies + First, [install Rust] and [Foundry], and then restart your terminal. Next, you will need to install the `cargo risczero` tool. + +```sh +# Install Rust +curl https://sh.rustup.rs -sSf | sh +# Install Foundry +curl -L https://foundry.paradigm.xyz | bash +``` + We'll use `cargo binstall` to get `cargo-risczero` installed. See [cargo-binstall] for more details. -```bash +```sh cargo install cargo-binstall cargo binstall cargo-risczero ``` Next we'll need to install the `risc0` toolchain with: -``` +```sh cargo risczero install ``` +Now you have all the tools you need to develop and deploy an application with RISC Zero. + +[install Rust]: https://doc.rust-lang.org/cargo/getting-started/installation.html +[Foundry]: https://getfoundry.sh/ +[cargo-binstall]: https://github.com/cargo-bins/cargo-binstall#cargo-binaryinstall + ## Quick Start -First, install the RISC Zero toolchain using the instructions above. + +First, install the RISC Zero toolchain using the [instructions above]. Now, you can initialize a new Bonsai project at a location of your choosing: -```bash +```sh forge init -t risc0/bonsai-foundry-template ./my-project ``` -Congratulations! You've just built your first Bonsai project. + +Congratulations! You've just started your first RISC Zero project. + Your new project consists of: + - a [zkVM program] (written in Rust), which specifies a computation that will be proven; - a [app contract] (written in Solidity), which receives the response; -- a [guest interface] (written in Rust), which lets you define how to parse and serialize the guest input and calldata so that the [RISC Zero zkVM] and Bonsai can interact with your contract. - +- a [guest interface] (written in Rust), which lets you define how to parse and serialize the guest input and calldata so that the [RISC Zero zkVM] and Bonsai can interact with your contract. -[install Rust]: https://doc.rust-lang.org/cargo/getting-started/installation.html -[Foundry]: https://getfoundry.sh/ -[cargo-binstall]: https://github.com/cargo-bins/cargo-binstall#cargo-binaryinstall +[instructions above]: #dependencies [zkVM program]: https://github.com/risc0/bonsai-foundry-template/tree/main/methods/guest/src/bin [app contract]: https://github.com/risc0/bonsai-foundry-template/tree/main/contracts [guest interface]: https://github.com/risc0/bonsai-foundry-template/tree/main/cli -### Test Your Project -- Use `cargo build` to test compilation of your zkVM program. +### Run the Tests + + - Use `cargo test` to run the tests in your zkVM program. -- Use `RISC0_DEV_MODE=false forge test -vvv` to test your Solidity contracts and their interaction with your zkVM program. + +- Use `RISC0_DEV_MODE=true forge test -vvv` to test your Solidity contracts and their interaction with your zkVM program. + +## Develop Your Application + +To build your application, you'll need to make changes in three folders: + +- write the code you want proven in the [methods] folder +- write the on-chain part of your project in the [contracts] folder +- write the guest interface in the [cli] folder ### Configuring Bonsai + ***Note:*** *The Bonsai proving service is still in early Alpha. To request an API key [complete the form here](https://bonsai.xyz/apply).* With the Bonsai proving service, you can produce a [Groth16 SNARK proof] that is verifiable on-chain. @@ -71,20 +107,21 @@ export BONSAI_API_KEY="YOUR_API_KEY" # see form linked above export BONSAI_API_URL="BONSAI_URL" # provided with your api key ``` + Now if you run `forge test` with `RISC0_DEV_MODE=false`, the test will run as before, but will additionally use the fully verifying `RiscZeroGroth16Verifier` contract instead of `RiscZeroGroth16VerifierTest` and will request a SNARK receipt from Bonsai. ```bash RISC0_DEV_MODE=false forge test -vvv ``` -## Next Steps -To build your application, you'll need to make changes in three folders: -- write the code you want proven in the [methods] folder -- write the on-chain part of your project in the [contracts] folder -- write the guest interface in the [cli] folder +[Groth16 SNARK proof]: https://www.risczero.com/news/on-chain-verification + +## Deploy Your Application -Then, you're ready to [deploy your project].
+When you're ready, follow the [deployment guide] to get your application running on [Sepolia]. +[deployment guide]: /deployment-guide.md +[Sepolia]: https://www.alchemy.com/overviews/sepolia-testnet ## Project Structure @@ -92,42 +129,28 @@ Below are the primary files in the project directory ```text . -├── Cargo.toml // Definitions for cargo and rust -├── foundry.toml // Definitions for foundry -├── cli // CLI for interacting with your application -│ ├── Cargo.toml -│ └── src -│ ├── interface.rs // Interface for interacting with your contract -│ └── main.rs // CLI for interacting with your application -├── contracts // Your Ethereum contracts live here -│ └── BonsaiStarter.sol // Starter template for basic callback contract -├── tests // Your Ethereum contract tests live here -│ └── BonsaiStarter.t.sol // Tests for basic callback contract -└── methods // [zkVM guest programs] are built here +├── Cargo.toml // Configuration for Cargo and Rust +├── foundry.toml // Configuration for Foundry +├── contracts +│ └── EvenNumber.sol // Basic example contract for you to modify +├── tests +│ └── EvenNumber.t.sol // Tests for the basic example contract +├── methods +│ ├── Cargo.toml +│ ├── guest +│ │ ├── Cargo.toml +│ │ └── src +│ │ └── bin // You can add additionally guest prgrams to this folder +│ │ └── is_even.rs // Example guest program for cheking if a number is even +│ └── src +│ └── lib.rs // Compiled image IDs and tests for your guest programs +└── cli ├── Cargo.toml - ├── build.rs // Instructions for the risc0-build rust crate - ├── guest // A rust crate containing your [zkVM guest programs] - │ ├── Cargo.toml - │ └── src - │ └── bin // Your [zkVM guest programs] live here - │ └── is_even.rs // Example [guest program] for cheking if a number is even └── src - └── lib.rs // Built RISC Zero guest programs are compiled into here + ├── interface.rs // Interface for interacting with your contract + └── main.rs // CLI for interacting with your application ``` - [methods]: /methods [cli]: /cli [contracts]: /contracts -[deploy your project]: /deployment-guide.md -[coprocessor]: https://twitter.com/RiscZero/status/1677316664772132864 -[Bonsai]: https://dev.bonsai.xyz/ -[Foundry]: https://getfoundry.sh/ -[Groth16 SNARK proof]: https://www.risczero.com/news/on-chain-verification -[RISC Zero examples]: https://github.com/risc0/risc0/tree/main/examples -[RISC Zero]: https://www.risczero.com/ -[RISC-V]: https://www.risczero.com/docs/reference-docs/about-risc-v -[https://book.getfoundry.sh/forge/tests]: https://book.getfoundry.sh/forge/tests -[receipt]: https://dev.risczero.com/zkvm/developer-guide/receipts -[zkVM guest program]: https://dev.risczero.com/zkvm/developer-guide/guest-code-101 -[RISC Zero zkVM]: https://dev.risczero.com/zkvm diff --git a/cli/src/guest_interface.rs b/cli/src/interface.rs similarity index 100% rename from cli/src/guest_interface.rs rename to cli/src/interface.rs diff --git a/cli/src/main.rs b/cli/src/main.rs index 7e6c60f8..85c946c4 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod interface; + use anyhow::Result; -use guest_interface::EvenNumberInterface; +use interface::EvenNumberInterface; use methods::GUEST_LIST; use risc0_ethereum_sdk::cli::{self, GuestInterface}; -mod guest_interface; - fn main() -> Result<()> { env_logger::init(); diff --git a/methods/guest/Cargo.toml b/methods/guest/Cargo.toml index 99990821..561fd45b 100644 --- a/methods/guest/Cargo.toml +++ b/methods/guest/Cargo.toml @@ -12,7 +12,7 @@ path = "src/bin/is_even.rs" [dependencies] alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } alloy-sol-types = { version = "0.6" } -risc0-zkvm = { version = "0.20.0", default-features = false, features = ['std'] } +risc0-zkvm = { version = "0.20", default-features = false, features = ['std'] } [profile.release] codegen-units = 1 diff --git a/sdk/src/snark.rs b/sdk/src/snark.rs index 458ba485..9ab24a12 100644 --- a/sdk/src/snark.rs +++ b/sdk/src/snark.rs @@ -21,7 +21,7 @@ use ethers::abi::Token; sol! { /// Groth16 seal construction from [RiscZeroGroth16Verifier.sol]. /// - /// [RiscZeroGroth16Verifier.sol]: https://github.com/risc0/risc0/blob/v0.20.0/bonsai/ethereum/contracts/groth16/RiscZeroGroth16Verifier.sol#L76-L81 + /// [RiscZeroGroth16Verifier.sol]: https://github.com/risc0/risc0/blob/v0.20.1/bonsai/ethereum/contracts/groth16/RiscZeroGroth16Verifier.sol#L76-L81 #[derive(Debug)] struct Seal { uint256[2] a; diff --git a/tests/BonsaiStarter.t.sol b/tests/EvenNumber.t.sol similarity index 100% rename from tests/BonsaiStarter.t.sol rename to tests/EvenNumber.t.sol From 290208ce0250f4439680b3f1ddb117f15746479e Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Fri, 2 Feb 2024 16:22:50 -0800 Subject: [PATCH 02/10] cargo test has some meaningful tests --- Cargo.lock | 5 ++- Cargo.toml | 2 +- cli/Cargo.toml | 3 +- cli/src/interface.rs | 48 ++++++++++++++--------- cli/src/main.rs | 8 +--- methods/Cargo.toml | 4 ++ methods/guest/Cargo.lock | 55 --------------------------- methods/guest/Cargo.toml | 1 - methods/guest/src/bin/is_even.rs | 9 +---- methods/src/lib.rs | 36 ++++++++++++++++++ sdk/src/cli.rs | 65 ++++++++++++++++++++------------ sdk/src/eth.rs | 6 +-- sdk/src/lib.rs | 2 - sdk/src/prover.rs | 32 ++++++++-------- sdk/src/snark.rs | 4 +- 15 files changed, 141 insertions(+), 139 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c30e35a8..191598e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,7 +596,7 @@ dependencies = [ ] [[package]] -name = "bonsai-starter" +name = "bonsai-starter-cli" version = "0.1.0" dependencies = [ "alloy-primitives", @@ -604,6 +604,7 @@ dependencies = [ "anyhow", "bonsai-starter-methods", "env_logger", + "hex", "risc0-ethereum-sdk", ] @@ -611,7 +612,9 @@ dependencies = [ name = "bonsai-starter-methods" version = "0.1.0" dependencies = [ + "alloy-primitives", "risc0-build", + "risc0-zkvm", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 89974923..cc040b8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ methods = { path = "./methods", package = "bonsai-starter-methods" } risc0-build = { version = "0.20", features = ["guest-list"] } risc0-ethereum-sdk = { version = "0.1.0", path = "sdk" } risc0-zkvm = { version = "0.20", default-features = false } -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive", "std"] } [profile.release] debug = 1 diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 31f44d82..424353a6 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bonsai-starter" +name = "bonsai-starter-cli" version = { workspace = true } edition = { workspace = true } @@ -8,5 +8,6 @@ alloy-primitives = { workspace = true } alloy-sol-types = { workspace = true } anyhow = { workspace = true } env_logger = { version = "0.10" } +hex = "0.4.3" methods = { workspace = true } risc0-ethereum-sdk = { workspace = true } diff --git a/cli/src/interface.rs b/cli/src/interface.rs index 00f32f86..9d5c3dc0 100644 --- a/cli/src/interface.rs +++ b/cli/src/interface.rs @@ -14,10 +14,10 @@ use std::str::FromStr; -use alloy_primitives::U256; -use alloy_sol_types::{sol, SolInterface, SolValue}; +use alloy_primitives::{FixedBytes, U256}; +use alloy_sol_types::{sol, SolInterface}; use anyhow::Result; -use risc0_ethereum_sdk::{cli::GuestInterface, serialize, snark::Proof}; +use risc0_ethereum_sdk::cli::GuestInterface; // You can modify this file to implement the `GuestInterface` trait // that lets you define how to parse and serialize the guest input and calldata @@ -32,24 +32,36 @@ sol! { } } -// `EvenNumberInterface` implementing the `GuestInterface` trait. -pub struct EvenNumberInterface {} +/// Implementation of `GuestInterface` for the `EvenNumber` example application. +pub struct EvenNumberInterface; + impl GuestInterface for EvenNumberInterface { - // Parses a `String` as the guest input returning its serialization, - // encoded as `Vec`, compatible with the zkVM and Bonsai. - fn serialize_input(&self, input: String) -> Result> { - serialize(U256::from_str(&input)?) + type Input = U256; + type Journal = U256; + + /// Parses a `String` as the guest input. + /// + /// Returned data will be what is read into the guest with `env::read()`. + fn parse_input(&self, input: String) -> Result { + Ok(U256::from_str(&input)?) } - // Extracts the calldata ABI encoded from a proof. - fn calldata(&self, proof: Proof) -> Result> { - let x = U256::abi_decode(&proof.journal, true)?; - let calldata = IEvenNumber::IEvenNumberCalls::set(IEvenNumber::setCall { - x, - post_state_digest: proof.post_state_digest, - seal: proof.seal, - }); + /// Encodes the proof into calldata to match the function to call on the Ethereum contract. + fn encode_calldata( + &self, + journal: Self::Journal, + post_state_digest: FixedBytes<32>, + seal: Vec, + ) -> Result> { + // Unpack the journal. In this this it only contains a single number. + let x = journal; - Ok(calldata.abi_encode()) + // Encode the function call for `IEvenNumber.set(x)` + Ok(IEvenNumber::IEvenNumberCalls::set(IEvenNumber::setCall { + x, + post_state_digest, + seal, + }) + .abi_encode()) } } diff --git a/cli/src/main.rs b/cli/src/main.rs index 85c946c4..62f95e2c 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -17,15 +17,11 @@ mod interface; use anyhow::Result; use interface::EvenNumberInterface; use methods::GUEST_LIST; -use risc0_ethereum_sdk::cli::{self, GuestInterface}; +use risc0_ethereum_sdk::cli; fn main() -> Result<()> { env_logger::init(); - // Initialize an EvenNumberInterface for parsing guest input and generating - // calldata. - let interface: &dyn GuestInterface = &EvenNumberInterface {}; - // Run the CLI for publishing on Ethereum - cli::run(GUEST_LIST, interface) + cli::run(GUEST_LIST, EvenNumberInterface) } diff --git a/methods/Cargo.toml b/methods/Cargo.toml index 90669d8f..be4924f6 100644 --- a/methods/Cargo.toml +++ b/methods/Cargo.toml @@ -11,3 +11,7 @@ risc0-build = { workspace = true } [dependencies] risc0-build = { workspace = true } + +[dev-dependencies] +risc0-zkvm = { workspace = true } +alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } diff --git a/methods/guest/Cargo.lock b/methods/guest/Cargo.lock index 92d8832f..0dd08212 100644 --- a/methods/guest/Cargo.lock +++ b/methods/guest/Cargo.lock @@ -46,36 +46,6 @@ dependencies = [ "bytes", ] -[[package]] -name = "alloy-sol-macro" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0b5ab0cb07c21adf9d72e988b34e8200ce648c2bba8d009183bb1c50fb1216" -dependencies = [ - "const-hex", - "dunce", - "heck", - "indexmap", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.48", - "syn-solidity", - "tiny-keccak", -] - -[[package]] -name = "alloy-sol-types" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c08f62ded7ce03513bfb60ef5cad4fff5d4f67eac6feb4df80426b7b9ffb06e" -dependencies = [ - "alloy-primitives", - "alloy-sol-macro", - "const-hex", - "serde", -] - [[package]] name = "anyhow" version = "1.0.79" @@ -414,7 +384,6 @@ name = "bonsai-starter-methods-guest" version = "0.1.0" dependencies = [ "alloy-primitives", - "alloy-sol-types", "risc0-zkvm", ] @@ -597,12 +566,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - [[package]] name = "ecdsa" version = "0.16.9" @@ -763,12 +726,6 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "hex" version = "0.4.3" @@ -1514,18 +1471,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syn-solidity" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63bef2e2c735acbc06874eca3a8506f02a3c4700e6e748afc92cc2e4220e8a03" -dependencies = [ - "paste", - "proc-macro2", - "quote", - "syn 2.0.48", -] - [[package]] name = "tap" version = "1.0.1" diff --git a/methods/guest/Cargo.toml b/methods/guest/Cargo.toml index 561fd45b..0d6ca57f 100644 --- a/methods/guest/Cargo.toml +++ b/methods/guest/Cargo.toml @@ -11,7 +11,6 @@ path = "src/bin/is_even.rs" [dependencies] alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } -alloy-sol-types = { version = "0.6" } risc0-zkvm = { version = "0.20", default-features = false, features = ['std'] } [profile.release] diff --git a/methods/guest/src/bin/is_even.rs b/methods/guest/src/bin/is_even.rs index 9036b145..dacdb28a 100644 --- a/methods/guest/src/bin/is_even.rs +++ b/methods/guest/src/bin/is_even.rs @@ -12,14 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![no_main] - use alloy_primitives::U256; -use alloy_sol_types::SolValue; use risc0_zkvm::guest::env; -risc0_zkvm::guest::entry!(main); - pub fn main() { // Read data sent from the application contract. let number: U256 = env::read(); @@ -29,6 +24,6 @@ pub fn main() { assert!(number.bit(0) == false, "number is not even"); // Commit the journal that will be received by the application contract. - // Encoded types should match the args expected by the application. - env::commit_slice(number.abi_encode().as_slice()); + // Data types committed here (e.g. U256) should match your `GuestInterface::Journal`. + env::commit(&number); } diff --git a/methods/src/lib.rs b/methods/src/lib.rs index 2a5dd3b2..3f0869c1 100644 --- a/methods/src/lib.rs +++ b/methods/src/lib.rs @@ -14,3 +14,39 @@ //! Generated crate containing the image ID and ELF binary of the build guest. include!(concat!(env!("OUT_DIR"), "/methods.rs")); + +#[cfg(test)] +mod tests { + use alloy_primitives::U256; + use risc0_zkvm::{default_prover, ExecutorEnv}; + + #[test] + fn proves_even_number() { + let even_number = U256::from(1304); + + let env = ExecutorEnv::builder() + .write(&even_number) + .unwrap() + .build() + .unwrap(); + + let receipt = default_prover().prove(env, super::IS_EVEN_ELF).unwrap(); + + let x: U256 = receipt.journal.decode().unwrap(); + assert_eq!(x, even_number); + } + + #[test] + #[should_panic(expected = "number is not even")] + fn rejects_odd_number() { + let odd_number = U256::from(75); + + let env = ExecutorEnv::builder() + .write(&odd_number) + .unwrap() + .build() + .unwrap(); + + default_prover().prove(env, super::IS_EVEN_ELF).unwrap(); + } +} diff --git a/sdk/src/cli.rs b/sdk/src/cli.rs index 6aac0006..7e052ea3 100644 --- a/sdk/src/cli.rs +++ b/sdk/src/cli.rs @@ -14,6 +14,7 @@ use std::io::Write; +use alloy_primitives::FixedBytes; use anyhow::{anyhow, Context, Result}; use clap::Parser; use risc0_build::GuestListEntry; @@ -66,34 +67,44 @@ enum Command { }, } -/// GuestInterface for parsing guest input and calldata. +/// GuestInterface for parsing guest input and encoding calldata. pub trait GuestInterface { - /// Parses a `String` as the guest input returning its serialization, - /// encoded as `Vec`, compatible with the zkVM and Bonsai. - fn serialize_input(&self, input: String) -> Result>; - - /// Extracts the calldata ABI encoded from a proof. - fn calldata(&self, proof: Proof) -> Result>; + /// Input type expected by the guest from `env::read()`. + type Input: serde::Serialize; + + /// Journal data type written by the guest via `env::commit()`. + type Journal: serde::de::DeserializeOwned; + + /// Parses a `String` as the guest input. + fn parse_input(&self, input: String) -> Result; + + /// Encodes the proof into calldata to match the function to call on the Ethereum contract. + fn encode_calldata( + &self, + journal: Self::Journal, + post_state_digest: FixedBytes<32>, + seal: Vec, + ) -> Result>; } /// Execute or return image id. /// If some input is provided, returns the Ethereum ABI and hex encoded proof. -pub fn query<'a>( - guest_list: &[GuestListEntry<'a>], +pub fn query( + guest_list: &[GuestListEntry], guest_binary: String, input: Option, - guest_interface: &dyn GuestInterface, + guest_interface: impl GuestInterface, ) -> Result<()> { let elf = resolve_guest_entry(guest_list, &guest_binary)?; let image_id = compute_image_id(&elf)?; let output = match input { // Input provided. Return the Ethereum ABI encoded proof. Some(input) => { - let proof = prover::generate_proof(&elf, guest_interface.serialize_input(input)?)?; + let proof = prover::generate_proof(&elf, guest_interface.parse_input(input)?)?; hex::encode(proof.abi_encode()) } // No input. Return the Ethereum ABI encoded bytes32 image ID. - None => format!("0x{}", image_id.to_string()), + None => format!("0x{}", hex::encode(image_id)), }; print!("{output}"); std::io::stdout() @@ -103,20 +114,30 @@ pub fn query<'a>( } /// Request a proof and publish it on Ethereum. -pub fn publish<'a>( +pub fn publish( chain_id: u64, eth_wallet_private_key: String, rpc_url: String, contract: String, - guest_list: &[GuestListEntry<'a>], + guest_list: &[GuestListEntry], guest_binary: String, input: String, - guest_interface: &dyn GuestInterface, + guest_interface: impl GuestInterface, ) -> Result<()> { let elf = resolve_guest_entry(guest_list, &guest_binary)?; let tx_sender = eth::TxSender::new(chain_id, &rpc_url, ð_wallet_private_key, &contract)?; - let proof = prover::generate_proof(&elf, guest_interface.serialize_input(input)?)?; - let calldata = guest_interface.calldata(proof)?; + + let input = guest_interface.parse_input(input)?; + let Proof { + journal, + post_state_digest, + seal, + } = prover::generate_proof(&elf, input)?; + let calldata = guest_interface.encode_calldata( + risc0_zkvm::serde::from_slice(journal.as_slice())?, + post_state_digest, + seal, + )?; let runtime = tokio::runtime::Runtime::new()?; runtime.block_on(tx_sender.send(calldata))?; @@ -125,10 +146,7 @@ pub fn publish<'a>( } /// Run the CLI. -pub fn run<'a>( - guest_list: &[GuestListEntry<'a>], - guest_interface: &dyn GuestInterface, -) -> Result<()> { +pub fn run(guest_list: &[GuestListEntry], guest_interface: impl GuestInterface) -> Result<()> { match Command::parse() { Command::Query { guest_binary, @@ -156,10 +174,7 @@ pub fn run<'a>( Ok(()) } -fn resolve_guest_entry<'a>( - guest_list: &[GuestListEntry<'a>], - guest_binary: &String, -) -> Result> { +fn resolve_guest_entry(guest_list: &[GuestListEntry], guest_binary: &String) -> Result> { // Search list for requested binary name let potential_guest_image_id: [u8; 32] = match hex::decode(guest_binary.to_lowercase().trim_start_matches("0x")) { diff --git a/sdk/src/eth.rs b/sdk/src/eth.rs index ae280087..11eee9b6 100644 --- a/sdk/src/eth.rs +++ b/sdk/src/eth.rs @@ -24,9 +24,9 @@ pub(crate) struct TxSender { impl TxSender { pub(crate) fn new( chain_id: u64, - rpc_url: &String, - private_key: &String, - contract: &String, + rpc_url: &str, + private_key: &str, + contract: &str, ) -> Result { let provider = Provider::::try_from(rpc_url)?; let wallet: LocalWallet = private_key.parse::()?.with_chain_id(chain_id); diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index fa9b6fd8..c9071ea0 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -16,5 +16,3 @@ pub mod cli; mod eth; pub mod prover; pub mod snark; - -pub use prover::serialize; diff --git a/sdk/src/prover.rs b/sdk/src/prover.rs index 6a26891d..481ccc5e 100644 --- a/sdk/src/prover.rs +++ b/sdk/src/prover.rs @@ -17,23 +17,14 @@ use std::time::Duration; use alloy_primitives::FixedBytes; use anyhow::{Context, Result}; use bonsai_sdk::alpha as bonsai_sdk; -use risc0_zkvm::{ - compute_image_id, default_executor, is_dev_mode, serde::to_vec, ExecutorEnv, Receipt, -}; +use risc0_zkvm::{compute_image_id, default_executor, is_dev_mode, ExecutorEnv, Receipt}; use crate::snark::{Proof, Seal}; -/// Serializes the given input as a `Vec` compatible with the zkVM and -/// Bonsai. -pub fn serialize(input: T) -> Result> { - let input_data = to_vec(&input)?; - Ok(bytemuck::cast_slice(&input_data).to_vec()) -} - /// Generates a snark proof for the given elf and input. /// When `RISC0_DEV_MODE` is set, executes the elf locally, /// as opposed to sending the proof request to the Bonsai service. -pub fn generate_proof(elf: &[u8], input: Vec) -> Result { +pub(crate) fn generate_proof(elf: &[u8], input: impl serde::Serialize) -> Result { match is_dev_mode() { true => DevModeProver::prove(elf, input), false => BonsaiProver::prove(elf, input), @@ -47,9 +38,9 @@ trait Prover { struct DevModeProver {} impl DevModeProver { - fn prove(elf: &[u8], input: Vec) -> Result { + fn prove(elf: &[u8], input: impl serde::Serialize) -> Result { let env = ExecutorEnv::builder() - .write_slice(&input) + .write(&input)? .build() .context("Failed to build exec env")?; let exec = default_executor(); @@ -59,9 +50,15 @@ impl DevModeProver { } } +/// Serializes the given input as a `Vec` compatible with Bonsai. +fn serialize_input_to_bytes(input: impl serde::Serialize) -> Result> { + let input_encoded = risc0_zkvm::serde::to_vec(&input)?; + Ok(bytemuck::allocation::cast_vec(input_encoded)) +} + struct BonsaiProver {} impl BonsaiProver { - fn prove(elf: &[u8], input: Vec) -> Result { + fn prove(elf: &[u8], input: impl serde::Serialize) -> Result { let client = bonsai_sdk::Client::from_env(risc0_zkvm::VERSION)?; // Compute the image_id, then upload the ELF with the image_id as its key. @@ -71,7 +68,8 @@ impl BonsaiProver { log::info!("Image ID: 0x{}", image_id_hex); // Prepare input data and upload it. - let input_id = { client.upload_input(input)? }; + let input_bytes = serialize_input_to_bytes(input)?; + let input_id = client.upload_input(input_bytes)?; // Start a session running the prover. let session = client.create_session(image_id_hex, input_id, vec![])?; @@ -91,7 +89,7 @@ impl BonsaiProver { // Download the receipt, containing the output. let receipt_url = res .receipt_url - .expect("API error, missing receipt on completed session"); + .context("API error, missing receipt on completed session")?; let receipt_buf = client.download(&receipt_url)?; let receipt: Receipt = bincode::deserialize(&receipt_buf)?; @@ -118,7 +116,7 @@ impl BonsaiProver { continue; } "SUCCEEDED" => { - break res.output.expect("No snark generated :("); + break res.output.context("No snark generated :(")?; } _ => { panic!( diff --git a/sdk/src/snark.rs b/sdk/src/snark.rs index 9ab24a12..7bfe4569 100644 --- a/sdk/src/snark.rs +++ b/sdk/src/snark.rs @@ -87,7 +87,7 @@ impl TryFrom for Seal { /// Snark proof as generated by Bonsai. #[derive(Clone, Debug)] -pub struct Proof { +pub(crate) struct Proof { /// Journal pub journal: Vec, /// Post state digest @@ -105,7 +105,7 @@ impl Proof { } } - pub fn abi_encode(self) -> Vec { + pub(crate) fn abi_encode(self) -> Vec { let calldata = vec![ Token::Bytes(self.journal), Token::FixedBytes(self.post_state_digest.to_vec()), From 10815c25d7493ae005dcb9fa5625fb0db7aa0db1 Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Fri, 2 Feb 2024 16:44:11 -0800 Subject: [PATCH 03/10] formatting changes --- README.md | 1 - tests/EvenNumber.t.sol | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 83a3af34..7184235f 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,6 @@ Your new project consists of: ### Run the Tests - - Use `cargo test` to run the tests in your zkVM program. - Use `RISC0_DEV_MODE=true forge test -vvv` to test your Solidity contracts and their interaction with your zkVM program. diff --git a/tests/EvenNumber.t.sol b/tests/EvenNumber.t.sol index 12e2f143..905c85e0 100644 --- a/tests/EvenNumber.t.sol +++ b/tests/EvenNumber.t.sol @@ -34,21 +34,22 @@ contract EvenNumberTest is BonsaiTest { assertEq(evenNumber.get(), 0); } - function test_Set_Even() public { + function testSetEven() public { set(12345678); } - function testFail_Set_Odd() public { + function testFailSetOdd() public { set(123456789); } - function test_Set_Zero() public { + function testSetZero() public { set(0); } function set(uint256 number) internal { (bytes memory journal, bytes32 post_state_digest, bytes memory seal) = queryImageOutputAndSeal(imageId, abi.encode(number)); + evenNumber.set(abi.decode(journal, (uint256)), post_state_digest, seal); assertEq(evenNumber.get(), number); } From bef731ede3a4c106a7d9ad83b534ac0dd204cff5 Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Fri, 2 Feb 2024 16:59:16 -0800 Subject: [PATCH 04/10] revert introduction of GuestInterface::Journal --- Cargo.lock | 1 + cli/src/interface.rs | 9 +++--- methods/Cargo.toml | 1 + methods/guest/Cargo.lock | 55 ++++++++++++++++++++++++++++++++ methods/guest/Cargo.toml | 1 + methods/guest/src/bin/is_even.rs | 5 +-- methods/src/lib.rs | 3 +- sdk/src/cli.rs | 5 +-- 8 files changed, 68 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 191598e9..54e44cc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,6 +613,7 @@ name = "bonsai-starter-methods" version = "0.1.0" dependencies = [ "alloy-primitives", + "alloy-sol-types", "risc0-build", "risc0-zkvm", ] diff --git a/cli/src/interface.rs b/cli/src/interface.rs index 9d5c3dc0..6f2406e1 100644 --- a/cli/src/interface.rs +++ b/cli/src/interface.rs @@ -15,7 +15,7 @@ use std::str::FromStr; use alloy_primitives::{FixedBytes, U256}; -use alloy_sol_types::{sol, SolInterface}; +use alloy_sol_types::{sol, SolInterface, SolValue}; use anyhow::Result; use risc0_ethereum_sdk::cli::GuestInterface; @@ -37,7 +37,6 @@ pub struct EvenNumberInterface; impl GuestInterface for EvenNumberInterface { type Input = U256; - type Journal = U256; /// Parses a `String` as the guest input. /// @@ -49,12 +48,12 @@ impl GuestInterface for EvenNumberInterface { /// Encodes the proof into calldata to match the function to call on the Ethereum contract. fn encode_calldata( &self, - journal: Self::Journal, + journal: Vec, post_state_digest: FixedBytes<32>, seal: Vec, ) -> Result> { - // Unpack the journal. In this this it only contains a single number. - let x = journal; + // Decode the journal. Must match what was written in the guest with `env::commit_slice` + let x = U256::abi_decode(&journal, true)?; // Encode the function call for `IEvenNumber.set(x)` Ok(IEvenNumber::IEvenNumberCalls::set(IEvenNumber::setCall { diff --git a/methods/Cargo.toml b/methods/Cargo.toml index be4924f6..fe35e246 100644 --- a/methods/Cargo.toml +++ b/methods/Cargo.toml @@ -15,3 +15,4 @@ risc0-build = { workspace = true } [dev-dependencies] risc0-zkvm = { workspace = true } alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } +alloy-sol-types = { version = "0.6" } diff --git a/methods/guest/Cargo.lock b/methods/guest/Cargo.lock index 0dd08212..92d8832f 100644 --- a/methods/guest/Cargo.lock +++ b/methods/guest/Cargo.lock @@ -46,6 +46,36 @@ dependencies = [ "bytes", ] +[[package]] +name = "alloy-sol-macro" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b0b5ab0cb07c21adf9d72e988b34e8200ce648c2bba8d009183bb1c50fb1216" +dependencies = [ + "const-hex", + "dunce", + "heck", + "indexmap", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.48", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-types" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c08f62ded7ce03513bfb60ef5cad4fff5d4f67eac6feb4df80426b7b9ffb06e" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + [[package]] name = "anyhow" version = "1.0.79" @@ -384,6 +414,7 @@ name = "bonsai-starter-methods-guest" version = "0.1.0" dependencies = [ "alloy-primitives", + "alloy-sol-types", "risc0-zkvm", ] @@ -566,6 +597,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "ecdsa" version = "0.16.9" @@ -726,6 +763,12 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hex" version = "0.4.3" @@ -1471,6 +1514,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63bef2e2c735acbc06874eca3a8506f02a3c4700e6e748afc92cc2e4220e8a03" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tap" version = "1.0.1" diff --git a/methods/guest/Cargo.toml b/methods/guest/Cargo.toml index 0d6ca57f..561fd45b 100644 --- a/methods/guest/Cargo.toml +++ b/methods/guest/Cargo.toml @@ -11,6 +11,7 @@ path = "src/bin/is_even.rs" [dependencies] alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } +alloy-sol-types = { version = "0.6" } risc0-zkvm = { version = "0.20", default-features = false, features = ['std'] } [profile.release] diff --git a/methods/guest/src/bin/is_even.rs b/methods/guest/src/bin/is_even.rs index dacdb28a..46b21a62 100644 --- a/methods/guest/src/bin/is_even.rs +++ b/methods/guest/src/bin/is_even.rs @@ -13,6 +13,7 @@ // limitations under the License. use alloy_primitives::U256; +use alloy_sol_types::SolValue; use risc0_zkvm::guest::env; pub fn main() { @@ -24,6 +25,6 @@ pub fn main() { assert!(number.bit(0) == false, "number is not even"); // Commit the journal that will be received by the application contract. - // Data types committed here (e.g. U256) should match your `GuestInterface::Journal`. - env::commit(&number); + // Encoded types should match the args expected by the application. + env::commit_slice(number.abi_encode().as_slice()); } diff --git a/methods/src/lib.rs b/methods/src/lib.rs index 3f0869c1..2492c2a8 100644 --- a/methods/src/lib.rs +++ b/methods/src/lib.rs @@ -18,6 +18,7 @@ include!(concat!(env!("OUT_DIR"), "/methods.rs")); #[cfg(test)] mod tests { use alloy_primitives::U256; + use alloy_sol_types::SolValue; use risc0_zkvm::{default_prover, ExecutorEnv}; #[test] @@ -32,7 +33,7 @@ mod tests { let receipt = default_prover().prove(env, super::IS_EVEN_ELF).unwrap(); - let x: U256 = receipt.journal.decode().unwrap(); + let x = U256::abi_decode(&receipt.journal.bytes, true).unwrap(); assert_eq!(x, even_number); } diff --git a/sdk/src/cli.rs b/sdk/src/cli.rs index 7e052ea3..74371cf4 100644 --- a/sdk/src/cli.rs +++ b/sdk/src/cli.rs @@ -72,16 +72,13 @@ pub trait GuestInterface { /// Input type expected by the guest from `env::read()`. type Input: serde::Serialize; - /// Journal data type written by the guest via `env::commit()`. - type Journal: serde::de::DeserializeOwned; - /// Parses a `String` as the guest input. fn parse_input(&self, input: String) -> Result; /// Encodes the proof into calldata to match the function to call on the Ethereum contract. fn encode_calldata( &self, - journal: Self::Journal, + journal: Vec, post_state_digest: FixedBytes<32>, seal: Vec, ) -> Result>; From b4341858925ba046985e130916c0d61908be2021 Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Fri, 2 Feb 2024 17:05:12 -0800 Subject: [PATCH 05/10] align with test naming in the forge book --- tests/EvenNumber.t.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/EvenNumber.t.sol b/tests/EvenNumber.t.sol index 905c85e0..94bac935 100644 --- a/tests/EvenNumber.t.sol +++ b/tests/EvenNumber.t.sol @@ -34,15 +34,15 @@ contract EvenNumberTest is BonsaiTest { assertEq(evenNumber.get(), 0); } - function testSetEven() public { + function test_SetEven() public { set(12345678); } - function testFailSetOdd() public { + function testFail_SetOdd() public { set(123456789); } - function testSetZero() public { + function test_SetZero() public { set(0); } From e8f10d864fe5aacf414ccf5e358a9db80896d167 Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Fri, 2 Feb 2024 17:12:44 -0800 Subject: [PATCH 06/10] rename tests/RiscZeroGroth16VerifierTest.sol to tests/MockRiscZeroVerifier.sol --- README.md | 1 - tests/EvenNumber.t.sol | 20 +++++++++++-------- ...ifierTest.sol => MockRiscZeroVerifier.sol} | 17 ++++------------ 3 files changed, 16 insertions(+), 22 deletions(-) rename tests/{RiscZeroGroth16VerifierTest.sol => MockRiscZeroVerifier.sol} (73%) diff --git a/README.md b/README.md index 7184235f..5d630468 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,6 @@ Your new project consists of: ### Run the Tests - Use `cargo test` to run the tests in your zkVM program. - - Use `RISC0_DEV_MODE=true forge test -vvv` to test your Solidity contracts and their interaction with your zkVM program. ## Develop Your Application diff --git a/tests/EvenNumber.t.sol b/tests/EvenNumber.t.sol index 94bac935..30c23fde 100644 --- a/tests/EvenNumber.t.sol +++ b/tests/EvenNumber.t.sol @@ -20,7 +20,7 @@ import {BonsaiTest} from "bonsai/BonsaiTest.sol"; import {console2} from "forge-std/console2.sol"; import {IRiscZeroVerifier} from "bonsai/IRiscZeroVerifier.sol"; import {ControlID, RiscZeroGroth16Verifier} from "bonsai/groth16/RiscZeroGroth16Verifier.sol"; -import {RiscZeroGroth16VerifierTest} from "./RiscZeroGroth16VerifierTest.sol"; +import {MockRiscZeroVerifier} from "./MockRiscZeroVerifier.sol"; import {EvenNumber} from "../contracts/EvenNumber.sol"; contract EvenNumberTest is BonsaiTest { @@ -35,18 +35,22 @@ contract EvenNumberTest is BonsaiTest { } function test_SetEven() public { - set(12345678); + uint256 number = 12345678; + (bytes memory journal, bytes32 post_state_digest, bytes memory seal) = + queryImageOutputAndSeal(imageId, abi.encode(number)); + + evenNumber.set(abi.decode(journal, (uint256)), post_state_digest, seal); + assertEq(evenNumber.get(), number); } function testFail_SetOdd() public { - set(123456789); + uint256 number = 123456789; + // Attempting to prove that 123456789 is even should fail. + queryImageOutputAndSeal(imageId, abi.encode(number)); } function test_SetZero() public { - set(0); - } - - function set(uint256 number) internal { + uint256 number = 0; (bytes memory journal, bytes32 post_state_digest, bytes memory seal) = queryImageOutputAndSeal(imageId, abi.encode(number)); @@ -61,7 +65,7 @@ contract EvenNumberTest is BonsaiTest { console2.log("Deployed RiscZeroGroth16Verifier to", address(verifier)); return verifier; } else { - IRiscZeroVerifier verifier = new RiscZeroGroth16VerifierTest(); + IRiscZeroVerifier verifier = new MockRiscZeroVerifier(); console2.log("Deployed RiscZeroGroth16VerifierTest to", address(verifier)); return verifier; } diff --git a/tests/RiscZeroGroth16VerifierTest.sol b/tests/MockRiscZeroVerifier.sol similarity index 73% rename from tests/RiscZeroGroth16VerifierTest.sol rename to tests/MockRiscZeroVerifier.sol index 37873f1f..aa0f48ee 100644 --- a/tests/RiscZeroGroth16VerifierTest.sol +++ b/tests/MockRiscZeroVerifier.sol @@ -29,16 +29,8 @@ import { SystemExitCode } from "bonsai/IRiscZeroVerifier.sol"; -/// @notice Groth16 verifier contract for RISC Zero receipts of execution. -contract RiscZeroGroth16VerifierTest is IRiscZeroVerifier { - uint256 public immutable CONTROL_ID_0; - uint256 public immutable CONTROL_ID_1; - - constructor() { - CONTROL_ID_0 = 0; - CONTROL_ID_1 = 0; - } - +/// @notice Mock verifier contract for RISC Zero receipts of execution. +contract MockRiscZeroVerifier is IRiscZeroVerifier { /// @inheritdoc IRiscZeroVerifier function verify( bytes calldata seal, @@ -49,14 +41,13 @@ contract RiscZeroGroth16VerifierTest is IRiscZeroVerifier { ) public view returns (bool) { // Require that the seal be specifically empty. // Reject if the caller may have sent a real seal. - return CONTROL_ID_0 == 0 && CONTROL_ID_1 == 0 && seal.length == 0 && postStateDigest == bytes32(0); + return seal.length == 0 && postStateDigest == bytes32(0); } /// @inheritdoc IRiscZeroVerifier function verify_integrity(Receipt memory receipt) public view returns (bool) { // Require that the seal be specifically empty. // Reject if the caller may have sent a real seal. - return CONTROL_ID_0 == 0 && CONTROL_ID_1 == 0 && receipt.seal.length == 0 - && receipt.claim.postStateDigest == bytes32(0); + return receipt.seal.length == 0 && receipt.claim.postStateDigest == bytes32(0); } } From 3baec77bbeffd9d871bd610a6ee105344454acef Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Fri, 2 Feb 2024 17:17:21 -0800 Subject: [PATCH 07/10] moving links around --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5d630468..920e71d9 100644 --- a/README.md +++ b/README.md @@ -76,9 +76,9 @@ Your new project consists of: - a [guest interface] (written in Rust), which lets you define how to parse and serialize the guest input and calldata so that the [RISC Zero zkVM] and Bonsai can interact with your contract. [instructions above]: #dependencies -[zkVM program]: https://github.com/risc0/bonsai-foundry-template/tree/main/methods/guest/src/bin -[app contract]: https://github.com/risc0/bonsai-foundry-template/tree/main/contracts -[guest interface]: https://github.com/risc0/bonsai-foundry-template/tree/main/cli +[zkVM program]: ./methods/guest/src/bin +[app contract]: ./contracts +[guest interface]: ./cli ### Run the Tests @@ -93,6 +93,10 @@ To build your application, you'll need to make changes in three folders: - write the on-chain part of your project in the [contracts] folder - write the guest interface in the [cli] folder +[methods]: ./methods +[cli]: ./cli +[contracts]: ./contracts + ### Configuring Bonsai ***Note:*** *The Bonsai proving service is still in early Alpha. To request an API key [complete the form here](https://bonsai.xyz/apply).* @@ -148,7 +152,3 @@ Below are the primary files in the project directory ├── interface.rs // Interface for interacting with your contract └── main.rs // CLI for interacting with your application ``` - -[methods]: /methods -[cli]: /cli -[contracts]: /contracts From 2cf4bdfbc74dd6da77fa6b06e14a926c170b9869 Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Mon, 5 Feb 2024 10:52:37 -0800 Subject: [PATCH 08/10] change mock verify to pure --- tests/MockRiscZeroVerifier.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/MockRiscZeroVerifier.sol b/tests/MockRiscZeroVerifier.sol index aa0f48ee..cfe95a9c 100644 --- a/tests/MockRiscZeroVerifier.sol +++ b/tests/MockRiscZeroVerifier.sol @@ -38,14 +38,14 @@ contract MockRiscZeroVerifier is IRiscZeroVerifier { /*imageId*/ bytes32 postStateDigest, bytes32 /*journalDigest*/ - ) public view returns (bool) { + ) public pure returns (bool) { // Require that the seal be specifically empty. // Reject if the caller may have sent a real seal. return seal.length == 0 && postStateDigest == bytes32(0); } /// @inheritdoc IRiscZeroVerifier - function verify_integrity(Receipt memory receipt) public view returns (bool) { + function verify_integrity(Receipt memory receipt) public pure returns (bool) { // Require that the seal be specifically empty. // Reject if the caller may have sent a real seal. return receipt.seal.length == 0 && receipt.claim.postStateDigest == bytes32(0); From 49871208ba64239b09c9b73e16fb210c3cbdd7a6 Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Mon, 5 Feb 2024 10:58:55 -0800 Subject: [PATCH 09/10] Update sdk/src/prover.rs Co-authored-by: Angelo Capossele --- sdk/src/prover.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/prover.rs b/sdk/src/prover.rs index 481ccc5e..ceca3b9b 100644 --- a/sdk/src/prover.rs +++ b/sdk/src/prover.rs @@ -53,7 +53,7 @@ impl DevModeProver { /// Serializes the given input as a `Vec` compatible with Bonsai. fn serialize_input_to_bytes(input: impl serde::Serialize) -> Result> { let input_encoded = risc0_zkvm::serde::to_vec(&input)?; - Ok(bytemuck::allocation::cast_vec(input_encoded)) + Ok(bytemuck::cast_slice(&input_encoded).to_vec()) } struct BonsaiProver {} From 8bf89677a2f35b8bb87b4ed5a776cc0a5d2a715a Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Mon, 5 Feb 2024 15:07:53 -0800 Subject: [PATCH 10/10] run cargo sort --- methods/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/methods/Cargo.toml b/methods/Cargo.toml index fe35e246..c41d043b 100644 --- a/methods/Cargo.toml +++ b/methods/Cargo.toml @@ -13,6 +13,6 @@ risc0-build = { workspace = true } risc0-build = { workspace = true } [dev-dependencies] -risc0-zkvm = { workspace = true } alloy-primitives = { version = "0.6", default-features = false, features = ["rlp", "serde", "std"] } alloy-sol-types = { version = "0.6" } +risc0-zkvm = { workspace = true }