Skip to content

Commit

Permalink
build sdk example and link in doc
Browse files Browse the repository at this point in the history
  • Loading branch information
alv-around committed Dec 23, 2024
1 parent e88d71b commit 2643ae5
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 98 deletions.
116 changes: 19 additions & 97 deletions book/src/advanced-usage/sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,75 +8,35 @@ For more information on the basic CLI flow, see [Overview of Basic Usage](../wri

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.

```rust
use std::{fs, sync::Arc};
use eyre::Result;
use openvm::platform::memory::MEM_SIZE;
use openvm_build::{GuestOptions, TargetFilter};
use openvm_native_recursion::halo2::utils::CacheHalo2ParamsReader;
use openvm_sdk::{
config::{AggConfig, AppConfig, SdkVmConfig},
prover::AppProver,
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,
}
```rust,no_run,noplayground
{{ #include ../../../crates/sdk/examples/sdk.rs:dependencies }}
```

## Building and Transpiling a Program

The SDK provides lower-level control over the building and transpiling process.

```rust
// 1. Build the VmConfig with the extensions needed.
let sdk = Sdk;
let vm_config = SdkVmConfig::builder()
.system(Default::default())
.rv32i(Default::default())
.rv32m(Default::default())
.io(Default::default())
.build();

// 2a. Build the ELF with guest options and a target filter.
let target_path = "your_path_project_root";
let guest_opts = GuestOptions::default();
let target_filter = TargetFilter {
name: target_path.to_string(),
kind: "bin".to_string(),
};
let elf = sdk.build(guest_opts, target_path, &Some(target_filter))?;
// 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)?;

// 3. Transpile the ELF into a VmExe
let exe = sdk.transpile(elf, vm_config.transpiler())?;
```rust,no_run,noplayground
{{ #include ../../../crates/sdk/examples/sdk.rs:build }}
{{ #include ../../../crates/sdk/examples/sdk.rs:read_elf}}
{{ #include ../../../crates/sdk/examples/sdk.rs:transpilation }}
```

### Using `SdkVmConfig`

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 }}
```

## Running a Program

To run your program and see the public value output, you can do the following:

```rust
// 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);

// 5. Run the program
let output = sdk.execute(exe.clone(), vm_config.clone(), stdin.clone())?;
println!("public values output: {:?}", output);
```rust,no_run,noplayground
{{ #include ../../../crates/sdk/examples/sdk.rs:execution }}
```

### Using `StdIn`
Expand All @@ -90,62 +50,24 @@ The `StdIn` struct allows you to format any serializable type into a VM-readable

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
// 6. 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);

// 7. Commit the exe
let app_committed_exe = sdk.commit_app_exe(app_fri_params, exe)?;

// 8. Generate an AppProvingKey
let app_pk = Arc::new(sdk.app_keygen(app_config)?);

// 9a. Generate a proof
let proof = sdk.generate_app_proof(app_pk.clone(), app_committed_exe.clone(), stdin.clone())?;
// 9b. Generate a proof with an AppProver with custom fields
let app_prover = AppProver::new(app_pk.app_vm_pk.clone(), app_committed_exe.clone())
.with_program_name("test_program");
let proof = app_prover.generate_app_proof(stdin.clone());
```rust,no_run,noplayground
{{ #include ../../../crates/sdk/examples/sdk.rs:proof_generation }}
```

## Verifying 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
// 10. Verify your program
let app_vk = app_pk.get_vk();
sdk.verify_app_proof(&app_vk, &proof)?;
```rust,no_run,noplayground
{{ #include ../../../crates/sdk/examples/sdk.rs:verification }}
```

## End-to-end EVM Proof Generation and Verification

Generating and verifying an EVM proof is an extension of the above process.

```rust
// 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);
```rust,no_run,noplayground
{{ #include ../../../crates/sdk/examples/sdk.rs:evm_verification }}
```

> ⚠️ **WARNING**
Expand Down
130 changes: 130 additions & 0 deletions crates/sdk/examples/sdk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// 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},
prover::AppProver,
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<dyn std::error::Error>> {
// 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<dyn std::error::Error>> {
// 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);

// 5. Run the program
let output = sdk.execute(exe.clone(), vm_config.clone(), stdin.clone())?;
println!("public values output: {:?}", output);
// ANCHOR_END: execution

// ANCHOR: proof_generation
// 6. 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);

// 7. Commit the exe
let app_committed_exe = sdk.commit_app_exe(app_fri_params, exe)?;

// 8. Generate an AppProvingKey
let app_pk = Arc::new(sdk.app_keygen(app_config)?);

// 9a. Generate a proof
let proof = sdk.generate_app_proof(app_pk.clone(), app_committed_exe.clone(), stdin.clone())?;
// 9b. Generate a proof with an AppProver with custom fields
let app_prover = AppProver::new(app_pk.app_vm_pk.clone(), app_committed_exe.clone())
.with_program_name("test_program");
let proof = app_prover.generate_app_proof(stdin.clone());
// ANCHOR_END: proof_generation

// ANCHOR: verification
// 10. Verify your program
let app_vk = app_pk.get_vk();
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(())
}
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion crates/sdk/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ fn test_sdk_guest_build_and_transpile() {
// .with_options(vec!["--release"]);
;
let mut pkg_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_path_buf();
pkg_dir.push("example");
pkg_dir.push("guest");
let one = sdk
.build(guest_opts.clone(), &pkg_dir, &Default::default())
.unwrap();
Expand Down

0 comments on commit 2643ae5

Please sign in to comment.