|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +## Agent Quickstart (Read First) |
| 4 | + |
| 5 | +- Prefer targeted commands (`-p <crate>` or `cd <crate-dir>`) over workspace-wide runs; full workspace builds/tests are slow. |
| 6 | +- Use the CI-like build profile: `cargo build --profile fast -p <crate>` (note: `--cargo-profile` is a **nextest** flag, not a Cargo build flag). |
| 7 | +- Formatting requires nightly rustfmt: `cargo +nightly fmt --all` (stable `cargo fmt` will fail due to unstable options in `rustfmt.toml`). |
| 8 | +- Run tests with nextest when available: `cargo nextest run --cargo-profile=fast -p <crate>`; fallback: `cargo test -p <crate>`. |
| 9 | +- Speed knobs for local runs: `OPENVM_FAST_TEST=1` and `OPENVM_SKIP_DEBUG=1` (see below). |
| 10 | + |
| 11 | +## Project Overview |
| 12 | + |
| 13 | +OpenVM is a modular zkVM (zero-knowledge virtual machine) framework built on STARK proofs. It features a no-CPU architecture where all functionality (including RISC-V support) is implemented via composable extensions. The proof system is built on top of Plonky3 and the [stark-backend](https://github.com/openvm-org/stark-backend). |
| 14 | + |
| 15 | +## Build & Development Commands |
| 16 | + |
| 17 | +### Rust Toolchain |
| 18 | + |
| 19 | +- Rust 1.90.0 (stable), specified in `rust-toolchain.toml` |
| 20 | +- Nightly is only needed for: |
| 21 | + - `rustfmt` (unstable formatting options) |
| 22 | + - guest program compilation / some integration tests (requires `rust-src`, pinned nightly: `nightly-2025-08-02`) |
| 23 | + |
| 24 | +### Building |
| 25 | + |
| 26 | +```bash |
| 27 | +cargo build -p <crate> # debug build (targeted) |
| 28 | +cargo build --profile fast -p <crate> # optimized dev build (opt-level=1, incremental, good for testing) |
| 29 | +cargo build --release -p <crate> # release build |
| 30 | +``` |
| 31 | + |
| 32 | +### Formatting & Linting |
| 33 | + |
| 34 | +```bash |
| 35 | +cargo +nightly fmt --all # format (nightly required for unstable options) |
| 36 | +cargo +nightly fmt --all -- --check # check formatting |
| 37 | +cargo clippy -p openvm-circuit --all-targets --tests -- -D warnings # lint (targeted) |
| 38 | +cargo clippy --workspace --all-targets --tests -- -D warnings # lint (slower) |
| 39 | +cargo shear # check for unused dependencies (install via: cargo install cargo-shear) |
| 40 | +``` |
| 41 | + |
| 42 | +Formatting uses unstable options: `group_imports = "StdExternalCrate"`, `imports_granularity = "Crate"`. Configure IDE with `rust-analyzer.rustfmt.extraArgs: ["+nightly"]`. |
| 43 | + |
| 44 | +### Testing |
| 45 | + |
| 46 | +Tests use [cargo-nextest](https://nexte.st/). The `fast` cargo profile is used in CI for test runs (optimized dev build). |
| 47 | +Install with `cargo install cargo-nextest`. |
| 48 | +Note: in nextest, `--cargo-profile` selects the Cargo build profile; `--profile` selects the nextest runner profile (e.g. `heavy`). |
| 49 | + |
| 50 | +**Do not** run all workspace tests at once unless doing a final integration test. Build and test only specific crates during development. |
| 51 | + |
| 52 | +```bash |
| 53 | +# Run tests for a specific crate (most common pattern) |
| 54 | +cargo nextest run --cargo-profile=fast -p openvm-circuit # VM crate tests |
| 55 | +cargo nextest run --cargo-profile=fast -p openvm-rv32im-circuit # extension circuit tests |
| 56 | + |
| 57 | +# If nextest isn't installed, fall back to cargo test |
| 58 | +cargo test -p openvm-circuit |
| 59 | + |
| 60 | +# Run a single test by name |
| 61 | +cargo nextest run --cargo-profile=fast -p openvm-circuit -- test_name |
| 62 | + |
| 63 | +# Run tests in a working directory (as CI does) |
| 64 | +cd extensions/rv32im/circuit && cargo nextest run --cargo-profile=fast |
| 65 | + |
| 66 | +# Integration tests for extensions (requires nightly rust-src for guest program compilation) |
| 67 | +rustup component add rust-src --toolchain nightly-2025-08-02 |
| 68 | +cd extensions/rv32im/tests && cargo nextest run --cargo-profile=fast --profile=heavy |
| 69 | + |
| 70 | +# Run with parallelism (used in CI) |
| 71 | +cargo nextest run --cargo-profile=fast --features parallel |
| 72 | +``` |
| 73 | + |
| 74 | +### Environment Variables for Tests |
| 75 | + |
| 76 | +- `OPENVM_FAST_TEST=1`: CI sets this; may reduce test sizes |
| 77 | +- `OPENVM_SKIP_DEBUG=1`: Skips debug-mode constraint checking in `air_test` (faster CI runs) |
| 78 | + |
| 79 | +### Nextest Profiles |
| 80 | + |
| 81 | +- Default profile: standard parallel execution |
| 82 | +- `heavy` profile: `--test-threads=2`, used for integration tests that are memory-intensive |
| 83 | + |
| 84 | +## Architecture |
| 85 | + |
| 86 | +### Key Crate Hierarchy |
| 87 | + |
| 88 | +- `crates/vm` (`openvm-circuit`): VM circuit framework, system chips, trait definitions |
| 89 | +- `crates/sdk` (`openvm-sdk`): Developer SDK, proof aggregation, on-chain verifier generation |
| 90 | +- `crates/cli` (`cargo-openvm`): CLI for compile/execute/prove |
| 91 | +- `crates/toolchain/`: Transpiler, instructions, platform runtime, build tools |
| 92 | +- `crates/circuits/primitives`: Primitive chips/sub-chips reusable across circuits |
| 93 | +- `crates/circuits/mod-builder`: Modular arithmetic circuit builder |
| 94 | +- `crates/continuations`: Aggregation programs for multi-segment proving |
| 95 | + |
| 96 | +The main VM crate with architecture traits and system implementation is `openvm-circuit` in `crates/vm/`. |
| 97 | +See `docs/repo/layout.md` for full crate layout of the project. |
| 98 | + |
| 99 | +### Core Concepts |
| 100 | + |
| 101 | +The VM has **no CPU**. All instruction handling (including base RISC-V) is provided by **extensions**. Each extension has up to four components: |
| 102 | + |
| 103 | +| Component | Purpose | Example path | |
| 104 | +| ------------ | ------------------------------------------------------------- | ------------------------------- | |
| 105 | +| `circuit` | AIR constraints + chips for proving | `extensions/rv32im/circuit/` | |
| 106 | +| `transpiler` | Converts RISC-V ELF instructions to OpenVM instructions | `extensions/rv32im/transpiler/` | |
| 107 | +| `guest` | Rust library with intrinsics for guest programs | `extensions/rv32im/guest/` | |
| 108 | +| `tests` | Integration tests with guest programs in `programs/examples/` | `extensions/rv32im/tests/` | |
| 109 | + |
| 110 | +### Extension Framework (Three Traits) |
| 111 | + |
| 112 | +Each extension implements three traits, each independent and for a different phase: |
| 113 | + |
| 114 | +1. **`VmExecutionExtension`** - registers executors for new opcodes (runtime execution) |
| 115 | +2. **`VmCircuitExtension`** - registers AIRs (constraint system, determines verifying key) |
| 116 | +3. **`VmProverExtension`** - registers chips for trace generation (can vary by prover backend: CPU vs GPU) |
| 117 | + |
| 118 | +Extensions are composed into a `VmConfig` using the `#[derive(VmConfig)]` macro: |
| 119 | + |
| 120 | +```rust |
| 121 | +#[derive(VmConfig)] |
| 122 | +pub struct MyConfig { |
| 123 | + #[config] |
| 124 | + pub rv32im: Rv32ImConfig, // existing config (implements VmConfig) |
| 125 | + #[extension] |
| 126 | + pub my_ext: MyExtension, // new extension |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +### Chip Architecture (Adapter + Core pattern) |
| 131 | + |
| 132 | +Most chips follow the adapter/core split via the integration API: |
| 133 | + |
| 134 | +- **AdapterAir** handles system interactions (memory bus, execution bus, program bus) |
| 135 | +- **CoreAir** implements instruction-specific arithmetic constraints |
| 136 | +- Combined via `VmAirWrapper<AdapterAir, CoreAir>` and `VmChipWrapper<F, Filler>` |
| 137 | + |
| 138 | +Naming convention: `FooExecutor`, `FooFiller`, `FooCoreAir` for a chip named `Foo`. |
| 139 | + |
| 140 | +### Three Execution Modes |
| 141 | + |
| 142 | +1. **Pure execution** (`Executor<F>`): Runs program, returns final state. Uses precomputed function pointers. |
| 143 | +2. **Metered execution** (`MeteredExecutor<F>`): Tracks per-chip trace heights for segmentation. |
| 144 | +3. **Preflight execution** (`PreflightExecutor<F, RA>`): Generates execution records for trace generation. |
| 145 | + |
| 146 | +### Guest Programs |
| 147 | + |
| 148 | +Guest programs (run inside the VM) use `#![no_main]` / `#![no_std]` with `openvm::entry!(main)`: |
| 149 | + |
| 150 | +```rust |
| 151 | +#![cfg_attr(not(feature = "std"), no_main)] |
| 152 | +#![cfg_attr(not(feature = "std"), no_std)] |
| 153 | +openvm::entry!(main); |
| 154 | +pub fn main() { /* ... */ } |
| 155 | +``` |
| 156 | + |
| 157 | +Guest programs are compiled to RISC-V ELF, then transpiled to OpenVM instructions. They live in `programs/examples/` within test crates. |
| 158 | + |
| 159 | +### Integration Test Pattern |
| 160 | + |
| 161 | +```rust |
| 162 | +let elf = build_example_program_at_path(get_programs_dir!(), "program_name")?; |
| 163 | +let exe = VmExe::from_elf(elf, Transpiler::<F>::default() |
| 164 | + .with_extension(Rv32ITranspilerExtension) |
| 165 | + .with_extension(Rv32MTranspilerExtension) |
| 166 | + .with_extension(Rv32IoTranspilerExtension))?; |
| 167 | +let config = Rv32ImConfig::default(); |
| 168 | +air_test(Rv32ImCpuBuilder, config, exe); |
| 169 | +``` |
| 170 | + |
| 171 | +### Proof Field |
| 172 | + |
| 173 | +The primary field is **BabyBear** (31-bit prime field from Plonky3). Final on-chain verification uses BN254 via Halo2. |
| 174 | + |
| 175 | +### Versioning |
| 176 | + |
| 177 | +OpenVM uses semver naming but with ZK-specific semantics: patch versions preserve verifying key (`MultiStarkVerifyingKey`) compatibility. See `VERSIONING.md`. |
| 178 | + |
| 179 | +## CUDA/GPU Support |
| 180 | + |
| 181 | +CUDA is behind the `cuda` feature flag, disabled by default. Feature-gate non-CUDA-compatible code with `#[cfg(not(feature = "cuda"))]`. GPU prover extensions implement `VmProverExtension` separately (e.g., `Rv32ImGpuProverExt`). |
0 commit comments