From 930dd54aa6cb8857e25836c4125e8cd56c133332 Mon Sep 17 00:00:00 2001 From: Zach Langley Date: Sun, 15 Dec 2024 21:26:42 -0500 Subject: [PATCH 01/27] docs/crates cleanup (#1062) * docs/crates cleanup * Apply suggestions from code review * chore: another warning * chore: spacing * chore: mv * chore: link benchmarks * chore: update --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- docs/crates/README.md | 3 +- docs/crates/benchmarks.md | 14 ++- docs/crates/stark.md | 145 ------------------------------ docs/crates/vm-extensions.md | 17 +--- docs/crates/vm.md | 167 +++++++++++++++++------------------ 5 files changed, 90 insertions(+), 256 deletions(-) delete mode 100644 docs/crates/stark.md diff --git a/docs/crates/README.md b/docs/crates/README.md index 5306cb62b6..1ea30bfdb1 100644 --- a/docs/crates/README.md +++ b/docs/crates/README.md @@ -2,7 +2,8 @@ Code-level guides to the crates in the repository. -- [`openvm-stark-backend`](./stark.md): Proof system backend - `openvm-circuit` - [VM Architecture and Chips](./vm.md) - [VM Extensions](./vm-extensions.md) +- `openvm-benchmarks` + - [Running Benchmarks](./benchmarks.md) diff --git a/docs/crates/benchmarks.md b/docs/crates/benchmarks.md index 8c1a4d8a8a..150bf00002 100644 --- a/docs/crates/benchmarks.md +++ b/docs/crates/benchmarks.md @@ -3,19 +3,15 @@ To run benchmarks, install python3 and run (from root of repo): ```bash -python ci/scripts/bench.py +python ci/scripts/bench.py --instance_type --memory_allocator ``` -where `` is a benchmark implemented as a rust binary (located in `src/bin` in a crate). Current benchmark options are: - -- `verify_fibair` -- `fibonacci` -- `regex` - in the `benchmarks` crate. - The benchmark outputs a JSON of metrics. You can process this into markdown with: +where `` is a benchmark implemented as a rust binary (located in `src/bin` in the `openvm-benchmarks` crate). +For local benchmarking, the `--instance_type` flag can take an arbitrary string. +The benchmark outputs a JSON of metrics. You can process this into markdown with: ```bash -python ci/scripts/metric_unify/main.py +python ci/scripts/metric_unify/main.py --aggregation-json ci/scripts/metric_unify/aggregation.json ``` Currently the processing is done automatically at the end of `bench.py`. The script automatically detects if you have a previously saved metric file for the same benchmark and includes the diff report in the output. diff --git a/docs/crates/stark.md b/docs/crates/stark.md deleted file mode 100644 index 20287a0956..0000000000 --- a/docs/crates/stark.md +++ /dev/null @@ -1,145 +0,0 @@ -# STARK Backend - -### Traits for Constraints - -An AIR in our system represents the set of constraints and metadata necessary to generate and verify a STARK proof. This is implemened through the following set of traits, which are split between core plonky3 and our `stark-backend` crate, which provides: - -- the ability to handle logUp / interactions -- the ability to handle separate cached traces - -#### From plonky3 - -```rust -pub trait BaseAir { - fn width(&self) -> usize; -} - -pub trait Air: BaseAir { - fn eval(&self, builder: &mut AB); -} - -pub trait AirBuilder { - type F: Field; // use for constants - type Var: Into + Copy + // .. concrete type of row values - type Expr: AbstractField + // .. most general expression for a constraint -} -``` - -The way `Air` works is that you always implement `Air` with respect to "**some** `AirBuilder` with some properties (additional trait bounds)". However in practice we implement `Air` for "**all** `AirBuilder`s with some properties". - -The struct implementing `Air` should be **stateless**. The struct should only contain configuration parameters necessary to determine the AIR constraints. - -```rust -pub trait BaseAirWithPublicValues: BaseAir { - fn num_public_values(&self) -> usize { - 0 - } -} - -// to use default impl: -impl BaseAirWithPublicValues for MyAir {} -``` - -#### From `openvm-stark-backend` - -For cached trace support: - -```rust -/// An AIR with 1 or more main trace partitions. -pub trait PartitionedBaseAir: BaseAir { - /// By default, an AIR has no cached main trace. - fn cached_main_widths(&self) -> Vec { - vec![] - } - /// By default, an AIR has only one private main trace. - fn common_main_width(&self) -> usize { - self.width() - } -} - -// to use default impl: -impl PartitionedBaseAir for MyAir {} -``` - -The common main trace is the "usual" main trace. All common main trace across all AIRs are committed into one commitment. Cached main are additional sections of main trace that are committed individually. Cached trace is not used in VM **except** by ProgramAir, where the OpenVM `Program` is committed into a dedicated commitment. - -```rust -pub trait Rap: Sync -where - AB: PermutationAirBuilder, -{ - fn eval(&self, builder: &mut AB); -} -``` - -We auto-implement `Rap` for any `Air where AB: InteractionBuilder`. The `Rap` adds in the extension field columns specified by interactions; note that these columns are not specified explicitly in plonky3 trace generation. - -![image](../../assets/rap.png) - -So when you implement `Air` you automatically implement `Rap` **for some** AirBuilder. - -The stark-backend uses three different concrete `AirBuilder` implementations: - -- `SymbolicRapBuilder>` -- `ProverConstraintFolder<'a, SC>` -- `DebugConstraintBuilder<'a, SC>` - -that depend on a `SC: StarkGenericConfig`. The `SC` specifies FRI proof system configuration parameters. - -```rust -pub trait AnyRap: - Rap>> // for keygen to extract fixed data about the RAP - + for<'a> Rap> // for prover quotient polynomial calculation - + for<'a> Rap> // for debugging - + BaseAirWithPublicValues> - + PartitionedBaseAir> { - // .. -} -``` - -This is an **auto-implemented** trait on any struct that implements `Air` for all AirBuilders the backend cares about above, for a **specific** `SC`. - -The backend wants to be able to prove multiple different AIRs together. So it must take a bunch of different `dyn AnyRap`. For some sizing reasons, instead it must take `Arc>` where `Arc` is a smart pointer to get around lifetimes and cloning issues. It is best to always use `Arc`, don't mix `Arc, Rc, Box` for the above purpose. - -### Traits for Trace Generation - -To generate a proof, we pair an AIR (represented by `Arc>`) with a set of methods to generate input traces in the `Chip` trait: - -```rust -pub trait Chip { - fn air(&self) -> Arc>; - - /// Generate all necessary input for proving a single AIR. - fn generate_air_proof_input(self) -> AirProofInput; - fn generate_air_proof_input_with_id(self, air_id: usize) -> (usize, AirProofInput) { - (air_id, self.generate_air_proof_input()) - } -} -``` - -The struct implementing `Chip` is stateful and stores **records**, which are the minimal amount of data necessary to generate the values in the trace matrix. A chip owns exactly one AIR. - -- We must have `Chip` generic in `SC` to avoid many issues with returning `Arc>`. -- If you have an enum of `Chip`s, you can derive `Chip` on the enum using proc-macro `#[derive(Chip)]` from `afs_derive`. The macro expects the enum to be generic in ``. - -#### `StarkGenericConfig` - -`StarkGenericConfig` is a complicated trait with deeply nested associated types. There are various typedefs to get associated types out of it. The most important is `Val`; this is the field `F` you want. Import `Val` from `afs_stark_backend::config::Val`, which is a re-export of `p3_uni_stark::Val`. - -Usual way to implement: - -```rust -impl Chip for MyChip> -where Val: PrimeField32 { - // .. -} -``` - -If you need `F` for some reason and the above doesn't work, another way is: - -```rust -impl Chip for MyChip -where Domain: PolynomialSpace { - // .. -} -``` diff --git a/docs/crates/vm-extensions.md b/docs/crates/vm-extensions.md index 5ce4ce54a1..ea15304ba7 100644 --- a/docs/crates/vm-extensions.md +++ b/docs/crates/vm-extensions.md @@ -12,7 +12,8 @@ pub trait VmExtension { } ``` -The `VmExtensionTrait` is a way to specify how to construct a collection of chips and all assign opcodes to be handled by them. This data is collected into a `VmInventory` struct, which is returned. +The `VmExtension` trait is a way to specify how to construct a collection of chips and all assign opcodes to be handled +by them. This data is collected into a `VmInventory` struct, which is returned. To handle previous chip dependencies necessary for chip construction and also automatic bus index management, we provide a `VmInventoryBuilder` api. @@ -123,7 +124,7 @@ The macro will also make two big enums: one that is an enum of the `Ext*::Execut The macro will then generate a `create_chip_complex` function. -For that we need to understand what `VmChipComplex` is: it replaces the role of the previous `VmChipSet` and consists of: +For that we need to understand what `VmChipComplex` consists of: - System chips - `VmInventory` @@ -152,19 +153,9 @@ function. What this does in words: For each extension's inventory generation, the `VmInventoryBuilder` is provided with a view of all current chips already inside the running chip complex. This means the inventory generation process is sequential in the order the extensions are specified, and each extension has borrow access to all chips constructed by any extension before it. -### `VirtualMachine` - -The top level structs of `VirtualMachine`, `VmExecutor`, `SegmentExecutor` remain almost entirely the same, but now has `VmConfig` as a generic: - -```rust -pub struct VirtualMachine; -``` - -TODO: discuss usage - ## Examples -The `extensions/` folder contains extensions implementing all non-system functionality via several extensions. For example, the `Rv32I`, `Rv32M`, and `Rv32Io` extensions implement `VmExtension` in [`openvm-rv32im-circuit`](../../extensions/rv32im/circuit/) and correspond to the RISC-V 32-bit base and multiplication instruction sets and an extension for IO, respectively. +The [`extensions/`](../../extensions/) folder contains extensions implementing all non-system functionality via custom extensions. For example, the `Rv32I`, `Rv32M`, and `Rv32Io` extensions implement `VmExtension` in [`openvm-rv32im-circuit`](../../extensions/rv32im/circuit/) and correspond to the RISC-V 32-bit base and multiplication instruction sets and an extension for IO, respectively. # Design Choices diff --git a/docs/crates/vm.md b/docs/crates/vm.md index d60049d8ea..ce873f37bf 100644 --- a/docs/crates/vm.md +++ b/docs/crates/vm.md @@ -2,36 +2,40 @@ ### `InstructionExecutor` Trait -We define an **instruction** to be a VM **opcode** combined with the **operands** to the opcode. Running the instrumented runtime for an opcode is encapsulated in the following trait: +We define an **instruction** to be an **opcode** combined with the **operands** for the opcode. Running the instrumented +runtime for an opcode is encapsulated in the following trait: ```rust pub trait InstructionExecutor { - /// Runtime execution of the instruction, if the instruction is - /// owned by the current instance. May internally store records of - /// this call for later trace generation. + /// Runtime execution of the instruction, if the instruction is owned by the + /// current instance. May internally store records of this call for later trace generation. fn execute( &mut self, instruction: Instruction, - from_state: ExecutionState, - ) -> Result, ExecutionError>; + from_state: ExecutionState, + ) -> Result>; } ``` +There is a `struct VmOpcode(usize)` to protect the global opcode `usize`, which must be globally unique for each opcode +supported in a given VM. + ### Chips for Opcode Groups -We divide all opcodes in the VM into groups, each of which is handled by a single **chip**. A chip should be a struct of type `C` and associated Air of type `A` which satisfy the following trait bounds: +Opcodes are partitioned into groups, each of which is handled by a single **chip**. A chip should be a struct of +type `C` and associated Air of type `A` which satisfy the following trait bounds: ```rust C: Chip + InstructionExecutor A: Air + BaseAir + BaseAirWithPublicValues ``` -Together, these perform the following functionalities: - -- **Keygen:** This is done via the `.eval()` function from `Air` -- **Trace Generation:** This is done by calling `.execute()` from `InstructionExecutor` which stores execution records and then `generate_air_proof_input()` from `Chip` which generates the trace using the corresponding records. +Together, these provide the following functionalities: -There is a `struct VmOpcode(usize)` to protect the global opcode usize. +- **Keygen:** Performed via the `Air::::eval()` function. +- **Trace Generation:** This is done by calling `InstructionExecutor::::execute()` which computes and stores + execution records and then `Chip::::generate_air_proof_input()` which generates the trace using the corresponding + records. ### Phantom Sub-Instructions @@ -53,103 +57,80 @@ pub trait PhantomSubExecutor { pub struct PhantomDiscriminant(pub u16); ``` -The `PhantomChip` maintains a map `FxHashMap>>` to handle different phantom sub-instructions. +The `PhantomChip` internally maintains a mapping from `PhantomDiscriminant` to `Box>>` to +handle different phantom sub-instructions. ### VM Configuration -**This section needs to be updated for extensions.** - -Each specific instantiation of a modular VM is defined in the following structs which handle VMs with/without continuations: +Each specific instantiation of a modular VM is defined by the following struct: ```rust -pub struct VirtualMachine { - pub config: VC, - /// Streams are shared between `ExecutionSegment`s and within each - /// segment shared with any chip(s) that handle hint opcodes - streams: Arc>>, - initial_memory: Option>, -} - -pub struct SingleSegmentVM { - pub config: VC, - _marker: PhantomData, +pub struct VirtualMachine { + pub engine: E, + pub executor: VmExecutor, VC>, } ``` -The `Streams` holds an `input_stream` and `hint_stream`: +The engine type `E` should be `openvm_stark_backend::engine::StarkEngine `and the VM config type `VC` is +`openvm_circuit::arch::config::VmConfig>`, shown below. ```rust -pub struct Streams { - pub input_stream: VecDeque>, - pub hint_stream: VecDeque, -} -``` - -Configuration of opcodes and memory is handled by: +pub trait VmConfig: Clone + Serialize + DeserializeOwned { + type Executor: InstructionExecutor + AnyEnum + ChipUsageGetter; + type Periphery: AnyEnum + ChipUsageGetter; -```rust -pub struct VC { - /// List of all executors except modular executors. - pub executors: Vec, - /// List of all supported modulus - pub supported_modulus: Vec, - - pub poseidon2_max_constraint_degree: usize, - pub memory_config: MemoryConfig, - pub num_public_values: usize, - pub max_segment_len: usize, - pub collect_metrics: bool, -} + /// Must contain system config + fn system(&self) -> &SystemConfig; + fn system_mut(&mut self) -> &mut SystemConfig; -pub struct MemoryConfig { - pub addr_space_max_bits: usize, - pub pointer_max_bits: usize, - pub clk_max_bits: usize, - pub decomp: usize, - pub persistence_type: PersistenceType, + fn create_chip_complex( + &self, + ) -> Result, VmInventoryError>; } ``` +A `VmConfig` has two associated types: `Executor` and `Periphery`. The `Executor` is typically an enum over chips that +are instruction executors, while `Periphery` is an enum for the chips that are not. +See [VM Extensions](./vm-extensions.md) for more details. + ### ZK Operations for the VM #### Keygen -TODO: Update for `VmChipComplex`. +Key generation is computed from the `VmConfig` describing the VM. The `VmConfig` is used to create the `VmChipComplex`, +which in turn provides the list of AIRs that are used in the proving and verification process. #### Trace Generation Trace generation proceeds from: -> `VirtualMachine.execute_and_generate_with_cached_program()` +> `VirtualMachine::execute_and_generate_with_cached_program()` -with subsets of functionality offered by `.execute()` and `execute_and_generate()`. The following struct tracks each continuation segment: +with subsets of functionality offered by `VirtualMachine::execute()` and `VirtualMachine::execute_and_generate()`. The +following struct tracks each continuation segment: ```rust -pub struct ExecutionSegment { - pub config: VC, - pub chip_set: VmChipSet, - - // The streams should be mutated in serial without thread-safety, - // but the `VmCoreChip` trait requires thread-safety. - pub streams: Arc>>, - - pub final_memory: Option>, - - pub cycle_tracker: CycleTracker, - /// Collected metrics for this segment alone. - /// Only collected when `config.collect_metrics` is true. - pub(crate) collected_metrics: VmMetrics, +pub struct ExecutionSegment> { + pub chip_complex: VmChipComplex, + pub final_memory: Option>, + pub air_names: Vec, + pub since_last_segment_check: usize, } ``` This will: -- Split the execution into `ExecutionSegment`s using `ExecutionSegment.execute_from_pc()`, which calls `ExecutionSegment.should_segment()` to segment online. Note that this creates a `VmChipSet` for each segment from `VmConfig.create_chip_set()`, where **each segment contains each chip**. It also passes all streams to all segments and runs the generation in serial. -- Generate traces for each segment by calling `VmChipSet.generate_proof_input()`, which iterates through all chips in order and calls `generate_proof_input()`. +- Split the execution into `ExecutionSegment`s using `ExecutionSegment.execute_from_pc()`, which calls + `ExecutionSegment.should_segment()` to segment online. Note that this creates a `VmChipComplex` for each segment from + `VmConfig.create_chip_set()`, where **each segment contains each chip**. It also passes all streams to all segments + and runs the generation in serial. +- Generate traces for each segment by calling `VmChipSet.generate_proof_input()`, which iterates through all chips in + order and calls `generate_proof_input()`. #### Proof Generation -This is done by calling `StarkEngine.prove()` on `ProofInput` created from each segment in `generate_proof_input()`. There is no SDK-level API for this in `VirtualMachine` at present. +Prove generation is performed by calling `StarkEngine.prove()` on `ProofInput` created from each segment in +`generate_proof_input()`. There is no SDK-level API for this in `VirtualMachine` at present. ## VM Integration API @@ -168,14 +149,21 @@ Most chips in the VM satisfy this, with notable exceptions being Keccak and Pose - `VmCoreChip>` - `VmCoreAir>` -[!WARNING] -The word **core** will be banned from usage outside of this context. +> [!WARNING] +> The word **core** will be banned from usage outside of this context. -Main idea: each VM chip will be created from an AdapterChip and a CoreChip. Analogously, the VM AIR is created from an AdapterAir and CoreAir so that the columns of the VM AIR are formed by concatenating the columns from the AdapterAir followed by the CoreAir. +Main idea: each VM chip is created from an `AdapterChip` and a `CoreChip`. Analogously, the VM AIR is created from an +`AdapterAir` and `CoreAir` so that the columns of the VM AIR are formed by concatenating the columns from the +`AdapterAir` followed by the `CoreAir`. -The AdapterChip is responsible for all interactions with the VM system: it owns interactions with the memory bus, program bus, execution bus. It will read data from memory and expose the data (but not intermediate pointers, address spaces, etc.) to the CoreChip and then write data provided by the CoreChip back to memory. +The `AdapterChip` is responsible for all interactions with the VM system: it owns interactions with the memory bus, +program bus, execution bus. It will read data from memory and expose the data (but not intermediate pointers, address +spaces, etc.) to the CoreChip and then write data provided by the CoreChip back to memory. -The AdapterAir does not see the CoreAir, but the CoreAir is able to see the AdapterAir, meaning that the same AdapterAir can be used with several CoreAir's. The AdapterInterface provides a way for CoreAir to provide expressions to be included in AdapterAir constraints -- in particular AdapterAir interactions can still involve CoreAir expressions. +The `AdapterAir` does not see the `CoreAir`, but the `CoreAir` is able to see the `AdapterAir`, meaning that the same +`AdapterAir` +can be used with several `CoreAir`'s. The AdapterInterface provides a way for `CoreAir` to provide expressions to be +included in `AdapterAir` constraints -- in particular `AdapterAir` interactions can still involve `CoreAir` expressions. Traits with their associated types and functions: @@ -192,24 +180,24 @@ pub trait VmAdapterChip { type ReadRecord: Send; /// Records generated by adapter after main instruction execution type WriteRecord: Send; - /// AdapterAir should not have public values + /// `AdapterAir` should not have public values type Air: BaseAir + Clone; - type Interface: VmAdapterInterface; + type Interface: VmAdapterInterface; fn preprocess( &mut self, memory: &mut MemoryChip, instruction: &Instruction, - ) -> Result<(Reads>, Self::ReadRecord)>; + ) -> Result<(>::Reads, Self::ReadRecord)>; fn postprocess( &mut self, memory: &mut MemoryChip, instruction: &Instruction, - from_state: ExecutionState, + from_state: ExecutionState, ctx: AdapterRuntimeContext>, read_record: &Self::ReadRecord, - ) -> Result<(ExecutionState, Self::WriteRecord)>; + ) -> Result<(ExecutionState, Self::WriteRecord)>; /// Populates `row_slice` with values corresponding to `record`. /// The provided `row_slice` will have length equal to `self.air().width()`. @@ -220,7 +208,10 @@ pub trait VmAdapterChip { row_slice: &mut [F], read_record: Self::ReadRecord, write_record: Self::WriteRecord, + aux_cols_factory: &MemoryAuxColsFactory, ); + + fn air(&self) -> &Self::Air; } pub trait VmAdapterAir: BaseAir { @@ -272,7 +263,7 @@ pub struct AdapterRuntimeContext> { pub writes: I::Writes, } -// For passing from CoreAir to AdapterAir with T = AB::Expr +// For passing from `CoreAir` to `AdapterAir` with T = AB::Expr pub struct AdapterAirContext> { /// Leave as `None` to allow the adapter to decide the `to_pc` automatically. pub to_pc: Option, @@ -282,8 +273,8 @@ pub struct AdapterAirContext> { } ``` -[!WARNING] -You do not need to implement `Air` on the struct you implement `VmAdapterAir` or `VmCoreAir` on. +> [!WARNING] +> You do not need to implement `Air` on the struct you implement `VmAdapterAir` or `VmCoreAir` on. ### Creating a Chip from Adapter and Core @@ -366,4 +357,4 @@ pub struct ImmInstruction { pub opcode: T, pub imm: T } -``` \ No newline at end of file +``` From c9fc62368d498486a7ead66a444e6bd3e9aaa3e2 Mon Sep 17 00:00:00 2001 From: Golovanov399 Date: Mon, 16 Dec 2024 05:38:41 +0300 Subject: [PATCH 02/27] Turn MathJax on, replace $...$ with \\(...\\) (#1067) --- book/book.toml | 4 +--- book/src/custom-extensions/algebra.md | 11 +++++------ book/src/custom-extensions/ecc.md | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/book/book.toml b/book/book.toml index 2e20f98145..c1c5a8953f 100644 --- a/book/book.toml +++ b/book/book.toml @@ -7,6 +7,4 @@ title = "OpenVM Book" [output.html] site-url = "https://book.openvm.dev/" -additional-head = [ - "" -] \ No newline at end of file +mathjax-support = true \ No newline at end of file diff --git a/book/src/custom-extensions/algebra.md b/book/src/custom-extensions/algebra.md index b5b00aea3e..47585c97be 100644 --- a/book/src/custom-extensions/algebra.md +++ b/book/src/custom-extensions/algebra.md @@ -1,6 +1,6 @@ # OpenVM Algebra -The OpenVM Algebra extension provides tools to create and manipulate modular arithmetic structures and their complex extensions. For example, if $p$ is prime, OpenVM Algebra can handle modular arithmetic in $\mathbb{F}_p$​ and its quadratic extension fields $\mathbb{F}_p[x]/(x^2 + 1)$. +The OpenVM Algebra extension provides tools to create and manipulate modular arithmetic structures and their complex extensions. For example, if \\(p\\) is prime, OpenVM Algebra can handle modular arithmetic in \\(\mathbb{F}_p\\)​ and its quadratic extension fields \\(\mathbb{F}_p[x]/(x^2 + 1)\\). The functional part is provided by the `openvm-algebra-guest` crate, which is a guest library that can be used in any OpenVM program. The macros for creating corresponding structs are in the `openvm-algebra-moduli-setup` and `openvm-algebra-complex-macros` crates. @@ -8,7 +8,7 @@ The functional part is provided by the `openvm-algebra-guest` crate, which is a - `IntMod` trait: Defines the type `Repr` and constants `MODULUS`, `NUM_LIMBS`, `ZERO`, and `ONE`. It also provides basic methods for constructing a modular arithmetic object and performing arithmetic operations. - - `Repr` typically is `[u8; NUM_LIMBS]`, representing the number’s underlying storage. + - `Repr` typically is `[u8; NUM_LIMBS]`, representing the number's underlying storage. - `MODULUS` is the compile-time known modulus. - `ZERO` and `ONE` represent the additive and multiplicative identities, respectively. - Constructors include `from_repr`, `from_le_bytes`, `from_be_bytes`, `from_u8`, `from_u32`, and `from_u64`. @@ -21,7 +21,6 @@ The functional part is provided by the `openvm-algebra-guest` crate, which is a To [leverage](./overview.md) compile-time known moduli for performance, you declare, initialize, and then set up the arithmetic structures: 1. **Declare**: Use the `moduli_declare!` macro to define a modular arithmetic struct. This can be done multiple times in various crates or modules: - ```rust moduli_declare! { Bls12_381Fp { modulus = "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab" }, @@ -42,7 +41,7 @@ moduli_init! { This step enumerates the declared moduli (e.g., `0` for the first one, `1` for the second one) and sets up internal linkage so the compiler can generate the appropriate RISC-V instructions associated with each modulus. -3. **Setup**: At runtime, before performing arithmetic, a setup instruction must be sent to ensure security and correctness. For the $i$-th modulus, you call `setup_()` (e.g., `setup_0()` or `setup_1()`). Alternatively, `setup_all_moduli()` can be used to handle all declared moduli. +3. **Setup**: At runtime, before performing arithmetic, a setup instruction must be sent to ensure security and correctness. For the \\(i\\)-th modulus, you call `setup_()` (e.g., `setup_0()` or `setup_1()`). Alternatively, `setup_all_moduli()` can be used to handle all declared moduli. **Summary**: - `moduli_declare!`: Declares modular arithmetic structures and can be done multiple times. @@ -51,7 +50,7 @@ This step enumerates the declared moduli (e.g., `0` for the first one, `1` for t ## Complex field extension -Complex extensions, such as $\mathbb{F}_p[x]/(x^2 + 1)$, are defined similarly using `complex_declare!` and `complex_init!`: +Complex extensions, such as \\(\mathbb{F}_p[x]/(x^2 + 1)\\), are defined similarly using `complex_declare!` and `complex_init!`: 1. **Declare**: @@ -154,4 +153,4 @@ supported_modulus = ["1157920892373161954235709850086879078532699846656405640394 supported_modulus = ["115792089237316195423570985008687907853269984665640564039457584007908834671663"] ``` -The `supported_modulus` parameter is a list of moduli that the guest program will use. They must be provided in decimal format in the `.toml` file. \ No newline at end of file +The `supported_modulus` parameter is a list of moduli that the guest program will use. They must be provided in decimal format in the `.toml` file. diff --git a/book/src/custom-extensions/ecc.md b/book/src/custom-extensions/ecc.md index 6e37c13fc1..9436d6b4a8 100644 --- a/book/src/custom-extensions/ecc.md +++ b/book/src/custom-extensions/ecc.md @@ -38,7 +38,7 @@ sw_declare! { } ``` -Each declared curve must specify the `mod_type` (implementing `IntMod`) and a constant `b` for the Weierstrass curve equation $y^2 = x^3 + b$. +Each declared curve must specify the `mod_type` (implementing `IntMod`) and a constant `b` for the Weierstrass curve equation \\(y^2 = x^3 + b\\). This creates `Bls12_381G1Affine` and `Bn254G1Affine` structs which implement the `Group` and `WeierstrassPoint` traits. The underlying memory layout of the structs uses the memory layout of the `Bls12_381Fp` and `Bn254Fp` structs, respectively. 2. **Init**: Called once, it enumerates these curves and allows the compiler to produce optimized instructions: From 979a4087cff579c5425517d70ea8fd93227feef8 Mon Sep 17 00:00:00 2001 From: Zach Langley Date: Sun, 15 Dec 2024 21:39:55 -0500 Subject: [PATCH 03/27] docs: Add Continuation VM doc to continuations.md (#1055) * docs: Add Continuation VM doc to continuations.md * Update language * comments * fix agg-2 image --- assets/agg-2.png | Bin 0 -> 88297 bytes assets/agg.png | Bin 0 -> 91907 bytes docs/specs/aggregation.md | 103 ------------------ docs/specs/continuations.md | 205 ++++++++++++++++++++++++++++++++++-- 4 files changed, 199 insertions(+), 109 deletions(-) create mode 100644 assets/agg-2.png create mode 100644 assets/agg.png delete mode 100644 docs/specs/aggregation.md diff --git a/assets/agg-2.png b/assets/agg-2.png new file mode 100644 index 0000000000000000000000000000000000000000..11fcc8de813fa0d824192b83a52f51783baa56f0 GIT binary patch literal 88297 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 z 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

cWMY99%wvNbo!VQVgQKrJS9ejle2U`I7<1 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 G`~LuDY1+^L literal 0 HcmV?d00001 diff --git a/assets/agg.png b/assets/agg.png new file mode 100644 index 0000000000000000000000000000000000000000..2e03723445cb7652f7ad02e7a32e07c90fbfbbf0 GIT binary patch literal 91907 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 - -## Static Aggregation - -Assume that we have a static (i.e., known ahead of time) list `allowed_vks` of STARK verifying keys (unique identifiers for STARK circuits). - -Suppose we have a variable-length list of proofs `proofs` where `proofs.len()` is independent of `allowed_vks.len()`. The goal is to produce a single STARK proof that asserts that `proofs[i]` verifies with respect verifying key `vk[i]` where `allowed_vks` contains `vk[i]`, for all `i`. Additionally, there should be the optionality to store a commitment to the ordered list of `(hash(vk[i]), public_values[i])` where `public_values[i]` are the public values of proof `i`. - -We aggregate `proofs` using a tree-structure. The arity of the tree can be adjusted for performance; -by default it is 2. The height of the tree is variable and equal to $\lceil \log{n} \rceil$ where $n$ is the number of proofs and the base of logarithm is the arity. - -We distinguish between three types of nodes in the tree: - -- Leaf -- Internal -- Root - -Each node of the tree will be a STARK VM circuit, _without continuations_, proving a VM program that runs STARK verification on an `arity` number of proofs. We make the distinction that each type of node in the tree may be a **different** VM circuit, meaning with different chip configurations. All VM circuits must support the opcodes necessary to do STARK verification. - -For each node type, a different program is run in the VM circuit: - -- Leaf: the program verifies `<=leaf_arity` proofs, where each proof is verified with respect to one of the verification keys in `allowed_vks`. The leaf program will have the proof, public values, and verifying keys of each proof in program memory, and the program can be augmented with additional checks (for example, state transitions checks are necessary for continuations). -- Internal: the program verifies `<= internal_arity` proofs, where all proofs are verified with respect to the same verifying key. This verifying key is either that of a leaf circuit or that of an internal circuit (the present circuit itself). The circuit cannot know the verifying key of itself, so to avoid a circular dependency, the hash of the verifying key is made a public value. -- Root: this program _may_ just be the same as the Internal program, but for the purposes of optimizing [on-chain aggregation](#on-chain-aggregation), there is the possiblity for it to be different. The root program verifies `<= root_arity` proofs, where all proofs are of the internal circuit. Note that `root_arity` may be `1`. - -### STARK Configurations - -Before proceeding, we must discuss the topic of STARK configurations: any STARK proof depends on at least three configuration parameters: - -- `F` the base field of the AIRs -- `EF` the extension field of the AIRs used for challenge values -- the hash function used for the FRI PCS. This hash function must be able to hash `F` and `EF` elements, where elements can be packed before hashing. - -For all Leaf and Internal circuits [above](#static-aggregation), we use an **Inner Config**. Example Inner Configs are: - -- `F` is BabyBear, `EF` is quartic extension of BabyBear, hash is BabyBearPoseidon2 -- `F` is BabyBear, `EF` is quartic extension of BabyBear, hash is SHA256 -- `F` is Mersenne31, `EF` is quartic extension of Mersenne31, hash is Mersenne31Poseidon2 -- `F` is Mersenne31, `EF` is quartic extension of Mersenne31, hash is SHA256 - -We discuss considerations for choice of hash below. - -On the other hand, the Root circuit will use an **Outer Config**. Example Outer Configs are: - -- `F` is BabyBear, `EF` is quartic extension of BabyBear, hash is BN254FrPoseidon2 (or BN254FrPoseidon1) -- ~~`F` is BabyBear, `EF` is quartic extension of BabyBear, hash is SHA256~~ -- `F` is BN254Fr, `EF` is BN254Fr, hash is BN254FrPoseidon2 (or BN254FrPoseidon1) -- ~~`F` is BN254Fr, `EF` is BN254Fr, hash is SHA256~~ -- Analogous configurations with BabyBear replaced with Mersenne31. - -To explain, since `31 * 8 < 254`, eight BabyBear field elements can be packed together and embedded (non-algebraically) into a BN254Fr field element. In this way BN254FrPoseidon2 can be used to hash BabyBear elements. - -The choice of hash function in the Outer Config only affects what hash must be verified in the Halo2 circuit for on-chain aggregation (see [below](#on-chain-aggregation)). For performance, it is therefore always better to use BN254FrPoseidon2 for the Outer Config. - -### On-chain Aggregation - -The Root circuit above is the last STARK circuit, whose single proof will in turn verify all initial `proofs`. Due to the size of STARK proofs, for on-chain verification we must wrap this proof inside an elliptic curve based SNARK proof so that the final SNARK proof can be verified on-chain (where on-chain currently means within an Ethereum Virtual Machine). - -We create a Halo2 circuit that verifies any proof of the Root STARK circuit. This is a non-universal circuit whose verifying key depends on the specific STARK circuit to be verified. The majority of the verification logic can be code-generated into the `halo2-lib` eDSL which uses a special vertical custom gate specialized for cheap on-chain verification cost. There are two main performance considerations: - -#### 1. Hash - -To perform FRI verification in the Halo2 circuit, the circuit must constrain calculations of STARK Outer Config hashes. As mentioned above, this hash will be BN254FrPoseidon2. The constraints for this hash can either be implemented directly using the `halo2-base` vertical gate, or with a custom gate. The custom gate will be faster but with higher verification cost. There are two approaches to consider: - -Approach A - -- Use a single Halo2 circuit with only thinnest `halo2-base` vertical gate to verify the Root STARK circuit proof. - -Approach B - -- Use a first Halo2 circuit with custom gate for BN254FrPoseidon2 to verify the Root STARK circuit proof. -- Use a second Halo2 circuit with only the thinnest `halo2-base` vertical gate to verify the previous Halo2 circuit. - -Approach B is likely better, provided that the time to generate both proofs is faster than the time to generate the single proof in Approach A. - -#### 2. Outer Config Base Field - -The Outer Config base field `F` can be either a 31-bit field or BN254Fr. - -When `F` is 31-bit field: - -- For FRI folding and other arithmetic in STARK verification, the Halo2 circuit must perform BabyBear prime field arithmetic and extension field arithmetic inside the halo2 circuit. These are non-native arithmetic operations. - -When `F` is BN254Fr and `EF` is BN254Fr: - -- Halo2 circuit only needs to perform native field arithmetic inside the halo2 circuit. -- The Root STARK circuit must now perform non-native BabyBear field arithmetic and extension field arithmetic inside the STARK to support the verification of the STARKs with the Inner Config. This non-native arithmetic is still expected to be much faster in the STARK than in Halo2, but the added chip complexity may also increase verifier cost in the Halo2 circuit. -- If the Inner Config hash is BabyBearPoseidon2, now the Root STARK circuit must constrain BabyBearPoseidon2 inside a circuit with base field BN254Fr. This is definitely not efficient. **Therefore it is not possible for the Outer Config base field to be BN254Fr if the Inner Config hash is BabyBearPoseidon2.** -- This Outer Config is only possible if the Inner Config hash is a hash that does not depend on the native field (e.g., SHA256 or Blake2b or Blake3). - - **Observation:** even if the hash used for the Internal circuit is SHA256, the Leaf circuit can still be proven using BabyBearPoseidon2. Likewise, it is even possible to have the Internal circuits use BabyBearPoseidon2 at higher depths in the tree (away from the root). The only requirement is that the last Internal circuit proof, which will be verified by the Root circuit, needs to be proven with SHA256 as the hash. - -TODO: to determine which Outer Config is best, we will: - -- Instrument the cost of non-native small field arithmetic in the Halo2 circuit. -- Benchmark an aggregation VM with Inner Config hash BabyBearPoseidon2 proven over BabyBearPoseidon2 versus one with Inner Config hash SHA256 proven over SHA256. - -## Dynamic Aggregation - -TODO diff --git a/docs/specs/continuations.md b/docs/specs/continuations.md index f45c847eaf..65f518fe65 100644 --- a/docs/specs/continuations.md +++ b/docs/specs/continuations.md @@ -1,3 +1,201 @@ +# Aggregation + +Given the execution segments of a program, each segment will be proven in parallel within a **Application VM** (App VM). +These proofs are subsequently aggregated into an aggregation tree by a **leaf aggregation +program**. This segment aggregation program runs inside _a different VM_, referred to as the **Aggregation VM** (Agg +VM), which operates without continuations enabled. + +The aggregation program takes a variable number of consecutive segment proofs and consolidates them into a single proof +that captures the entire range of segments. + +![Aggregation example](../../assets/agg.png) + +The following figure shows that the shape of the aggregation tree is not fixed. + +![Another aggregation example](../../assets/agg-2.png) + +We will now give an overview of the steps of the overall aggregation, starting from the final smart contract verifier +and going down to the application proof. + +## Smart Contract + +A smart contract is deployed by on-chain, which provides a function to verify a Halo2 proof. + +## Static Verifier Wrapper + +The **Static Verifier Wrapper** is a Halo2 SNARK verifier circuit generated by OpenVM. The static verifier +wrapper is determined by the following parameters: + +* Number of public values +* The Aggregation VM chip constraints (but **not** the App VM chips) + +## Continuation Verifier + +The continuation verifier is a Halo2 circuit (static verifier) together with some single segment VM circuits (Agg VM). +The continuation verifier depends on the specific circuit design of the static verifier and Aggregation VM, as well as +the number of user public values, but it does not depend on the App VM's circuit. + +The continuation verifier ensures that a set of ordered App VM segment proofs collectively validates the execution of a +specific `VmExe` on a specific App VM, with given inputs. + +### Static Verifier + +The Static Verifier is a Halo2 verifier circuit that validates a Root VM Verifier proof and exposes its public values. + +Static Verifier Requirements: + +* The height of each trace is fixed. +* Trace heights are in a descending order. + +Public Values Exposed: + +* Exe commit encoded in Bn254 +* Leaf commit encoded in Bn254 +* User public values in BabyBear + +Parameters (which could result in a different circuit): + +* Number of public values (from upper stream) +* k in Halo2 +* Determines the number of columns of the circuit. + +* Number of public values (from upstream) +* k in Halo2 (determines the number of columns in the circuit) +* Root VM verifier + * VK (including the heights of all traces) + * Root verifier program commitment + +### Aggregation VM + +The Aggregation VM organizes proofs into an aggregation tree, where nodes include: + +* Root VM Verifier +* Internal VM Verifier +* Leaf VM Verifier + +Each node can have an arbitrary number of children, enabling flexible tree structures to optimize for cost reduction +(more children) or latency reduction (less children) during proving. + +### Root VM Verifier + +The Root VM Verifier is proven in RootConfig, using commitments via Bn254Poseidon2. All traces are padded to a constant +height for verification. + +The Root VM Verifier verifies 1 or more proofs of: + +- Leaf VM Verifier +- Internal VM Verifier + +In practice, Root VM verifier only verifies one proof to guarantee constant heights. + +Logical Input: + +* Root input + +Cached Trace Commit: + +* `ProgramAir`: commits the root verifier program + +Public values: + +* `RootVmVerifierPvs` + * Note: exe_commit is the commitment of the executable. The way to compute it can be found here. + +Parameters: + +* For circuit: + * Root VM Config +* For root verifier program: + * Root FRI parameters to compute its commitment + * Internal verifier circuit \+ program commitment + * Leaf verifier circuit \+ program commitment + +### Internal VM Verifier + +The Internal VM Verifier validates one or more proofs of: + +* Leaf VM Verifier +* Internal VM Verifier + +Logical Input: + +* `InternalVmVerifierInput` + +Cached Trace Commit: + +* `ProgramAir`: commits the internal verifier program. `agg_vm_pk` contains it. + +Public values: + +* `InternalVmVerifierPvs` + +Parameters: + +* For circuit: + * Internal VM Config +* For root verifier program: + * Internal FRI parameters to compute its commitment + * Internal verifier circuit \+ program commitment + * Leaf verifier circuit \+ program commitment + +### Leaf VM Verifier + +Verify 1 or more proofs of: + +* segment circuits + +Logical Input: + +* `LeafVmVerifierInput` + +Cached Trace Commit: + +* ProgramAir: commits the leaf verifier program. The leaf verifier program commits . + +Public values: + +* `VmVerifierPvs` + +Parameters: + +* For circuit: + * Leaf VM Config +* For leaf verifier program: + * It’s not a part of the Continuation Verifier because it depends on the VK of the App VM and it doesn’t affect the VK + of the static verifier. + +### App VM + +App VM executes an executable with inputs and returns a list of segment proofs. + +## Segment + +Logical Input: + +* App VM input stream + +Cached Trace Commit: + +* ProgramAir: commits the program the App VM executed. + +Public values: + +* `VmConnectorPvs` +* `MemoryMerklePvs` + +User Public Values: + +* Up to `num_public_values` public values in a dedicated memory space. These public values are not exposed as public + values of segment circuits, but will be exposed by the final proof. + +Parameters: + +* Number of public values (from upstream) +* For circuit: + * App VM Config +* For App program: + * App FRI parameters to compute its commitment. + # Continuations Our high-level continuations framework follows previous standard designs (Starkware, Risc0), but uses a novel persistent @@ -82,9 +280,4 @@ and has the following interactions on the MERKLE_BUS**(-1, 0, (as - AS_OFFSET) \* 2^L, node_label, hash_final)** It receives `values` from the `MEMORY_BUS` and constrains `hash = compress(values, 0)` via the `POSEIDON2_DIRECT_BUS`. - -## Aggregation - -Given the execution segments of a program, we will prove each segment in a VM segment circuit in parallel. These proofs will then be aggregated in an [aggregation tree](../aggregation.md) by a segment aggregation program. This segment aggregation program will be run inside **a different VM** which **does not** have continuations turned on. The latter VM is called an **Aggregation VM**. - -See [Aggregation](../aggregation.md) for more details. +The aggregation program takes a variable number of consecutive segment proofs and consolidates them into a single proof From a82377326a59314ed35926538002760754bb386f Mon Sep 17 00:00:00 2001 From: stephenh-axiom-xyz Date: Sun, 15 Dec 2024 22:11:42 -0500 Subject: [PATCH 04/27] docs: SDK and CLI usage for proving and verifying (#1051) * docs: SDK and CLI usage for proving and verifying * docs: overview * docs: more updates * Update book/src/advanced-usage/sdk.md * chore: delete unused * chore: remove link * docs: more SDK + CLI stuff * docs: stdin section --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/advanced-usage/sdk.md | 131 +++++++++++++++++++++ book/src/advanced-usage/testing-program.md | 60 +--------- book/src/writing-apps/compile.md | 15 +++ book/src/writing-apps/onchain-verify.md | 28 +++++ book/src/writing-apps/overview.md | 76 ++++++++++++ book/src/writing-apps/prove.md | 43 +++++++ book/src/writing-apps/testing.md | 1 - book/src/writing-apps/verify.md | 30 ++++- crates/toolchain/build/src/lib.rs | 14 +++ 9 files changed, 337 insertions(+), 61 deletions(-) create mode 100644 book/src/advanced-usage/sdk.md delete mode 100644 book/src/writing-apps/testing.md diff --git a/book/src/advanced-usage/sdk.md b/book/src/advanced-usage/sdk.md new file mode 100644 index 0000000000..51a0145de3 --- /dev/null +++ b/book/src/advanced-usage/sdk.md @@ -0,0 +1,131 @@ +# Using the SDK + +While the CLI provides a convenient way to build, prove, and verify programs, you may want more fine-grained control over the process. The OpenVM Rust SDK allows you to customize various aspects of the workflow programmatically. + +For more information on the basic CLI flow, see [Overview of Basic Usage](./overview.md). Writing a guest program is the same as in the CLI. + +## 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. + +```rust +use openvm::{platform::memory::MEM_SIZE, transpiler::elf::Elf}; +use openvm_circuit::arch::instructions::exe::OpenVmExe +use openvm_circuit::arch::VmExecutor; +use openvm_sdk::{config::SdkVmConfig, Sdk, StdIn}; + +let sdk = Sdk; + +#[derive(Serialize, Deserialize)] +pub struct SomeStruct { + pub a: u64, + pub b: u64, +} +``` + +## 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 vm_config = SdkVmConfig::builder() + .system(Default::default()) + .rv32i(Default::default()) + .io(Default::default()) + .build(); + +// 2a. Build the ELF with guest options and a target filter. +let guest_opts = GuestOptions::default().with_features(vec!["parallel"]); +let target_filter = TargetFilter::default().with_kind("bin".to_string()); +let elf = sdk.build(guest_opts, "your_path_project_root", &target_filter)?; +// 2b. Load the ELF from a file +let elf = Elf::decode("your_path_to_elf", MEM_SIZE as u32)?; + +// 3. Transpile the ELF into a VmExe +let exe = sdk.transpile(elf, vm_config.transpiler())?; +``` + +### 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. + +## 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; // anything that can be serialized +let mut stdin = StdIn::default(); +stdin.write(&my_input); + +// 5. Run the program +let output = sdk.execute(exe, vm_config, input)?; +``` + +### 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** +> 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 + +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 = sdk.app_keygen(app_config)?; + +// 9a. Generate a proof +let proof = sdk.generate_app_proof(app_pk, app_committed_exe, stdin)?; +// 9b. Generate a proof with an AppProver with custom fields +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); +``` + +## 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)?; +``` + +## 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 = Halo2ParamsReader::new(DEFAULT_PARAMS_DIR); +let agg_config = AggConfig::default(); +let agg_pk = sdk.agg_keygen(agg_config, &halo2_params_reader)?; + +// 12. Generate an EVM proof +let proof = sdk.generate_evm_proof(&halo2_params_reader, app_pk, app_committed_exe, agg_pk, stdin)?; + +// 13. Generate the SNARK verifier contract +let verifier = sdk.generate_snark_verifier_contract(&halo2_params_reader, &agg_pk)?; + +// 14. Verify the EVM proof +sdk.verify_evm_proof(&verifier, &proof)?; +``` + +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 [onchain verify](../writing-apps/onchain-verify.md) doc. + +> ⚠️ **WARNING** +> `cargo openvm setup` requires very large amounts of computation and memory (~200 GB). diff --git a/book/src/advanced-usage/testing-program.md b/book/src/advanced-usage/testing-program.md index 1db3d71521..afd89ad955 100644 --- a/book/src/advanced-usage/testing-program.md +++ b/book/src/advanced-usage/testing-program.md @@ -10,65 +10,7 @@ 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)?; -``` +For more information on building, transpiling, running, generating proofs, and verifying proofs with the CLI, see the [CLI](../writing-apps/overview.md)section. To do the same with the SDK, see the [SDK](sdk.md) section. ## Troubleshooting diff --git a/book/src/writing-apps/compile.md b/book/src/writing-apps/compile.md index f3b18f2570..cdcfcb0c6b 100644 --- a/book/src/writing-apps/compile.md +++ b/book/src/writing-apps/compile.md @@ -7,3 +7,18 @@ First let's define some key terms used in cross-compilation: There are multiple things happening in the `cargo openvm build` command as in the section [here](./write-program.md). In short, this command compiles on host to an executable for guest target. It first compiles the program normally on your *host* platform with RISC-V and then transpiles it to a different target. See here for some explanation of [cross-compilation](https://rust-lang.github.io/rustup/cross-compilation.html). Right now we use `riscv32im-risc0-zkvm-elf` target which is available in the [Rust toolchain](https://doc.rust-lang.org/rustc/platform-support/riscv32im-risc0-zkvm-elf.html), but we will contribute an OpenVM target to Rust in the future. + +## Running a Program + +After building and transpiling a program, you can execute it using the `run` command. The `run` command has the following arguments: + +```bash +cargo openvm run + --exe + --config + --input +``` + +If `--exe` and/or `--config` are not provided, the command will search for these files in `./openvm/app.vmexe` and `./openvm.toml` respectively. If `./openvm.toml` is not present, a default configuration will be used. + +If your program doesn't require inputs, you can (and should) omit the `--input` flag. diff --git a/book/src/writing-apps/onchain-verify.md b/book/src/writing-apps/onchain-verify.md index ea369b8c26..60a0398552 100644 --- a/book/src/writing-apps/onchain-verify.md +++ b/book/src/writing-apps/onchain-verify.md @@ -1 +1,29 @@ # Onchain Verification + +## Generating the Aggregation Proving Key and EVM Verifier Contract + +The workflow for generating an end-to-end EVM proof requires first generating an aggregation proving key and EVM verifier contract. This can be done by running the following command: + +```bash +cargo openvm setup +``` +> ⚠️ **WARNING** +> This command requires very large amounts of computation and memory (~200 GB). + +Upon a successful run, the command will write `agg.pk` and `verifier.sol` to `~/.openvm/`, where `~` is the directory specified by environment variable `$HOME`. Every command that requires these files will look for them in this directory. + +> ⚠️ **WARNING** +> If the `$HOME` environment variable is not set, this command may fail. + +Note that `cargo openvm setup` may attempt to download other files (i.e. KZG parameters) from an AWS S3 bucket into `~/.openvm/`. + +## Generating and Verifying an EVM Proof + +To generate and verify an EVM proof, you need to run the following commands: + +```bash +cargo openvm prove evm --input +cargo openvm verify evm +``` + +These commands are very similar to their `app` subcommand counterparts. For more information on the `prove` and `verify` commands, see the [prove](./prove.md) and [verify](./verify.md) docs. diff --git a/book/src/writing-apps/overview.md b/book/src/writing-apps/overview.md index 6e66d0352f..0637d04452 100644 --- a/book/src/writing-apps/overview.md +++ b/book/src/writing-apps/overview.md @@ -1 +1,77 @@ # Overview of Basic Usage + +## Writing a Program + +The first step to using OpenVM is to write a Rust program that can be executed by an OpenVM virtual machine. Writing a program for OpenVM is very similar to writing a standard Rust program, with a few key differences necessary to support the OpenVM environment. For more detailed information about writing programs, see the [Writing Programs](./write-program.md) guide. + +## Building and Transpiling a Program + +At this point, you should have a guest program with a `Cargo.toml` file in the root of your project directory. What's next? + +The first thing you will want to do is build and transpile your program using the following command: + +```bash +cargo openvm build +``` + +By default this will build the project located in the current directory. To see if it runs correctly, you can try executing it with the following: + +```bash +cargo openvm run --input +``` + +Note if your program doesn't require inputs, you can omit the `--input` flag. + +For more information on both commands, see the [build](./build.md) docs. + +### Inputs + +The `--input` field needs to either be a hex string or a file path to a file that will be read as bytes. Note that if your hex string represents a single number, it should be written in little-endian format (as this is what the VM expects). To see how more complex inputs can be converted into a VM-readable format, see the **Using StdIn** section of the [SDK](../advanced-usage/sdk.md) doc. + +## Generating a Proof + +Given an app configuration TOML file, you first need to generate a proving and verifying key: + +```bash +cargo openvm keygen +``` + +After generating the keys, you can generate a proof by running: + +```bash +cargo openvm prove app --input +``` + +Again, if your program doesn't require inputs, you can omit the `--input` flag. + +For more information on the `keygen` and `prove` commands, see the [prove](./prove.md) doc. + +## Verifying a Proof + +To verify a proof using the CLI, you need to provide the verifying key and the proof. + +```bash +cargo openvm verify app +``` + +For more information on the `verify` command, see the [verify](./verify.md) doc. + +## End-to-end EVM Proof Generation and Verification + +The process above details the workflow necessary to build, prove, and verify a guest program at the application level. However, to generate the end-to-end EVM proof, you need to (a) setup the aggregation proving key and verifier contract and (b) generate/verify the proof at the EVM level. + +To do (a), you need to run the following command. If you've run it previously on your machine, there is no need to do so again. This will write files necessary for EVM proving in `~/.openvm/`. + +```bash +cargo openvm setup +``` + +> ⚠️ **WARNING** +> This command requires very large amounts of computation and memory (~200 GB). + +To do (b), you simply need to replace `app` in `cargo openvm prove` and `cargo openvm verify` as such: + +```bash +cargo openvm prove evm --input +cargo openvm verify evm +``` diff --git a/book/src/writing-apps/prove.md b/book/src/writing-apps/prove.md index e9d3a9bc66..39450a33de 100644 --- a/book/src/writing-apps/prove.md +++ b/book/src/writing-apps/prove.md @@ -1 +1,44 @@ # Generating Proofs + +Generating a proof using the CLI is simple - first generate a key, then generate your proof. Using command defaults, this looks like: + +```bash +cargo openvm keygen +cargo openvm prove [app | evm] +``` + +## Key Generation + +The `keygen` CLI command has the following optional arguments: + +```bash +cargo openvm keygen + --config + --output + --vk_output +``` + +If `--config` is not provided, the command will search for `./openvm.toml` and use that as the application configuration if present. If it is not present, a default configuration will be used. + +If `--output` and/or `--vk_output` are not provided, the keys will be written to default locations `./openvm/app.pk` and/or `./openvm/app.vk` respectively. + +## Proof Generation + +The `prove` CLI command has the following optional arguments: + +```bash +cargo openvm prove [app | evm] + --app_pk + --exe + --input + --output +``` + +If your program doesn't require inputs, you can (and should) omit the `--input` flag. + +If `--app_pk` and/or `--exe` are not provided, the command will search for these files in `./openvm/app.pk` and `./openvm/app.vmexe` respectively. Similarly, if `--output` is not provided then the command will write the proof to `./openvm/[app | evm].proof` by default. + +The `app` subcommand is used to generate an application-level proof, while the `evm` command generates an end-to-end EVM proof. + +> ⚠️ **WARNING** +> In order to run the `evm` subcommand, you must have previously called the costly `cargo openvm setup`, which requires very large amounts of computation and memory (~200 GB). diff --git a/book/src/writing-apps/testing.md b/book/src/writing-apps/testing.md deleted file mode 100644 index f00b526a98..0000000000 --- a/book/src/writing-apps/testing.md +++ /dev/null @@ -1 +0,0 @@ -# Testing diff --git a/book/src/writing-apps/verify.md b/book/src/writing-apps/verify.md index ea369b8c26..5c95f69488 100644 --- a/book/src/writing-apps/verify.md +++ b/book/src/writing-apps/verify.md @@ -1 +1,29 @@ -# Onchain Verification +# Verifying Proofs + +## Application Level + +Verifying a proof at the application level requires both the proof and application verifying key. + +```bash +cargo openvm verify app + --app_vk + --proof +``` + +If you omit `--app_vk` and/or `--proof`, the command will search for those files at `./openvm/app.vk` and `./openvm/app.proof` respectively. + +Once again, if you omitted `--output` and `--vk_output` in the `keygen` and `prove` commands, you can omit `--app_vk` and `--proof` in the `verify` command. + +## EVM Level + +Verifying a proof at the EVM level requires just the proof, as the command uses the verifier generated when `cargo openvm setup` was called. + +```bash +cargo openvm verify evm --proof +``` + +If `proof` is omitted, the command will search for the proof at `./openvm/evm.proof`. + +As with all other EVM-level commands, `cargo openvm setup` is a prerequisite for `verify`. +> ⚠️ **WARNING** +> `cargo openvm setup` requires very large amounts of computation and memory (~200 GB). diff --git a/crates/toolchain/build/src/lib.rs b/crates/toolchain/build/src/lib.rs index c55af96d75..7b95e1729f 100644 --- a/crates/toolchain/build/src/lib.rs +++ b/crates/toolchain/build/src/lib.rs @@ -333,6 +333,20 @@ pub struct TargetFilter { pub kind: Option, } +impl TargetFilter { + /// Set substring of target name to match. + pub fn with_name_substr(mut self, name_substr: String) -> Self { + self.name_substr = Some(name_substr); + self + } + + /// Set kind of target to match. + pub fn with_kind(mut self, kind: String) -> Self { + self.kind = Some(kind); + self + } +} + /// Finds the unique executable target in the given package and target directory, /// using the given target filter. pub fn find_unique_executable, Q: AsRef>( From 6b3e68a5048ddf19e743951838cbbaa557b4b1e0 Mon Sep 17 00:00:00 2001 From: Golovanov399 Date: Mon, 16 Dec 2024 06:21:45 +0300 Subject: [PATCH 05/27] [book] Write the manual on how to create a new extension (#1060) * Write the manual * Update book/src/new-extension/howto.md * Update book/src/new-extension/howto.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Some comments * Other comments * Rename --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/advanced-usage/new-extension.md | 41 ++++++++++++++++++++++++ book/src/introduction.md | 4 +-- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 book/src/advanced-usage/new-extension.md diff --git a/book/src/advanced-usage/new-extension.md b/book/src/advanced-usage/new-extension.md new file mode 100644 index 0000000000..ecbd7dd134 --- /dev/null +++ b/book/src/advanced-usage/new-extension.md @@ -0,0 +1,41 @@ +# Creating a New Extension + +Extensions in OpenVM let you introduce additional functionality without disrupting the existing system. Consider, for example, an extension that provides two new operations on `u32` values: one that squares a number, and another that multiplies it by three. With such an extension: + +1. You define functions like `square(x: u32) -> u32` and `mul3(x: u32) -> u32` for use in guest code. +2. When the compiler encounters these functions, it generates corresponding custom [RISC-V instructions](https://github.com/openvm-org/openvm/blob/main/docs/specs/RISCV.md). +3. During the transpilation phase, these custom instructions are translated into OpenVM instructions. +4. At runtime, the OpenVM program sends these new instructions to a specialized [chip](https://github.com/openvm-org/openvm/blob/main/docs/specs/circuit.md) that computes the results and ensures their correctness. + +This modular architecture means the extension cleanly adds new capabilities while leaving the rest of OpenVM untouched. The entire system, including the extension’s operations, can still be proven correct. + +Conceptually, a new extension consists of three parts: +- **Guest**: High-level Rust code that defines and uses the new operations. +- **Transpiler**: Logic that converts custom RISC-V instructions into corresponding OpenVM instructions. +- **Circuit**: The special chips that enforce correctness of instruction execution through polynomial constraints. + +## Guest + +In the guest component, your goal is to produce the instructions that represent the new operations. When you want to perform an operation (for example, “calculate _this_ new function of _these_ arguments and write the result _here_”), you generate a custom instruction. You can use the helper macros `custom_insn_r!` and `custom_insn_i!` from `openvm_platform` to ensure these instructions follow the [RISC-V specification](https://riscv.org/specifications/ratified/). For more details, see the RISC-V [contributor documentation](https://github.com/openvm-org/openvm/blob/main/docs/specs/RISCV.md). + +## Transpiler + +The transpiler maps the newly introduced RISC-V instructions to their OpenVM counterparts. To achieve this, implement a struct that provides the `TranspilerExtension` trait, which includes: + +```rust +fn process_custom(&self, instruction_stream: &[u32]) -> Option<(Instruction, usize)>; +``` + +This function checks if the given instruction stream starts with one of your custom instructions. If so, it returns the corresponding OpenVM instruction and how many 32-bit words were consumed. If not, it returns `None`. + +Note that almost always the valid instruction consists of a single 32-bit RISC-V word (so whenever `Some(_, sz)` is returned, `sz` is 1), but in general this may not be the case. + +## Circuit + +The circuit component is where the extension’s logic is enforced in a zero-knowledge proof context. Here, you create a chip that: + +- Implements the computing logic, so that the output always corresponds to the correct result of the new operation. The chip has access to the memory shared with the other chips from the VM via [our special architecture](https://github.com/openvm-org/openvm/blob/main/docs/specs/ISA.md). +- Properly constrains all the inputs, outputs and intermediate variables using polynomial equations in such a way that there is no way to fill these variables with values that correspond to an incorrect output while fitting the constraints. + + +For more technical details on writing circuits and constraints, consult the OpenVM [contributor documentation](https://github.com/openvm-org/openvm/blob/main/docs/specs/README.md), which provides specifications and guidelines for integrating your extension into the OpenVM framework. diff --git a/book/src/introduction.md b/book/src/introduction.md index 80d66d608f..2e77c1675d 100644 --- a/book/src/introduction.md +++ b/book/src/introduction.md @@ -18,7 +18,7 @@ OpenVM is an open-source zero-knowledge virtual machine (zkVM) framework focused The following chapters will guide you through: -- [Getting started](./getting-started/install.md) +- [Getting started](./getting-started/install.md). - [Writing applications](./writing-apps/overview.md) in Rust targeting OpenVM and generating proofs. - [Using existing extensions](./custom-extensions/overview.md) to optimize your Rust programs. -- How to add custom VM extensions +- [How to add custom VM extensions](./advanced-usage/new-extension.md). From 79451a74576068f883e8b869402f8bb3ed5261f4 Mon Sep 17 00:00:00 2001 From: Golovanov399 Date: Mon, 16 Dec 2024 06:25:07 +0300 Subject: [PATCH 06/27] [book] describe `build` flags in the book (#1066) * ChatGPT here is the `cargo openvm build -h` output please generate the manual chapter about it * Rename `compile.md` -> `build.md` * chore: summary * fixes --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/SUMMARY.md | 6 +- book/src/writing-apps/build.md | 141 +++++++++++++++++++++++++++++++ book/src/writing-apps/compile.md | 24 ------ 3 files changed, 144 insertions(+), 27 deletions(-) create mode 100644 book/src/writing-apps/build.md delete mode 100644 book/src/writing-apps/compile.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 939a8948eb..38f675db2d 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -12,8 +12,7 @@ - [Overview](./writing-apps/overview.md) - [Writing a Program](./writing-apps/write-program.md) -- [Cross-Compilation](./writing-apps/compile.md) -- [Testing](./writing-apps/testing.md) +- [Cross-Compilation](./writing-apps/build.md) - [Generating Proofs](./writing-apps/prove.md) - [Onchain Verification](./writing-apps/verify.md) @@ -29,4 +28,5 @@ # Advanced Usage - [Overview](./advanced-usage/overview.md) -- [Testing the program](./advanced-usage/testing-program.md) +- [SDK](./advanced-usage/sdk.md) +- [Testing](./advanced-usage/testing-program.md) diff --git a/book/src/writing-apps/build.md b/book/src/writing-apps/build.md new file mode 100644 index 0000000000..aadbb7b3f9 --- /dev/null +++ b/book/src/writing-apps/build.md @@ -0,0 +1,141 @@ +# Cross-Compilation + +First let's define some key terms used in cross-compilation: + +- **host** - the machine you're compiling and/or proving on. Note that one can compile and prove on different machines, but they are both called _host_ as they are traditional machine architectures. +- **guest** - the executable to be run in a different VM architecture (e.g. the OpenVM runtime, or Android app). + +There are multiple things happening in the `cargo openvm build` command as in the section [here](./write-program.md). In short, this command compiles on host to an executable for guest target. +It first compiles the program normally on your _host_ platform with RISC-V and then transpiles it to a different target. See here for some explanation of [cross-compilation](https://rust-lang.github.io/rustup/cross-compilation.html). +Right now we use `riscv32im-risc0-zkvm-elf` target which is available in the [Rust toolchain](https://doc.rust-lang.org/rustc/platform-support/riscv32im-risc0-zkvm-elf.html), but we will contribute an OpenVM target to Rust in the future. + +## Build flags + +The following flags are available for the `cargo openvm build` command: + +- `--manifest-dir ` + + **Description**: Specifies the directory containing the `Cargo.toml` file for the guest code. + + **Default**: The current directory (`.`). + + **Usage Example**: If your `Cargo.toml` is located in `my_project/`, you can run: + + ```bash + cargo openvm build --manifest-dir my_project + ``` + + This ensures the build command is executed in that directory. + +- `--features ` + + **Description**: Passes a list of feature flags to the Cargo build process. These flags enable or disable conditional compilation features defined in your `Cargo.toml`. + + **Usage Example**: To enable the `my_feature` feature: + + ```bash + cargo openvm build --features my_feature + ``` + +- `--bin` + + **Description**: Restricts the build to binary targets. If your project has multiple target types (binaries, libraries, examples, etc.), using `--bin` ensures only binary targets are considered. + + **Usage Example**: + + ```bash + cargo openvm build --bin + ``` + +- `--example` + + **Description**: Restricts the build to example targets. Projects often include code samples or demos under the examples directory, and this flag focuses on compiling those. + + **Usage Example**: + + ```bash + cargo openvm build --example + ``` + +- `--name ` + + **Description**: Filters targets by name. Only targets whose names contain the given substring will be built. + + **Usage Example**: To build only targets that have `client` in their name: + + ```bash + cargo openvm build --name client + ``` + +- `--no-transpile` + + **Description**: After building the guest code, doesn't transpile the target ELF into an OpenVM-compatible executable (by default it does). + + **Usage Example**: + + ```bash + cargo openvm build --no-transpile + ``` + +- `--config ` + + **Description**: Specifies the path to a .toml configuration file that defines which VM extensions to use. + + **Default**: `./openvm.toml` if `--config` flag is not provided. + + **Usage Example**: + + ```bash + cargo openvm build --config path/to/openvm.toml + ``` + + This allows you to customize the extensions. Currently the CLI only supports known extensions listed in the [Using Existing Extensions](../custom-extensions/overview.md) section. To use other extensions, use the [SDK](../advanced-usage/sdk.md). + +- `--exe-output ` + + **Description**: Sets the output path for the transpiled program. + + **Default**: `./openvm/app.vmexe` if `--exe-output` flag is not provided. + + **Usage Example**: To specify a custom output filename: + + ```bash + cargo openvm build --exe-output ./output/custom_name.vmexe + ``` + +- `--profile ` + + **Description**: Determines the build profile used by Cargo. Common profiles are dev (faster builds, less optimization) and release (slower builds, more optimization). + + **Default**: release + + **Usage Example**: + + ```bash + cargo openvm build --profile dev + ``` + +- `--help` + + **Description**: Prints a help message describing the available options and their usage. + + **Usage Example**: + + ```bash + cargo openvm build --help + ``` + +## Running a Program + +After building and transpiling a program, you can execute it using the `run` command. The `run` command has the following arguments: + +```bash +cargo openvm run + --exe + --config + --input +``` + +If `--exe` and/or `--config` are not provided, the command will search for these files in `./openvm/app.vmexe` and `./openvm.toml` respectively. If `./openvm.toml` is not present, a default configuration will be used. + +If your program doesn't require inputs, you can (and should) omit the `--input` flag. diff --git a/book/src/writing-apps/compile.md b/book/src/writing-apps/compile.md deleted file mode 100644 index cdcfcb0c6b..0000000000 --- a/book/src/writing-apps/compile.md +++ /dev/null @@ -1,24 +0,0 @@ -# Cross-Compilation - -First let's define some key terms used in cross-compilation: -- **host** - the machine you're compiling and/or proving on. Note that one can compile and prove on different machines, but they are both called *host* as they are traditional machine architectures. -- **guest** - the executable to be run in a different VM architecture (e.g. the OpenVM runtime, or Android app). - -There are multiple things happening in the `cargo openvm build` command as in the section [here](./write-program.md). In short, this command compiles on host to an executable for guest target. -It first compiles the program normally on your *host* platform with RISC-V and then transpiles it to a different target. See here for some explanation of [cross-compilation](https://rust-lang.github.io/rustup/cross-compilation.html). -Right now we use `riscv32im-risc0-zkvm-elf` target which is available in the [Rust toolchain](https://doc.rust-lang.org/rustc/platform-support/riscv32im-risc0-zkvm-elf.html), but we will contribute an OpenVM target to Rust in the future. - -## Running a Program - -After building and transpiling a program, you can execute it using the `run` command. The `run` command has the following arguments: - -```bash -cargo openvm run - --exe - --config - --input -``` - -If `--exe` and/or `--config` are not provided, the command will search for these files in `./openvm/app.vmexe` and `./openvm.toml` respectively. If `./openvm.toml` is not present, a default configuration will be used. - -If your program doesn't require inputs, you can (and should) omit the `--input` flag. From 2856a6c0ceeccb60e9ba1133837dddd40dbc4c1a Mon Sep 17 00:00:00 2001 From: stephenh-axiom-xyz Date: Sun, 15 Dec 2024 22:32:27 -0500 Subject: [PATCH 07/27] fix: output config TOML parse error when TOML exists but is incorrect (#1069) --- crates/cli/src/util.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/cli/src/util.rs b/crates/cli/src/util.rs index a80e9043e3..581f00acd9 100644 --- a/crates/cli/src/util.rs +++ b/crates/cli/src/util.rs @@ -83,13 +83,13 @@ pub(crate) fn read_to_stdin(input: &Option) -> Result { } pub(crate) fn read_config_toml_or_default(config: &PathBuf) -> Result> { - let mut app_config: Result> = read_to_struct_toml(config); - if app_config.is_err() { + if config.exists() { + read_to_struct_toml(config) + } else { println!( "{:?} not found, using default application configuration", config ); - app_config = Ok(default_app_config()); + Ok(default_app_config()) } - app_config } From e850856944402b6c57962f7f8c53264d71918a5b Mon Sep 17 00:00:00 2001 From: Yi Sun Date: Sun, 15 Dec 2024 21:37:36 -0600 Subject: [PATCH 08/27] chore: remove overview, testing from advanced, add new-extension (#1070) --- book/src/SUMMARY.md | 3 +-- book/src/advanced-usage/overview.md | 1 - book/src/advanced-usage/testing-program.md | 21 --------------------- 3 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 book/src/advanced-usage/overview.md delete mode 100644 book/src/advanced-usage/testing-program.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 38f675db2d..fb4852b228 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -27,6 +27,5 @@ # Advanced Usage -- [Overview](./advanced-usage/overview.md) - [SDK](./advanced-usage/sdk.md) -- [Testing](./advanced-usage/testing-program.md) +- [Creating a New Extension](./advanced-usage/new-extension.md) diff --git a/book/src/advanced-usage/overview.md b/book/src/advanced-usage/overview.md deleted file mode 100644 index 07dd0c5c77..0000000000 --- a/book/src/advanced-usage/overview.md +++ /dev/null @@ -1 +0,0 @@ -# Overview diff --git a/book/src/advanced-usage/testing-program.md b/book/src/advanced-usage/testing-program.md deleted file mode 100644 index afd89ad955..0000000000 --- a/book/src/advanced-usage/testing-program.md +++ /dev/null @@ -1,21 +0,0 @@ -## 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 - -For more information on building, transpiling, running, generating proofs, and verifying proofs with the CLI, see the [CLI](../writing-apps/overview.md)section. To do the same with the SDK, see the [SDK](sdk.md) section. - -## Troubleshooting - -todo - -## FAQ - -todo \ No newline at end of file From b91081d108bb35f6bc2f4ba3e5121fed9a196c66 Mon Sep 17 00:00:00 2001 From: stephenh-axiom-xyz Date: Sun, 15 Dec 2024 22:42:14 -0500 Subject: [PATCH 09/27] docs: SDK code runs (#1071) --- book/src/advanced-usage/sdk.md | 64 +++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/book/src/advanced-usage/sdk.md b/book/src/advanced-usage/sdk.md index 51a0145de3..e4f2fba1f5 100644 --- a/book/src/advanced-usage/sdk.md +++ b/book/src/advanced-usage/sdk.md @@ -9,12 +9,19 @@ For more information on the basic CLI flow, see [Overview of Basic Usage](./over 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 openvm::{platform::memory::MEM_SIZE, transpiler::elf::Elf}; -use openvm_circuit::arch::instructions::exe::OpenVmExe -use openvm_circuit::arch::VmExecutor; -use openvm_sdk::{config::SdkVmConfig, Sdk, StdIn}; - -let sdk = Sdk; +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 { @@ -29,6 +36,7 @@ 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()) @@ -40,7 +48,8 @@ let guest_opts = GuestOptions::default().with_features(vec!["parallel"]); let target_filter = TargetFilter::default().with_kind("bin".to_string()); let elf = sdk.build(guest_opts, "your_path_project_root", &target_filter)?; // 2b. Load the ELF from a file -let elf = Elf::decode("your_path_to_elf", MEM_SIZE as u32)?; +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())?; @@ -55,12 +64,13 @@ 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; // anything that can be serialized +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, vm_config, input)?; +let output = sdk.execute(exe.clone(), vm_config.clone(), stdin.clone())?; +println!("public values output: {:?}", output); ``` ### Using `StdIn` @@ -84,15 +94,14 @@ let app_config = AppConfig::new(app_fri_params, vm_config); let app_committed_exe = sdk.commit_app_exe(app_fri_params, exe)?; // 8. Generate an AppProvingKey -let app_pk = sdk.app_keygen(app_config)?; +let app_pk = Arc::new(sdk.app_keygen(app_config)?); // 9a. Generate a proof -let proof = sdk.generate_app_proof(app_pk, app_committed_exe, stdin)?; +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 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_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()); ``` ## Verifying Proofs @@ -111,20 +120,33 @@ 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 = Halo2ParamsReader::new(DEFAULT_PARAMS_DIR); +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 an EVM proof -let proof = sdk.generate_evm_proof(&halo2_params_reader, app_pk, app_committed_exe, agg_pk, stdin)?; - -// 13. Generate the SNARK verifier contract +// 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 -sdk.verify_evm_proof(&verifier, &proof)?; +let success = sdk.verify_evm_proof(&verifier, &proof); +assert!(success); ``` +> ⚠️ **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. + 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 [onchain verify](../writing-apps/onchain-verify.md) doc. > ⚠️ **WARNING** From b44367771171e68d33ed8d33e7667349148a3428 Mon Sep 17 00:00:00 2001 From: stephenh-axiom-xyz Date: Sun, 15 Dec 2024 22:57:32 -0500 Subject: [PATCH 10/27] fix: remove char in docs (#1072) --- book/src/advanced-usage/sdk.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/advanced-usage/sdk.md b/book/src/advanced-usage/sdk.md index e4f2fba1f5..39d6d1fc5a 100644 --- a/book/src/advanced-usage/sdk.md +++ b/book/src/advanced-usage/sdk.md @@ -145,7 +145,7 @@ assert!(success); > 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. +> 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 [onchain verify](../writing-apps/onchain-verify.md) doc. From 410e4aae987abdf2ed08e7ef90859ff703d6e5d3 Mon Sep 17 00:00:00 2001 From: Yu Jiang Tham Date: Sun, 15 Dec 2024 19:57:52 -0800 Subject: [PATCH 11/27] [docs] `ecc-pairing` book page (#1054) * ecc-pairing initial draft * Fix links * Update book/src/SUMMARY.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Update book/src/using-extensions/pairing.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Update book/src/using-extensions/pairing.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Update book/src/using-extensions/pairing.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Address PR comments (without CLI yet) * WIP: openvm.toml section * Update pairing w/ hardcoded input code * chore: remove unneeded * chore: remove unnecessary sections --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/custom-extensions/pairing.md | 181 +++++++++++++++++++- crates/toolchain/tests/src/pairing_tests.rs | 1 - 2 files changed, 180 insertions(+), 2 deletions(-) diff --git a/book/src/custom-extensions/pairing.md b/book/src/custom-extensions/pairing.md index ebb943f14c..0f9b1fc333 100644 --- a/book/src/custom-extensions/pairing.md +++ b/book/src/custom-extensions/pairing.md @@ -1 +1,180 @@ -# OpenVM Pairing \ No newline at end of file +# Elliptic Curve Pairing + +The pairing extension enables usage of the optimal Ate pairing check on the BN254 and BLS12-381 elliptic curves. The following field extension tower for $\mathbb{F}_{p^{12}}$ is used for pairings in this crate: + +$$ +\mathbb{F_{p^2}} = \mathbb{F_{p}}[u]/(u^2 - \beta)\\ +\mathbb{F_{p^6}} = \mathbb{F_{p^2}}[v]/(v^3 - \xi)\\ +\mathbb{F_{p^{12}}} = \mathbb{F_{p^6}}[w]/(w^2 - v) +$$ + +A full guest program example is available here: [pairing_check.rs](https://github.com/openvm-org/openvm/blob/c19c9ac60b135bb0f38fc997df5eb149db8144b4/crates/toolchain/tests/programs/examples/pairing_check.rs) + +## Guest program setup + +We'll be working with an example using the BLS12-381 elliptic curve. This is in addition to the setup that needs to be done in the [Writing a Program](../writing-apps/write-program.md) section. + +In the guest program, we will import the `PairingCheck` and `IntMod` traits, along with the BLS12-381 curve structs (**IMPORTANT:** this requires the `bls12_381` feature enabled in Cargo.toml for the `openvm-pairing-guest` dependency), and a few other values that we will need: + +```rust title="guest program" +use openvm_pairing_guest::{ + pairing::PairingCheck, + bls12_381::{Bls12_381, Fp, Fp2}, +}; +use openvm_ecc_guest::AffinePoint; +use openvm_algebra_guest::IntMod; +use openvm::io::read; +``` + +Additionally, we'll need to initialize our moduli and `Fp2` struct via the following macros. For a more in-depth description of these macros, please see the [OpenVM Algebra](./algebra.md) section. + +```rust +// These correspond to the BLS12-381 coordinate and scalar moduli, respectively +openvm_algebra_moduli_setup::moduli_init! { + "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" +} + +openvm_algebra_complex_macros::complex_init! { + Bls12_381Fp2 { mod_idx = 0 }, +} +``` + +And we'll run the required setup functions at the top of the guest program's `main()` function: + +```rust +setup_0(); +setup_all_complex_extensions(); +``` + +There are two moduli defined internally in the Bls12_381 feature. The `moduli_init!` macro thus requires both of them to be initialized. However, we do not need the scalar field of BLS12-381 (which is at index 1), and thus we only initialize the modulus from index 0, thus we only use `setup_0()` (as opposed to `setup_all_moduli()`, which will save us some columns when generating the trace). + +## Input values + +The inputs to the pairing check are `AffinePoint`s in $\mathbb{F}_p$ and $\mathbb{F}_{p^2}$. They can be constructed via the `AffinePoint::new` function, with the inner `Fp` and `Fp2` values constructed via various `from_...` functions. + +We can create a new struct to hold these `AffinePoint`s for the purpose of this guide. You may instead put them into a custom struct to serve your use case. + +```rust +#[derive(Clone, serde::Serialize, serde::Deserialize)] +pub struct PairingCheckInput { + p0: AffinePoint, + p1: AffinePoint, + q0: AffinePoint, + q1: AffinePoint, +} +``` + +## Pairing check + +Most users that use the pairing extension will want to assert that a pairing is valid (the final exponentiation equals one). With the `PairingCheck` trait imported from the previous section, we have access to the `pairing_check` function on the `Bls12_381` struct. After reading in the input struct, we can use its values in the `pairing_check`: + +```rust +let res = Bls12_381::pairing_check( + &[p0, p1], + &[q0, q1], +); +assert!(res.is_ok()) +``` + +## Additional functionality + +We also have access to each of the specific functions that the pairing check utilizes for either the BN254 or BLS12-381 elliptic curves. + +### Multi-Miller loop + +The multi-Miller loop requires the MultiMillerLoop trait can also be ran separately via: + +```rust +let f = Bls12_381::multi_miller_loop( + &[p0, p1], + &[q0, q1], +); +``` + +## Running via CLI + +### Config parameters + +For the guest program to build successfully, we'll need to create an `openvm.toml` configuration file somewhere. It contains all of the necessary configuration information for enabling the OpenVM components that are used in the pairing check. + +```toml +# openvm.toml +[app_vm_config.pairing] +supported_curves = ["Bls12_381"] + +[app_vm_config.modular] +supported_modulus = [ + "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", +] + +[app_vm_config.fp2] +supported_modulus = [ + "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", +] +``` + +### Full example code + +This example code contains hardcoded values and no inputs as an example that can be run via the CLI. + +```rust +#![no_main] +#![no_std] + +use hex_literal::hex; +use openvm_algebra_guest::{field::FieldExtension, IntMod}; +use openvm_ecc_guest::AffinePoint; +use openvm_pairing_guest::{ + bls12_381::{Bls12_381, Fp, Fp2}, + pairing::PairingCheck, +}; + +openvm::entry!(main); + +openvm_algebra_moduli_setup::moduli_init! { + "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" +} + +openvm_algebra_complex_macros::complex_init! { + Bls12_381Fp2 { mod_idx = 0 }, +} + +pub fn main() { + setup_0(); + setup_all_complex_extensions(); + + let p0 = AffinePoint::new( + Fp::from_be_bytes(&hex!("17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb")), + Fp::from_be_bytes(&hex!("08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1")) + ); + let p1 = AffinePoint::new( + Fp2::from_coeffs([ + Fp::from_be_bytes(&hex!("1638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053")), + Fp::from_be_bytes(&hex!("0a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577")) + ]), + Fp2::from_coeffs([ + Fp::from_be_bytes(&hex!("0468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899")), + Fp::from_be_bytes(&hex!("0f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3")) + ]), + ); + let q0 = AffinePoint::new( + Fp::from_be_bytes(&hex!("0572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e")), + Fp::from_be_bytes(&hex!("166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28")) + ); + let q1 = AffinePoint::new( + Fp2::from_coeffs([ + Fp::from_be_bytes(&hex!("024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8")), + Fp::from_be_bytes(&hex!("13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e")) + ]), + Fp2::from_coeffs([ + Fp::from_be_bytes(&hex!("0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801")), + Fp::from_be_bytes(&hex!("0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be")) + ]), + ); + + let res = Bls12_381::pairing_check(&[p0, -q0], &[p1, q1]); + assert!(res.is_ok()); +} +``` diff --git a/crates/toolchain/tests/src/pairing_tests.rs b/crates/toolchain/tests/src/pairing_tests.rs index 1aea3af067..65912bfb86 100644 --- a/crates/toolchain/tests/src/pairing_tests.rs +++ b/crates/toolchain/tests/src/pairing_tests.rs @@ -515,7 +515,6 @@ mod bls12_381 { G2Affine::from(Q * Fr::from(2)), G2Affine::from(Q * Fr::from(1)), ]; - let s = S_mul.map(|s| AffinePoint::new(s.x, s.y)); let q = Q_mul.map(|p| AffinePoint::new(p.x, p.y)); From 83d9e99c4d7685da7864238338c98c4b9219c0a4 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Sun, 15 Dec 2024 23:00:10 -0500 Subject: [PATCH 12/27] chore: rename sections (#1073) --- book/src/SUMMARY.md | 4 ++-- book/src/writing-apps/build.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index fb4852b228..0a0689e521 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -12,7 +12,7 @@ - [Overview](./writing-apps/overview.md) - [Writing a Program](./writing-apps/write-program.md) -- [Cross-Compilation](./writing-apps/build.md) +- [Compiling](./writing-apps/build.md) - [Generating Proofs](./writing-apps/prove.md) - [Onchain Verification](./writing-apps/verify.md) @@ -21,7 +21,7 @@ - [Overview](./custom-extensions/overview.md) - [Keccak](./custom-extensions/keccak.md) - [Big Integer](./custom-extensions/bigint.md) -- [Algebra](./custom-extensions/algebra.md) +- [Algebra (Modular Arithmetic)](./custom-extensions/algebra.md) - [Elliptic Curve Cryptography](./custom-extensions/ecc.md) - [Elliptic Curve Pairing](./custom-extensions/pairing.md) diff --git a/book/src/writing-apps/build.md b/book/src/writing-apps/build.md index aadbb7b3f9..b5b0a8fd56 100644 --- a/book/src/writing-apps/build.md +++ b/book/src/writing-apps/build.md @@ -1,4 +1,4 @@ -# Cross-Compilation +# Compiling a Program First let's define some key terms used in cross-compilation: From aea81bf6d0c21cd44ba5fb67cb2285fa9137aa56 Mon Sep 17 00:00:00 2001 From: HrikB <23041116+HrikB@users.noreply.github.com> Date: Sun, 15 Dec 2024 20:15:31 -0800 Subject: [PATCH 13/27] Completed installation and quickstart sections (#1065) * docs: completed installation and quickstart sections * Apply suggestions from code review * update cli --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/getting-started/install.md | 42 +++++++++++++-- book/src/getting-started/quickstart.md | 73 ++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 15 deletions(-) diff --git a/book/src/getting-started/install.md b/book/src/getting-started/install.md index bb470b6b03..18ecdbac82 100644 --- a/book/src/getting-started/install.md +++ b/book/src/getting-started/install.md @@ -1,9 +1,30 @@ # Install -TODO: how to install `cargo-openvm`. -`cargo install --git <...>` +To use OpenVM for generating proofs, you must install the OpenVM command line tool `cargo-openvm`. -## Build from source +`cargo-openvm` can be installed in two different ways. You can either install via git URL or build from source. + +## Option 1: Install Via Git URL (Recommended) + +```bash +cargo install --git http://github.com/openvm-org/openvm.git cargo-openvm +``` + +This will globally install `cargo-openvm`. You can validate a successful installation with: + +```bash +cargo openvm --version +``` + +## Option 2: Build from source + +To build from source, you will need the nightly toolchain. You can install it with: + +```bash +rustup toolchain install nightly +``` + +Then, clone the repository and begin the installation. ```bash git clone https://github.com/openvm-org/openvm.git @@ -11,4 +32,17 @@ cd openvm cargo install --force --path crates/cli ``` -## Toolchain +This will globally install `cargo-openvm`. You can validate a successful installation with: + +```bash +cargo openvm --version +``` + +## Install Rust Toolchain + +In order for the `cargo-openvm` build command to work, you must install certain Rust nightly components: + +```bash +rustup install nightly-2024-10-30 +rustup component add rust-src --toolchain nightly-2024-10-30 +``` diff --git a/book/src/getting-started/quickstart.md b/book/src/getting-started/quickstart.md index c40f274cd1..335a9c2df4 100644 --- a/book/src/getting-started/quickstart.md +++ b/book/src/getting-started/quickstart.md @@ -10,17 +10,10 @@ First, create a new Rust project. cargo init fibonacci ``` -Since we are using some nightly features, we need to specify the Rust version. Run `rustup component add rust-src --toolchain nightly-2024-10-30` and 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 +[dependencies] openvm = { git = "https://github.com/openvm-org/openvm.git", features = ["std"] } ``` @@ -28,9 +21,13 @@ 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. +The `read` function takes input from the stdin (it also works with OpenVM runtime). + ```rust -use openvm::io::read; +// src/main.rs +use openvm::io::{read, reveal}; + +openvm::entry!(main); fn main() { let n: u64 = read(); @@ -41,6 +38,60 @@ fn main() { a = b; b = c; } - println!("{}", a); + reveal(a as u32, 0); + reveal((a >> 32) as u32, 1); } ``` + +## Build + +To build the program, run: + +```bash +cargo openvm build +``` + +This will output an OpenVM executable file to `./openvm/app.vmexe`. + +## Keygen + +Before generating any proofs, we will also need to generate the proving and verification keys. + +```bash +cargo openvm keygen +``` + +This will output a serialized proving key to `./openvm/app.pk` and a verification key to `./openvm/app.vk`. + +## Proof Generation + +Now we are ready to generate a proof! Simply run: + +```bash +OPENVM_FAST_TEST=1 cargo openvm prove app --input "0x0A00000000000000" +``` + +The `--input` field is passed to the program which receives it via the `io::read` function. +In our `main.rs` we called `read()` to get `n: u64`. The input here is `n = 100u64` _in little endian_. Note that this value must be padded to exactly 8 bytes (64 bits). + +The serialized proof will be output to `./openvm/app.proof`. + +The `OPENVM_FAST_TEST` environment variable is used to enable fast proving for testing purposes. To run with proof with secure parameters, remove the environmental variable. + +## Proof Verification + +Finally, the proof can be verified. + +```bash +cargo openvm verify app +``` + +The process should exit with no errors. + +## Runtime Execution + +If necessary, the executable can also be run _without_ proof generation. This can be useful for testing purposes. + +```bash +cargo openvm run --input "0x0A00000000000000" +``` From 68b5ee189f2001f95768d5bf55862ab368a43be8 Mon Sep 17 00:00:00 2001 From: Zach Langley Date: Sun, 15 Dec 2024 21:26:42 -0500 Subject: [PATCH 14/27] docs/crates cleanup (#1062) * docs/crates cleanup * Apply suggestions from code review * chore: another warning * chore: spacing * chore: mv * chore: link benchmarks * chore: update --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- docs/crates/README.md | 3 +- docs/crates/benchmarks.md | 14 ++- docs/crates/stark.md | 145 ------------------------------ docs/crates/vm-extensions.md | 17 +--- docs/crates/vm.md | 167 +++++++++++++++++------------------ 5 files changed, 90 insertions(+), 256 deletions(-) delete mode 100644 docs/crates/stark.md diff --git a/docs/crates/README.md b/docs/crates/README.md index 5306cb62b6..1ea30bfdb1 100644 --- a/docs/crates/README.md +++ b/docs/crates/README.md @@ -2,7 +2,8 @@ Code-level guides to the crates in the repository. -- [`openvm-stark-backend`](./stark.md): Proof system backend - `openvm-circuit` - [VM Architecture and Chips](./vm.md) - [VM Extensions](./vm-extensions.md) +- `openvm-benchmarks` + - [Running Benchmarks](./benchmarks.md) diff --git a/docs/crates/benchmarks.md b/docs/crates/benchmarks.md index 8c1a4d8a8a..150bf00002 100644 --- a/docs/crates/benchmarks.md +++ b/docs/crates/benchmarks.md @@ -3,19 +3,15 @@ To run benchmarks, install python3 and run (from root of repo): ```bash -python ci/scripts/bench.py +python ci/scripts/bench.py --instance_type --memory_allocator ``` -where `` is a benchmark implemented as a rust binary (located in `src/bin` in a crate). Current benchmark options are: - -- `verify_fibair` -- `fibonacci` -- `regex` - in the `benchmarks` crate. - The benchmark outputs a JSON of metrics. You can process this into markdown with: +where `` is a benchmark implemented as a rust binary (located in `src/bin` in the `openvm-benchmarks` crate). +For local benchmarking, the `--instance_type` flag can take an arbitrary string. +The benchmark outputs a JSON of metrics. You can process this into markdown with: ```bash -python ci/scripts/metric_unify/main.py +python ci/scripts/metric_unify/main.py --aggregation-json ci/scripts/metric_unify/aggregation.json ``` Currently the processing is done automatically at the end of `bench.py`. The script automatically detects if you have a previously saved metric file for the same benchmark and includes the diff report in the output. diff --git a/docs/crates/stark.md b/docs/crates/stark.md deleted file mode 100644 index 20287a0956..0000000000 --- a/docs/crates/stark.md +++ /dev/null @@ -1,145 +0,0 @@ -# STARK Backend - -### Traits for Constraints - -An AIR in our system represents the set of constraints and metadata necessary to generate and verify a STARK proof. This is implemened through the following set of traits, which are split between core plonky3 and our `stark-backend` crate, which provides: - -- the ability to handle logUp / interactions -- the ability to handle separate cached traces - -#### From plonky3 - -```rust -pub trait BaseAir { - fn width(&self) -> usize; -} - -pub trait Air: BaseAir { - fn eval(&self, builder: &mut AB); -} - -pub trait AirBuilder { - type F: Field; // use for constants - type Var: Into + Copy + // .. concrete type of row values - type Expr: AbstractField + // .. most general expression for a constraint -} -``` - -The way `Air` works is that you always implement `Air` with respect to "**some** `AirBuilder` with some properties (additional trait bounds)". However in practice we implement `Air` for "**all** `AirBuilder`s with some properties". - -The struct implementing `Air` should be **stateless**. The struct should only contain configuration parameters necessary to determine the AIR constraints. - -```rust -pub trait BaseAirWithPublicValues: BaseAir { - fn num_public_values(&self) -> usize { - 0 - } -} - -// to use default impl: -impl BaseAirWithPublicValues for MyAir {} -``` - -#### From `openvm-stark-backend` - -For cached trace support: - -```rust -/// An AIR with 1 or more main trace partitions. -pub trait PartitionedBaseAir: BaseAir { - /// By default, an AIR has no cached main trace. - fn cached_main_widths(&self) -> Vec { - vec![] - } - /// By default, an AIR has only one private main trace. - fn common_main_width(&self) -> usize { - self.width() - } -} - -// to use default impl: -impl PartitionedBaseAir for MyAir {} -``` - -The common main trace is the "usual" main trace. All common main trace across all AIRs are committed into one commitment. Cached main are additional sections of main trace that are committed individually. Cached trace is not used in VM **except** by ProgramAir, where the OpenVM `Program` is committed into a dedicated commitment. - -```rust -pub trait Rap: Sync -where - AB: PermutationAirBuilder, -{ - fn eval(&self, builder: &mut AB); -} -``` - -We auto-implement `Rap` for any `Air where AB: InteractionBuilder`. The `Rap` adds in the extension field columns specified by interactions; note that these columns are not specified explicitly in plonky3 trace generation. - -![image](../../assets/rap.png) - -So when you implement `Air` you automatically implement `Rap` **for some** AirBuilder. - -The stark-backend uses three different concrete `AirBuilder` implementations: - -- `SymbolicRapBuilder>` -- `ProverConstraintFolder<'a, SC>` -- `DebugConstraintBuilder<'a, SC>` - -that depend on a `SC: StarkGenericConfig`. The `SC` specifies FRI proof system configuration parameters. - -```rust -pub trait AnyRap: - Rap>> // for keygen to extract fixed data about the RAP - + for<'a> Rap> // for prover quotient polynomial calculation - + for<'a> Rap> // for debugging - + BaseAirWithPublicValues> - + PartitionedBaseAir> { - // .. -} -``` - -This is an **auto-implemented** trait on any struct that implements `Air` for all AirBuilders the backend cares about above, for a **specific** `SC`. - -The backend wants to be able to prove multiple different AIRs together. So it must take a bunch of different `dyn AnyRap`. For some sizing reasons, instead it must take `Arc>` where `Arc` is a smart pointer to get around lifetimes and cloning issues. It is best to always use `Arc`, don't mix `Arc, Rc, Box` for the above purpose. - -### Traits for Trace Generation - -To generate a proof, we pair an AIR (represented by `Arc>`) with a set of methods to generate input traces in the `Chip` trait: - -```rust -pub trait Chip { - fn air(&self) -> Arc>; - - /// Generate all necessary input for proving a single AIR. - fn generate_air_proof_input(self) -> AirProofInput; - fn generate_air_proof_input_with_id(self, air_id: usize) -> (usize, AirProofInput) { - (air_id, self.generate_air_proof_input()) - } -} -``` - -The struct implementing `Chip` is stateful and stores **records**, which are the minimal amount of data necessary to generate the values in the trace matrix. A chip owns exactly one AIR. - -- We must have `Chip` generic in `SC` to avoid many issues with returning `Arc>`. -- If you have an enum of `Chip`s, you can derive `Chip` on the enum using proc-macro `#[derive(Chip)]` from `afs_derive`. The macro expects the enum to be generic in ``. - -#### `StarkGenericConfig` - -`StarkGenericConfig` is a complicated trait with deeply nested associated types. There are various typedefs to get associated types out of it. The most important is `Val`; this is the field `F` you want. Import `Val` from `afs_stark_backend::config::Val`, which is a re-export of `p3_uni_stark::Val`. - -Usual way to implement: - -```rust -impl Chip for MyChip> -where Val: PrimeField32 { - // .. -} -``` - -If you need `F` for some reason and the above doesn't work, another way is: - -```rust -impl Chip for MyChip -where Domain: PolynomialSpace { - // .. -} -``` diff --git a/docs/crates/vm-extensions.md b/docs/crates/vm-extensions.md index 5ce4ce54a1..ea15304ba7 100644 --- a/docs/crates/vm-extensions.md +++ b/docs/crates/vm-extensions.md @@ -12,7 +12,8 @@ pub trait VmExtension { } ``` -The `VmExtensionTrait` is a way to specify how to construct a collection of chips and all assign opcodes to be handled by them. This data is collected into a `VmInventory` struct, which is returned. +The `VmExtension` trait is a way to specify how to construct a collection of chips and all assign opcodes to be handled +by them. This data is collected into a `VmInventory` struct, which is returned. To handle previous chip dependencies necessary for chip construction and also automatic bus index management, we provide a `VmInventoryBuilder` api. @@ -123,7 +124,7 @@ The macro will also make two big enums: one that is an enum of the `Ext*::Execut The macro will then generate a `create_chip_complex` function. -For that we need to understand what `VmChipComplex` is: it replaces the role of the previous `VmChipSet` and consists of: +For that we need to understand what `VmChipComplex` consists of: - System chips - `VmInventory` @@ -152,19 +153,9 @@ function. What this does in words: For each extension's inventory generation, the `VmInventoryBuilder` is provided with a view of all current chips already inside the running chip complex. This means the inventory generation process is sequential in the order the extensions are specified, and each extension has borrow access to all chips constructed by any extension before it. -### `VirtualMachine` - -The top level structs of `VirtualMachine`, `VmExecutor`, `SegmentExecutor` remain almost entirely the same, but now has `VmConfig` as a generic: - -```rust -pub struct VirtualMachine; -``` - -TODO: discuss usage - ## Examples -The `extensions/` folder contains extensions implementing all non-system functionality via several extensions. For example, the `Rv32I`, `Rv32M`, and `Rv32Io` extensions implement `VmExtension` in [`openvm-rv32im-circuit`](../../extensions/rv32im/circuit/) and correspond to the RISC-V 32-bit base and multiplication instruction sets and an extension for IO, respectively. +The [`extensions/`](../../extensions/) folder contains extensions implementing all non-system functionality via custom extensions. For example, the `Rv32I`, `Rv32M`, and `Rv32Io` extensions implement `VmExtension` in [`openvm-rv32im-circuit`](../../extensions/rv32im/circuit/) and correspond to the RISC-V 32-bit base and multiplication instruction sets and an extension for IO, respectively. # Design Choices diff --git a/docs/crates/vm.md b/docs/crates/vm.md index d60049d8ea..ce873f37bf 100644 --- a/docs/crates/vm.md +++ b/docs/crates/vm.md @@ -2,36 +2,40 @@ ### `InstructionExecutor` Trait -We define an **instruction** to be a VM **opcode** combined with the **operands** to the opcode. Running the instrumented runtime for an opcode is encapsulated in the following trait: +We define an **instruction** to be an **opcode** combined with the **operands** for the opcode. Running the instrumented +runtime for an opcode is encapsulated in the following trait: ```rust pub trait InstructionExecutor { - /// Runtime execution of the instruction, if the instruction is - /// owned by the current instance. May internally store records of - /// this call for later trace generation. + /// Runtime execution of the instruction, if the instruction is owned by the + /// current instance. May internally store records of this call for later trace generation. fn execute( &mut self, instruction: Instruction, - from_state: ExecutionState, - ) -> Result, ExecutionError>; + from_state: ExecutionState, + ) -> Result>; } ``` +There is a `struct VmOpcode(usize)` to protect the global opcode `usize`, which must be globally unique for each opcode +supported in a given VM. + ### Chips for Opcode Groups -We divide all opcodes in the VM into groups, each of which is handled by a single **chip**. A chip should be a struct of type `C` and associated Air of type `A` which satisfy the following trait bounds: +Opcodes are partitioned into groups, each of which is handled by a single **chip**. A chip should be a struct of +type `C` and associated Air of type `A` which satisfy the following trait bounds: ```rust C: Chip + InstructionExecutor A: Air + BaseAir + BaseAirWithPublicValues ``` -Together, these perform the following functionalities: - -- **Keygen:** This is done via the `.eval()` function from `Air` -- **Trace Generation:** This is done by calling `.execute()` from `InstructionExecutor` which stores execution records and then `generate_air_proof_input()` from `Chip` which generates the trace using the corresponding records. +Together, these provide the following functionalities: -There is a `struct VmOpcode(usize)` to protect the global opcode usize. +- **Keygen:** Performed via the `Air::::eval()` function. +- **Trace Generation:** This is done by calling `InstructionExecutor::::execute()` which computes and stores + execution records and then `Chip::::generate_air_proof_input()` which generates the trace using the corresponding + records. ### Phantom Sub-Instructions @@ -53,103 +57,80 @@ pub trait PhantomSubExecutor { pub struct PhantomDiscriminant(pub u16); ``` -The `PhantomChip` maintains a map `FxHashMap>>` to handle different phantom sub-instructions. +The `PhantomChip` internally maintains a mapping from `PhantomDiscriminant` to `Box>>` to +handle different phantom sub-instructions. ### VM Configuration -**This section needs to be updated for extensions.** - -Each specific instantiation of a modular VM is defined in the following structs which handle VMs with/without continuations: +Each specific instantiation of a modular VM is defined by the following struct: ```rust -pub struct VirtualMachine { - pub config: VC, - /// Streams are shared between `ExecutionSegment`s and within each - /// segment shared with any chip(s) that handle hint opcodes - streams: Arc>>, - initial_memory: Option>, -} - -pub struct SingleSegmentVM { - pub config: VC, - _marker: PhantomData, +pub struct VirtualMachine { + pub engine: E, + pub executor: VmExecutor, VC>, } ``` -The `Streams` holds an `input_stream` and `hint_stream`: +The engine type `E` should be `openvm_stark_backend::engine::StarkEngine `and the VM config type `VC` is +`openvm_circuit::arch::config::VmConfig>`, shown below. ```rust -pub struct Streams { - pub input_stream: VecDeque>, - pub hint_stream: VecDeque, -} -``` - -Configuration of opcodes and memory is handled by: +pub trait VmConfig: Clone + Serialize + DeserializeOwned { + type Executor: InstructionExecutor + AnyEnum + ChipUsageGetter; + type Periphery: AnyEnum + ChipUsageGetter; -```rust -pub struct VC { - /// List of all executors except modular executors. - pub executors: Vec, - /// List of all supported modulus - pub supported_modulus: Vec, - - pub poseidon2_max_constraint_degree: usize, - pub memory_config: MemoryConfig, - pub num_public_values: usize, - pub max_segment_len: usize, - pub collect_metrics: bool, -} + /// Must contain system config + fn system(&self) -> &SystemConfig; + fn system_mut(&mut self) -> &mut SystemConfig; -pub struct MemoryConfig { - pub addr_space_max_bits: usize, - pub pointer_max_bits: usize, - pub clk_max_bits: usize, - pub decomp: usize, - pub persistence_type: PersistenceType, + fn create_chip_complex( + &self, + ) -> Result, VmInventoryError>; } ``` +A `VmConfig` has two associated types: `Executor` and `Periphery`. The `Executor` is typically an enum over chips that +are instruction executors, while `Periphery` is an enum for the chips that are not. +See [VM Extensions](./vm-extensions.md) for more details. + ### ZK Operations for the VM #### Keygen -TODO: Update for `VmChipComplex`. +Key generation is computed from the `VmConfig` describing the VM. The `VmConfig` is used to create the `VmChipComplex`, +which in turn provides the list of AIRs that are used in the proving and verification process. #### Trace Generation Trace generation proceeds from: -> `VirtualMachine.execute_and_generate_with_cached_program()` +> `VirtualMachine::execute_and_generate_with_cached_program()` -with subsets of functionality offered by `.execute()` and `execute_and_generate()`. The following struct tracks each continuation segment: +with subsets of functionality offered by `VirtualMachine::execute()` and `VirtualMachine::execute_and_generate()`. The +following struct tracks each continuation segment: ```rust -pub struct ExecutionSegment { - pub config: VC, - pub chip_set: VmChipSet, - - // The streams should be mutated in serial without thread-safety, - // but the `VmCoreChip` trait requires thread-safety. - pub streams: Arc>>, - - pub final_memory: Option>, - - pub cycle_tracker: CycleTracker, - /// Collected metrics for this segment alone. - /// Only collected when `config.collect_metrics` is true. - pub(crate) collected_metrics: VmMetrics, +pub struct ExecutionSegment> { + pub chip_complex: VmChipComplex, + pub final_memory: Option>, + pub air_names: Vec, + pub since_last_segment_check: usize, } ``` This will: -- Split the execution into `ExecutionSegment`s using `ExecutionSegment.execute_from_pc()`, which calls `ExecutionSegment.should_segment()` to segment online. Note that this creates a `VmChipSet` for each segment from `VmConfig.create_chip_set()`, where **each segment contains each chip**. It also passes all streams to all segments and runs the generation in serial. -- Generate traces for each segment by calling `VmChipSet.generate_proof_input()`, which iterates through all chips in order and calls `generate_proof_input()`. +- Split the execution into `ExecutionSegment`s using `ExecutionSegment.execute_from_pc()`, which calls + `ExecutionSegment.should_segment()` to segment online. Note that this creates a `VmChipComplex` for each segment from + `VmConfig.create_chip_set()`, where **each segment contains each chip**. It also passes all streams to all segments + and runs the generation in serial. +- Generate traces for each segment by calling `VmChipSet.generate_proof_input()`, which iterates through all chips in + order and calls `generate_proof_input()`. #### Proof Generation -This is done by calling `StarkEngine.prove()` on `ProofInput` created from each segment in `generate_proof_input()`. There is no SDK-level API for this in `VirtualMachine` at present. +Prove generation is performed by calling `StarkEngine.prove()` on `ProofInput` created from each segment in +`generate_proof_input()`. There is no SDK-level API for this in `VirtualMachine` at present. ## VM Integration API @@ -168,14 +149,21 @@ Most chips in the VM satisfy this, with notable exceptions being Keccak and Pose - `VmCoreChip>` - `VmCoreAir>` -[!WARNING] -The word **core** will be banned from usage outside of this context. +> [!WARNING] +> The word **core** will be banned from usage outside of this context. -Main idea: each VM chip will be created from an AdapterChip and a CoreChip. Analogously, the VM AIR is created from an AdapterAir and CoreAir so that the columns of the VM AIR are formed by concatenating the columns from the AdapterAir followed by the CoreAir. +Main idea: each VM chip is created from an `AdapterChip` and a `CoreChip`. Analogously, the VM AIR is created from an +`AdapterAir` and `CoreAir` so that the columns of the VM AIR are formed by concatenating the columns from the +`AdapterAir` followed by the `CoreAir`. -The AdapterChip is responsible for all interactions with the VM system: it owns interactions with the memory bus, program bus, execution bus. It will read data from memory and expose the data (but not intermediate pointers, address spaces, etc.) to the CoreChip and then write data provided by the CoreChip back to memory. +The `AdapterChip` is responsible for all interactions with the VM system: it owns interactions with the memory bus, +program bus, execution bus. It will read data from memory and expose the data (but not intermediate pointers, address +spaces, etc.) to the CoreChip and then write data provided by the CoreChip back to memory. -The AdapterAir does not see the CoreAir, but the CoreAir is able to see the AdapterAir, meaning that the same AdapterAir can be used with several CoreAir's. The AdapterInterface provides a way for CoreAir to provide expressions to be included in AdapterAir constraints -- in particular AdapterAir interactions can still involve CoreAir expressions. +The `AdapterAir` does not see the `CoreAir`, but the `CoreAir` is able to see the `AdapterAir`, meaning that the same +`AdapterAir` +can be used with several `CoreAir`'s. The AdapterInterface provides a way for `CoreAir` to provide expressions to be +included in `AdapterAir` constraints -- in particular `AdapterAir` interactions can still involve `CoreAir` expressions. Traits with their associated types and functions: @@ -192,24 +180,24 @@ pub trait VmAdapterChip { type ReadRecord: Send; /// Records generated by adapter after main instruction execution type WriteRecord: Send; - /// AdapterAir should not have public values + /// `AdapterAir` should not have public values type Air: BaseAir + Clone; - type Interface: VmAdapterInterface; + type Interface: VmAdapterInterface; fn preprocess( &mut self, memory: &mut MemoryChip, instruction: &Instruction, - ) -> Result<(Reads>, Self::ReadRecord)>; + ) -> Result<(>::Reads, Self::ReadRecord)>; fn postprocess( &mut self, memory: &mut MemoryChip, instruction: &Instruction, - from_state: ExecutionState, + from_state: ExecutionState, ctx: AdapterRuntimeContext>, read_record: &Self::ReadRecord, - ) -> Result<(ExecutionState, Self::WriteRecord)>; + ) -> Result<(ExecutionState, Self::WriteRecord)>; /// Populates `row_slice` with values corresponding to `record`. /// The provided `row_slice` will have length equal to `self.air().width()`. @@ -220,7 +208,10 @@ pub trait VmAdapterChip { row_slice: &mut [F], read_record: Self::ReadRecord, write_record: Self::WriteRecord, + aux_cols_factory: &MemoryAuxColsFactory, ); + + fn air(&self) -> &Self::Air; } pub trait VmAdapterAir: BaseAir { @@ -272,7 +263,7 @@ pub struct AdapterRuntimeContext> { pub writes: I::Writes, } -// For passing from CoreAir to AdapterAir with T = AB::Expr +// For passing from `CoreAir` to `AdapterAir` with T = AB::Expr pub struct AdapterAirContext> { /// Leave as `None` to allow the adapter to decide the `to_pc` automatically. pub to_pc: Option, @@ -282,8 +273,8 @@ pub struct AdapterAirContext> { } ``` -[!WARNING] -You do not need to implement `Air` on the struct you implement `VmAdapterAir` or `VmCoreAir` on. +> [!WARNING] +> You do not need to implement `Air` on the struct you implement `VmAdapterAir` or `VmCoreAir` on. ### Creating a Chip from Adapter and Core @@ -366,4 +357,4 @@ pub struct ImmInstruction { pub opcode: T, pub imm: T } -``` \ No newline at end of file +``` From bcaddf635b43df0e239d71d7b78458c262244da0 Mon Sep 17 00:00:00 2001 From: Golovanov399 Date: Mon, 16 Dec 2024 05:38:41 +0300 Subject: [PATCH 15/27] Turn MathJax on, replace $...$ with \\(...\\) (#1067) --- book/book.toml | 4 +--- book/src/custom-extensions/algebra.md | 11 +++++------ book/src/custom-extensions/ecc.md | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/book/book.toml b/book/book.toml index 2e20f98145..c1c5a8953f 100644 --- a/book/book.toml +++ b/book/book.toml @@ -7,6 +7,4 @@ title = "OpenVM Book" [output.html] site-url = "https://book.openvm.dev/" -additional-head = [ - "" -] \ No newline at end of file +mathjax-support = true \ No newline at end of file diff --git a/book/src/custom-extensions/algebra.md b/book/src/custom-extensions/algebra.md index b5b00aea3e..47585c97be 100644 --- a/book/src/custom-extensions/algebra.md +++ b/book/src/custom-extensions/algebra.md @@ -1,6 +1,6 @@ # OpenVM Algebra -The OpenVM Algebra extension provides tools to create and manipulate modular arithmetic structures and their complex extensions. For example, if $p$ is prime, OpenVM Algebra can handle modular arithmetic in $\mathbb{F}_p$​ and its quadratic extension fields $\mathbb{F}_p[x]/(x^2 + 1)$. +The OpenVM Algebra extension provides tools to create and manipulate modular arithmetic structures and their complex extensions. For example, if \\(p\\) is prime, OpenVM Algebra can handle modular arithmetic in \\(\mathbb{F}_p\\)​ and its quadratic extension fields \\(\mathbb{F}_p[x]/(x^2 + 1)\\). The functional part is provided by the `openvm-algebra-guest` crate, which is a guest library that can be used in any OpenVM program. The macros for creating corresponding structs are in the `openvm-algebra-moduli-setup` and `openvm-algebra-complex-macros` crates. @@ -8,7 +8,7 @@ The functional part is provided by the `openvm-algebra-guest` crate, which is a - `IntMod` trait: Defines the type `Repr` and constants `MODULUS`, `NUM_LIMBS`, `ZERO`, and `ONE`. It also provides basic methods for constructing a modular arithmetic object and performing arithmetic operations. - - `Repr` typically is `[u8; NUM_LIMBS]`, representing the number’s underlying storage. + - `Repr` typically is `[u8; NUM_LIMBS]`, representing the number's underlying storage. - `MODULUS` is the compile-time known modulus. - `ZERO` and `ONE` represent the additive and multiplicative identities, respectively. - Constructors include `from_repr`, `from_le_bytes`, `from_be_bytes`, `from_u8`, `from_u32`, and `from_u64`. @@ -21,7 +21,6 @@ The functional part is provided by the `openvm-algebra-guest` crate, which is a To [leverage](./overview.md) compile-time known moduli for performance, you declare, initialize, and then set up the arithmetic structures: 1. **Declare**: Use the `moduli_declare!` macro to define a modular arithmetic struct. This can be done multiple times in various crates or modules: - ```rust moduli_declare! { Bls12_381Fp { modulus = "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab" }, @@ -42,7 +41,7 @@ moduli_init! { This step enumerates the declared moduli (e.g., `0` for the first one, `1` for the second one) and sets up internal linkage so the compiler can generate the appropriate RISC-V instructions associated with each modulus. -3. **Setup**: At runtime, before performing arithmetic, a setup instruction must be sent to ensure security and correctness. For the $i$-th modulus, you call `setup_()` (e.g., `setup_0()` or `setup_1()`). Alternatively, `setup_all_moduli()` can be used to handle all declared moduli. +3. **Setup**: At runtime, before performing arithmetic, a setup instruction must be sent to ensure security and correctness. For the \\(i\\)-th modulus, you call `setup_()` (e.g., `setup_0()` or `setup_1()`). Alternatively, `setup_all_moduli()` can be used to handle all declared moduli. **Summary**: - `moduli_declare!`: Declares modular arithmetic structures and can be done multiple times. @@ -51,7 +50,7 @@ This step enumerates the declared moduli (e.g., `0` for the first one, `1` for t ## Complex field extension -Complex extensions, such as $\mathbb{F}_p[x]/(x^2 + 1)$, are defined similarly using `complex_declare!` and `complex_init!`: +Complex extensions, such as \\(\mathbb{F}_p[x]/(x^2 + 1)\\), are defined similarly using `complex_declare!` and `complex_init!`: 1. **Declare**: @@ -154,4 +153,4 @@ supported_modulus = ["1157920892373161954235709850086879078532699846656405640394 supported_modulus = ["115792089237316195423570985008687907853269984665640564039457584007908834671663"] ``` -The `supported_modulus` parameter is a list of moduli that the guest program will use. They must be provided in decimal format in the `.toml` file. \ No newline at end of file +The `supported_modulus` parameter is a list of moduli that the guest program will use. They must be provided in decimal format in the `.toml` file. diff --git a/book/src/custom-extensions/ecc.md b/book/src/custom-extensions/ecc.md index 8690af860d..5a0dd3c36e 100644 --- a/book/src/custom-extensions/ecc.md +++ b/book/src/custom-extensions/ecc.md @@ -38,7 +38,7 @@ sw_declare! { } ``` -Each declared curve must specify the `mod_type` (implementing `IntMod`) and a constant `b` for the Weierstrass curve equation $y^2 = x^3 + b$. +Each declared curve must specify the `mod_type` (implementing `IntMod`) and a constant `b` for the Weierstrass curve equation \\(y^2 = x^3 + b\\). This creates `Bls12_381G1Affine` and `Bn254G1Affine` structs which implement the `Group` and `WeierstrassPoint` traits. The underlying memory layout of the structs uses the memory layout of the `Bls12_381Fp` and `Bn254Fp` structs, respectively. 2. **Init**: Called once, it enumerates these curves and allows the compiler to produce optimized instructions: From ea8d7908881580fed106b63cea400920cdf99a6f Mon Sep 17 00:00:00 2001 From: Zach Langley Date: Sun, 15 Dec 2024 21:39:55 -0500 Subject: [PATCH 16/27] docs: Add Continuation VM doc to continuations.md (#1055) * docs: Add Continuation VM doc to continuations.md * Update language * comments * fix agg-2 image --- assets/agg-2.png | Bin 0 -> 88297 bytes assets/agg.png | Bin 0 -> 91907 bytes docs/specs/aggregation.md | 103 ------------------ docs/specs/continuations.md | 205 ++++++++++++++++++++++++++++++++++-- 4 files changed, 199 insertions(+), 109 deletions(-) create mode 100644 assets/agg-2.png create mode 100644 assets/agg.png delete mode 100644 docs/specs/aggregation.md diff --git a/assets/agg-2.png b/assets/agg-2.png new file mode 100644 index 0000000000000000000000000000000000000000..11fcc8de813fa0d824192b83a52f51783baa56f0 GIT binary patch literal 88297 zcmeFZcUY5Yw>KKcQD zp+u<$2tiRgM8VKWL?EFD2oOTrcR%>Pd!KKgbN<--`o3@Pb6tna0zAp{+-0rb`mNtu zckW*}Z@Kkvd;bQ5!L}mK{%!|@Z9EBs{TT4mM(8&$?t6p(e#HD8;qVjqiu%d(FBt3q z4DtJK4&fQoLlKFWLo#K@`RD6Dj~#I9{qfLGCNB%Oy&Ua=2i`gHR(#>d)B87^*%PvH=Y}1>dTo6bv*+wjZiZ)nIw?|2O6-};UAUbekSo9BI9RIDq>T=c1&7l!~I*VzP<3EY)_gie_9`#$hbtJ>80bli0k#b;gp}($fJ#eK=k*0NUhE5t zpP%SqC3kk+nSWWJJTYE4HXLC)%3-&4WNc`4Dld1itzNoUpffSi2kWi*`2e^}9lxSy z9mV`@frpHD-NQ6TwhqgC(w&@}cnI%*p3L+$srIFgoAz)!M2eYx1?8&^ZqX4-ICJye zuyhKCs0a-te5`=!i`}O1i514ZpVirU`CO3`Z{lhAedbiTgGQ17^ZmJYx^M7o52n^efi*2~tdUcQWP9{QuEbcB7eAVwaQU~P z+Q|=ocAzA7b8>Ub%By-maEk5nv#I&6Y9Aw1VUfvjV4kp;-DhugVF(|1>tH&Y!NXv% zIq`{st+1LcYx9M{PS*c=68sjt^4{T?wQpcsE!Xw~2HP74`)+Fb3hRDcyLRKm+C9L= z-u&^Gwck7+{^`KlH~+Oank%`O??6yqibSY+B{X_0xJch$cUHGW3))hVkEqB8jBlyD zO)!t&7skpD-@|-8@Eof_wV*l-=FE8&zzcI zcCV^d<~yiQj8C_9sydH0duf!c+|QBM4L`YY+jxppBFe?nm%mIc?e-+v5gZGg@@O={ z!@WnlDLflBl>j^kx4ur}_S!-&zO~9B2siKIbZQiL(DalLvS?iA;9z3oE{mrUK`P;} z99!r58T3-&c3D!(y<>B9^X0aY>_jm&(Jo)P+_kw)q}2RPHQAev%grt?7aGTvUQI?y zC*#BmJ@odLq=HiKq1D95<`^kXFCt~$c=%a;XI_}w0E;ZpUftk@^+AIA6-S8_i1&aW7S$TOVqoy|NaFRo3cQ?UK zI$q*pyY(~E(YnaP*3Hk)N-f_>!{zPV{S5r@&WIVm+}ut&PtSsmIul38CRlmZW6u$i zlR4+&5|o)%UI}4c<^!v7gYyIOK4@MhZh258$#+Qw8L=Lwv*Y_h+;Vq!r>+dZ+on9K z@kbshWkyR@vpsbBuFcg&@j4l~iJnbg*F}sEZ!qR)DK*8iWXoo&<0HcO*5a1g>T@j< zJPU2G{4Mf4*=52gO*Y3-h**i1*ME()GEcq5yF>l@jfYy@FHlCD$8tX#OTqrJSfgd}nB;VoFQF)8tvki~?)ZP4#ADh8NhVd}$Ld%5?yx69@$UQ+hVrW=2=8nfZRO~g@ zY)z)LM96rZHY}g0WG!SW#X~GnZnl(;?Kd7}V!3j9-drW=L@9z$A8%q#5;x_`8wTHG z;TrPzcNw)hNb!PK>aplx3*qN3UDWI!VnKX#YAYQdKp6e=`nFcK;;oYnkB3ZvIpugP z)E(w8ys`C2Of6Mvez&Ps9olXGHy`Vwgzq&LBpUdq$`Ss<+l`mp8=+M_^b?G7_T2ZV zGS^~wZLl}j3N`lX-TMBpel%l7W-F+9**qbI;d- zRmP{K7et8XRrz<6JV^V{R6UAuFhxPsa0*lZIBb+CFE<)z%4>z@+85As-&pXF-Mn&Z z!1LRm$6e;YF0P=o+rZDGBsM>Jy0k}ID3FD@oY}@cWIFTK-Koemf#i<&3#<_qKiXIA z$XX7w^zQud#-(hf`B7h}r^OsAp``uQuuoudC}ZG@Lpz#RrPCu>SQfX!XKhrML^Bo5&px~56qOsuS(w39#gf>dl^58tMfhsm+E&tK zjJ;yijp#VDD7wOH;9+PiFGF;fmt9bxArliTN6WjG+i`kIZAD>&36i|oWDbYZmS(P+ zN8^?nFO=K!J1S`hfvvPrk#99ODZRBk6Q__yv>EUGJ5ruUB2g1 z+LExoZ9`_fj!TH-y-<#|>@3rT)ouRpHz`K+KX zQ^?HY195F+rk`HW$|wCweXo|${Z-Ck{$H3bttDO>1ZB4^@`zJr$+kM`jYnU`cmd! zFNE#9*>u*TRQKy+IE(FU^G$JbC6}9dFQS$;%eB(raUr8Nu&= zg?6tmH2v3!OYBsyR_C#L6kdh5DmvZgJvB_7NM?KWJ=keHzjC;fg68=f`=50x@Ia<$Nja4{k$>BPWRe}PZ|8?E`C#nC8kR&%xkvhE_EbK zz!Bh|Wiq0~N_sP2&AY0@D9X*f$K60Yv#qMC(v2Q8l-Iv;<;*svH1LFqitb1Kk>QF+ zv8RcNsosrGF`Dib>PGC)uw*l;S!)WV#a%E+3aDV|0>rZ-v1oP$J*8dQGbLl6-sSgL zPnJhcE`dM3lS{6IN#gH1$K6@Uv9(5tVYO4v1a(RsfeHtM%ttOWUz&UL8&;yPH!jDY# zgn16XR1u1WDV(&az~(s9N9|wVttTi41ZWL~NwpD2cxCQsY3YVhe20Cn91JhJ`Zdtx zI5T;~%wOwcIe%Wy_4@YbXJI|9)X1OzWnLpcyF6zsKmCP_r=jTTmZtX{PgicP5pFIW zdK+L@z^o!s9MoMZ199C&yt6b9#$@?aXJ;qD*FK~^r-U$TZC!+9zq$JHtop=IbrJTS zZ+TiShqDzuY8>#a6wO}VO1hepwn>qgZi}CFqoNul5rP5sv;ARv(pT*@E~wiMU6$0Q z%5h)c5wJYHEbZ+Lk{qOj%55;p9;OVp9imaYZOdKT+g##DCrLvYjk|RaYAPT^`UD2H zjDJ2{!c{aK>oJmOTc;F-S8Xuk|Bh4JH*0D~lvGW17cmO^15eb37J=MXQ#3@+}P!#OgB+(i4A~9saTX znef7F>MeYSbgmln{&?)z6K7u1&m)%TLA`*YqKGAFHCLdgc-FprB7dj4AEswWz z@IUT(;ojDL1T4ye;FibEv{HeVqqu6dK^Z}^pcyI961lIAjmgKO!-GD*R5iLBIu-xJ z$9p?==~sTwIGx{KXXe!H`ZV$)Q)yNw2k@Ik@J{(jdW*)%mm zU1nX2^W|X)05NN4#DQEM*rm!u#A)Or1?6s+7}N&#Du%OG`Bvg`3>nmx6;sbDSyNHhbVEhb{e|n#-A~ zAxZ`k?^C~SR%-J>5ff~2%il6qJB)G?J8|)k?FdjT_!Ny#z(=vE#^ZAdm_8$T(*1$> zzSo`EZYn(Er9br@$-+e{yD5($X*hzROR{^oMXI&hYRy+S@e*Q{Qc3vL9v%OZb}qwM z&+V~7@>r|0mt?gA9w`CCN?vBsy1EMtMgXAx8hftYjV*a2ZcRnE*WH#F^;IN#E}S1g z#m-oc@mSGLgluOwKbA;N)${#I0H2|>dQCd=vb0nbXvztR<@M0c5fmi%?&x_f{0XMX zc`gZKSi&Q&DyEelPzvX{0nVZ|^wa(rXJtQmkPpXjy;{mnxoY^4*?ocOR~vETi-(C1 ze#L`Lg>sj<-fwNG{2LJOSYBp<{G?BsA9JyQ+11yV!Fisgul28 z{zgCHNZdIdE5N0)_;9IG28a^GOx1uCt8&67r8E+iuVn4#*J>}?);dE^eHt>=gBrMa zxa8(%!s1kq>cHduNx8Dp9JDQ$uSufYo4y7mU zX(1ELYOOmPml$!|8*`~t_ER=10_jwIITPIM>EV0c-kzi*TW@Z zmCn*@XXK4Sr^@t=@_<2hh(rT})=u?e(ju*!$Nz zS$SdVh+R4^$s%uyMBqv`y&#rsolc>b;T_bIG$XG?)B?g~fPYp#S6Ce=>f0?9&|qIb z9*hCT4P&%!{`I6`|IOwc0$4^4C)dFaLHknej8aB`M5jehao`tCLL_d)i_(dk$aO7} zE=~p3a4iiBO?-UGNAiPt_Ev^2x8DqV>}Sr-$iArm^;ocY)^O0XhDx2t$F&?0`41L5 z6@=m4DFJT}t~T&w;rDWV4f6e0Eyy4-6x~hSDw53mGkpzmzS!scKf{gmBw3B+CuuL` zaf*WB&MjS~(j1=17Pkw;DV^Qgw>N+>*ZBLJ36c2@Rko|LH?Bp?86tlND`GiXV8}R; zD$DbbP4uWSOu9*|*@^JEJP$$YfH{APyIPBFSS@8Yl1Qr)0@s!jDW z6wI77H{WJnSWuAc=-1QJb$Q}{(ry;g_eBpm7C9)oR$L3%Wl^iiB;zG?D%n9jB5M9Y zTcl?*!K0m7jg3@<8KT?&nf5praVAw-o#->U11NOJ+!qAMYHZba9`wXqMA#8DFTK^L z*MvAlRyrx^oMT!>hHJtMF>6$1u13oT_pRc#R}j6Ew2AhhNd#OiHwpR=*@#$#Q+WoKL&d(|1T%O4PhQvC?;Q* zXzD7Bf#O=_>e&;w8gq#mKf?@-)>gA_b76jG`E~WwvU!n}8rq*7I$&XLydCBrxJI#K zcDt(JQ#|Lo*v_lYJt+u$DWqF4de29po{Yi6uxvixS+Kunud3Yd>#(Y!}Qw`JaN; zna`C}XKVG;)X{0>Otqx-RxLGFDsqklD|>5uKU)U0PC)ysndVQ{GX}YJ^@8aMWAK3Q z(Hf>h>{bpiH~$glANSu&*ZV)=%>Q54KL7tU`uB?U+&48_$tGCMhktm-^W!trfzSD& z`l|Vhi$`^+{Yn)rGeUu9eLC8TKvNaFciQnjQ$2QQEsb`-N4wj`ClIhJ+tbcO_8foZ(ZZ=-eUZ(|bDm=5WMkYd8{JiW>Q<5x(0@=(~+#I5mz6!^E-Q4$TM z01?PS%wEunmSPcsQxmDM-YCcKs`}R?N+YC5fC769CZnUvUDba5D?Rzz9yWT z=_KV^l_xr=pF6Mj1aK|;aP%mCtQC*xaBKJ-tvM+kY1Ok;8X!d;@T^YKaF#k!hCYA(EZGZg*@Uv-r)EU2PT-fK z^iUmbLN19U>A|!c^mz7{`4~^X zu3w0Six1Yv$}!x-hL-S=0k9hm-%Yb*d1WM?dq+upg(Y3Cv>wt`VFWb&d^8DYc%qSrATBm5Y z%cC-$P8C@k^|w+U=DYy}g|PiK#Qd#KYPpvxpSnI;AS0Rb*m!9Low z#meCiQ zv$vvopu5Gz#VyVbnPz5YLU+VsMaU&Rh$Dgeosn1n!J_Kvh)-jxw5i2~Yb%3X3uiDs z`)JVsJ8)rz>{!q;NX4{1*s0Ot=4iebzJ_UszDH0d}CjQgCTOv1w>H*VeQ&|%7}v9nSOW8=b% zC$bY-vJnZOM#A$51$!4X5Kx(9X9aRfO>SnGhw)TlX^V61LXxgmOQJ4rbuoyOib|$L zjcJU1wp7xxRJip!!tThqG>15|g(m1a&^P}IYTO@|XlDg#d@jOoyXlvp`9SY4>G8lO zm3EjE0PW-@m{(CH%Qg30x>E;SCN3EWtWM%H;B=re)xhBSTR9z>$n&Nnk^3@4W!CZ?iOA%U%__mis3B0uu5T5nCn= z8hvV+9Kq)R9n!Xl5{TCnh-SorZE`}yv$1~7LLWN-*!|%NY?S9uK?aY}hW<&Ys8fENTYp7G|(O+TwLB%{MJ`#fYjJwOIY7b=LfvSxTVV6}=d7+gTheqjuQoz5g(OXM<#8XQqpkyoN_lr@ zQy!8YEq~(X6=KvvvqJ$B@+1UgDW2VhE>upMpKj#hIN1ErG{0g57K=48HSPNHrK~vv zLQ5A^W)kG}6ztHHZqR5Ggz{_=ORxZt&xnQ7KsN>-SZrNe-}Xj zuN!Mk;ab91FLs<5c?1Efyjl3odt2lQw$Td-!U#5KNaY6(hK&gJp&Km1W(ObbIeuujd+WErcWFE#;4>m)VcO6!zad+nd;0<-HPM~hJ zb{)*Rqs*tP6YQzyslT3`xOHuHc_tl@2QxpFMiAnIzzaBk9gb^)taPSgKpWx%m2}C> zYyhZ&_e=p#OIIlMpycJ`sBAxC({y^bdm@O{d3c!=TuMED{S2`6(vdjRTxW_0BdxN$ z+(4BWehpX%DFgV5a6TTNA)xVa^17a93BfWvU9#Nj=fO{#l@PlyjK&d%D}8nVoq*$_%=eDq?LCbHHH zp^IkKh!^wV?Er3c0|(y%?_Qi_YCw^K)1IDUfm;R559QdMA3z*i01J4SzVcB=7uAuW zjBs;vI}@*%3DKu=*CG+&5(twBLUV#Diqn=#{q{fuVqk6QMmngBTW4xPEQ0%$H|w2y zcI+UE7~yTP`Z+!~kpLjp81M-ML9235cf0EOwzXx%hKZLe>Fteh>HOfW#{EMYC#5IO zi&fsd1baIE=|x0WIxDeNhi=w`#N!BCZ;gR?>7-2^C7in!5BuR{R_PCG%(@Q@g#cjX2M)$2A{}RUiPLA03WW>X@ly6EO^PBN2~|CybVLoo@w1ZMbIQ9J&SiMj@!_ zpz-Y65hx@8jLHUEN1ZNd4VtBL*KQ>fGh`6OgTmdjO4>|-@%)GFKwcfhH5WM3CLN7= zHGC*?a=36=1Sn5DP1Qqj{E#A7fmI?`H+=5vG)=$~zTaK@1cXP80W=*az<@yPZZUt~ zcC`0;eES_ai)Xh+8piVA5+4vUlZV3CG;GKjXXlNd5&=`E zJ{)gGI2?E45M)WaG%r1Y2nKb&VIL{PSO<2)6TkX030OG{e_O3g$` zK#K4>{kH%csBI&fn}WQhsHmt9Cm1Rn0}x-*zCUd6>D|q{y%$EC`@GWwpslwdS(u-? zx23sOG@I^0i}YgEL_mBHA`^w~)rP<(ZJnK+b8S)y5ZeNG6it`f61E=v1|HG@?woS` zdV{B6D2(UPKF>7+*a$(5-mPyR9_=%lbzv}4^;99ola`iNQV;6LAY#~*9K1Fd(&G+2 z#zQjc9EQesoioa@C0V4JMFe#hxupP4Kn=dV)fYMtP#QGWav3{Q-Up0W50De(ecI~` z0Z}m%&(+JDM+QR!TMGe-Ab5*s!|1IRqUkP4?`9uX%?4vGn_k9Q-G?^y<765|4{w0O zVB)*qGl+w#B?LH2jq`m ze9O-%B5R`}fRvvEq7dET`VTOje_88+xp5XmHOM%$tEWrA+E$3>i;IiJ19XWSYd$V) z6k@-gr1ZclHOO@U-9%2_S{JkX*;*c_pAGs5GJ;yvgn*h>Hb02lq!e`wa_nLd7TQwv z@qPV7f zKsr5T5`nFspWiO+%g-QZXajzl0@AWE=v`o=i6Fu7{`g>L#FQI54GelPS~NqQBp2vn zm#1qaGiU~6J%A*rB8uOBdjN%ZU@TXn#Uo1G6uQ`pHFwWw6fIju>-qP-27NtQ5NS(N zv(L@W$~x@q5#a@KjD+(hYSl9pkfjim<1JQiK(~UnUfwj+KhAu)w`S6jVnwpRL0+5@ z#)?Qa3GpRBtJX4+M)t5jR9uA7FsN%^YMB4`D(!6p`eecTem42&8{^D zA)DXFh&DuH2L={^YpWolWg<2g@>xJi0Cmfl2Ji!M1pYg@=wkpyUCMnOi>oHd3b#J| zDqQWM6A=kV#z4GoFYs6*Uk+h9A_yP{@GK~*fEaaJR=kA?*cvY=(Ghd;QWO+j0*9)i zmP<+PQyzjUaTi=-4?@_$dXgrD0Wkfy5C{x;G45!?C*1Q=Qqn;yU6L(+wMzw|mXio^ zXMjI%#dEQ6&4;_R)DbNJt=z2C#t7EhYKRuF4lRW)r7gfJ?Uuo~f@I#};GDMeynpM0eI&+}EW35PO5W)^*gAR(} zUvHPlq@ols+av(X^k6`!0c<7%3YQX(7muvHzKbLc2D#fQD8;t|WGW;iiGi2$L9(Id z1-Kl`Ae zr<1_~==*gSHiKs;D1(fAX!Napu1#~@?ez)Sq7^{0FG02oTw)rqC3$#s6v6ZTpFcx+ z`NCYi9BO&G&!z0fMQAJ z?X1o`-do-r4W;6M7?l8&06Q{9#LhN9Hex+n(<;Vv@TtH!MnU#FO;kZN#4FL81+cnY zu^OZ$>6d|MFv_GvhZF-A?@wFmhJsHQi$%=M&4scLXsy9SA*=9edU9|`WME(r()iG` zzP$mzQm@1@=SA3B%-xpr1gwqF$0%UrDV?;OJ?Gb)8>`LFB^B{#!0QOHip|k_0zenRF7-G!5?gD2D2u|7{ zoeh8>3N_vP2HFN7o&en@y%s0pWMDd)0cV7=VThuN=O^PprIiD+KL&_1PoEyP^ak40 zcj3l`8stUT`r=UEFZvM90BQ(Prtcgm2Wm>=LJ3Sw1mDi88T_jYRu@_ch)TY?n6&_D zAEhY9c>rvnWswMFT|IQrrcmV8W6o%BREO1JzB8a3;UL0UI#E0_fiXklKX>jN0%Aa( zfcpxE(qiE$0DLjTJTdP!>>dS@6>8&_Jx>5u>Vk|Q;_K~AL6iA;-oPcPfJ6lKxQC6E zk|h3+*#q6;2$Wv{)gw(V>g#%l!Ge@dFjjz+_zDK^gUBV@_dWK7Lop3ZYzfk7AZ{cW zxwA>G1EHFk2%!D&CWV_P1u7KKfsss!UMlDdte&ZI4)F(16xMCBc(O0>?Ln|>9s58e zf%3UjI6k_#c6Ab@LLlM-Aq?FNMJ%A_ae=PU{&6=l1H?g1Fn+ZhAhzj&&?8HR2pELB zS7Y}l%i+dP8Lxc3li>f87GzsNOH5}JKrkSjv_UzjWO+abWFC-RY173EfGlbcm9B|J zFrC-`4sJ_8#g}7 z-TZeMvR;X)W<6F9;N>`w3%I(v5;3yxA{V$zj%!ga$k!SD`1Uk|A)_;BG+LIR2Yf9c z2vJP;G=zQiSxa^6HhX?~brCXt3?D-Z0?^kERIH2_r($bAB&@6Bd~atDzYQsa_+{be zEK4q*BokZfZ-x1@2GuqLe}cjOD?8hzaBP?&+S#2glF_;?PI))|{x1h?t`ZxSZLSjJ zx$91Ud;uVpTvVA*#2i@eUakPTTEA;vH(Bd%Cp5nP_(RJt2ii`Ztb_gh#8_F`xY-y> zVJm5<{&=ClySLeb!5z7!XpG|FmRF~rSZ<4#vnMEM|?T z`RBe*A2Q1$ll9Zv$(j$yL#41|Wox>6owv)FvnZ2g1zfN_W;*VZ~Qr&x`iX zteu#9w)s&x~N6e_28b!!=52O=`L>teMs8(;4%Gu7}L^L$L;% zTpNog+`>3ygDI3@0og`ZdD})c!|Ae%D(#_+60Mzxi^(5Lvn&@ozME)~hafX;NZ!Mip^!hiHeFLFo`?UEPK6M`!%+ z4bz6|AC8V6k~aun~pU6_L-sanN7IyLDYIp6zpswS#VgggG z(^;9})cio*#c`+naf!-qg-^3k=M(g@0BokTWmef(T83fczxi-8pDM@J>Oa2NSeuRQ zE(=?2%!7S8;{M%ou2>rK(kKE|#M2U&okdQBLD7tUf|4QVh`j+jmMwH%t9`qjc{98o z*1K)3Q3D1$+4#?6FLD1o_Okz<$6ieSdF&Mn#$BTya}k{`>Zc#XWK2?n(e zpV?wd){1(1DBsm_mzD=1r!_h6=z|T2HzrcnCRj{Sjum+xu_~q;!M2baj>scb;05HU zX^tO7oEH!g0)Mow;>E~$i>bFxNfi2M;`T68UWOj%db97m5$t8X`^n3rknD0oOOtZ^ z=vZOJ-a5JKF#)4x@_E5p9;LI7vf|CcD~;S2`xPSResf!jT)%$3JUsAnT9H#}lGzFF zs*>4jM;);9rv`t{%anOO03FyAVX;iGF@`&MY~)dj^!aCh=_}0^cIK@~Dm)c8<7gZ3 zaI@);`>*Vq*k|E8*iw$;W*ozuS5lY586)JYF7sy zx}COoGMatnqQaY^VvQJ>|6#|AkFgbKNf}@S=Jk=-0rPE;Mf;mNhFB7a4t+ju?sl+s zy=NX|7f@W1%!kZp6d^o@RpjfsBq=*y3@9~f{PCBV0N+-{(6x7({`vAKAwV?yJ%xtB z{!6S97W1F+lNc>jNHwV0`F@YnyDm5~3FIUlMf@Zc-w*IECc6N{9PpKSbsEdIKcCM3 zs&@LK#OdM=v<-9ienru3Z_Hd5ofN&$hi7-VR8SA)lYP%K3#D4Lv5-p1I95=JRfer0 zOH6y{2Om|zBI~%|_4#D3N6EYe5B8$lYwIi9gZ&M<`=s-6xe8XjbV(Okbj5(1#`(s@=pG zsLbaeGZHq+PMyBE1JZpO9?2&-*L?F5_Si;q<~UW-EC5EI&TRV)tQpL(>!XhW=EK`t zBUPb5BALJb7n!W?=;#IX_0$T6M^?`gh15Np3ft4ahQwD&ZQvvKiRwkanwt;FTSUEG zIsPH(^iz=3y}XfgL!kMuVa;W=dhgOjuHy$e*p=$<{fz0Bd|-g5)^-VWll+4b{BH!g z|C~927Q_Dl>`wpk;N{t@&(I&2WVHv^9wM{IuKDCiqqHK;R%Lp4ZhI<~Oy;&bA~k%< zT^XXCu<-NFkhOvev)9J@#s#ldT^=evx6j|ZbF?}2*sW`T*b}`=g*A;^w`>u&Fx-N2xm(}j#_H#y3Wr<`8Gb_{)l@n1Qt#T<}NPR>)c6?}PNaw*(N3!NK+3%6DTU)_) z;>WoA7w_=gQz0h$cA_z_I!`qoDBA;pRAYukwR&FWE$`?RTEPOLl+pghd|CYXhi$On zL*Em>8Q>gHamGS`CUq2OpDEU(jy{IzE@d~ba^Um7FZdOI2_Maq8yn+h5REH4qCevvpE)dG zg*bP>r@jn^wzm7|@1=KRRGUZQ;Y3hz$aQpdDfJG~rY{o2?XuN}X42m4E^N95(D9rB zd*i?44eTxOgk7<`x&ey3uZPqh=*F9gFIcR`<5L8Zc@gGYbDn40v*S=bvNmW!C8Bj7 zGM#~&@3etS{~U}GxToUyk0X|*v~9rFmG;?y-D}mANF)=JWcJ3s;DJ|IUaj6{QnZOG z@q|X!nfT@cq+oT&>8G4~Or_Hov;FlA13_ZrU5?n2H$jPmh__g{$+5VJPu6iu`xPYa6q=y<_NM)WUk{%dEl9x|8?oj_ z3f)T$+2VfZpz+~YZnG+>jhv)`ky;~x&8C9H-?O8r(zE&7N5oTwh%d+c{CGHGWxGQG zSvO)KQ2{gf=<>o{S<^mN_^st$Kg#1bSEXXrAW=Z&s3Qdj&O-X}G~G*1R5GYqn|E7e zD$5_g_WSv?5Z{J)(i5pvIv8FbuXpU&ll$9MIWMRf%$MVhqc1iowLQxWZCSTTAyI>} z;>2mk>JQP(sS6L#W4$BZqZMu_R72Z#-H>?mF8^(#EbMISVbC<8@^Ckh&ENE4`+-jR z`fz7g7fAdgPK2?Js{-i&MU0$mhWx5g(P+fTHT4JBfS%hGh%^qAAC5CIu{AG0(1Q#+ zM~n>m&2^s>$|kc4<=tj>Fd@$dfkYw|BX0)o(uu5My(g=ec+S7Pywb8cXdIjk0QJZnluPPKItqTk1wXrrbThK%LpZ(o4$e8n7a&| zAuqbebRmIsIRza(qY=?);U--8XD@&o`f-DHG{E z|MKp>T6`#LKG}$~pd*9oT@kgy$CR-Ebk(sQ4}N{3*Wrh|wA+x9F%dsr#zpgQ!$nzU zhCI~1KjLOeVB?xjF<_Np14RHxny$ujD_O!~F~8A*z{3ezGH!lD^o7wSn7M~aTIHf|f#l8^Ev`G`173icFBW{H2+XEgNW zaJ(Mj^J6_@A7JhQ%d2~oeZRnWZOt4L(ASdTS+1KzwmB#X(2Sf*0>%f_k4`F~F9hx!v;YR%wPtFfsT zBP%vT*C}QzbrRtRI8GlgMkzJz(}~7bRqc(a->1_t<62#O!Qy*Je@& zQo0n2d5th zk^#Bg%cHuo`>G3Fv5KH#q75a@qw|d%FLxxeNAYvBN7Gzos6vHCw)P{)CUy z@_;O6Q6K;<0l!8t{d8;y!C_(aqk9s)QhRDG-IyET#3T*z{|U|qfC(0X@a<3 zCd$*_`xrFSm?3Z#P4SfKBaQ`0x3_AzCTqD9q@b*y(=wrBY-*`wYJU2n8L#arnQUlL zYkUks4Tqx0xR;uxQNo2bnoODzxoREMv%ivCd&YU=#?{i$nY6ariF=?Xtm$=;a^84; z)Fsu-%W735s{Drk4R%9mEzj&NPV!0xLM-b2pZATY|2m8bW%n0esx@P;OpXbg;87zU zhIHX1Q6k*INm>^YiU6vSf)y%dJ^=0_n*Bz%*cOWkAa-j#hM+Yy-1&K1;K(z-+xE_~DM1dZ{>2x&t`k9N_ zR(3fSqL)V>>`)^d+9#)@WEvgC84R@s-5;4i8xAzvK_e4@H|@TA-}ltpl~EL&#Ktwc z>H2j~P&t!4uWlcd=Qr)@?4vC%6YYUAm-!=3(y2|Iks(?HYXc@VuFnf8(@ zvhw5NSxt|cW4md>fQa_H=x~;yJHlK5>O=%(wS95-HassCA|USNpYq^kQ%jNte*lfQ zw^-rg39%fDC(HuUIV8K^tn}Jx2o{O1uMdElnk}TXmS~n-6E0{XEA$J9?m&1XHK(%{ zmKDN39h`8hHUwQ-=;$CxIbba3Xd9edyuZ9U?otwdvAftMq5GcWLD2F97@G0;*E<;Q zOy$^%O=IVfg%_kVU8J)}B%9%$dU40;~3vwUz2Lfs8xzv@JZ7 zYz0<2ebX#mM{W?0TorAa{KQWOf>G$Pe;{oRnGDK2e@4ww;2D*)iT41ZW0h`so{8I= zQO6EnGqKLS_Z5E@S0Q*TeZ(%@M{m{r)l1WoDueID5!YJa+!YvOOSt{cEU5nHUoQkcSox?!!?o$T- zT`Rv5FL_rpX+UZ1RIy$tLPu%I7A6>8ptu1K6M;kbNr(hhZXt%jkV%pFr<*;NTc#@p zzJMW-$t9v$>}Z&*5zDug@sv7&MM8`xY%tnwmd*p=LlvH)EWc;ZSxmjL(jB@SXxa2n zTi^c0&&g1srgnJs4iZ@XBL!n!9sF1Uzc!4nQPh1BgmX2JyLIHrmPUl1kTUme=Hey? z<~?44KYqhWlwTPZ7W3lTBug|?a#Kh)q7U!nK4zhK=9Q~UAS%pO;{(A#(&gGiA9s@? z#ZOf$S5L2l?IGma4CGxbWN0+T?+Y6*bWugmV^pBAqKF~qf#)f{m9Zd@!};}q$`BUE z3ZEa)jeh^Z!4b?p>|9t_ShBVY0ko-Usgi;sfuS%4L#L*})rTx`cbm!5qv=}F7qb&# zf#;299@%8PwLbG$F*A=8tsAQlbcyVcTEVL|28WS#uZ=b--2C)Te$P1Ll$_ZU_ao<; zmBb8q>#u+Zmdrn7+X1h#a!K}aEXoL(6&io7yJHx5ia9Wl?jxEd`E)I}g64?iJW%z( z&gf~;Wh{8hmwaq4*%j*ltE#TX00wL%_ULwtoT(Dc_Mz$P?HnB=BO^g;2`C#TszI2s zs||0aN{q5dqY>M-_jx3!O#;G&(Mmj5fLX}T%M0s$T^POGm+19WzLAu8 z{Ca5Q=c}{nSw|lfdeBTjZzx*!^6o=QMC7}g^vd3Z^{-E*R|%pI6U2z5D4et=mdD!F zBW9le`~%QC@%<68tflckc(^Hy5_{=U*Ll`tj~hK2r!8tRTKJ5YOfMYz=z@t}kPK9O z->*26DHZdNrOe&S=@q=YN-K4uE;gHfmvSNd^HKX9r#G&Ox|l=mo9;RJjik!o0aFK< z1kPI(bvHC7dAX2^-V8^@gAfTg>&v5^y}#(W7Ioj#di7w-mM@eSnynzDZCMoLeP$++ z$(_FC(t#Tn4EOpZKHjRg&5T#On&zJGTI7)5c|#w7ozcB4kYsz-`|bb29LfZSsCR0z zaZ9cA%V^a| z5_Rl`_)rm;r-VLTrL$V=tylCe75SV@etdiEE?@j|YD>-6kbqT_0v7-fhm#rTh#tNj>#xO?CZGNj(3toczCydSz()X817T!M7B1!ix_|8({r5YYMxe zHIwbQ)A6agqn+c7VyvNGxhvpF=$)sJe*$vVzbY+*5$$23hq@1Y3fXR@ZMHf$zFi88~6%)fou9%l=ZTQ7sACw9qR z-4rCr7!%0o51Dd`Q?T$4tVaEC<;L2vu$cA=?+EtJ`p`+?An2rC7TIcFdIIWtMxgR~ zHmiD|;?k))@OcL%puuSHX8mL8a-)&90z5PikIs#H2{itHE!$LcXZ?DJ!41Yrm+7^1 z&;dhTcuQmvZ;7U zO`ECWEtX?VVD}8aQ?EnOK}%sN?I)H7;rsM_zhpZx`$vW&;HJ-+{#%pwTu5sEGjZ&L zQ|Z!`2U}7n?X%CO26+iyH`sf9)UP(UhuK8jqtCg&UgJp}ihT2*90AazZ}s11(ZR2|$uv zQ|0TNZt-^_0|Y+}I5_T%-F5m_DCWx0EJBewG4K)wE3@yLU98qGbg z40Gh46&g(=((20G%fji^ z;uvQ`KCSjZh^Vsj@^VSMo}h^qWWbK?SgY>A=r62wWZoLhY?Wq6Hg8lTyP<11Eq(*0 zJ7G_He}GD*SFF_%cFZXL0DJZQEpAY?WZ>tu!T&#$75_t$-TxYRIHv62Sgi``YX_ev zW%tbA0$b+o89CbyKuc*)r2vrn@%?US3w6F;uLY+2Z$Rx#%V)=cD>lX}QLA%lIi^w3>*BiM5*=23E? zne+>vqwmHvs$5zEcRTN-?3grcx&PL9bE85;_z|0o*N)wI5MIFtzl;{JS3<$b`H--z zf?F<=`1vD$z+lJpcTCu7pmH^dXD^!X0Q%r_D~*wY(U_M_=?OJz&HVw!pq%@unGE$- zLS4*Jy9|i)>bRU%FqQKpsZ1GN;M-i`e~UrJG|Y|s0_Oc z)=O+N8xz~Nl&p4F)E19DgY7TQ%hRX_dC_E#{J7HD0!Nk82aDIkjyZ&=P6P;kfxV_t zg;g5Gpgd$Yu)@uT{c!9@2WEx&73d=sVTJ}5%4^fIHC+dat^ZLyt8-$yCxiC0i{4+J zcF7GL;Wqs30Q6E=U3bOt$Q@po^vf64fEkSLML?;0^_nC6uQ8Lg=lt(4ro?FFF#+Cu zw?XhsldfnTJT_Io-@L(az6%|l>!>o-O5PLkMP6qL=P$0EYNWV1mSKwnvRdX0yk@2E z@;)lTDm1>Aq(5eab5gU?{q}B3bo6r-e%Zd=&g<;&F^I;@K5};x+vKDhiJ0VPx4Z-|<9~}tv4PJN;;CbnY-Hyw z_21%R`-%C%<_R<|ND_FRfsN$+=29{B=b{`hKyYcG{}-}3!+BZG^FyhhUa0h&L=_n^ zKnmIU_*z3gN=EAIiAD!hqt;&;Ups;w)9$p(xTNn!#_O-y^$Uwvv8qFlvwZ~){(7fN z{s(jK0Tk8Rw2O|q6(blxk*E?RDT07xP$Udd;*e2-*328a`+fT9r)vjS+a|`)zi5EG3oPDOM2={k$d3p(5Vsj|(pQNgCk=NvdR~r^QZJgR)5oD!N z2i^v?xKSVrVfGsmP}WH6ZjuMmL|J{eSTte7VfmT7Zr*TIR7uqgvRxDWuMA2>4s%|b zobNw^QhJdZnri+3oC;Xo`_y1_{_mv8{{I<6xs-Y%BZKk_PRWwc&6~92Y-QF|vwdHe zL!>~BO7A=E=1z+q`z?v~=a)LHYzL`3*uqnC3#u&Bs5K}_)taO?U(0Nyi;T^RChbVe zCr>h~h(@}&vxo#KpXXMP2~ljC<9dv$Z{JTsi9COJa~*Gs|Hy*Be~7)s^wT?#t{VS+ z2s=N&;ixB%VM41mzfj_D8PBi4AELP09U`}yxUqFqjS_zohh-cNRg4RzbGG31`BuQd zp{waMxs87z9_6#UjJ8+x-)=X`dh)pYG@Uw1()>p&uBAkA6__;2?p*1&Z%^y@n%^|E=svpGI$w}8F4D)0)4F=W@b}hS zMoteWxA@MpaRYnB)q(B9%dG3u)#JOH`b%}Y=3U)2mj`UTYEE%t{D$ewuqG5L*EcW)1owRDH%Ch8rOIWj#CpP{mRYV| z(idOm_00CG(MGBxm?#qMmO^yjpj_UJiVV3*(?Wb8-QxG{%&TZKVq-NW%e-B4mUvmZrpUDam9RrZqqCmTHGQn8fP~OmifN{*>m^IdcIlui z_+s45>5>fYi@o82L(>&=g}tkUItmjRLdXnb)+E(!)YScb`(_Fd=+}C9@=hj> z&+53|tC)E-zQh@>X-(`<;}6FqCeZn7)Y$g9`$gpHYx*ywk0{h`g_(Z%IIbt5IJ_M- z{#=N}Z$6?)7GXl6Q0wix9oH_%qw`*{f>=5Jd=RV36i%?7(PXzDdZ#;Hco-jDYhZuQ zZEOx->&;TP#(LnNfMBh%z3mfVq@dG#CK;#7cyxFul1n%4%bTP?ny^3y&4Q9YzbLSJ z3rdFmeoM9GSGy@x#21rDIy7IkmZrw=yW2KS_2PKO>T8~pGc%WdH~SlrMLk(n3KkNK z^)y||DGonolEipYSF@-&A8)8Wvn&aNejt?#nNG!?z1m9^vn?CnLnZvpi@IZ=K6$)Sj~K~WoY5B|GC97n6_PkVo=7&62P!e+ zwMnc=8){2A&R7W#Z>L2Zk%|ptpjSYyQzKCED`Pxo1_mKhvE7-43?&@CU$hjQ$`$VY ztCy4M$PsMj`Kuw~Vfy|GPNU-Z1w#$8C*HqUN46d;eQ>{Oo}e%Lawww*cW2)BhS2o; zapD`Oy^%L`RxX-J+mIxs$mQ4ZSCHn%N4JRtN)z`S%=40*NwUzK9E|-|+f4Y{uE`Si zT==0?<){M1`RW4kKR&xP;cx5;k`}Nbtm>>R+1O=e90ia6pG7ZznSMD|6-7gDLwebb z&7_%gLk9Ri3B>lRN^-10D!sXRhwfog4TYAnx%)UZl!eP`ZCgHhv9x}5XP!({vrms? zo=k|V-ukk^^M+x797Qj;7n8VgS@-r1>X+)0h|g#2(HV?kTR#S|*;T!Z_lGt%3abJO zq@;^;q&^N;v4n`KO8km@6Ry+DT0={ImK!JRrbuHX`;3`%dxEe`A?cqi=8h|ms+@Tw z9KfZE)%P-6TBINhx?a=Om6)fM@RI=eEWU??-wbCw#hcHab>Zy$3Mx9`#>THj#Ux-#aT zf9Ok)JF|IW#P`j6zC+uqIg{6J`Rx86V{LdrD5jKlT5`l+KSykTL1OmxrRCnVzG!oK ztf|-h$w~3%6(-_09?v^VQ(GHlMT@iu(5cw=cN_tbdDJ-+8AzvUKf`C2Io_}vmpfB1 zGS0|fm|OloYlIow_PU!k2NEe>5jP%pH|8dE;-3y zw{u4`@+55(o!kAT`c!=UCN^YCZ|Ttp&O{c2@jdE=ofQ{~_0-sQTuCOigt4ES>317S zH_YQT_VAl47OJGdpCMyaz%Vz{Yf0=b%CdB?W?_5+hlH|o|Df(q?NdYOWl4{(0sgZw z8(3b;TCtmn@2fK^INon=we;#{IJeKWip5pa;m70F7?xXYX!4;t!*!mS_oj>3@zxPE zgAZSzrFX_VVmMi_ved8s*y{Jfr|3ewE( zDnEWJ6PpAcaAjmhsy(TEDDp}B0cv5JJu#?RR1ULrS9f@>;qq41tCV1xI^PFN>-NmD z3=wpKdE%5l2L4O#N%C5`a;tH1TOS6AlHlhb{N&!1^%ZEw)V@jMthleWR9L4d6O@JV zLrm$b@w(bb{jC<$_A}h#C(?4Tjv{^Sn|ZkKZu4H8(2<4)yKthUb3YZnYS*2fi##Dp z-$ACPi&@i`96#!Osy0KZ97l7K`$>7E*|wON0m)kE=iBibd!^cyxpAhXJc_3y<{_rN zD;tFdw8IC9OIoK*AHhTLev8D|d zFTY@n@c~fD-JSQL#`gDf0ybay9etKE>xwV;ob2fn-7PWw73R7!J*_Mgl51~YN~B&| z-+iMP_xrWcA(RXCU#G8_sJ%Pj^&$3r9!I~Y;&zy*d&i&m3B-^O4V`2Qv^|6BNezq3 z5QGSe&+_h66!@!(X5|R01zsfmv_9F!`$v?vpcKD+D)F3}<{LVzTIX$5O?1D3{S5z~ zn8bP05Q8NDydMoj&1-LJqk5mK!0bsF3euunZv1`wR?)2m|6yNRlP3RVvAW!2TR9&_ z>%6~nSM_qg+3wrk!1(&1rX2S9NpO_;|CA{C|3<8BlZcR_QPun0yZZAQCwHy{9q7>7 zk7jg!FYSL~(GKEwOz)Pi1gzFGTfrfR+o!npFj=`(;r?dt;kB^B#L8SRce zeDyPNmN|Rob0Zun$U7{2$~XIK z`xYF#w`Ii=O-bX9_}__cDvf0&`4VIP!V+WlUYDk?PnNxMGOUvQpU|OOLn-FF?^dq! zuFs@5<7WFAmFx63VObxi#bnYzapgF2ChKSJ?T=NR(w+m8*?=viX z|KHHV^N!sl43yupPbT$N{f@oqm88pqlPh&joH>|~FVD*>{XD&;$c>_#p^>PCag;VH zo-7*l-kTCxHN`D@8FR96`{Say&ZP1gf(8Ern)gl^W@fEg-Wc$QHl)y+& z%IAEvTAHBUFLt5)p+oJ3&hkFEYVgonHQK9=E<4wBUs!EttlD{=Uow5-( zc=ODE{UkFh7~SPDti=AR=rb-@saRylKij;N)@LWZIo0 z>aDk*vL5;4$BB0bac=eYA$CnKyXyIz)&bG;sMGtD8XI;4G);l%*p=N;N>tgQ{oBrK zAm_rrkR%{6m-bA@{|WL}zuP{X@IqFTVV1G3efDO*`^U4Fjwxv0b-Syjqf!6(C`W;7 zUa3}3l15(XYkO(yp^ep?6m6qC>(cv&tq-f7`R79YVX8p37PU~xqk4B%V};rmC@vMS zUFULA#x6`&UKx+SIr;tE4bwKUb|5jL_=G4g!5@3qTYU0ffU);KO5}TVH1HUO5Aa3R zQH2R@u)FR;on^jhpyOWcY(RsVr!Jaf-A9#g-h~o{l0<%33`M~;OD&un*RQ(?BRE#T z!s%(To|_g^*_KyNiEN)V`EsAhdXs<5?gzaR3iUpqeHwn}N#mHK*zVTyl80y|ND;&b zgB6LZ2$u|=F=7%C9BA6{ldbA%&N(u=H9e>e4eii7$N<-);%JxiyI~8H* zLL1vKQOZm8(X($Vdh?6ZClX`UOxDMI%_3;k>5(zGj(o4{>bkl)hfkchAmnIPPNlpi z_xu7`cLEe~jnM)Y$j5o;MMCGW_9AWIO5z;u4QchGG?lXX!SC~FKQfz{TT|9yAnDm8 zQT1k6EY{`6vkO)~KfQ!+Tg0W%6!ZL9=eA#+Zn@o@gFNs_dm8gBFd=#EPhN@D0O?9T za~T!%bixJ3^0)uqBhH>X$8XVb39ZI;UfsYT;ZAaBwP8U69%jJ#Cr{#Plv&wzPut5A z2tR;^C8QhX%?P8eo(iQ!L@5941i1x%_j!F7@@x9c z=TYy!%nwzS8aEyX?Gb~x8xJ0@&JS@8mQkHN;tCoMGnF&>-IGcF`GJ8aGgA?m9PuLscEx$V80c1i+vRt&0Uj_3t6o`c}E5!?{0&S!i#A+r? z@BY1kgxv6KX=%v?D&l8aI14n;=$FjwoSX{l>+ACJ@=k*E`@cEr2YYSwAXH@O*7?=I zGtwOdb5GFZWiFY4D{WJYu2e!b&=hKcX`-rH;kN;=`2L?$NY-(yRI?3+xP zZEF$NMUz@L9~qhFhuHTAE1>BKGUfN%6UE|$oHJOJsteaj8rJ^&4DU@C>@PDe&PfH%8~lZh8*H~WIo)#XHew^+49OKFaO@@o(lHm z!e>0bGlE?mbmJ+-pe!7lrU1eZq0OsAf;S$D9IXwpvi<_w8~BY2C*Qim2Ho_kTUW{x)JYLZhQI z!D@V-A#uG!%1SOqF7syH5# z=Y}3X4#R3#_o*%LeMkPEp_$uTquB6pSh;Ea#pbx&+%MCD`wx;#{Y0sa8s&v$1_a$M zSTI>h+q33YefbGsHzJ|i&tO?(Xy{w0jLcSgBcLpc*u$7GqM62o3sOKaDyJHN3TV~9 zV5|qrY=!4ay5X;xpv=a`5Yk#^3!fcX+MpicD9j3X8ZLauoRm$!9+iHj)ueQ5BS&8; z_9da8X1sLeO=3fnsEGmnj;p5FVn}TZ>F}qSVyXC|}+kUtXM}MFlX*`|WsYJsi#tb5tmw^zf}&I_OvW z+dCoH^}EjIu1TQZPnW2%Y_9VdG+#!M#q7<&y0x&{t06U$3AZMB&cZHwd*&xO4eEVh z`=mNB3rjqgANv0J@ggTTR|Cp$HMF&}YzNEODUTN(6-J>X-o{rCNm+Bv3@5(~Q$BZ7 zJ%aH#$M}QwPrp*y1O_e!S$&v)MeaYMxrhsG-?`IuPI(ecS^bZ_^{rduRccqgDD(Br zEfws_O1BCQY*Zzb(e_k0n{R_sizXYTlOPL>UAV2~Ecu{IB~QV#qHS@VsI*`FyPC@n z(Rp_cl#(AV>gG9svcMiWNgJ+Cbt}Oyf=*TW#w9fGL!;dfvNzXnV0mPw z{gRq8S#Y{qM*SHzFdH3H_mJ6#>S!sD#Oe0mUGvAeFAU2oDn{_gM44IE2OOXgba)Fp ze+;pham)&=kluJ$_vv%3$PbI&qAhU(ddVYl+y&V-bmDtc>miz7RKyDlhu>y-Hp#s@ zKVNyU+#Vw>{Y-rk{LTPZYmWkJy^~(YBh||?&q;l7Ck@NqohvIY32p1g(@5O-UF_V1-%POPBg0{ z{=3^&gJpThJCQ3u<`H7?eu93DD)`aeoo!^xi-E+57YJi$g1g_?@G753c`MJSO)(s$5S+Xa{c}N$DiFHzxrS102zRn@$qy9phY-P zXz~J#v!!aK;Dn5TcevG09*`w7_Qt7c|q?5B?k#{b7q-P#+vFJBZ-F^Fn|&{i+_ z(-ruAE0{DdsO;vm>R}6_6H&`Jey*Yh(W!d5nym&172wDCmTP(m{%4cZMab8X6&|H29}67ry;p+;^wXz?Wo{ z4|^#fa{|I8gcRu$*9*n5M#@7 z@KHebnf;drus$ij`1cc|0$5+bWB*=!LW+PFT`x6nXUH?C(gLBBFl5)@sZ+sMKv=}d z&rg{C_wQ4zkp*$$n)W-%?hK`FD7{}Q^?mvBrEZBu7$|+rNb>Ig-do4F$h`DJe-T6f zZP$s($(dl0`Fk*P)rR&BJFwwDe!N3=?r$hHFN?UHV&6@-n%^H!AmI?9&fh5o#-2UMwAD%;SYJ^Oc zv2n_izwrWU&zDE{!@?Bb`D23a`m;F3f=&=|kK&Obkx0az>~O@>xy}s`@G)R}j}O*aYx($pCRIud6VzS!AKM#f^*Ls+bOC$%5C++ z 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

cWMY99%wvNbo!VQVgQKrJS9ejle2U`I7<1 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 G`~LuDY1+^L literal 0 HcmV?d00001 diff --git a/assets/agg.png b/assets/agg.png new file mode 100644 index 0000000000000000000000000000000000000000..2e03723445cb7652f7ad02e7a32e07c90fbfbbf0 GIT binary patch literal 91907 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 - -## Static Aggregation - -Assume that we have a static (i.e., known ahead of time) list `allowed_vks` of STARK verifying keys (unique identifiers for STARK circuits). - -Suppose we have a variable-length list of proofs `proofs` where `proofs.len()` is independent of `allowed_vks.len()`. The goal is to produce a single STARK proof that asserts that `proofs[i]` verifies with respect verifying key `vk[i]` where `allowed_vks` contains `vk[i]`, for all `i`. Additionally, there should be the optionality to store a commitment to the ordered list of `(hash(vk[i]), public_values[i])` where `public_values[i]` are the public values of proof `i`. - -We aggregate `proofs` using a tree-structure. The arity of the tree can be adjusted for performance; -by default it is 2. The height of the tree is variable and equal to $\lceil \log{n} \rceil$ where $n$ is the number of proofs and the base of logarithm is the arity. - -We distinguish between three types of nodes in the tree: - -- Leaf -- Internal -- Root - -Each node of the tree will be a STARK VM circuit, _without continuations_, proving a VM program that runs STARK verification on an `arity` number of proofs. We make the distinction that each type of node in the tree may be a **different** VM circuit, meaning with different chip configurations. All VM circuits must support the opcodes necessary to do STARK verification. - -For each node type, a different program is run in the VM circuit: - -- Leaf: the program verifies `<=leaf_arity` proofs, where each proof is verified with respect to one of the verification keys in `allowed_vks`. The leaf program will have the proof, public values, and verifying keys of each proof in program memory, and the program can be augmented with additional checks (for example, state transitions checks are necessary for continuations). -- Internal: the program verifies `<= internal_arity` proofs, where all proofs are verified with respect to the same verifying key. This verifying key is either that of a leaf circuit or that of an internal circuit (the present circuit itself). The circuit cannot know the verifying key of itself, so to avoid a circular dependency, the hash of the verifying key is made a public value. -- Root: this program _may_ just be the same as the Internal program, but for the purposes of optimizing [on-chain aggregation](#on-chain-aggregation), there is the possiblity for it to be different. The root program verifies `<= root_arity` proofs, where all proofs are of the internal circuit. Note that `root_arity` may be `1`. - -### STARK Configurations - -Before proceeding, we must discuss the topic of STARK configurations: any STARK proof depends on at least three configuration parameters: - -- `F` the base field of the AIRs -- `EF` the extension field of the AIRs used for challenge values -- the hash function used for the FRI PCS. This hash function must be able to hash `F` and `EF` elements, where elements can be packed before hashing. - -For all Leaf and Internal circuits [above](#static-aggregation), we use an **Inner Config**. Example Inner Configs are: - -- `F` is BabyBear, `EF` is quartic extension of BabyBear, hash is BabyBearPoseidon2 -- `F` is BabyBear, `EF` is quartic extension of BabyBear, hash is SHA256 -- `F` is Mersenne31, `EF` is quartic extension of Mersenne31, hash is Mersenne31Poseidon2 -- `F` is Mersenne31, `EF` is quartic extension of Mersenne31, hash is SHA256 - -We discuss considerations for choice of hash below. - -On the other hand, the Root circuit will use an **Outer Config**. Example Outer Configs are: - -- `F` is BabyBear, `EF` is quartic extension of BabyBear, hash is BN254FrPoseidon2 (or BN254FrPoseidon1) -- ~~`F` is BabyBear, `EF` is quartic extension of BabyBear, hash is SHA256~~ -- `F` is BN254Fr, `EF` is BN254Fr, hash is BN254FrPoseidon2 (or BN254FrPoseidon1) -- ~~`F` is BN254Fr, `EF` is BN254Fr, hash is SHA256~~ -- Analogous configurations with BabyBear replaced with Mersenne31. - -To explain, since `31 * 8 < 254`, eight BabyBear field elements can be packed together and embedded (non-algebraically) into a BN254Fr field element. In this way BN254FrPoseidon2 can be used to hash BabyBear elements. - -The choice of hash function in the Outer Config only affects what hash must be verified in the Halo2 circuit for on-chain aggregation (see [below](#on-chain-aggregation)). For performance, it is therefore always better to use BN254FrPoseidon2 for the Outer Config. - -### On-chain Aggregation - -The Root circuit above is the last STARK circuit, whose single proof will in turn verify all initial `proofs`. Due to the size of STARK proofs, for on-chain verification we must wrap this proof inside an elliptic curve based SNARK proof so that the final SNARK proof can be verified on-chain (where on-chain currently means within an Ethereum Virtual Machine). - -We create a Halo2 circuit that verifies any proof of the Root STARK circuit. This is a non-universal circuit whose verifying key depends on the specific STARK circuit to be verified. The majority of the verification logic can be code-generated into the `halo2-lib` eDSL which uses a special vertical custom gate specialized for cheap on-chain verification cost. There are two main performance considerations: - -#### 1. Hash - -To perform FRI verification in the Halo2 circuit, the circuit must constrain calculations of STARK Outer Config hashes. As mentioned above, this hash will be BN254FrPoseidon2. The constraints for this hash can either be implemented directly using the `halo2-base` vertical gate, or with a custom gate. The custom gate will be faster but with higher verification cost. There are two approaches to consider: - -Approach A - -- Use a single Halo2 circuit with only thinnest `halo2-base` vertical gate to verify the Root STARK circuit proof. - -Approach B - -- Use a first Halo2 circuit with custom gate for BN254FrPoseidon2 to verify the Root STARK circuit proof. -- Use a second Halo2 circuit with only the thinnest `halo2-base` vertical gate to verify the previous Halo2 circuit. - -Approach B is likely better, provided that the time to generate both proofs is faster than the time to generate the single proof in Approach A. - -#### 2. Outer Config Base Field - -The Outer Config base field `F` can be either a 31-bit field or BN254Fr. - -When `F` is 31-bit field: - -- For FRI folding and other arithmetic in STARK verification, the Halo2 circuit must perform BabyBear prime field arithmetic and extension field arithmetic inside the halo2 circuit. These are non-native arithmetic operations. - -When `F` is BN254Fr and `EF` is BN254Fr: - -- Halo2 circuit only needs to perform native field arithmetic inside the halo2 circuit. -- The Root STARK circuit must now perform non-native BabyBear field arithmetic and extension field arithmetic inside the STARK to support the verification of the STARKs with the Inner Config. This non-native arithmetic is still expected to be much faster in the STARK than in Halo2, but the added chip complexity may also increase verifier cost in the Halo2 circuit. -- If the Inner Config hash is BabyBearPoseidon2, now the Root STARK circuit must constrain BabyBearPoseidon2 inside a circuit with base field BN254Fr. This is definitely not efficient. **Therefore it is not possible for the Outer Config base field to be BN254Fr if the Inner Config hash is BabyBearPoseidon2.** -- This Outer Config is only possible if the Inner Config hash is a hash that does not depend on the native field (e.g., SHA256 or Blake2b or Blake3). - - **Observation:** even if the hash used for the Internal circuit is SHA256, the Leaf circuit can still be proven using BabyBearPoseidon2. Likewise, it is even possible to have the Internal circuits use BabyBearPoseidon2 at higher depths in the tree (away from the root). The only requirement is that the last Internal circuit proof, which will be verified by the Root circuit, needs to be proven with SHA256 as the hash. - -TODO: to determine which Outer Config is best, we will: - -- Instrument the cost of non-native small field arithmetic in the Halo2 circuit. -- Benchmark an aggregation VM with Inner Config hash BabyBearPoseidon2 proven over BabyBearPoseidon2 versus one with Inner Config hash SHA256 proven over SHA256. - -## Dynamic Aggregation - -TODO diff --git a/docs/specs/continuations.md b/docs/specs/continuations.md index f45c847eaf..65f518fe65 100644 --- a/docs/specs/continuations.md +++ b/docs/specs/continuations.md @@ -1,3 +1,201 @@ +# Aggregation + +Given the execution segments of a program, each segment will be proven in parallel within a **Application VM** (App VM). +These proofs are subsequently aggregated into an aggregation tree by a **leaf aggregation +program**. This segment aggregation program runs inside _a different VM_, referred to as the **Aggregation VM** (Agg +VM), which operates without continuations enabled. + +The aggregation program takes a variable number of consecutive segment proofs and consolidates them into a single proof +that captures the entire range of segments. + +![Aggregation example](../../assets/agg.png) + +The following figure shows that the shape of the aggregation tree is not fixed. + +![Another aggregation example](../../assets/agg-2.png) + +We will now give an overview of the steps of the overall aggregation, starting from the final smart contract verifier +and going down to the application proof. + +## Smart Contract + +A smart contract is deployed by on-chain, which provides a function to verify a Halo2 proof. + +## Static Verifier Wrapper + +The **Static Verifier Wrapper** is a Halo2 SNARK verifier circuit generated by OpenVM. The static verifier +wrapper is determined by the following parameters: + +* Number of public values +* The Aggregation VM chip constraints (but **not** the App VM chips) + +## Continuation Verifier + +The continuation verifier is a Halo2 circuit (static verifier) together with some single segment VM circuits (Agg VM). +The continuation verifier depends on the specific circuit design of the static verifier and Aggregation VM, as well as +the number of user public values, but it does not depend on the App VM's circuit. + +The continuation verifier ensures that a set of ordered App VM segment proofs collectively validates the execution of a +specific `VmExe` on a specific App VM, with given inputs. + +### Static Verifier + +The Static Verifier is a Halo2 verifier circuit that validates a Root VM Verifier proof and exposes its public values. + +Static Verifier Requirements: + +* The height of each trace is fixed. +* Trace heights are in a descending order. + +Public Values Exposed: + +* Exe commit encoded in Bn254 +* Leaf commit encoded in Bn254 +* User public values in BabyBear + +Parameters (which could result in a different circuit): + +* Number of public values (from upper stream) +* k in Halo2 +* Determines the number of columns of the circuit. + +* Number of public values (from upstream) +* k in Halo2 (determines the number of columns in the circuit) +* Root VM verifier + * VK (including the heights of all traces) + * Root verifier program commitment + +### Aggregation VM + +The Aggregation VM organizes proofs into an aggregation tree, where nodes include: + +* Root VM Verifier +* Internal VM Verifier +* Leaf VM Verifier + +Each node can have an arbitrary number of children, enabling flexible tree structures to optimize for cost reduction +(more children) or latency reduction (less children) during proving. + +### Root VM Verifier + +The Root VM Verifier is proven in RootConfig, using commitments via Bn254Poseidon2. All traces are padded to a constant +height for verification. + +The Root VM Verifier verifies 1 or more proofs of: + +- Leaf VM Verifier +- Internal VM Verifier + +In practice, Root VM verifier only verifies one proof to guarantee constant heights. + +Logical Input: + +* Root input + +Cached Trace Commit: + +* `ProgramAir`: commits the root verifier program + +Public values: + +* `RootVmVerifierPvs` + * Note: exe_commit is the commitment of the executable. The way to compute it can be found here. + +Parameters: + +* For circuit: + * Root VM Config +* For root verifier program: + * Root FRI parameters to compute its commitment + * Internal verifier circuit \+ program commitment + * Leaf verifier circuit \+ program commitment + +### Internal VM Verifier + +The Internal VM Verifier validates one or more proofs of: + +* Leaf VM Verifier +* Internal VM Verifier + +Logical Input: + +* `InternalVmVerifierInput` + +Cached Trace Commit: + +* `ProgramAir`: commits the internal verifier program. `agg_vm_pk` contains it. + +Public values: + +* `InternalVmVerifierPvs` + +Parameters: + +* For circuit: + * Internal VM Config +* For root verifier program: + * Internal FRI parameters to compute its commitment + * Internal verifier circuit \+ program commitment + * Leaf verifier circuit \+ program commitment + +### Leaf VM Verifier + +Verify 1 or more proofs of: + +* segment circuits + +Logical Input: + +* `LeafVmVerifierInput` + +Cached Trace Commit: + +* ProgramAir: commits the leaf verifier program. The leaf verifier program commits . + +Public values: + +* `VmVerifierPvs` + +Parameters: + +* For circuit: + * Leaf VM Config +* For leaf verifier program: + * It’s not a part of the Continuation Verifier because it depends on the VK of the App VM and it doesn’t affect the VK + of the static verifier. + +### App VM + +App VM executes an executable with inputs and returns a list of segment proofs. + +## Segment + +Logical Input: + +* App VM input stream + +Cached Trace Commit: + +* ProgramAir: commits the program the App VM executed. + +Public values: + +* `VmConnectorPvs` +* `MemoryMerklePvs` + +User Public Values: + +* Up to `num_public_values` public values in a dedicated memory space. These public values are not exposed as public + values of segment circuits, but will be exposed by the final proof. + +Parameters: + +* Number of public values (from upstream) +* For circuit: + * App VM Config +* For App program: + * App FRI parameters to compute its commitment. + # Continuations Our high-level continuations framework follows previous standard designs (Starkware, Risc0), but uses a novel persistent @@ -82,9 +280,4 @@ and has the following interactions on the MERKLE_BUS**(-1, 0, (as - AS_OFFSET) \* 2^L, node_label, hash_final)** It receives `values` from the `MEMORY_BUS` and constrains `hash = compress(values, 0)` via the `POSEIDON2_DIRECT_BUS`. - -## Aggregation - -Given the execution segments of a program, we will prove each segment in a VM segment circuit in parallel. These proofs will then be aggregated in an [aggregation tree](../aggregation.md) by a segment aggregation program. This segment aggregation program will be run inside **a different VM** which **does not** have continuations turned on. The latter VM is called an **Aggregation VM**. - -See [Aggregation](../aggregation.md) for more details. +The aggregation program takes a variable number of consecutive segment proofs and consolidates them into a single proof From 175465eb8361d6599434c30e4bc9253774e3e0e0 Mon Sep 17 00:00:00 2001 From: stephenh-axiom-xyz Date: Sun, 15 Dec 2024 22:11:42 -0500 Subject: [PATCH 17/27] docs: SDK and CLI usage for proving and verifying (#1051) * docs: SDK and CLI usage for proving and verifying * docs: overview * docs: more updates * Update book/src/advanced-usage/sdk.md * chore: delete unused * chore: remove link * docs: more SDK + CLI stuff * docs: stdin section --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/advanced-usage/sdk.md | 131 +++++++++++++++++++++ book/src/advanced-usage/testing-program.md | 60 +--------- book/src/writing-apps/compile.md | 15 +++ book/src/writing-apps/onchain-verify.md | 28 +++++ book/src/writing-apps/overview.md | 76 ++++++++++++ book/src/writing-apps/prove.md | 43 +++++++ book/src/writing-apps/testing.md | 1 - book/src/writing-apps/verify.md | 30 ++++- crates/toolchain/build/src/lib.rs | 14 +++ 9 files changed, 337 insertions(+), 61 deletions(-) create mode 100644 book/src/advanced-usage/sdk.md delete mode 100644 book/src/writing-apps/testing.md diff --git a/book/src/advanced-usage/sdk.md b/book/src/advanced-usage/sdk.md new file mode 100644 index 0000000000..51a0145de3 --- /dev/null +++ b/book/src/advanced-usage/sdk.md @@ -0,0 +1,131 @@ +# Using the SDK + +While the CLI provides a convenient way to build, prove, and verify programs, you may want more fine-grained control over the process. The OpenVM Rust SDK allows you to customize various aspects of the workflow programmatically. + +For more information on the basic CLI flow, see [Overview of Basic Usage](./overview.md). Writing a guest program is the same as in the CLI. + +## 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. + +```rust +use openvm::{platform::memory::MEM_SIZE, transpiler::elf::Elf}; +use openvm_circuit::arch::instructions::exe::OpenVmExe +use openvm_circuit::arch::VmExecutor; +use openvm_sdk::{config::SdkVmConfig, Sdk, StdIn}; + +let sdk = Sdk; + +#[derive(Serialize, Deserialize)] +pub struct SomeStruct { + pub a: u64, + pub b: u64, +} +``` + +## 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 vm_config = SdkVmConfig::builder() + .system(Default::default()) + .rv32i(Default::default()) + .io(Default::default()) + .build(); + +// 2a. Build the ELF with guest options and a target filter. +let guest_opts = GuestOptions::default().with_features(vec!["parallel"]); +let target_filter = TargetFilter::default().with_kind("bin".to_string()); +let elf = sdk.build(guest_opts, "your_path_project_root", &target_filter)?; +// 2b. Load the ELF from a file +let elf = Elf::decode("your_path_to_elf", MEM_SIZE as u32)?; + +// 3. Transpile the ELF into a VmExe +let exe = sdk.transpile(elf, vm_config.transpiler())?; +``` + +### 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. + +## 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; // anything that can be serialized +let mut stdin = StdIn::default(); +stdin.write(&my_input); + +// 5. Run the program +let output = sdk.execute(exe, vm_config, input)?; +``` + +### 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** +> 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 + +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 = sdk.app_keygen(app_config)?; + +// 9a. Generate a proof +let proof = sdk.generate_app_proof(app_pk, app_committed_exe, stdin)?; +// 9b. Generate a proof with an AppProver with custom fields +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); +``` + +## 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)?; +``` + +## 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 = Halo2ParamsReader::new(DEFAULT_PARAMS_DIR); +let agg_config = AggConfig::default(); +let agg_pk = sdk.agg_keygen(agg_config, &halo2_params_reader)?; + +// 12. Generate an EVM proof +let proof = sdk.generate_evm_proof(&halo2_params_reader, app_pk, app_committed_exe, agg_pk, stdin)?; + +// 13. Generate the SNARK verifier contract +let verifier = sdk.generate_snark_verifier_contract(&halo2_params_reader, &agg_pk)?; + +// 14. Verify the EVM proof +sdk.verify_evm_proof(&verifier, &proof)?; +``` + +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 [onchain verify](../writing-apps/onchain-verify.md) doc. + +> ⚠️ **WARNING** +> `cargo openvm setup` requires very large amounts of computation and memory (~200 GB). diff --git a/book/src/advanced-usage/testing-program.md b/book/src/advanced-usage/testing-program.md index 1db3d71521..afd89ad955 100644 --- a/book/src/advanced-usage/testing-program.md +++ b/book/src/advanced-usage/testing-program.md @@ -10,65 +10,7 @@ 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)?; -``` +For more information on building, transpiling, running, generating proofs, and verifying proofs with the CLI, see the [CLI](../writing-apps/overview.md)section. To do the same with the SDK, see the [SDK](sdk.md) section. ## Troubleshooting diff --git a/book/src/writing-apps/compile.md b/book/src/writing-apps/compile.md index f3b18f2570..cdcfcb0c6b 100644 --- a/book/src/writing-apps/compile.md +++ b/book/src/writing-apps/compile.md @@ -7,3 +7,18 @@ First let's define some key terms used in cross-compilation: There are multiple things happening in the `cargo openvm build` command as in the section [here](./write-program.md). In short, this command compiles on host to an executable for guest target. It first compiles the program normally on your *host* platform with RISC-V and then transpiles it to a different target. See here for some explanation of [cross-compilation](https://rust-lang.github.io/rustup/cross-compilation.html). Right now we use `riscv32im-risc0-zkvm-elf` target which is available in the [Rust toolchain](https://doc.rust-lang.org/rustc/platform-support/riscv32im-risc0-zkvm-elf.html), but we will contribute an OpenVM target to Rust in the future. + +## Running a Program + +After building and transpiling a program, you can execute it using the `run` command. The `run` command has the following arguments: + +```bash +cargo openvm run + --exe + --config + --input +``` + +If `--exe` and/or `--config` are not provided, the command will search for these files in `./openvm/app.vmexe` and `./openvm.toml` respectively. If `./openvm.toml` is not present, a default configuration will be used. + +If your program doesn't require inputs, you can (and should) omit the `--input` flag. diff --git a/book/src/writing-apps/onchain-verify.md b/book/src/writing-apps/onchain-verify.md index ea369b8c26..60a0398552 100644 --- a/book/src/writing-apps/onchain-verify.md +++ b/book/src/writing-apps/onchain-verify.md @@ -1 +1,29 @@ # Onchain Verification + +## Generating the Aggregation Proving Key and EVM Verifier Contract + +The workflow for generating an end-to-end EVM proof requires first generating an aggregation proving key and EVM verifier contract. This can be done by running the following command: + +```bash +cargo openvm setup +``` +> ⚠️ **WARNING** +> This command requires very large amounts of computation and memory (~200 GB). + +Upon a successful run, the command will write `agg.pk` and `verifier.sol` to `~/.openvm/`, where `~` is the directory specified by environment variable `$HOME`. Every command that requires these files will look for them in this directory. + +> ⚠️ **WARNING** +> If the `$HOME` environment variable is not set, this command may fail. + +Note that `cargo openvm setup` may attempt to download other files (i.e. KZG parameters) from an AWS S3 bucket into `~/.openvm/`. + +## Generating and Verifying an EVM Proof + +To generate and verify an EVM proof, you need to run the following commands: + +```bash +cargo openvm prove evm --input +cargo openvm verify evm +``` + +These commands are very similar to their `app` subcommand counterparts. For more information on the `prove` and `verify` commands, see the [prove](./prove.md) and [verify](./verify.md) docs. diff --git a/book/src/writing-apps/overview.md b/book/src/writing-apps/overview.md index 6e66d0352f..0637d04452 100644 --- a/book/src/writing-apps/overview.md +++ b/book/src/writing-apps/overview.md @@ -1 +1,77 @@ # Overview of Basic Usage + +## Writing a Program + +The first step to using OpenVM is to write a Rust program that can be executed by an OpenVM virtual machine. Writing a program for OpenVM is very similar to writing a standard Rust program, with a few key differences necessary to support the OpenVM environment. For more detailed information about writing programs, see the [Writing Programs](./write-program.md) guide. + +## Building and Transpiling a Program + +At this point, you should have a guest program with a `Cargo.toml` file in the root of your project directory. What's next? + +The first thing you will want to do is build and transpile your program using the following command: + +```bash +cargo openvm build +``` + +By default this will build the project located in the current directory. To see if it runs correctly, you can try executing it with the following: + +```bash +cargo openvm run --input +``` + +Note if your program doesn't require inputs, you can omit the `--input` flag. + +For more information on both commands, see the [build](./build.md) docs. + +### Inputs + +The `--input` field needs to either be a hex string or a file path to a file that will be read as bytes. Note that if your hex string represents a single number, it should be written in little-endian format (as this is what the VM expects). To see how more complex inputs can be converted into a VM-readable format, see the **Using StdIn** section of the [SDK](../advanced-usage/sdk.md) doc. + +## Generating a Proof + +Given an app configuration TOML file, you first need to generate a proving and verifying key: + +```bash +cargo openvm keygen +``` + +After generating the keys, you can generate a proof by running: + +```bash +cargo openvm prove app --input +``` + +Again, if your program doesn't require inputs, you can omit the `--input` flag. + +For more information on the `keygen` and `prove` commands, see the [prove](./prove.md) doc. + +## Verifying a Proof + +To verify a proof using the CLI, you need to provide the verifying key and the proof. + +```bash +cargo openvm verify app +``` + +For more information on the `verify` command, see the [verify](./verify.md) doc. + +## End-to-end EVM Proof Generation and Verification + +The process above details the workflow necessary to build, prove, and verify a guest program at the application level. However, to generate the end-to-end EVM proof, you need to (a) setup the aggregation proving key and verifier contract and (b) generate/verify the proof at the EVM level. + +To do (a), you need to run the following command. If you've run it previously on your machine, there is no need to do so again. This will write files necessary for EVM proving in `~/.openvm/`. + +```bash +cargo openvm setup +``` + +> ⚠️ **WARNING** +> This command requires very large amounts of computation and memory (~200 GB). + +To do (b), you simply need to replace `app` in `cargo openvm prove` and `cargo openvm verify` as such: + +```bash +cargo openvm prove evm --input +cargo openvm verify evm +``` diff --git a/book/src/writing-apps/prove.md b/book/src/writing-apps/prove.md index e9d3a9bc66..39450a33de 100644 --- a/book/src/writing-apps/prove.md +++ b/book/src/writing-apps/prove.md @@ -1 +1,44 @@ # Generating Proofs + +Generating a proof using the CLI is simple - first generate a key, then generate your proof. Using command defaults, this looks like: + +```bash +cargo openvm keygen +cargo openvm prove [app | evm] +``` + +## Key Generation + +The `keygen` CLI command has the following optional arguments: + +```bash +cargo openvm keygen + --config + --output + --vk_output +``` + +If `--config` is not provided, the command will search for `./openvm.toml` and use that as the application configuration if present. If it is not present, a default configuration will be used. + +If `--output` and/or `--vk_output` are not provided, the keys will be written to default locations `./openvm/app.pk` and/or `./openvm/app.vk` respectively. + +## Proof Generation + +The `prove` CLI command has the following optional arguments: + +```bash +cargo openvm prove [app | evm] + --app_pk + --exe + --input + --output +``` + +If your program doesn't require inputs, you can (and should) omit the `--input` flag. + +If `--app_pk` and/or `--exe` are not provided, the command will search for these files in `./openvm/app.pk` and `./openvm/app.vmexe` respectively. Similarly, if `--output` is not provided then the command will write the proof to `./openvm/[app | evm].proof` by default. + +The `app` subcommand is used to generate an application-level proof, while the `evm` command generates an end-to-end EVM proof. + +> ⚠️ **WARNING** +> In order to run the `evm` subcommand, you must have previously called the costly `cargo openvm setup`, which requires very large amounts of computation and memory (~200 GB). diff --git a/book/src/writing-apps/testing.md b/book/src/writing-apps/testing.md deleted file mode 100644 index f00b526a98..0000000000 --- a/book/src/writing-apps/testing.md +++ /dev/null @@ -1 +0,0 @@ -# Testing diff --git a/book/src/writing-apps/verify.md b/book/src/writing-apps/verify.md index ea369b8c26..5c95f69488 100644 --- a/book/src/writing-apps/verify.md +++ b/book/src/writing-apps/verify.md @@ -1 +1,29 @@ -# Onchain Verification +# Verifying Proofs + +## Application Level + +Verifying a proof at the application level requires both the proof and application verifying key. + +```bash +cargo openvm verify app + --app_vk + --proof +``` + +If you omit `--app_vk` and/or `--proof`, the command will search for those files at `./openvm/app.vk` and `./openvm/app.proof` respectively. + +Once again, if you omitted `--output` and `--vk_output` in the `keygen` and `prove` commands, you can omit `--app_vk` and `--proof` in the `verify` command. + +## EVM Level + +Verifying a proof at the EVM level requires just the proof, as the command uses the verifier generated when `cargo openvm setup` was called. + +```bash +cargo openvm verify evm --proof +``` + +If `proof` is omitted, the command will search for the proof at `./openvm/evm.proof`. + +As with all other EVM-level commands, `cargo openvm setup` is a prerequisite for `verify`. +> ⚠️ **WARNING** +> `cargo openvm setup` requires very large amounts of computation and memory (~200 GB). diff --git a/crates/toolchain/build/src/lib.rs b/crates/toolchain/build/src/lib.rs index c55af96d75..7b95e1729f 100644 --- a/crates/toolchain/build/src/lib.rs +++ b/crates/toolchain/build/src/lib.rs @@ -333,6 +333,20 @@ pub struct TargetFilter { pub kind: Option, } +impl TargetFilter { + /// Set substring of target name to match. + pub fn with_name_substr(mut self, name_substr: String) -> Self { + self.name_substr = Some(name_substr); + self + } + + /// Set kind of target to match. + pub fn with_kind(mut self, kind: String) -> Self { + self.kind = Some(kind); + self + } +} + /// Finds the unique executable target in the given package and target directory, /// using the given target filter. pub fn find_unique_executable, Q: AsRef>( From fcb33e49bc43fd5654bc035a2d058775d09b9bee Mon Sep 17 00:00:00 2001 From: Golovanov399 Date: Mon, 16 Dec 2024 06:21:45 +0300 Subject: [PATCH 18/27] [book] Write the manual on how to create a new extension (#1060) * Write the manual * Update book/src/new-extension/howto.md * Update book/src/new-extension/howto.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Some comments * Other comments * Rename --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/advanced-usage/new-extension.md | 41 ++++++++++++++++++++++++ book/src/introduction.md | 4 +-- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 book/src/advanced-usage/new-extension.md diff --git a/book/src/advanced-usage/new-extension.md b/book/src/advanced-usage/new-extension.md new file mode 100644 index 0000000000..ecbd7dd134 --- /dev/null +++ b/book/src/advanced-usage/new-extension.md @@ -0,0 +1,41 @@ +# Creating a New Extension + +Extensions in OpenVM let you introduce additional functionality without disrupting the existing system. Consider, for example, an extension that provides two new operations on `u32` values: one that squares a number, and another that multiplies it by three. With such an extension: + +1. You define functions like `square(x: u32) -> u32` and `mul3(x: u32) -> u32` for use in guest code. +2. When the compiler encounters these functions, it generates corresponding custom [RISC-V instructions](https://github.com/openvm-org/openvm/blob/main/docs/specs/RISCV.md). +3. During the transpilation phase, these custom instructions are translated into OpenVM instructions. +4. At runtime, the OpenVM program sends these new instructions to a specialized [chip](https://github.com/openvm-org/openvm/blob/main/docs/specs/circuit.md) that computes the results and ensures their correctness. + +This modular architecture means the extension cleanly adds new capabilities while leaving the rest of OpenVM untouched. The entire system, including the extension’s operations, can still be proven correct. + +Conceptually, a new extension consists of three parts: +- **Guest**: High-level Rust code that defines and uses the new operations. +- **Transpiler**: Logic that converts custom RISC-V instructions into corresponding OpenVM instructions. +- **Circuit**: The special chips that enforce correctness of instruction execution through polynomial constraints. + +## Guest + +In the guest component, your goal is to produce the instructions that represent the new operations. When you want to perform an operation (for example, “calculate _this_ new function of _these_ arguments and write the result _here_”), you generate a custom instruction. You can use the helper macros `custom_insn_r!` and `custom_insn_i!` from `openvm_platform` to ensure these instructions follow the [RISC-V specification](https://riscv.org/specifications/ratified/). For more details, see the RISC-V [contributor documentation](https://github.com/openvm-org/openvm/blob/main/docs/specs/RISCV.md). + +## Transpiler + +The transpiler maps the newly introduced RISC-V instructions to their OpenVM counterparts. To achieve this, implement a struct that provides the `TranspilerExtension` trait, which includes: + +```rust +fn process_custom(&self, instruction_stream: &[u32]) -> Option<(Instruction, usize)>; +``` + +This function checks if the given instruction stream starts with one of your custom instructions. If so, it returns the corresponding OpenVM instruction and how many 32-bit words were consumed. If not, it returns `None`. + +Note that almost always the valid instruction consists of a single 32-bit RISC-V word (so whenever `Some(_, sz)` is returned, `sz` is 1), but in general this may not be the case. + +## Circuit + +The circuit component is where the extension’s logic is enforced in a zero-knowledge proof context. Here, you create a chip that: + +- Implements the computing logic, so that the output always corresponds to the correct result of the new operation. The chip has access to the memory shared with the other chips from the VM via [our special architecture](https://github.com/openvm-org/openvm/blob/main/docs/specs/ISA.md). +- Properly constrains all the inputs, outputs and intermediate variables using polynomial equations in such a way that there is no way to fill these variables with values that correspond to an incorrect output while fitting the constraints. + + +For more technical details on writing circuits and constraints, consult the OpenVM [contributor documentation](https://github.com/openvm-org/openvm/blob/main/docs/specs/README.md), which provides specifications and guidelines for integrating your extension into the OpenVM framework. diff --git a/book/src/introduction.md b/book/src/introduction.md index 80d66d608f..2e77c1675d 100644 --- a/book/src/introduction.md +++ b/book/src/introduction.md @@ -18,7 +18,7 @@ OpenVM is an open-source zero-knowledge virtual machine (zkVM) framework focused The following chapters will guide you through: -- [Getting started](./getting-started/install.md) +- [Getting started](./getting-started/install.md). - [Writing applications](./writing-apps/overview.md) in Rust targeting OpenVM and generating proofs. - [Using existing extensions](./custom-extensions/overview.md) to optimize your Rust programs. -- How to add custom VM extensions +- [How to add custom VM extensions](./advanced-usage/new-extension.md). From 2773fcb03ecfb3286274f33d67f8c3925c96be3b Mon Sep 17 00:00:00 2001 From: Golovanov399 Date: Mon, 16 Dec 2024 06:25:07 +0300 Subject: [PATCH 19/27] [book] describe `build` flags in the book (#1066) * ChatGPT here is the `cargo openvm build -h` output please generate the manual chapter about it * Rename `compile.md` -> `build.md` * chore: summary * fixes --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/SUMMARY.md | 6 +- book/src/writing-apps/build.md | 141 +++++++++++++++++++++++++++++++ book/src/writing-apps/compile.md | 24 ------ 3 files changed, 144 insertions(+), 27 deletions(-) create mode 100644 book/src/writing-apps/build.md delete mode 100644 book/src/writing-apps/compile.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 939a8948eb..38f675db2d 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -12,8 +12,7 @@ - [Overview](./writing-apps/overview.md) - [Writing a Program](./writing-apps/write-program.md) -- [Cross-Compilation](./writing-apps/compile.md) -- [Testing](./writing-apps/testing.md) +- [Cross-Compilation](./writing-apps/build.md) - [Generating Proofs](./writing-apps/prove.md) - [Onchain Verification](./writing-apps/verify.md) @@ -29,4 +28,5 @@ # Advanced Usage - [Overview](./advanced-usage/overview.md) -- [Testing the program](./advanced-usage/testing-program.md) +- [SDK](./advanced-usage/sdk.md) +- [Testing](./advanced-usage/testing-program.md) diff --git a/book/src/writing-apps/build.md b/book/src/writing-apps/build.md new file mode 100644 index 0000000000..aadbb7b3f9 --- /dev/null +++ b/book/src/writing-apps/build.md @@ -0,0 +1,141 @@ +# Cross-Compilation + +First let's define some key terms used in cross-compilation: + +- **host** - the machine you're compiling and/or proving on. Note that one can compile and prove on different machines, but they are both called _host_ as they are traditional machine architectures. +- **guest** - the executable to be run in a different VM architecture (e.g. the OpenVM runtime, or Android app). + +There are multiple things happening in the `cargo openvm build` command as in the section [here](./write-program.md). In short, this command compiles on host to an executable for guest target. +It first compiles the program normally on your _host_ platform with RISC-V and then transpiles it to a different target. See here for some explanation of [cross-compilation](https://rust-lang.github.io/rustup/cross-compilation.html). +Right now we use `riscv32im-risc0-zkvm-elf` target which is available in the [Rust toolchain](https://doc.rust-lang.org/rustc/platform-support/riscv32im-risc0-zkvm-elf.html), but we will contribute an OpenVM target to Rust in the future. + +## Build flags + +The following flags are available for the `cargo openvm build` command: + +- `--manifest-dir ` + + **Description**: Specifies the directory containing the `Cargo.toml` file for the guest code. + + **Default**: The current directory (`.`). + + **Usage Example**: If your `Cargo.toml` is located in `my_project/`, you can run: + + ```bash + cargo openvm build --manifest-dir my_project + ``` + + This ensures the build command is executed in that directory. + +- `--features ` + + **Description**: Passes a list of feature flags to the Cargo build process. These flags enable or disable conditional compilation features defined in your `Cargo.toml`. + + **Usage Example**: To enable the `my_feature` feature: + + ```bash + cargo openvm build --features my_feature + ``` + +- `--bin` + + **Description**: Restricts the build to binary targets. If your project has multiple target types (binaries, libraries, examples, etc.), using `--bin` ensures only binary targets are considered. + + **Usage Example**: + + ```bash + cargo openvm build --bin + ``` + +- `--example` + + **Description**: Restricts the build to example targets. Projects often include code samples or demos under the examples directory, and this flag focuses on compiling those. + + **Usage Example**: + + ```bash + cargo openvm build --example + ``` + +- `--name ` + + **Description**: Filters targets by name. Only targets whose names contain the given substring will be built. + + **Usage Example**: To build only targets that have `client` in their name: + + ```bash + cargo openvm build --name client + ``` + +- `--no-transpile` + + **Description**: After building the guest code, doesn't transpile the target ELF into an OpenVM-compatible executable (by default it does). + + **Usage Example**: + + ```bash + cargo openvm build --no-transpile + ``` + +- `--config ` + + **Description**: Specifies the path to a .toml configuration file that defines which VM extensions to use. + + **Default**: `./openvm.toml` if `--config` flag is not provided. + + **Usage Example**: + + ```bash + cargo openvm build --config path/to/openvm.toml + ``` + + This allows you to customize the extensions. Currently the CLI only supports known extensions listed in the [Using Existing Extensions](../custom-extensions/overview.md) section. To use other extensions, use the [SDK](../advanced-usage/sdk.md). + +- `--exe-output ` + + **Description**: Sets the output path for the transpiled program. + + **Default**: `./openvm/app.vmexe` if `--exe-output` flag is not provided. + + **Usage Example**: To specify a custom output filename: + + ```bash + cargo openvm build --exe-output ./output/custom_name.vmexe + ``` + +- `--profile ` + + **Description**: Determines the build profile used by Cargo. Common profiles are dev (faster builds, less optimization) and release (slower builds, more optimization). + + **Default**: release + + **Usage Example**: + + ```bash + cargo openvm build --profile dev + ``` + +- `--help` + + **Description**: Prints a help message describing the available options and their usage. + + **Usage Example**: + + ```bash + cargo openvm build --help + ``` + +## Running a Program + +After building and transpiling a program, you can execute it using the `run` command. The `run` command has the following arguments: + +```bash +cargo openvm run + --exe + --config + --input +``` + +If `--exe` and/or `--config` are not provided, the command will search for these files in `./openvm/app.vmexe` and `./openvm.toml` respectively. If `./openvm.toml` is not present, a default configuration will be used. + +If your program doesn't require inputs, you can (and should) omit the `--input` flag. diff --git a/book/src/writing-apps/compile.md b/book/src/writing-apps/compile.md deleted file mode 100644 index cdcfcb0c6b..0000000000 --- a/book/src/writing-apps/compile.md +++ /dev/null @@ -1,24 +0,0 @@ -# Cross-Compilation - -First let's define some key terms used in cross-compilation: -- **host** - the machine you're compiling and/or proving on. Note that one can compile and prove on different machines, but they are both called *host* as they are traditional machine architectures. -- **guest** - the executable to be run in a different VM architecture (e.g. the OpenVM runtime, or Android app). - -There are multiple things happening in the `cargo openvm build` command as in the section [here](./write-program.md). In short, this command compiles on host to an executable for guest target. -It first compiles the program normally on your *host* platform with RISC-V and then transpiles it to a different target. See here for some explanation of [cross-compilation](https://rust-lang.github.io/rustup/cross-compilation.html). -Right now we use `riscv32im-risc0-zkvm-elf` target which is available in the [Rust toolchain](https://doc.rust-lang.org/rustc/platform-support/riscv32im-risc0-zkvm-elf.html), but we will contribute an OpenVM target to Rust in the future. - -## Running a Program - -After building and transpiling a program, you can execute it using the `run` command. The `run` command has the following arguments: - -```bash -cargo openvm run - --exe - --config - --input -``` - -If `--exe` and/or `--config` are not provided, the command will search for these files in `./openvm/app.vmexe` and `./openvm.toml` respectively. If `./openvm.toml` is not present, a default configuration will be used. - -If your program doesn't require inputs, you can (and should) omit the `--input` flag. From 9bb4fc4cdb112b01e850e93ab83809011c301c34 Mon Sep 17 00:00:00 2001 From: stephenh-axiom-xyz Date: Sun, 15 Dec 2024 22:32:27 -0500 Subject: [PATCH 20/27] fix: output config TOML parse error when TOML exists but is incorrect (#1069) --- crates/cli/src/util.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/cli/src/util.rs b/crates/cli/src/util.rs index a80e9043e3..581f00acd9 100644 --- a/crates/cli/src/util.rs +++ b/crates/cli/src/util.rs @@ -83,13 +83,13 @@ pub(crate) fn read_to_stdin(input: &Option) -> Result { } pub(crate) fn read_config_toml_or_default(config: &PathBuf) -> Result> { - let mut app_config: Result> = read_to_struct_toml(config); - if app_config.is_err() { + if config.exists() { + read_to_struct_toml(config) + } else { println!( "{:?} not found, using default application configuration", config ); - app_config = Ok(default_app_config()); + Ok(default_app_config()) } - app_config } From 515411edfc4cf338f2142ba31d6cba30d8107565 Mon Sep 17 00:00:00 2001 From: Yi Sun Date: Sun, 15 Dec 2024 21:37:36 -0600 Subject: [PATCH 21/27] chore: remove overview, testing from advanced, add new-extension (#1070) --- book/src/SUMMARY.md | 3 +-- book/src/advanced-usage/overview.md | 1 - book/src/advanced-usage/testing-program.md | 21 --------------------- 3 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 book/src/advanced-usage/overview.md delete mode 100644 book/src/advanced-usage/testing-program.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 38f675db2d..fb4852b228 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -27,6 +27,5 @@ # Advanced Usage -- [Overview](./advanced-usage/overview.md) - [SDK](./advanced-usage/sdk.md) -- [Testing](./advanced-usage/testing-program.md) +- [Creating a New Extension](./advanced-usage/new-extension.md) diff --git a/book/src/advanced-usage/overview.md b/book/src/advanced-usage/overview.md deleted file mode 100644 index 07dd0c5c77..0000000000 --- a/book/src/advanced-usage/overview.md +++ /dev/null @@ -1 +0,0 @@ -# Overview diff --git a/book/src/advanced-usage/testing-program.md b/book/src/advanced-usage/testing-program.md deleted file mode 100644 index afd89ad955..0000000000 --- a/book/src/advanced-usage/testing-program.md +++ /dev/null @@ -1,21 +0,0 @@ -## 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 - -For more information on building, transpiling, running, generating proofs, and verifying proofs with the CLI, see the [CLI](../writing-apps/overview.md)section. To do the same with the SDK, see the [SDK](sdk.md) section. - -## Troubleshooting - -todo - -## FAQ - -todo \ No newline at end of file From e52f9faf918402cb808699d2f5c5d8f56e404728 Mon Sep 17 00:00:00 2001 From: stephenh-axiom-xyz Date: Sun, 15 Dec 2024 22:42:14 -0500 Subject: [PATCH 22/27] docs: SDK code runs (#1071) --- book/src/advanced-usage/sdk.md | 64 +++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/book/src/advanced-usage/sdk.md b/book/src/advanced-usage/sdk.md index 51a0145de3..e4f2fba1f5 100644 --- a/book/src/advanced-usage/sdk.md +++ b/book/src/advanced-usage/sdk.md @@ -9,12 +9,19 @@ For more information on the basic CLI flow, see [Overview of Basic Usage](./over 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 openvm::{platform::memory::MEM_SIZE, transpiler::elf::Elf}; -use openvm_circuit::arch::instructions::exe::OpenVmExe -use openvm_circuit::arch::VmExecutor; -use openvm_sdk::{config::SdkVmConfig, Sdk, StdIn}; - -let sdk = Sdk; +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 { @@ -29,6 +36,7 @@ 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()) @@ -40,7 +48,8 @@ let guest_opts = GuestOptions::default().with_features(vec!["parallel"]); let target_filter = TargetFilter::default().with_kind("bin".to_string()); let elf = sdk.build(guest_opts, "your_path_project_root", &target_filter)?; // 2b. Load the ELF from a file -let elf = Elf::decode("your_path_to_elf", MEM_SIZE as u32)?; +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())?; @@ -55,12 +64,13 @@ 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; // anything that can be serialized +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, vm_config, input)?; +let output = sdk.execute(exe.clone(), vm_config.clone(), stdin.clone())?; +println!("public values output: {:?}", output); ``` ### Using `StdIn` @@ -84,15 +94,14 @@ let app_config = AppConfig::new(app_fri_params, vm_config); let app_committed_exe = sdk.commit_app_exe(app_fri_params, exe)?; // 8. Generate an AppProvingKey -let app_pk = sdk.app_keygen(app_config)?; +let app_pk = Arc::new(sdk.app_keygen(app_config)?); // 9a. Generate a proof -let proof = sdk.generate_app_proof(app_pk, app_committed_exe, stdin)?; +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 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_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()); ``` ## Verifying Proofs @@ -111,20 +120,33 @@ 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 = Halo2ParamsReader::new(DEFAULT_PARAMS_DIR); +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 an EVM proof -let proof = sdk.generate_evm_proof(&halo2_params_reader, app_pk, app_committed_exe, agg_pk, stdin)?; - -// 13. Generate the SNARK verifier contract +// 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 -sdk.verify_evm_proof(&verifier, &proof)?; +let success = sdk.verify_evm_proof(&verifier, &proof); +assert!(success); ``` +> ⚠️ **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. + 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 [onchain verify](../writing-apps/onchain-verify.md) doc. > ⚠️ **WARNING** From 7851c0653dbfb2f8b0d4e9051ce2e7717ce21f1f Mon Sep 17 00:00:00 2001 From: stephenh-axiom-xyz Date: Sun, 15 Dec 2024 22:57:32 -0500 Subject: [PATCH 23/27] fix: remove char in docs (#1072) --- book/src/advanced-usage/sdk.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/advanced-usage/sdk.md b/book/src/advanced-usage/sdk.md index e4f2fba1f5..39d6d1fc5a 100644 --- a/book/src/advanced-usage/sdk.md +++ b/book/src/advanced-usage/sdk.md @@ -145,7 +145,7 @@ assert!(success); > 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. +> 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 [onchain verify](../writing-apps/onchain-verify.md) doc. From db140e9021a8bafa6b92dc14b04fbab20657753c Mon Sep 17 00:00:00 2001 From: Yu Jiang Tham Date: Sun, 15 Dec 2024 19:57:52 -0800 Subject: [PATCH 24/27] [docs] `ecc-pairing` book page (#1054) * ecc-pairing initial draft * Fix links * Update book/src/SUMMARY.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Update book/src/using-extensions/pairing.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Update book/src/using-extensions/pairing.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Update book/src/using-extensions/pairing.md Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> * Address PR comments (without CLI yet) * WIP: openvm.toml section * Update pairing w/ hardcoded input code * chore: remove unneeded * chore: remove unnecessary sections --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/custom-extensions/pairing.md | 181 +++++++++++++++++++- crates/toolchain/tests/src/pairing_tests.rs | 1 - 2 files changed, 180 insertions(+), 2 deletions(-) diff --git a/book/src/custom-extensions/pairing.md b/book/src/custom-extensions/pairing.md index ebb943f14c..0f9b1fc333 100644 --- a/book/src/custom-extensions/pairing.md +++ b/book/src/custom-extensions/pairing.md @@ -1 +1,180 @@ -# OpenVM Pairing \ No newline at end of file +# Elliptic Curve Pairing + +The pairing extension enables usage of the optimal Ate pairing check on the BN254 and BLS12-381 elliptic curves. The following field extension tower for $\mathbb{F}_{p^{12}}$ is used for pairings in this crate: + +$$ +\mathbb{F_{p^2}} = \mathbb{F_{p}}[u]/(u^2 - \beta)\\ +\mathbb{F_{p^6}} = \mathbb{F_{p^2}}[v]/(v^3 - \xi)\\ +\mathbb{F_{p^{12}}} = \mathbb{F_{p^6}}[w]/(w^2 - v) +$$ + +A full guest program example is available here: [pairing_check.rs](https://github.com/openvm-org/openvm/blob/c19c9ac60b135bb0f38fc997df5eb149db8144b4/crates/toolchain/tests/programs/examples/pairing_check.rs) + +## Guest program setup + +We'll be working with an example using the BLS12-381 elliptic curve. This is in addition to the setup that needs to be done in the [Writing a Program](../writing-apps/write-program.md) section. + +In the guest program, we will import the `PairingCheck` and `IntMod` traits, along with the BLS12-381 curve structs (**IMPORTANT:** this requires the `bls12_381` feature enabled in Cargo.toml for the `openvm-pairing-guest` dependency), and a few other values that we will need: + +```rust title="guest program" +use openvm_pairing_guest::{ + pairing::PairingCheck, + bls12_381::{Bls12_381, Fp, Fp2}, +}; +use openvm_ecc_guest::AffinePoint; +use openvm_algebra_guest::IntMod; +use openvm::io::read; +``` + +Additionally, we'll need to initialize our moduli and `Fp2` struct via the following macros. For a more in-depth description of these macros, please see the [OpenVM Algebra](./algebra.md) section. + +```rust +// These correspond to the BLS12-381 coordinate and scalar moduli, respectively +openvm_algebra_moduli_setup::moduli_init! { + "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" +} + +openvm_algebra_complex_macros::complex_init! { + Bls12_381Fp2 { mod_idx = 0 }, +} +``` + +And we'll run the required setup functions at the top of the guest program's `main()` function: + +```rust +setup_0(); +setup_all_complex_extensions(); +``` + +There are two moduli defined internally in the Bls12_381 feature. The `moduli_init!` macro thus requires both of them to be initialized. However, we do not need the scalar field of BLS12-381 (which is at index 1), and thus we only initialize the modulus from index 0, thus we only use `setup_0()` (as opposed to `setup_all_moduli()`, which will save us some columns when generating the trace). + +## Input values + +The inputs to the pairing check are `AffinePoint`s in $\mathbb{F}_p$ and $\mathbb{F}_{p^2}$. They can be constructed via the `AffinePoint::new` function, with the inner `Fp` and `Fp2` values constructed via various `from_...` functions. + +We can create a new struct to hold these `AffinePoint`s for the purpose of this guide. You may instead put them into a custom struct to serve your use case. + +```rust +#[derive(Clone, serde::Serialize, serde::Deserialize)] +pub struct PairingCheckInput { + p0: AffinePoint, + p1: AffinePoint, + q0: AffinePoint, + q1: AffinePoint, +} +``` + +## Pairing check + +Most users that use the pairing extension will want to assert that a pairing is valid (the final exponentiation equals one). With the `PairingCheck` trait imported from the previous section, we have access to the `pairing_check` function on the `Bls12_381` struct. After reading in the input struct, we can use its values in the `pairing_check`: + +```rust +let res = Bls12_381::pairing_check( + &[p0, p1], + &[q0, q1], +); +assert!(res.is_ok()) +``` + +## Additional functionality + +We also have access to each of the specific functions that the pairing check utilizes for either the BN254 or BLS12-381 elliptic curves. + +### Multi-Miller loop + +The multi-Miller loop requires the MultiMillerLoop trait can also be ran separately via: + +```rust +let f = Bls12_381::multi_miller_loop( + &[p0, p1], + &[q0, q1], +); +``` + +## Running via CLI + +### Config parameters + +For the guest program to build successfully, we'll need to create an `openvm.toml` configuration file somewhere. It contains all of the necessary configuration information for enabling the OpenVM components that are used in the pairing check. + +```toml +# openvm.toml +[app_vm_config.pairing] +supported_curves = ["Bls12_381"] + +[app_vm_config.modular] +supported_modulus = [ + "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", +] + +[app_vm_config.fp2] +supported_modulus = [ + "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", +] +``` + +### Full example code + +This example code contains hardcoded values and no inputs as an example that can be run via the CLI. + +```rust +#![no_main] +#![no_std] + +use hex_literal::hex; +use openvm_algebra_guest::{field::FieldExtension, IntMod}; +use openvm_ecc_guest::AffinePoint; +use openvm_pairing_guest::{ + bls12_381::{Bls12_381, Fp, Fp2}, + pairing::PairingCheck, +}; + +openvm::entry!(main); + +openvm_algebra_moduli_setup::moduli_init! { + "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" +} + +openvm_algebra_complex_macros::complex_init! { + Bls12_381Fp2 { mod_idx = 0 }, +} + +pub fn main() { + setup_0(); + setup_all_complex_extensions(); + + let p0 = AffinePoint::new( + Fp::from_be_bytes(&hex!("17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb")), + Fp::from_be_bytes(&hex!("08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1")) + ); + let p1 = AffinePoint::new( + Fp2::from_coeffs([ + Fp::from_be_bytes(&hex!("1638533957d540a9d2370f17cc7ed5863bc0b995b8825e0ee1ea1e1e4d00dbae81f14b0bf3611b78c952aacab827a053")), + Fp::from_be_bytes(&hex!("0a4edef9c1ed7f729f520e47730a124fd70662a904ba1074728114d1031e1572c6c886f6b57ec72a6178288c47c33577")) + ]), + Fp2::from_coeffs([ + Fp::from_be_bytes(&hex!("0468fb440d82b0630aeb8dca2b5256789a66da69bf91009cbfe6bd221e47aa8ae88dece9764bf3bd999d95d71e4c9899")), + Fp::from_be_bytes(&hex!("0f6d4552fa65dd2638b361543f887136a43253d9c66c411697003f7a13c308f5422e1aa0a59c8967acdefd8b6e36ccf3")) + ]), + ); + let q0 = AffinePoint::new( + Fp::from_be_bytes(&hex!("0572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e")), + Fp::from_be_bytes(&hex!("166a9d8cabc673a322fda673779d8e3822ba3ecb8670e461f73bb9021d5fd76a4c56d9d4cd16bd1bba86881979749d28")) + ); + let q1 = AffinePoint::new( + Fp2::from_coeffs([ + Fp::from_be_bytes(&hex!("024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8")), + Fp::from_be_bytes(&hex!("13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e")) + ]), + Fp2::from_coeffs([ + Fp::from_be_bytes(&hex!("0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801")), + Fp::from_be_bytes(&hex!("0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be")) + ]), + ); + + let res = Bls12_381::pairing_check(&[p0, -q0], &[p1, q1]); + assert!(res.is_ok()); +} +``` diff --git a/crates/toolchain/tests/src/pairing_tests.rs b/crates/toolchain/tests/src/pairing_tests.rs index 1aea3af067..65912bfb86 100644 --- a/crates/toolchain/tests/src/pairing_tests.rs +++ b/crates/toolchain/tests/src/pairing_tests.rs @@ -515,7 +515,6 @@ mod bls12_381 { G2Affine::from(Q * Fr::from(2)), G2Affine::from(Q * Fr::from(1)), ]; - let s = S_mul.map(|s| AffinePoint::new(s.x, s.y)); let q = Q_mul.map(|p| AffinePoint::new(p.x, p.y)); From 6f3255edcc1509b964eaad072c410b4ba40246e4 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Sun, 15 Dec 2024 23:00:10 -0500 Subject: [PATCH 25/27] chore: rename sections (#1073) --- book/src/SUMMARY.md | 4 ++-- book/src/writing-apps/build.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index fb4852b228..0a0689e521 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -12,7 +12,7 @@ - [Overview](./writing-apps/overview.md) - [Writing a Program](./writing-apps/write-program.md) -- [Cross-Compilation](./writing-apps/build.md) +- [Compiling](./writing-apps/build.md) - [Generating Proofs](./writing-apps/prove.md) - [Onchain Verification](./writing-apps/verify.md) @@ -21,7 +21,7 @@ - [Overview](./custom-extensions/overview.md) - [Keccak](./custom-extensions/keccak.md) - [Big Integer](./custom-extensions/bigint.md) -- [Algebra](./custom-extensions/algebra.md) +- [Algebra (Modular Arithmetic)](./custom-extensions/algebra.md) - [Elliptic Curve Cryptography](./custom-extensions/ecc.md) - [Elliptic Curve Pairing](./custom-extensions/pairing.md) diff --git a/book/src/writing-apps/build.md b/book/src/writing-apps/build.md index aadbb7b3f9..b5b0a8fd56 100644 --- a/book/src/writing-apps/build.md +++ b/book/src/writing-apps/build.md @@ -1,4 +1,4 @@ -# Cross-Compilation +# Compiling a Program First let's define some key terms used in cross-compilation: From 3c8d8a91baae353de815ca59c6d045133ba501fb Mon Sep 17 00:00:00 2001 From: HrikB <23041116+HrikB@users.noreply.github.com> Date: Sun, 15 Dec 2024 20:15:31 -0800 Subject: [PATCH 26/27] Completed installation and quickstart sections (#1065) * docs: completed installation and quickstart sections * Apply suggestions from code review * update cli --------- Co-authored-by: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> --- book/src/getting-started/install.md | 42 +++++++++++++-- book/src/getting-started/quickstart.md | 73 ++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 15 deletions(-) diff --git a/book/src/getting-started/install.md b/book/src/getting-started/install.md index bb470b6b03..18ecdbac82 100644 --- a/book/src/getting-started/install.md +++ b/book/src/getting-started/install.md @@ -1,9 +1,30 @@ # Install -TODO: how to install `cargo-openvm`. -`cargo install --git <...>` +To use OpenVM for generating proofs, you must install the OpenVM command line tool `cargo-openvm`. -## Build from source +`cargo-openvm` can be installed in two different ways. You can either install via git URL or build from source. + +## Option 1: Install Via Git URL (Recommended) + +```bash +cargo install --git http://github.com/openvm-org/openvm.git cargo-openvm +``` + +This will globally install `cargo-openvm`. You can validate a successful installation with: + +```bash +cargo openvm --version +``` + +## Option 2: Build from source + +To build from source, you will need the nightly toolchain. You can install it with: + +```bash +rustup toolchain install nightly +``` + +Then, clone the repository and begin the installation. ```bash git clone https://github.com/openvm-org/openvm.git @@ -11,4 +32,17 @@ cd openvm cargo install --force --path crates/cli ``` -## Toolchain +This will globally install `cargo-openvm`. You can validate a successful installation with: + +```bash +cargo openvm --version +``` + +## Install Rust Toolchain + +In order for the `cargo-openvm` build command to work, you must install certain Rust nightly components: + +```bash +rustup install nightly-2024-10-30 +rustup component add rust-src --toolchain nightly-2024-10-30 +``` diff --git a/book/src/getting-started/quickstart.md b/book/src/getting-started/quickstart.md index c40f274cd1..335a9c2df4 100644 --- a/book/src/getting-started/quickstart.md +++ b/book/src/getting-started/quickstart.md @@ -10,17 +10,10 @@ First, create a new Rust project. cargo init fibonacci ``` -Since we are using some nightly features, we need to specify the Rust version. Run `rustup component add rust-src --toolchain nightly-2024-10-30` and 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 +[dependencies] openvm = { git = "https://github.com/openvm-org/openvm.git", features = ["std"] } ``` @@ -28,9 +21,13 @@ 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. +The `read` function takes input from the stdin (it also works with OpenVM runtime). + ```rust -use openvm::io::read; +// src/main.rs +use openvm::io::{read, reveal}; + +openvm::entry!(main); fn main() { let n: u64 = read(); @@ -41,6 +38,60 @@ fn main() { a = b; b = c; } - println!("{}", a); + reveal(a as u32, 0); + reveal((a >> 32) as u32, 1); } ``` + +## Build + +To build the program, run: + +```bash +cargo openvm build +``` + +This will output an OpenVM executable file to `./openvm/app.vmexe`. + +## Keygen + +Before generating any proofs, we will also need to generate the proving and verification keys. + +```bash +cargo openvm keygen +``` + +This will output a serialized proving key to `./openvm/app.pk` and a verification key to `./openvm/app.vk`. + +## Proof Generation + +Now we are ready to generate a proof! Simply run: + +```bash +OPENVM_FAST_TEST=1 cargo openvm prove app --input "0x0A00000000000000" +``` + +The `--input` field is passed to the program which receives it via the `io::read` function. +In our `main.rs` we called `read()` to get `n: u64`. The input here is `n = 100u64` _in little endian_. Note that this value must be padded to exactly 8 bytes (64 bits). + +The serialized proof will be output to `./openvm/app.proof`. + +The `OPENVM_FAST_TEST` environment variable is used to enable fast proving for testing purposes. To run with proof with secure parameters, remove the environmental variable. + +## Proof Verification + +Finally, the proof can be verified. + +```bash +cargo openvm verify app +``` + +The process should exit with no errors. + +## Runtime Execution + +If necessary, the executable can also be run _without_ proof generation. This can be useful for testing purposes. + +```bash +cargo openvm run --input "0x0A00000000000000" +``` From fb017b319e0356a71bcaf6d1fd6f285c42627263 Mon Sep 17 00:00:00 2001 From: Arayi Date: Sun, 15 Dec 2024 23:32:46 -0500 Subject: [PATCH 27/27] Ecc test --- crates/toolchain/tests/Cargo.toml | 3 ++- crates/toolchain/tests/src/ecc_tests.rs | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/toolchain/tests/Cargo.toml b/crates/toolchain/tests/Cargo.toml index 5536cd2015..4f5d30e68c 100644 --- a/crates/toolchain/tests/Cargo.toml +++ b/crates/toolchain/tests/Cargo.toml @@ -35,7 +35,8 @@ openvm-pairing-guest = { workspace = true, features = [ openvm-instructions = { workspace = true } openvm-platform = { workspace = true } openvm = { workspace = true } - +openvm-sdk = { workspace = true } +toml = "0.7" eyre.workspace = true test-case.workspace = true tempfile.workspace = true diff --git a/crates/toolchain/tests/src/ecc_tests.rs b/crates/toolchain/tests/src/ecc_tests.rs index 510a94e5e3..5587ac4295 100644 --- a/crates/toolchain/tests/src/ecc_tests.rs +++ b/crates/toolchain/tests/src/ecc_tests.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +use std::{fs::File, io::Write, str::FromStr}; use derive_more::derive::From; use eyre::Result; @@ -31,6 +31,7 @@ use openvm_rv32im_circuit::{ use openvm_rv32im_transpiler::{ Rv32ITranspilerExtension, Rv32IoTranspilerExtension, Rv32MTranspilerExtension, }; +use openvm_sdk::config::SdkVmConfig; use openvm_stark_backend::p3_field::{AbstractField, PrimeField32}; use openvm_stark_sdk::p3_baby_bear::BabyBear; use openvm_transpiler::{transpiler::Transpiler, FromElf}; @@ -116,6 +117,21 @@ fn test_complex_two_moduli_runtime() -> Result<()> { #[test] fn test_ec_runtime() -> Result<()> { let elf = build_example_program_with_features("ec", ["k256"])?; + let vm_config = SdkVmConfig::builder() + .system(SystemConfig::default().with_continuations().into()) + .rv32i(Default::default()) + .rv32m(Default::default()) + .io(Default::default()) + .modular(ModularExtension::new(vec![SECP256K1_CONFIG.modulus.clone(), SECP256K1_CONFIG.scalar.clone()])) + .ecc(WeierstrassExtension::new(vec![SECP256K1_CONFIG.clone()])) + .build(); + // Convert to TOML string + let toml_string = toml::to_string(&vm_config)?; + + // Write to file + let mut file = File::create("vm_config.toml")?; + file.write_all(toml_string.as_bytes())?; + let openvm_exe = VmExe::from_elf( elf, Transpiler::::default() @@ -125,8 +141,8 @@ fn test_ec_runtime() -> Result<()> { .with_extension(EccTranspilerExtension) .with_extension(ModularTranspilerExtension), )?; - let config = Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone()]); - new_air_test_with_min_segments(config, openvm_exe, vec![], 1, false); + // let config = Rv32WeierstrassConfig::new(vec![SECP256K1_CONFIG.clone()]); + new_air_test_with_min_segments(vm_config, openvm_exe, vec![], 1, false); Ok(()) }