Skip to content

Commit

Permalink
[docs] user book: writing program (#1039)
Browse files Browse the repository at this point in the history
* 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
luffykai authored Dec 15, 2024
1 parent 2088ad4 commit 705abe7
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 0 deletions.
80 changes: 80 additions & 0 deletions book/src/advanced-usage/testing-program.md
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
6 changes: 6 additions & 0 deletions book/src/getting-started/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@ TODO: how to install `cargo-openvm`.

## Build from source

```bash
git clone https://github.com/openvm-org/openvm.git
cd openvm
cargo install --force --path crates/cli
```

## Toolchain
45 changes: 45 additions & 0 deletions book/src/getting-started/quickstart.md
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);
}
```
44 changes: 44 additions & 0 deletions book/src/writing-apps/write-program.md
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`

0 comments on commit 705abe7

Please sign in to comment.