diff --git a/book/src/advanced-usage/sdk.md b/book/src/advanced-usage/sdk.md index 5e9ffe32a7..72b748be55 100644 --- a/book/src/advanced-usage/sdk.md +++ b/book/src/advanced-usage/sdk.md @@ -6,10 +6,10 @@ For more information on the basic CLI flow, see [Overview of Basic Usage](../wri ## Imports and Setup -If you have a guest program and would like to try running the **host program** specified below, you can do so by adding the following imports and setup at the top of the file. You may need to modify the imports and/or the `SomeStruct` struct to match your program. +If you have a guest program and would like to try running the **host program** specified in the next section, you can do so by adding the following imports and setup at the top of the file. You may need to modify the imports and/or the `SomeStruct` struct to match your program. ```rust,no_run,noplayground -{{ #include ../../../crates/sdk/examples/sdk.rs:dependencies }} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:dependencies }} ``` ## Building and Transpiling a Program @@ -17,10 +17,10 @@ If you have a guest program and would like to try running the **host program** s The SDK provides lower-level control over the building and transpiling process. ```rust,no_run,noplayground -{{ #include ../../../crates/sdk/examples/sdk.rs:build }} -{{ #include ../../../crates/sdk/examples/sdk.rs:read_elf}} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:build }} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:read_elf}} -{{ #include ../../../crates/sdk/examples/sdk.rs:transpilation }} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:transpilation }} ``` ### Using `SdkVmConfig` @@ -28,7 +28,7 @@ The SDK provides lower-level control over the building and transpiling process. The `SdkVmConfig` struct allows you to specify the extensions and system configuration your VM will use. To customize your own configuration, you can use the `SdkVmConfig::builder()` method and set the extensions and system configuration you want. ```rust,no_run,noplayground -{{ #include ../../../crates/sdk/examples/sdk.rs:vm_config }} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:vm_config }} ``` ## Running a Program @@ -36,47 +36,89 @@ The `SdkVmConfig` struct allows you to specify the extensions and system configu To run your program and see the public value output, you can do the following: ```rust,no_run,noplayground -{{ #include ../../../crates/sdk/examples/sdk.rs:execution }} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:execution }} ``` ### Using `StdIn` The `StdIn` struct allows you to format any serializable type into a VM-readable format by passing in a reference to your struct into `StdIn::write` as above. You also have the option to pass in a `&[u8]` into `StdIn::write_bytes`, or a `&[F]` into `StdIn::write_field` where `F` is the `openvm_stark_sdk::p3_baby_bear::BabyBear` field type. -> **Generating CLI Bytes** +> **Generating CLI Bytes** > To get the VM byte representation of a serializable struct `data` (i.e. for use in the CLI), you can print out the result of `openvm::serde::to_vec(data).unwrap()` in a Rust host program. -## Generating Proofs +## Generating and Verifying Proofs + +There are two types of proofs that you can generate, with the sections below continuing from this point. + +- [App Proof](#app-proof): Generates STARK proof(s) of the guest program +- [EVM Proof](#evm-proof): Generates a halo2 proof that can be posted on-chain + +## App Proof + +### Generating App Proofs After building and transpiling a program, you can then generate a proof. To do so, you need to commit your `VmExe`, generate an `AppProvingKey`, format your input into `StdIn`, and then generate a proof. ```rust,no_run,noplayground -{{ #include ../../../crates/sdk/examples/sdk.rs:proof_generation }} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:proof_generation }} ``` -## Verifying Proofs +For large guest programs, the program will be proved in multiple continuation segments and the returned `proof: ContinuationVmProof` object consists of multiple STARK proofs, one for each segment. + +### Verifying App Proofs After generating a proof, you can verify it. To do so, you need your verifying key (which you can get from your `AppProvingKey`) and the output of your `generate_app_proof` call. ```rust,no_run,noplayground -{{ #include ../../../crates/sdk/examples/sdk.rs:verification }} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:verification }} ``` -## End-to-end EVM Proof Generation and Verification +## EVM Proof + +### Setup -Generating and verifying an EVM proof is an extension of the above process. +To generate an EVM proof, you'll first need to ensure that you have followed the [CLI installation steps](../../getting-started/install.md). get the appropraite KZG params by running the following command. + +```bash +cargo openvm setup +``` + +> ⚠️ **WARNING** +> +> `cargo openvm setup` requires very large amounts of computation and memory (~200 GB). + +
+Also note that there are additional dependencies for the EVM Proof flow. Click here to view. ```rust,no_run,noplayground -{{ #include ../../../crates/sdk/examples/sdk.rs:evm_verification }} +{{ #include ../../../crates/sdk/examples/sdk_app.rs:dependencies }} ``` -> ⚠️ **WARNING** -> Generating an EVM proof will require a substantial amount of computation and memory. If you have run `cargo openvm setup` and don't need a specialized aggregation configuration, consider deserializing the proving key from the file `~/.openvm/agg.pk` instead of generating it. +
-> ⚠️ **WARNING** -> The aggregation proving key `agg_pk` above is large. Avoid cloning it if possible. +### Keygen -Note that `DEFAULT_PARAMS_DIR` is the directory where Halo2 parameters are stored by the `cargo openvm setup` CLI command. For more information on the setup process, see the `EVM Level` section of the [verify](../writing-apps/verify.md) doc. +Now, you'll need to generate the app proving key for the next step. -> ⚠️ **WARNING** -> `cargo openvm setup` requires very large amounts of computation and memory (~200 GB). +```rust,no_run,noplayground +{{ #include ../../../crates/sdk/examples/sdk_evm.rs:keygen }} +``` + +> ⚠️ **WARNING** +> +> If you have run `cargo openvm setup` and don't need a specialized aggregation configuration, consider deserializing the proving key from the file `~/.openvm/agg.pk` instead of generating it, to save computation. + +### EVM Proof Generation and Verification + +You can now run the aggregation keygen, proof, and verification functions for the EVM proof. + +**Note**: you **do not** need to generate the app proof with the `generate_app_proof` function, as the EVM proof function will handle this automatically. + +```rust,no_run,noplayground +{{ #include ../../../crates/sdk/examples/sdk_evm.rs:evm_verification }} +``` + +> ⚠️ **WARNING** +> The aggregation proving key `agg_pk` above is large. Avoid cloning it if possible. + +Note that `DEFAULT_PARAMS_DIR` is the directory where Halo2 parameters are stored by the `cargo openvm setup` CLI command. For more information on the setup process, see the `EVM Level` section of the [verify](../../writing-apps/verify.md) doc. diff --git a/crates/sdk/examples/sdk.rs b/crates/sdk/examples/sdk_app.rs similarity index 78% rename from crates/sdk/examples/sdk.rs rename to crates/sdk/examples/sdk_app.rs index 5c60053764..05a33d56e0 100644 --- a/crates/sdk/examples/sdk.rs +++ b/crates/sdk/examples/sdk_app.rs @@ -4,9 +4,8 @@ use std::{fs, sync::Arc}; use eyre::Result; use openvm::platform::memory::MEM_SIZE; use openvm_build::GuestOptions; -use openvm_native_recursion::halo2::utils::CacheHalo2ParamsReader; use openvm_sdk::{ - config::{AggConfig, AppConfig, SdkVmConfig}, + config::{AppConfig, SdkVmConfig}, prover::AppProver, Sdk, StdIn, }; @@ -102,29 +101,5 @@ fn main() -> Result<(), Box> { sdk.verify_app_proof(&app_vk, &proof)?; // ANCHOR_END: verification - // ANCHOR: evm_verification - // 11. Generate the aggregation proving key - const DEFAULT_PARAMS_DIR: &str = concat!(env!("HOME"), "/.openvm/params/"); - let halo2_params_reader = CacheHalo2ParamsReader::new(DEFAULT_PARAMS_DIR); - let agg_config = AggConfig::default(); - let agg_pk = sdk.agg_keygen(agg_config, &halo2_params_reader)?; - - // 12. Generate the SNARK verifier contract - let verifier = sdk.generate_snark_verifier_contract(&halo2_params_reader, &agg_pk)?; - - // 13. Generate an EVM proof - let proof = sdk.generate_evm_proof( - &halo2_params_reader, - app_pk, - app_committed_exe, - agg_pk, - stdin, - )?; - - // 14. Verify the EVM proof - let success = sdk.verify_evm_proof(&verifier, &proof); - assert!(success); - // ANCHOR_END: evm_verification - Ok(()) } diff --git a/crates/sdk/examples/sdk_evm.rs b/crates/sdk/examples/sdk_evm.rs new file mode 100644 index 0000000000..24bd6add55 --- /dev/null +++ b/crates/sdk/examples/sdk_evm.rs @@ -0,0 +1,112 @@ +// ANCHOR: dependencies +use std::{fs, sync::Arc}; + +use eyre::Result; +use openvm::platform::memory::MEM_SIZE; +use openvm_build::GuestOptions; +use openvm_native_recursion::halo2::utils::CacheHalo2ParamsReader; +use openvm_sdk::{ + config::{AggConfig, AppConfig, SdkVmConfig}, + Sdk, StdIn, +}; +use openvm_stark_sdk::config::FriParameters; +use openvm_transpiler::elf::Elf; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct SomeStruct { + pub a: u64, + pub b: u64, +} +// ANCHOR_END: dependencies + +#[allow(dead_code, unused_variables)] +fn read_elf() -> Result<(), Box> { + // ANCHOR: read_elf + // 2b. Load the ELF from a file + let elf_bytes = fs::read("your_path_to_elf")?; + let elf = Elf::decode(&elf_bytes, MEM_SIZE as u32)?; + // ANCHOR_END: read_elf + Ok(()) +} + +#[allow(unused_variables, unused_doc_comments)] +fn main() -> Result<(), Box> { + // ANCHOR: vm_config + let vm_config = SdkVmConfig::builder() + .system(Default::default()) + .rv32i(Default::default()) + .rv32m(Default::default()) + .io(Default::default()) + .build(); + // ANCHOR_END: vm_config + + /// to import example guest code in crate replace `target_path` for: + /// ``` + /// use std::path::PathBuf; + /// + /// let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf(); + /// path.push("guest"); + /// let target_path = path.to_str().unwrap(); + /// ``` + // ANCHOR: build + // 1. Build the VmConfig with the extensions needed. + let sdk = Sdk; + + // 2a. Build the ELF with guest options and a target filter. + let guest_opts = GuestOptions::default(); + let target_path = "your_path_project_root"; + let elf = sdk.build(guest_opts, target_path, &Default::default())?; + // ANCHOR_END: build + + // ANCHOR: transpilation + // 3. Transpile the ELF into a VmExe + let exe = sdk.transpile(elf, vm_config.transpiler())?; + // ANCHOR_END: transpilation + + // ANCHOR: execution + // 4. Format your input into StdIn + let my_input = SomeStruct { a: 1, b: 2 }; // anything that can be serialized + let mut stdin = StdIn::default(); + stdin.write(&my_input); + // ANCHOR_END: execution + + // ANCHOR: keygen + // 5. Set app configuration + let app_log_blowup = 2; + let app_fri_params = FriParameters::standard_with_100_bits_conjectured_security(app_log_blowup); + let app_config = AppConfig::new(app_fri_params, vm_config); + + // 6. Commit the exe + let app_committed_exe = sdk.commit_app_exe(app_fri_params, exe)?; + + // 7. Generate an AppProvingKey + let app_pk = Arc::new(sdk.app_keygen(app_config)?); + // ANCHOR_END: keygen + + // ANCHOR: evm_verification + // 8. Generate the aggregation proving key + const DEFAULT_PARAMS_DIR: &str = concat!(env!("HOME"), "/.openvm/params/"); + let halo2_params_reader = CacheHalo2ParamsReader::new(DEFAULT_PARAMS_DIR); + let agg_config = AggConfig::default(); + let agg_pk = sdk.agg_keygen(agg_config, &halo2_params_reader)?; + + // 9. Generate the SNARK verifier smart contract + let verifier = sdk.generate_snark_verifier_contract(&halo2_params_reader, &agg_pk)?; + + // 10. Generate an EVM proof + let proof = sdk.generate_evm_proof( + &halo2_params_reader, + app_pk, + app_committed_exe, + agg_pk, + stdin, + )?; + + // 11. Verify the EVM proof + let success = sdk.verify_evm_proof(&verifier, &proof); + assert!(success); + // ANCHOR_END: evm_verification + + Ok(()) +}