-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[docs] user book: writing program (#1039)
* wip * update * Update book/src/getting-started/quickstart.md * Update book/src/getting-started/quickstart.md * update * move to write program * add partial quickstart * address comments * address some comments * wip
- Loading branch information
Showing
4 changed files
with
175 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
|
||
## Testing the program | ||
|
||
### Running on the host machine | ||
|
||
To test the program on the host machine, one can use the `std` feature: `cargo run --features std`. So for example to run the [fibonacci program](https://github.com/openvm-org/openvm/tree/main/benchmarks/programs/fibonacci): | ||
|
||
```bash | ||
printf '\xA0\x86\x01\x00\x00\x00\x00\x00' | cargo run --features std | ||
``` | ||
|
||
### Running with the OpenVM runtime | ||
|
||
*TODO*: point to how to install CLI | ||
|
||
First to build the guest program: | ||
``` | ||
cargo axiom build | ||
``` | ||
|
||
This compiles the guest program into an [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) that can be found at `target/riscv32im-risc0-zkvm-elf` directory. | ||
Next, a host program is needed to run the ELF with openvm runtime. This is where one can configure the openvm with different parameters. There are a few steps: | ||
|
||
```rust | ||
use openvm::transpiler::{openvm_platform::memory::MEM_SIZE, elf::Elf}; | ||
use openvm_circuit::arch::instructions::exe::OpenVmExe | ||
use openvm_circuit::arch::VmExecutor; | ||
use openvm_sdk::{config::SdkVmConfig, Sdk, StdIn}; | ||
|
||
let sdk = Sdk; | ||
// 1. Build the vm config with the extensions needed. | ||
// TODO: link to extension | ||
let vm_config = SdkVmConfig::builder() | ||
.system(Default::default()) | ||
.rv32i(Default::default()) | ||
.io(Default::default()) | ||
.build(); | ||
|
||
// 2. Load the ELF | ||
let elf = Elf::decode("your_path_to_elf", MEM_SIZE as u32)?; | ||
let exe = OpenVmExe::from_elf(elf, vm_config.transpiler()).unwrap(); | ||
|
||
// 3. Prepare the input data | ||
let my_input = SomeStruct; // anything that can be serialized | ||
let mut stdin = StdIn::default(); | ||
stdin.write(StdIn::from_bytes(my_input.as_bytes())); | ||
|
||
// 4. Run the program | ||
let executor = VmExecutor::<_, _>::new(vm_config); | ||
executor.execute(exe, stdin)?; | ||
``` | ||
Some example host programs can be found [here](https://github.com/openvm-org/openvm/tree/main/benchmarks/src/bin). | ||
|
||
### Generating to prove | ||
|
||
To generate a proof besides executing the program, instead of using `executor` above (step 4), do the following: | ||
```rust | ||
// Some additional configuration. | ||
let app_log_blowup = 2; | ||
let app_fri_params = FriParameters::standard_with_100_bits_conjectured_security(app_log_blowup); | ||
let app_config = AppConfig { ... }; | ||
|
||
// Keygen and prove | ||
let app_pk = sdk.app_keygen(app_config)?; | ||
let app_committed_exe = sdk.commit_app_exe(app_fri_params, exe)?; | ||
let mut app_prover = | ||
AppProver::new(app_pk.app_vm_pk.clone(), app_committed_exe) | ||
.with_program_name(program_name); | ||
let proof = app_prover.generate_app_proof(stdin); | ||
let app_vk = app_pk.get_vk(); | ||
sdk.verify_app_proof(&app_vk, &proof)?; | ||
``` | ||
|
||
## Troubleshooting | ||
|
||
todo | ||
|
||
## FAQ | ||
|
||
todo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,46 @@ | ||
# Quickstart | ||
|
||
In this section we will build and run a fibonacci program. | ||
|
||
## Setup | ||
|
||
First, create a new Rust project. | ||
|
||
```bash | ||
cargo init fibonacci | ||
``` | ||
|
||
Since we are using some nightly features, we need to specify the Rust version. Create a `rust-toolchain.toml` file with the following content: | ||
|
||
```toml | ||
[toolchain] | ||
channel = "nightly-2024-10-30" # "1.82.0" | ||
components = ["clippy", "rustfmt"] | ||
``` | ||
|
||
In `Cargo.toml`, add the following dependency: | ||
|
||
```toml | ||
openvm = { git = "https://github.com/openvm-org/openvm.git", features = ["std"] } | ||
``` | ||
|
||
Note that `std` is not enabled by default, so explicitly enabling it is required. | ||
|
||
## The fibonacci program | ||
|
||
The `read` function takes input from the stdin, and it also works with OpenVM runtime. | ||
```rust | ||
use openvm::io::read; | ||
|
||
fn main() { | ||
let n: u64 = read(); | ||
let mut a: u64 = 0; | ||
let mut b: u64 = 1; | ||
for _ in 0..n { | ||
let c: u64 = a.wrapping_add(b); | ||
a = b; | ||
b = c; | ||
} | ||
println!("{}", a); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,45 @@ | ||
# Writing a Program | ||
|
||
## Writing a guest program | ||
|
||
See the example [fibonacci program](https://github.com/openvm-org/openvm-example-fibonacci). | ||
|
||
The guest program should be a `no_std` Rust crate. As long as it is `no_std`, you can import any other | ||
`no_std` crates and write Rust as you normally would. Import the `openvm` library crate to use `openvm` intrinsic functions (for example `openvm::io::*`). | ||
|
||
The guest program also needs `#![no_main]` because `no_std` does not have certain default handlers. These are provided by the `openvm::entry!` macro. You should still create a `main` function, and then add `openvm::entry!(main)` for the macro to set up the function to run as a normal `main` function. While the function can be named anything when `target_os = "zkvm"`, for compatibility with std you should still name the function `main`. | ||
|
||
To support both `std` and `no_std` execution, the top of your guest program should have: | ||
|
||
```rust | ||
#![cfg_attr(not(feature = "std"), no_main)] | ||
#![cfg_attr(not(feature = "std"), no_std)] | ||
``` | ||
|
||
More examples of guest programs can be found in the [benchmarks/programs](https://github.com/openvm-org/openvm/tree/main/benchmarks/programs) directory. | ||
|
||
### no-std | ||
|
||
Although it's usually ok to use std (like in quickstart), not all std functionalities are supported (e.g., randomness). There might be unexpected runtime errors if one uses std, so it is recommended you develop no_std libraries if possible to reduce surprises. | ||
Even without std, `assert!` and `panic!` can work as normal. To use `std` features, one should add the following to `Cargo.toml` feature sections: | ||
```toml | ||
[features] | ||
std = ["openvm/std"] | ||
``` | ||
|
||
### Building and running | ||
|
||
*TODO*: point to CLI installation instructions | ||
|
||
## Handling I/O | ||
|
||
`openvm::io` provides a few functions to read and write data. | ||
|
||
`read` takes from stdin the next vec and deserialize it into a generic type `T`, so one should specify the type when calling it: | ||
```rust | ||
let n: u64 = read(); | ||
``` | ||
|
||
`read_vec` will just read a vector and return `Vec<u8>`. | ||
|
||
`reveal` |