From 28995b706877338f7a60b40617115e89a072fd27 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 14 Jul 2026 09:52:06 +0800 Subject: [PATCH 01/15] fix: add batch vk --- crates/build-guest/src/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index 2a09a626..18d91944 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -341,6 +341,15 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re write_commitment_as_evm_hex(&output_path, vm_commit_u32)?; } + // Write the aggregation VK for batch proofs so the coordinator can verify + // deferred batch proofs independently (v0.9.0+). + if project_name == "batch" { + let batch_mvk_path = release_output_dir.join("batch_root_verifier_vk"); + write_object_to_file(&batch_mvk_path, sdk.agg_vk().clone()) + .expect("failed to write batch_root_verifier_vk"); + println!("{LOG_PREFIX} Wrote batch aggregation VK to {batch_mvk_path:?}"); + } + use scroll_zkvm_types::{types_agg::ProgramCommitment, utils::serialize_vk}; let app_vk = serialize_vk::serialize(&ProgramCommitment { exe: exe_commit_u32, From 66f63594a78f4c637ff227ae60cfdd28d753a2b1 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 14 Jul 2026 11:56:50 +0800 Subject: [PATCH 02/15] chore: upgrade openvm to develop-v2.1.0 (RV64) - Retarget all openvm-org/openvm.git deps to branch develop-v2.1.0 (locked at fd569c7); stark-backend stays on tag v2.0.0 as pinned by that branch - Migrate guest to RV64: riscv64im-unknown-openvm-elf target via the openvm-1.94.0 toolchain, openvm-rv32im-* -> openvm-riscv-* renames, openvm.toml rv32i/rv32m -> rv64i/rv64m - SDK API: Sdk::riscv64, compile-then-execute for execute* calls - Hint stream is now u64-based; user public values are u16 cells (2 LE bytes each), pi hash fills the first 16 of 32 cells - Patch locally generated EVM verifier for 2-bytes-per-PV calldata (upstream template bug on this branch); regenerate all guest assets (commitments, openVmVk.json, verifier.sol/bin) - Host toolchain: nightly-2026-01-18 (openvm-sdk tco feature) GPU e2e: single-chunk, multi-chunk, batch, bundle all pass --- AGENTS.md | 54 +- Cargo.lock | 424 +-- Cargo.toml | 64 +- Makefile | 2 +- crates/build-guest/src/main.rs | 72 +- crates/build-guest/src/verifier.rs | 9 +- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- crates/circuits/batch-circuit/openvm.toml | 4 +- crates/circuits/batch-circuit/src/circuit.rs | 9 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- crates/circuits/bundle-circuit/openvm.toml | 4 +- crates/circuits/bundle-circuit/src/circuit.rs | 9 +- crates/circuits/chunk-circuit/Cargo.toml | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- crates/circuits/chunk-circuit/openvm.toml | 4 +- crates/integration/src/testers/bundle.rs | 6 +- crates/integration/src/utils/mod.rs | 25 +- crates/prover/src/utils/vm.rs | 6 +- crates/types/chunk/src/scroll/execute.rs | 2 +- crates/types/circuit/Cargo.toml | 2 +- crates/types/circuit/src/io.rs | 25 +- crates/types/circuit/src/lib.rs | 18 +- crates/types/src/proof.rs | 13 +- crates/types/src/zkvm.rs | 2 +- docs/openvm-v2-migration.md | 43 + releases/dev/verifier/Halo2Verifier.sol | 3352 +++++++---------- releases/dev/verifier/verifier.bin | Bin 19781 -> 19824 bytes releases/dev/verifier/verifier.sol | 31 +- rust-toolchain.toml | 5 +- 32 files changed, 1886 insertions(+), 2313 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e02fb0f8..33cb5429 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ Critical context for AI agents working on this repo. Read this before making cha ## OpenVM Version Sensitivity -This project uses **OpenVM v2.0.0** as its ZKVM. Guest executables (`.vmexe`) and host code **must be built from the exact same OpenVM version**. Even a minor version bump can change: +This project uses **OpenVM `develop-v2.1.0` branch** (RV64 guest toolchain) as its ZKVM. Guest executables (`.vmexe`) and host code **must be built from the exact same OpenVM version**. Even a minor version bump can change: - The guest/host data layout (hint streams, public inputs) - The Halo2 SRS degree requirement @@ -21,29 +21,61 @@ This project uses **OpenVM v2.0.0** as its ZKVM. Guest executables (`.vmexe`) an - Field algebra APIs - ECC constructor signatures +### v2.1.0 (RV64) migration notes + +Compared to v2.0.0, the `develop-v2.1.0` branch changes: + +- Guest target is now `riscv64im-unknown-openvm-elf` (built into the `openvm-1.94.0` + rust fork toolchain). Guest builds MUST use `OPENVM_RUST_TOOLCHAIN=openvm-1.94.0` + (the default in the Makefile and in `openvm-build`). The old + `riscv32im-risc0-zkvm-elf` / `nightly-2025-11-20` combination is gone. +- Crate renames: `openvm-rv32im-{guest,transpiler,circuit}` → `openvm-riscv-{guest,transpiler,circuit}`. +- `openvm.toml`: `[app_vm_config.rv32i]`/`rv32m` → `rv64i`/`rv64m`. +- SDK API: `Sdk::riscv32`/`AppConfig::riscv32` → `riscv64`; `Sdk::execute*` now + takes a compiled instance — call `sdk.compile*` / `sdk.compile_metered_cost` + first, then `sdk.execute(&compiled, ...)` / `sdk.execute_metered_cost(&compiled, ...)`. +- Hint stream words are 8 bytes: `hint_store_u32!` → `hint_store_u64!` / + `hint_buffer_chunked`, and the hint-stream length prefix is a `u64`. +- User public values are **u16 cells** (2 little-endian bytes per cell) instead of + 1 byte per u32 cell. `NUM_PUBLIC_VALUES` is still 32 cells (= 64 bytes); the + 32-byte pi hash fills the first 16 cells. +- Guest cfg gates: `target_os = "zkvm"` → `target_os = "openvm"`. +- ⚠️ **EVM verifier template bug on this branch**: the SDK packs user public + values as 2 LE bytes per u16 cell in `verifier_calldata`, but the Solidity + template (`crates/sdk/contracts/template/OpenVmHalo2Verifier.sol`) still + expects 1 byte per PV, causing `InvalidPublicValuesLength` reverts. + `crates/build-guest/src/main.rs::patch_verifier_for_u16_public_values` + rewrites the locally generated wrapper to accept 2 bytes per cell. If that + function errors with "template fragment not found", upstream has changed the + template — review whether the patch is still needed. +- Host toolchain: `rust-toolchain.toml` uses `nightly-2026-01-18` (required by the + openvm-sdk `tco` feature). + ### How to update OpenVM dependencies correctly -OpenVM is declared as a **git dependency** (`tag = "v2.0.0"`) in `Cargo.toml`, and the exact commit is also pinned in `Cargo.lock`. The `openvm-org/openvm.git` and `openvm-org/stark-backend.git` entries MUST stay on matching tags — `openvm`'s own `Cargo.toml` pins a specific `stark-backend` tag, and a mismatch produces duplicate-registry / type-mismatch errors. Because the tag is immutable, the declared ref and the locked commit should always agree. The real hazard is a bare `cargo update`: it will **not** change the OpenVM tag, but it will bump unrelated crates.io packages (e.g. `alloy`, `revm`) which often break compatibility with the `scroll-tech/reth` and `sbv` forks. +OpenVM is declared as a **git dependency** (`branch = "develop-v2.1.0"`) in `Cargo.toml`, and the exact commit is also pinned in `Cargo.lock`. The `openvm-org/stark-backend.git` entries MUST stay on the tag that `openvm`'s own `Cargo.toml` pins for that branch (currently `tag = "v2.0.0"`) — a mismatch produces duplicate-registry / type-mismatch errors. A branch ref moves: after fetching, verify the locked commit is the one you expect. The real hazard is a bare `cargo update`: it will bump unrelated crates.io packages (e.g. `alloy`, `revm`) which often break compatibility with the `scroll-tech/reth` and `sbv` forks. **Do NOT run a global `cargo update` unless you are prepared to upgrade the entire `alloy`/`revm`/`reth`/`sbv` dependency chain together.** -To move to a newer OpenVM tag, retarget every `openvm-org/openvm.git` and `openvm-org/stark-backend.git` entry in `Cargo.toml` to the new tag, then refresh only those git sources — `cargo metadata` is enough — rather than a global `cargo update`. Verify with `git diff Cargo.lock` that no other package's version/source changed. Then rebuild guests and run tests as described below. +To move to a newer OpenVM ref, retarget every `openvm-org/openvm.git` entry in `Cargo.toml` to the new tag/branch and set `openvm-org/stark-backend.git` to whatever tag that openvm ref's own `Cargo.toml` pins, then refresh only those git sources — `cargo metadata` is enough — rather than a global `cargo update`. Verify with `git diff Cargo.lock` that no other package's version/source changed. Then rebuild guests and run tests as described below. ### After ANY OpenVM version upgrade, you MUST: 1. **Update the hardcoded version string** in `crates/build-guest/src/verifier.rs`: ```rust - let solidity_sdk_tag = "v2.0"; // MUST match openvm-solidity-sdk tag - let verifier_path = "v2.0-deferral"; // bundle/deferral verifier + let solidity_sdk_tag = "v2.1"; // MUST match openvm-solidity-sdk tag + let verifier_path = "v2.1-deferral"; // bundle/deferral verifier ``` + (As of the `develop-v2.1.0` upgrade, `openvm-solidity-sdk` has no `v2.1` tag yet, + so the download fails and `auto` mode falls back to local verifier generation.) 2. **Force-rebuild ALL guest assets** (auto mode skips existing files): ```bash # Local build - OPENVM_RUST_TOOLCHAIN=nightly-2025-11-20 cargo run --release -p scroll-zkvm-build-guest -- --mode force + OPENVM_RUST_TOOLCHAIN=openvm-1.94.0 cargo run --release -p scroll-zkvm-build-guest -- --mode force # Docker build (matches CI) - OPENVM_RUST_TOOLCHAIN=nightly-2025-11-20 make build-guest + OPENVM_RUST_TOOLCHAIN=openvm-1.94.0 make build-guest ``` This regenerates: `app.elf`, `app.vmexe`, commitment `.rs` files, `openVmVk.json`, and the EVM verifier (`verifier.sol` + `verifier.bin`). @@ -67,7 +99,7 @@ To move to a newer OpenVM tag, retarget every `openvm-org/openvm.git` and `openv These are cached proving keys. They are **not** automatically invalidated on version bumps. 5. **Check SRS params** in `~/.openvm/params/`: - - OpenVM v2.0.0 requires `kzg_bn254_24.srs` (2 GB) + - OpenVM v2.x requires `kzg_bn254_24.srs` (2 GB) - If the file is empty/corrupted, replace it (check for `.1` or `.part` suffixes from interrupted downloads) 6. **Clear test output cache** before re-running integration tests: @@ -101,7 +133,7 @@ This happens when: **Fix**: Regenerate with: ```bash -OPENVM_RUST_TOOLCHAIN=nightly-2025-11-20 cargo run --release -p scroll-zkvm-build-guest -- --mode force +OPENVM_RUST_TOOLCHAIN=openvm-1.94.0 cargo run --release -p scroll-zkvm-build-guest -- --mode force ``` (The default `auto` mode will fall back to local generation if the download fails; use `RECOMPUTE_MODE=yes` to force local generation immediately.) @@ -119,7 +151,7 @@ The `build-guest.sh` script may fail if a stale `build-guest.cid` file exists. U # Force rebuild all guest assets (required after OpenVM upgrade). # Default RECOMPUTE_MODE=auto falls back to local generation if the download fails. # Use RECOMPUTE_MODE=yes to skip the download and force local generation. -OPENVM_RUST_TOOLCHAIN=nightly-2025-11-20 cargo run --release -p scroll-zkvm-build-guest -- --mode force +OPENVM_RUST_TOOLCHAIN=openvm-1.94.0 cargo run --release -p scroll-zkvm-build-guest -- --mode force # Run end-to-end tests (ALWAYS use make, never raw cargo test) GPU=1 make test-e2e-bundle @@ -183,3 +215,5 @@ If any of these mismatch, the EVM verifier will reject proofs with `ProofVerific - `chunk-circuit`: requires `system.config.continuation_enabled = true` - `batch-circuit` / `bundle-circuit`: aggregation FRI params are supplied in code via `AggregationConfig { params: default_agg_params() }`; the checked-in `openvm.toml` files do not contain `leaf_fri_params` - FRI params format in OpenVM v2: `commit_proof_of_work_bits` + `query_proof_of_work_bits` +- VM extension sections in `openvm.toml` are `[app_vm_config.rv64i]` / `[app_vm_config.rv64m]` (RV64) +- Guest ELFs land in `target/riscv64im-unknown-openvm-elf/maxperf/` diff --git a/Cargo.lock b/Cargo.lock index 38a3637e..f7afa416 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,54 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "abi_stable" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d6512d3eb05ffe5004c59c206de7f99c34951504056ce23fc953842f12c445" -dependencies = [ - "abi_stable_derive", - "abi_stable_shared", - "const_panic", - "core_extensions", - "crossbeam-channel", - "generational-arena", - "libloading", - "lock_api", - "parking_lot", - "paste", - "repr_offset", - "rustc_version 0.4.1", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] -name = "abi_stable_derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7178468b407a4ee10e881bc7a328a65e739f0863615cca4429d43916b05e898" -dependencies = [ - "abi_stable_shared", - "as_derive_utils", - "core_extensions", - "proc-macro2", - "quote", - "rustc_version 0.4.1", - "syn 1.0.109", - "typed-arena", -] - -[[package]] -name = "abi_stable_shared" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b5df7688c123e63f4d4d649cba63f2967ba7f7861b1664fca3f77d3dad2b63" -dependencies = [ - "core_extensions", -] - [[package]] name = "addr2line" version = "0.25.1" @@ -1104,18 +1056,6 @@ dependencies = [ "serde", ] -[[package]] -name = "as_derive_utils" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff3c96645900a44cf11941c111bd08a6573b0e2f9f69bc9264b179d8fae753c4" -dependencies = [ - "core_extensions", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "async-stream" version = "0.3.6" @@ -1717,15 +1657,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "const_panic" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e262cdaac42494e3ae34c43969f9cdeb7da178bdb4b66fa6a1ea2edb4c8ae652" -dependencies = [ - "typewit", -] - [[package]] name = "constant_time_eq" version = "0.3.1" @@ -1757,21 +1688,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core_extensions" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bb5e5d0269fd4f739ea6cedaf29c16d81c27a7ce7582008e90eb50dcd57003" -dependencies = [ - "core_extensions_proc_macros", -] - -[[package]] -name = "core_extensions_proc_macros" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533d38ecd2709b7608fb8e18e4504deb99e9a72879e6aa66373a76d8dc4259ea" - [[package]] name = "cpufeatures" version = "0.2.17" @@ -2650,15 +2566,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" -[[package]] -name = "generational-arena" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" -dependencies = [ - "cfg-if", -] - [[package]] name = "generic-array" version = "0.14.9" @@ -2822,7 +2729,7 @@ dependencies = [ "crossbeam", "ff 0.13.1", "group 0.13.0", - "halo2curves-axiom 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "halo2curves-axiom 0.7.2", "itertools 0.11.0", "maybe-rayon", "pairing 0.23.0", @@ -2917,8 +2824,8 @@ dependencies = [ [[package]] name = "halo2curves-axiom" -version = "0.7.2" -source = "git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2#3a65a710e27fe03711f6fb4fc0c4469ae351974a" +version = "0.7.3" +source = "git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.3#d744f712fbeaf62576b2b10842822919551c5ef8" dependencies = [ "blake2b_simd", "digest 0.10.7", @@ -3460,7 +3367,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "ecdsa", "elliptic-curve", @@ -3512,12 +3419,12 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "winapi", + "windows-link 0.2.1", ] [[package]] @@ -4185,7 +4092,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4193,25 +4100,26 @@ dependencies = [ "num-bigint", "openvm-custom-insn", "openvm-platform", - "openvm-rv32im-guest", + "openvm-riscv-guest", "serde", ] [[package]] name = "openvm-algebra-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "blstrs", "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", - "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", + "halo2curves-axiom 0.7.3", "num-bigint", "num-traits", "once_cell", "openvm-algebra-transpiler", + "openvm-algebra-utils", "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", @@ -4221,8 +4129,8 @@ dependencies = [ "openvm-cuda-common", "openvm-instructions", "openvm-mod-circuit-builder", - "openvm-rv32-adapters", - "openvm-rv32im-circuit", + "openvm-riscv-adapters", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -4234,7 +4142,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-macros-common", "quote", @@ -4244,15 +4152,15 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ - "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", + "halo2curves-axiom 0.7.3", "num-bigint", "once_cell", "openvm-algebra-complex-macros", "openvm-algebra-moduli-macros", "openvm-custom-insn", - "openvm-rv32im-guest", + "openvm-riscv-guest", "serde-big-array", "strum_macros 0.26.4", ] @@ -4260,7 +4168,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "num-bigint", "num-prime", @@ -4272,21 +4180,31 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-algebra-guest", + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] +[[package]] +name = "openvm-algebra-utils" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +dependencies = [ + "num-bigint", + "num-traits", + "rand 0.9.4", +] + [[package]] name = "openvm-benchmarks-prove" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "clap", "eyre", @@ -4309,7 +4227,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4323,7 +4241,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4338,9 +4256,9 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", - "openvm-rv32-adapters", - "openvm-rv32im-circuit", - "openvm-rv32im-transpiler", + "openvm-riscv-adapters", + "openvm-riscv-circuit", + "openvm-riscv-transpiler", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -4350,7 +4268,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4359,22 +4277,22 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-bigint-guest", + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", - "openvm-rv32im-transpiler", + "openvm-riscv-transpiler", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4386,9 +4304,8 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ - "abi_stable", "backtrace", "bytesize", "cfg-if", @@ -4416,6 +4333,7 @@ dependencies = [ "p3-field", "rand 0.9.4", "rustc-hash 2.1.1", + "rvr-openvm", "serde", "serde-big-array", "static_assertions", @@ -4426,7 +4344,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4437,7 +4355,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4457,7 +4375,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4479,7 +4397,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "cfg-if", "derivative", @@ -4585,17 +4503,22 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "proc-macro2", "quote", "syn 2.0.110", ] +[[package]] +name = "openvm-decoder" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" + [[package]] name = "openvm-deferral-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "cfg-if", "dashmap", @@ -4613,7 +4536,7 @@ dependencies = [ "openvm-deferral-transpiler", "openvm-instructions", "openvm-poseidon2-air", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "p3-field", @@ -4625,7 +4548,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4634,7 +4557,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4650,13 +4573,13 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "blstrs", "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", - "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", + "halo2curves-axiom 0.7.3", "hex-literal 1.1.0", "lazy_static", "num-bigint", @@ -4672,7 +4595,8 @@ dependencies = [ "openvm-ecc-transpiler", "openvm-instructions", "openvm-mod-circuit-builder", - "openvm-rv32-adapters", + "openvm-riscv-adapters", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -4684,18 +4608,18 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "ecdsa", "elliptic-curve", "group 0.13.0", - "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", + "halo2curves-axiom 0.7.3", "once_cell", "openvm", "openvm-algebra-guest", "openvm-custom-insn", "openvm-ecc-sw-macros", - "openvm-rv32im-guest", + "openvm-riscv-guest", "serde", "strum_macros 0.26.4", ] @@ -4703,7 +4627,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-macros-common", "quote", @@ -4713,21 +4637,21 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ + "openvm-decoder", "openvm-ecc-guest", "openvm-instructions", "openvm-instructions-derive", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-instructions" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4744,7 +4668,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "quote", "syn 2.0.110", @@ -4753,7 +4677,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4762,7 +4686,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4777,7 +4701,7 @@ dependencies = [ "openvm-cuda-common", "openvm-instructions", "openvm-keccak256-transpiler", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "p3-keccak-air", @@ -4790,7 +4714,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-platform", ] @@ -4798,21 +4722,21 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-keccak256-guest", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-macros-common" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "syn 2.0.110", ] @@ -4820,7 +4744,7 @@ dependencies = [ [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4838,10 +4762,10 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "group 0.13.0", - "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", + "halo2curves-axiom 0.7.3", "hex-literal 1.1.0", "itertools 0.14.0", "num-bigint", @@ -4855,20 +4779,20 @@ dependencies = [ "openvm-ecc-sw-macros", "openvm-pairing-guest", "openvm-platform", - "openvm-rv32im-guest", + "openvm-riscv-guest", "serde", ] [[package]] name = "openvm-pairing-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", - "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", + "halo2curves-axiom 0.7.3", "num-bigint", "num-traits", "openvm-algebra-circuit", @@ -4883,7 +4807,7 @@ dependencies = [ "openvm-mod-circuit-builder", "openvm-pairing-guest", "openvm-pairing-transpiler", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -4894,10 +4818,10 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "blstrs", - "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", + "halo2curves-axiom 0.7.3", "hex-literal 1.1.0", "itertools 0.14.0", "lazy_static", @@ -4915,30 +4839,30 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ + "openvm-decoder", "openvm-instructions", "openvm-pairing-guest", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] [[package]] name = "openvm-platform" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "libm", "openvm-custom-insn", - "openvm-rv32im-guest", + "openvm-riscv-guest", ] [[package]] name = "openvm-poseidon2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "derivative", "lazy_static", @@ -4956,7 +4880,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4984,16 +4908,16 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "quote", "syn 2.0.110", ] [[package]] -name = "openvm-rv32-adapters" +name = "openvm-riscv-adapters" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5001,16 +4925,16 @@ dependencies = [ "openvm-circuit-primitives", "openvm-circuit-primitives-derive", "openvm-instructions", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", ] [[package]] -name = "openvm-rv32im-circuit" +name = "openvm-riscv-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5027,7 +4951,7 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", - "openvm-rv32im-transpiler", + "openvm-riscv-transpiler", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", @@ -5037,25 +4961,25 @@ dependencies = [ ] [[package]] -name = "openvm-rv32im-guest" +name = "openvm-riscv-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", ] [[package]] -name = "openvm-rv32im-transpiler" +name = "openvm-riscv-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", - "openvm-rv32im-guest", + "openvm-riscv-guest", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "serde", "strum 0.26.3", "tracing", @@ -5064,7 +4988,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "alloy-sol-types", "bitcode", @@ -5103,7 +5027,7 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "bon", "cfg-if", @@ -5124,8 +5048,8 @@ dependencies = [ "openvm-keccak256-transpiler", "openvm-pairing-circuit", "openvm-pairing-transpiler", - "openvm-rv32im-circuit", - "openvm-rv32im-transpiler", + "openvm-riscv-circuit", + "openvm-riscv-transpiler", "openvm-sha2-circuit", "openvm-sha2-transpiler", "openvm-stark-backend", @@ -5139,7 +5063,7 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-sha2-guest", "sha2 0.10.9", @@ -5148,7 +5072,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "ndarray", "num_enum", @@ -5162,7 +5086,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5178,7 +5102,7 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", - "openvm-rv32im-circuit", + "openvm-riscv-circuit", "openvm-sha2-air", "openvm-sha2-transpiler", "openvm-stark-backend", @@ -5191,7 +5115,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-platform", ] @@ -5199,14 +5123,14 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ + "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-sha2-guest", "openvm-stark-backend", "openvm-transpiler", - "rrs-lib", "strum 0.26.3", ] @@ -5277,7 +5201,7 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "halo2-base", "itertools 0.14.0", @@ -5301,14 +5225,14 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "elf", "eyre", + "openvm-decoder", "openvm-instructions", "openvm-platform", "openvm-stark-backend", - "rrs-lib", "rustc-demangle", "thiserror 1.0.69", ] @@ -5316,7 +5240,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "bitcode", "cfg-if", @@ -5346,7 +5270,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "openvm-deferral-guest", ] @@ -5354,7 +5278,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "bitcode", "eyre", @@ -5393,7 +5317,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" dependencies = [ "ecdsa", "elliptic-curve", @@ -6296,15 +6220,6 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" -[[package]] -name = "repr_offset" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1070755bd29dffc19d0971cab794e607839ba2ef4b69a9e6fbc8733c1b72ea" -dependencies = [ - "tstr", -] - [[package]] name = "reqwest" version = "0.12.24" @@ -7713,6 +7628,58 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "rvr-openvm" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +dependencies = [ + "openvm-instructions", + "openvm-platform", + "openvm-riscv-guest", + "openvm-stark-backend", + "rvr-openvm-build", + "rvr-openvm-ext-ffi-common", + "rvr-openvm-ir", + "rvr-openvm-lift", + "thiserror 1.0.69", +] + +[[package]] +name = "rvr-openvm-build" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" + +[[package]] +name = "rvr-openvm-ext-ffi-common" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +dependencies = [ + "openvm-instructions", + "openvm-platform", +] + +[[package]] +name = "rvr-openvm-ir" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +dependencies = [ + "serde", +] + +[[package]] +name = "rvr-openvm-lift" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +dependencies = [ + "libloading", + "openvm-instructions", + "openvm-riscv-transpiler", + "openvm-stark-backend", + "rvr-openvm-ext-ffi-common", + "rvr-openvm-ir", + "thiserror 1.0.69", +] + [[package]] name = "ryu" version = "1.0.20" @@ -7981,7 +7948,7 @@ version = "0.9.0" dependencies = [ "bincode 2.0.1", "ecies", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v2.0.0)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0)", "openvm", "openvm-algebra-complex-macros", "openvm-algebra-guest", @@ -7990,9 +7957,9 @@ dependencies = [ "openvm-keccak256", "openvm-pairing", "openvm-pairing-guest", - "openvm-rv32im-guest", + "openvm-riscv-guest", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v2.0.0)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0)", "scroll-zkvm-types-chunk", "scroll-zkvm-types-circuit", ] @@ -8123,7 +8090,7 @@ version = "0.9.0" dependencies = [ "alloy-primitives", "c-kzg", - "halo2curves-axiom 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "halo2curves-axiom 0.7.2", "itertools 0.14.0", "openvm", "openvm-algebra-guest", @@ -8159,12 +8126,12 @@ dependencies = [ "ecies", "hex-literal 0.4.1", "itertools 0.14.0", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v2.0.0)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0)", "openvm-ecc-guest", "openvm-pairing", "openvm-pairing-guest", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v2.0.0)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0)", "sbv-core", "sbv-helpers", "sbv-primitives", @@ -8183,7 +8150,7 @@ dependencies = [ "openvm", "openvm-custom-insn", "openvm-deferral-guest", - "openvm-rv32im-guest", + "openvm-riscv-guest", "openvm-verify-stark-guest", "scroll-zkvm-types-base", ] @@ -9305,39 +9272,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tstr" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f8e0294f14baae476d0dd0a2d780b2e24d66e349a9de876f5126777a37bdba7" -dependencies = [ - "tstr_proc_macros", -] - -[[package]] -name = "tstr_proc_macros" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a" - -[[package]] -name = "typed-arena" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" - [[package]] name = "typenum" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "typewit" -version = "1.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c1ae7cc0fdb8b842d65d127cb981574b0d2b249b74d1c7a2986863dc134f71" - [[package]] name = "ucd-trie" version = "0.1.7" diff --git a/Cargo.toml b/Cargo.toml index 41ae7a6f..89eb3004 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,50 +26,50 @@ version = "0.9.0" [workspace.dependencies] # openvm guest libs -openvm = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } -openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-custom-insn = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } -openvm-sha2-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-p256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", package = "p256", features = [ +openvm = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0" } +openvm-algebra-complex-macros = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-custom-insn = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-sha2 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0" } +openvm-sha2-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-p256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", package = "p256", features = [ "std", ] } -openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", package = "k256", features = [ +openvm-k256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", package = "k256", features = [ "std", ] } -openvm-pairing = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } -openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-rv32im-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } +openvm-pairing = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0" } +openvm-keccak256 = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-keccak256-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-algebra-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-ecc-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-bigint-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-pairing-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-riscv-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } # openvm host libs -openvm-benchmarks-prove = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-benchmarks-utils = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-build = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-instructions = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-static-verifier = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-verify-stark-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-deferral-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } +openvm-benchmarks-prove = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-benchmarks-utils = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-build = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-instructions = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-sdk-config = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-static-verifier = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-verify-stark-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-deferral-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } openvm-cuda-backend = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v2.0.0", default-features = false } -openvm-deferral-guest = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-rv32im-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } -openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false, features = [ +openvm-deferral-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-riscv-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } +openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false, features = [ "parallel", "evm-prove", "tco", "unprotected" ] } -openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0", default-features = false } +openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } # more openvm related libs openvm-stark-backend = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v2.0.0", default-features = false } diff --git a/Makefile b/Makefile index b3e0fff1..b95ea797 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ export RUST_BACKTRACE RUST_LOG ?= off,scroll_zkvm_integration=debug,scroll_zkvm_verifier=debug,scroll_zkvm_prover=debug,p3_fri=warn,p3_dft=warn,openvm_circuit=warn export RUST_LOG -OPENVM_RUST_TOOLCHAIN ?= nightly-2025-11-20 +OPENVM_RUST_TOOLCHAIN ?= openvm-1.94.0 export OPENVM_RUST_TOOLCHAIN # Set GPU config if GPU=1 is set diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index 18d91944..fa35a04f 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -299,7 +299,7 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re fs::create_dir_all(&path_assets)?; let elf_src = workspace_dir .join("target") - .join("riscv32im-risc0-zkvm-elf") + .join("riscv64im-unknown-openvm-elf") .join("maxperf") .join(format!("scroll-zkvm-{project_name}-circuit")); let path_app_elf: PathBuf = path_assets.join("app.elf"); @@ -436,7 +436,7 @@ fn build_recompute_sdk( let batch_app_config: AppConfig = if batch_config_path.exists() { toml::from_str(&fs::read_to_string(&batch_config_path)?)? } else { - AppConfig::riscv32(app_params.clone()) + AppConfig::riscv64(app_params.clone()) }; let batch_sdk = Sdk::builder() .app_config(batch_app_config) @@ -449,7 +449,7 @@ fn build_recompute_sdk( let bundle_app_config: AppConfig = if bundle_config_path.exists() { toml::from_str(&fs::read_to_string(&bundle_config_path)?)? } else { - AppConfig::riscv32(app_params.clone()) + AppConfig::riscv64(app_params.clone()) }; // The bundle's deferral circuit verifies batch proofs; its memory layout must @@ -475,10 +475,62 @@ pub fn build_evm_verifier( let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); let agg_params = default_agg_params(); let sdk = build_recompute_sdk(release_output_dir, &app_params, &agg_params)?; - let verifier = sdk.generate_halo2_verifier_solidity()?; + let mut verifier = sdk.generate_halo2_verifier_solidity()?; + verifier.openvm_verifier_code = + patch_verifier_for_u16_public_values(&verifier.openvm_verifier_code)?; + // The SDK compiled the artifact bytecode from the *unpatched* source. + // Clear it so `write_evm_verifier_artifacts` recompiles with solc from + // the patched verifier.sol written to disk. + verifier.artifact.bytecode = Vec::new(); Ok((sdk, verifier)) } +/// Patch the locally generated `OpenVmHalo2Verifier.sol` for u16 public values. +/// +/// On the `develop-v2.1.0` branch, user public values are u16 cells (2 bytes +/// each), and the SDK packs them as 2 little-endian bytes per cell in +/// `EvmProof::verifier_calldata`. The Solidity template on this branch still +/// expects 1 byte per public value, so the generated wrapper reverts with +/// `InvalidPublicValuesLength`. Until upstream updates the template, rewrite +/// the generated wrapper to: +/// +/// - accept `2 * PUBLIC_VALUES_LENGTH` calldata bytes, and +/// - expand each u16 cell (little-endian in calldata) into a big-endian +/// `bytes32` word. +/// +/// Fails loudly if the expected template fragments are not found, so we notice +/// when upstream changes the template (e.g. ships a proper u16 fix). +fn patch_verifier_for_u16_public_values(sol_code: &str) -> Result { + const OLD_LEN_CHECK: &str = "if (publicValues.length != PUBLIC_VALUES_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length);"; + const NEW_LEN_CHECK: &str = "if (publicValues.length != PUBLIC_VALUES_LENGTH * 2) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH * 2, publicValues.length);"; + const OLD_LOOP: &str = " // Copy each byte of the public values into the proof. It copies the + // most significant bytes of public values first. + let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) + for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { + calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01) + }"; + const NEW_LOOP: &str = " // Copy each u16 public value cell into its own bytes32 word. The + // calldata packs each cell as 2 little-endian bytes; the word is + // big-endian, so the low byte lands at offset 0x1f and the high + // byte at 0x1e of each word. + let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) + for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { + calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, shl(1, i)), 0x01) + calldatacopy(sub(add(publicValuesMemOffset, shl(5, i)), 1), add(add(publicValues.offset, shl(1, i)), 1), 0x01) + }"; + + let mut patched = sol_code.to_string(); + for (old, new) in [(OLD_LEN_CHECK, NEW_LEN_CHECK), (OLD_LOOP, NEW_LOOP)] { + if !patched.contains(old) { + return Err(eyre::eyre!( + "verifier template fragment not found; upstream may have changed the OpenVmHalo2Verifier template (u16 public values patch needs review)" + )); + } + patched = patched.replace(old, new); + } + Ok(patched) +} + fn write_evm_verifier_artifacts( verifier_output_dir: &Path, verifier: &openvm_sdk::types::EvmHalo2Verifier, @@ -545,15 +597,15 @@ fn compile_solidity_bytecode(verifier_output_dir: &Path) -> Result> { // matches as closely as possible. let sources: std::collections::HashMap = [ ( - "src/v2.0-deferral/interfaces/IOpenVmHalo2Verifier.sol".to_string(), + "src/v2.1-deferral/interfaces/IOpenVmHalo2Verifier.sol".to_string(), read(&interface_path)?, ), ( - "src/v2.0-deferral/Halo2Verifier.sol".to_string(), + "src/v2.1-deferral/Halo2Verifier.sol".to_string(), read(&halo2_path)?, ), ( - "src/v2.0-deferral/OpenVmHalo2Verifier.sol".to_string(), + "src/v2.1-deferral/OpenVmHalo2Verifier.sol".to_string(), read(&parent_path)?, ), ] @@ -630,7 +682,7 @@ fn compile_solidity_bytecode(verifier_output_dir: &Path) -> Result> { let bytecode_hex = parsed .get("contracts") - .and_then(|c| c.get("src/v2.0-deferral/OpenVmHalo2Verifier.sol")) + .and_then(|c| c.get("src/v2.1-deferral/OpenVmHalo2Verifier.sol")) .and_then(|c| c.get("OpenVmHalo2Verifier")) .and_then(|c| c.get("evm")) .and_then(|c| c.get("bytecode")) @@ -693,7 +745,7 @@ fn generate_evm_verifier( } RecomputeMode::No => { println!("{LOG_PREFIX} RECOMPUTE_MODE=no: downloading pre-built verifier only."); - let sdk = Sdk::riscv32(app_params, agg_params); + let sdk = Sdk::riscv64(app_params, agg_params); let verifier = verifier::download_evm_verifier()?; write_evm_verifier_artifacts(verifier_output_dir, &verifier, &sdk, force_overwrite)?; } @@ -704,7 +756,7 @@ fn generate_evm_verifier( match verifier::download_evm_verifier() { Ok(verifier) => { println!("{LOG_PREFIX} Download succeeded; using pre-built verifier."); - let sdk = Sdk::riscv32(app_params, agg_params); + let sdk = Sdk::riscv64(app_params, agg_params); write_evm_verifier_artifacts( verifier_output_dir, &verifier, diff --git a/crates/build-guest/src/verifier.rs b/crates/build-guest/src/verifier.rs index 1fec1cdc..18d38a16 100644 --- a/crates/build-guest/src/verifier.rs +++ b/crates/build-guest/src/verifier.rs @@ -10,11 +10,12 @@ use eyre::Result; pub fn download_evm_verifier() -> Result { // The `openvm-solidity-sdk` release tag to download from. This is NOT the // same as the `openvm` crate version; the SDK follows its own tagging. - let solidity_sdk_tag = "v2.0"; + let solidity_sdk_tag = "v2.1"; // We generate/download the bundle (deferral-enabled) verifier. The plain - // `v2.0-base` verifier is used for leaf circuits that do not defer proof - // verification. - let verifier_path = "v2.0-deferral"; + // `v2.1-base` verifier is used for leaf circuits that do not defer proof + // verification. Note: openvm-solidity-sdk has not published a v2.1 tag yet, + // so the download will fail and auto mode falls back to local generation. + let verifier_path = "v2.1-deferral"; let verifier_url = format!( "https://raw.githubusercontent.com/openvm-org/openvm-solidity-sdk/{solidity_sdk_tag}/src/{verifier_path}/OpenVmHalo2Verifier.sol" ); diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index ed996ef2..8ea0752d 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1863431439, 1670830010, 33016243, 26011158, 931370893, 994260763, 630117706, 207332781]; +pub const COMMIT: [u32; 8] = [484008805, 495385384, 580625652, 1256154140, 344157297, 193294640, 204686231, 1298907128]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index 9129f9cc..e194b577 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [405660519, 24296687, 1842754465, 1433680155, 781042942, 896967232, 568979095, 327499695]; +pub const COMMIT: [u32; 8] = [1294116814, 1474253328, 1120614043, 965568099, 1164275634, 1855860028, 258237225, 196946449]; diff --git a/crates/circuits/batch-circuit/openvm.toml b/crates/circuits/batch-circuit/openvm.toml index a309c5b2..bfb51ff7 100644 --- a/crates/circuits/batch-circuit/openvm.toml +++ b/crates/circuits/batch-circuit/openvm.toml @@ -5,9 +5,9 @@ num_queries = 100 commit_proof_of_work_bits = 16 query_proof_of_work_bits = 16 -[app_vm_config.rv32i] +[app_vm_config.rv64i] -[app_vm_config.rv32m] +[app_vm_config.rv64m] [app_vm_config.io] diff --git a/crates/circuits/batch-circuit/src/circuit.rs b/crates/circuits/batch-circuit/src/circuit.rs index bae66db0..4e93351f 100644 --- a/crates/circuits/batch-circuit/src/circuit.rs +++ b/crates/circuits/batch-circuit/src/circuit.rs @@ -86,10 +86,17 @@ impl AggCircuit for BatchCircuit { proofs .iter() .map(|proof| { + // Each public value is a u16 cell (2 bytes, little-endian); the + // pi hash occupies the first 32 bytes (16 cells). let transformed = proof .public_values .iter() - .map(|&val| u8::try_from(val).expect("0 < public value < 256")) + .flat_map(|&val| { + u16::try_from(val) + .expect("public value fits in u16") + .to_le_bytes() + }) + .take(32) .collect::>(); B256::from_slice(transformed.as_slice()) }) diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 0367eaa9..1c7c9692 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [230646913, 1550155984, 1593546189, 445636947, 993877920, 922842868, 418587344, 1363280000]; +pub const COMMIT: [u32; 8] = [1443277551, 653435895, 1375066366, 326410668, 1121253390, 342859750, 1593789325, 668948641]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index fefe129f..e0c1c65f 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1986621377, 858531750, 1460740544, 1489416258, 402142684, 1028207948, 2010771520, 956067622]; +pub const COMMIT: [u32; 8] = [307979900, 1253096756, 1500738532, 1272243460, 647335365, 313600294, 213468467, 466651622]; diff --git a/crates/circuits/bundle-circuit/openvm.toml b/crates/circuits/bundle-circuit/openvm.toml index a727c8fc..277ae5f1 100644 --- a/crates/circuits/bundle-circuit/openvm.toml +++ b/crates/circuits/bundle-circuit/openvm.toml @@ -5,9 +5,9 @@ num_queries = 100 commit_proof_of_work_bits = 16 query_proof_of_work_bits = 16 -[app_vm_config.rv32i] +[app_vm_config.rv64i] -[app_vm_config.rv32m] +[app_vm_config.rv64m] [app_vm_config.io] diff --git a/crates/circuits/bundle-circuit/src/circuit.rs b/crates/circuits/bundle-circuit/src/circuit.rs index a7e8b4dc..00b17cfc 100644 --- a/crates/circuits/bundle-circuit/src/circuit.rs +++ b/crates/circuits/bundle-circuit/src/circuit.rs @@ -79,10 +79,17 @@ impl AggCircuit for BundleCircuit { proofs .iter() .map(|proof| { + // Each public value is a u16 cell (2 bytes, little-endian); the + // pi hash occupies the first 32 bytes (16 cells). let transformed = proof .public_values .iter() - .map(|&val| u8::try_from(val).expect("0 < public value < 256")) + .flat_map(|&val| { + u16::try_from(val) + .expect("public value fits in u16") + .to_le_bytes() + }) + .take(32) .collect::>(); B256::from_slice(transformed.as_slice()) }) diff --git a/crates/circuits/chunk-circuit/Cargo.toml b/crates/circuits/chunk-circuit/Cargo.toml index 9318aed9..b64aa42c 100644 --- a/crates/circuits/chunk-circuit/Cargo.toml +++ b/crates/circuits/chunk-circuit/Cargo.toml @@ -22,7 +22,7 @@ openvm-ecc-guest = { workspace = true } openvm-keccak256 = { workspace = true } openvm-pairing-guest = { workspace = true, features = ["bn254"] } openvm-sha2 = { workspace = true } -openvm-rv32im-guest= { workspace = true } +openvm-riscv-guest= { workspace = true } [features] diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 67a4cc79..6f07e05b 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [531865979, 758192281, 811911046, 811449566, 1267419821, 805792427, 542783805, 385536798]; +pub const COMMIT: [u32; 8] = [908836225, 991040821, 1510474027, 1845433726, 1048440467, 1276051553, 1035576080, 1258921324]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index 377afbee..efbbb3d1 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [555659689, 632784023, 888007277, 1549787677, 735342146, 1738460513, 1543370985, 1220762107]; +pub const COMMIT: [u32; 8] = [177016299, 1080091031, 1310488645, 1551948772, 1390988486, 911933392, 1165989125, 952863336]; diff --git a/crates/circuits/chunk-circuit/openvm.toml b/crates/circuits/chunk-circuit/openvm.toml index 9ddc457b..896f4bfc 100644 --- a/crates/circuits/chunk-circuit/openvm.toml +++ b/crates/circuits/chunk-circuit/openvm.toml @@ -5,13 +5,13 @@ num_queries = 100 commit_proof_of_work_bits = 16 query_proof_of_work_bits = 16 -[app_vm_config.rv32i] +[app_vm_config.rv64i] [app_vm_config.io] [app_vm_config.keccak] -[app_vm_config.rv32m] +[app_vm_config.rv64m] range_tuple_checker_sizes = [256, 8192] [app_vm_config.bigint] diff --git a/crates/integration/src/testers/bundle.rs b/crates/integration/src/testers/bundle.rs index 35a60500..c7c8888a 100644 --- a/crates/integration/src/testers/bundle.rs +++ b/crates/integration/src/testers/bundle.rs @@ -131,11 +131,7 @@ impl BundleTaskGenerator { let pi_hash = info.pi_hash_by_version(version); let proof = AggregationInput { - public_values: pi_hash - .as_slice() - .iter() - .map(|&b| b as u32) - .collect::>(), + public_values: crate::utils::pi_hash_to_public_values(&pi_hash), commitment, }; batch_proofs.push(proof); diff --git a/crates/integration/src/utils/mod.rs b/crates/integration/src/utils/mod.rs index edb72841..bc94393c 100644 --- a/crates/integration/src/utils/mod.rs +++ b/crates/integration/src/utils/mod.rs @@ -40,6 +40,19 @@ fn blks_tx_bytes<'a>(blks: impl Iterator) -> Vec { }) } +/// Encode a 32-byte pi hash as OpenVM public values: each public value is a +/// u16 cell (2 little-endian bytes), so the hash fills the first 16 cells and +/// the remaining cells (up to `NUM_PUBLIC_VALUES`) are zero. +pub(crate) fn pi_hash_to_public_values(pi_hash: &B256) -> Vec { + let mut public_values = pi_hash + .as_slice() + .chunks_exact(2) + .map(|c| u16::from_le_bytes([c[0], c[1]]) as u32) + .collect::>(); + public_values.resize(scroll_zkvm_types::types_agg::NUM_PUBLIC_VALUES, 0); + public_values +} + #[derive(Clone, Debug)] pub struct LastHeader { pub batch_index: u64, @@ -316,11 +329,7 @@ pub fn build_batch_witnesses( .map(|chunk_info| { let pi_hash = chunk_info.pi_hash_by_version(version); AggregationInput { - public_values: pi_hash - .as_slice() - .iter() - .map(|&b| b as u32) - .collect::>(), + public_values: pi_hash_to_public_values(&pi_hash), commitment, } }) @@ -389,11 +398,7 @@ pub fn build_batch_witnesses_validium( .map(|chunk_info| { let pi_hash = chunk_info.pi_hash_by_version(version); AggregationInput { - public_values: pi_hash - .as_slice() - .iter() - .map(|&b| b as u32) - .collect::>(), + public_values: pi_hash_to_public_values(&pi_hash), commitment, } }) diff --git a/crates/prover/src/utils/vm.rs b/crates/prover/src/utils/vm.rs index ee6be715..7c1411ee 100644 --- a/crates/prover/src/utils/vm.rs +++ b/crates/prover/src/utils/vm.rs @@ -16,7 +16,8 @@ pub fn execute_guest( inputs: &StdIn, ) -> Result { let exe = sdk.convert_to_exe(exe)?; - match sdk.execute_metered_cost(exe.clone(), inputs.clone()) { + let compiled_metered_cost = sdk.compile_metered_cost(exe.clone())?; + match sdk.execute_metered_cost(&compiled_metered_cost, inputs.clone()) { Ok((public_values, (_cost, instret))) => { if public_values.iter().all(|&x| x == 0) { return Err(SdkError::Other(eyre::eyre!( @@ -30,7 +31,8 @@ pub fn execute_guest( } Err(e) => { tracing::warn!("Metered execution failed: {e}, falling back to execute"); - let public_values = sdk.execute(exe, inputs.clone())?; + let compiled = sdk.compile(exe)?; + let public_values = sdk.execute(&compiled, inputs.clone())?; if public_values.iter().all(|&x| x == 0) { return Err(SdkError::Other(eyre::eyre!( "public_values are all 0s upon execute" diff --git a/crates/types/chunk/src/scroll/execute.rs b/crates/types/chunk/src/scroll/execute.rs index 512bf82e..d0127215 100644 --- a/crates/types/chunk/src/scroll/execute.rs +++ b/crates/types/chunk/src/scroll/execute.rs @@ -84,7 +84,7 @@ pub fn execute(witness: ChunkWitness) -> Result { }), }; - #[cfg(target_os = "zkvm")] + #[cfg(target_os = "openvm")] println!("chunk_info = {}", chunk_info); Ok(chunk_info) diff --git a/crates/types/circuit/Cargo.toml b/crates/types/circuit/Cargo.toml index 0b776e7f..8d51dc04 100644 --- a/crates/types/circuit/Cargo.toml +++ b/crates/types/circuit/Cargo.toml @@ -11,7 +11,7 @@ version.workspace = true scroll-zkvm-types-base.workspace = true alloy-primitives.workspace = true openvm = { workspace = true, features = ["std"] } -openvm-rv32im-guest.workspace = true +openvm-riscv-guest.workspace = true openvm-custom-insn.workspace = true openvm-verify-stark-guest.workspace = true openvm-deferral-guest.workspace = true diff --git a/crates/types/circuit/src/io.rs b/crates/types/circuit/src/io.rs index 8a368d7d..9e0f4a77 100644 --- a/crates/types/circuit/src/io.rs +++ b/crates/types/circuit/src/io.rs @@ -5,29 +5,28 @@ use openvm::platform as openvm_platform; /// /// rkyv needs special alignment for its data structures, use a pre-aligned buffer with rkyv::access_unchecked /// is more efficient than rkyv::access. -#[cfg(target_os = "zkvm")] +#[cfg(target_os = "openvm")] #[inline(always)] pub fn read_witnesses_rkyv_raw() -> Vec { use std::alloc::{GlobalAlloc, Layout, System}; - openvm_rv32im_guest::hint_input(); - let mut len: u32 = 0; - openvm_rv32im_guest::hint_store_u32!((&mut len) as *mut u32 as u32); - let num_words = len.div_ceil(4); - let size = (num_words * 4) as usize; + openvm_riscv_guest::hint_input(); + // The hint-stream length prefix is a single 8-byte word on the rv64 guest. + let mut len: u64 = 0; + openvm_riscv_guest::hint_store_u64!((&mut len) as *mut u64); + let num_words = (len as usize).div_ceil(8); + let size = num_words * 8; let layout = Layout::from_size_align(size, 16).unwrap(); let ptr_start = unsafe { System.alloc(layout) }; - let mut ptr = ptr_start; - for _ in 0..num_words { - openvm_rv32im_guest::hint_store_u32!(ptr as u32); - ptr = unsafe { ptr.add(4) }; - } + // SAFETY: `ptr_start` points to an allocation of `size == num_words * 8` bytes, + // so the chunked dword writes stay within the allocation. + unsafe { openvm_riscv_guest::hint_buffer_chunked(ptr_start, num_words) }; unsafe { Vec::from_raw_parts(ptr_start, len as usize, size) } } /// Read the witnesses from the hint stream. pub fn read_witnesses() -> Vec { - #[cfg(not(target_os = "zkvm"))] + #[cfg(not(target_os = "openvm"))] return openvm::io::read_vec(); // avoid compiler complaint - #[cfg(target_os = "zkvm")] + #[cfg(target_os = "openvm")] return read_witnesses_rkyv_raw(); } diff --git a/crates/types/circuit/src/lib.rs b/crates/types/circuit/src/lib.rs index 51884428..30f9e9ca 100644 --- a/crates/types/circuit/src/lib.rs +++ b/crates/types/circuit/src/lib.rs @@ -60,7 +60,7 @@ where fn verify_proofs(witness: &Self::Witness) -> Vec { let proofs = witness.get_proofs(); - #[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] + #[cfg(target_os = "openvm")] { let input_commits: Vec<[u8; 32]> = openvm::io::read(); assert_eq!( @@ -79,7 +79,7 @@ where } } - #[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] + #[cfg(not(target_os = "openvm"))] { for proof in proofs.iter() { Self::verify_commitments(&proof.commitment); @@ -135,25 +135,29 @@ fn u32_array_to_commit(arr: &[u32; 8]) -> [u8; 32] { } /// Verify a root proof using deferred STARK verification (v2). -#[cfg(all(target_os = "zkvm", target_arch = "riscv32"))] +#[cfg(target_os = "openvm")] fn verify_proof(commitment: &ProgramCommitment, public_inputs: &[u32], input_commit: &[u8; 32]) { use openvm_verify_stark_guest::{ProofOutput, verify_stark}; // Sanity check for the number of public-input values. assert_eq!(public_inputs.len(), NUM_PUBLIC_VALUES); - // OpenVM stores each user public value byte as a 32-bit field element; the - // verify-stark guest helper collapses them back to dense bytes. + // OpenVM stores each user public value as a u16 cell in a 32-bit field + // element; the verify-stark guest helper collapses them back to dense + // bytes (2 little-endian bytes per cell). let expected = ProofOutput { app_exe_commit: u32_array_to_commit(&commitment.exe), app_vm_commit: u32_array_to_commit(&commitment.vm), - user_public_values: public_inputs.iter().map(|&w| w as u8).collect(), + user_public_values: public_inputs + .iter() + .flat_map(|&w| (w as u16).to_le_bytes()) + .collect(), }; verify_stark::<0>(input_commit, &expected); } -#[cfg(not(all(target_os = "zkvm", target_arch = "riscv32")))] +#[cfg(not(target_os = "openvm"))] fn verify_proof(_commitment: &ProgramCommitment, _public_inputs: &[u32], _input_commit: &[u8; 32]) { // This function is guest-only: the actual deferred STARK verification happens inside // the zkvm guest via `openvm_verify_stark_guest::verify_stark`. Calling it on a non-zkvm diff --git a/crates/types/src/proof.rs b/crates/types/src/proof.rs index a46006a0..60134d8c 100644 --- a/crates/types/src/proof.rs +++ b/crates/types/src/proof.rs @@ -25,7 +25,7 @@ pub struct EvmProof { //pub accumulator: Vec, /// The public inputs of the SNARK proof. /// Previously the `instance`s are U256 values, with accumulator and digests. - /// For real user PI values, they will be like 0x0000..00000ab, only 1 byte non zero. + /// For real user PI values, they will be like 0x0000..00000ab, only 2 bytes (u16 cell) non zero. /// Usually of length (12+2+32)x32 /// Now: the `instance` is splitted. The `user_public_values` is "dense". /// Each byte is valid PI. Usually of length 32. @@ -220,8 +220,9 @@ impl ProofEnum { } Self::Evm(evm_proof) => { // The first 12 scalars are accumulators. - // The next 2 scalars are digests. - // The next 32 scalars are the public input hash. + // The next 2 scalars are app commits. + // The remaining scalars are user public values: each holds a + // u16 cell in its low 2 bytes (scalars are big-endian encoded). let pi_hash_bytes = evm_proof .instances .iter() @@ -230,11 +231,11 @@ impl ProofEnum { .cloned() .collect::>(); - // The 32 scalars of public input hash actually only have the LSB that is the - // meaningful byte. pi_hash_bytes .chunks_exact(32) - .map(|bytes32_chunk| bytes32_chunk[31] as u32) + .map(|bytes32_chunk| { + (bytes32_chunk[30] as u32) << 8 | bytes32_chunk[31] as u32 + }) .collect::>() } } diff --git a/crates/types/src/zkvm.rs b/crates/types/src/zkvm.rs index 9fb4496a..fb4e9522 100644 --- a/crates/types/src/zkvm.rs +++ b/crates/types/src/zkvm.rs @@ -17,5 +17,5 @@ fn build_agg_pk() -> AggProvingKey { leaf: leaf_params_with_100_bits_security(), internal: internal_params_with_100_bits_security(), }; - Sdk::riscv32(app_params, agg_params).agg_pk().clone() + Sdk::riscv64(app_params, agg_params).agg_pk().clone() } diff --git a/docs/openvm-v2-migration.md b/docs/openvm-v2-migration.md index 6beb8c4b..3f445f72 100644 --- a/docs/openvm-v2-migration.md +++ b/docs/openvm-v2-migration.md @@ -275,3 +275,46 @@ Still required to complete the upgrade (per the checklist above): force-rebuild guest assets with the default `RECOMPUTE_MODE=auto` (or `yes` to skip the download attempt), clear stale `.output/` caches, and re-run the `make test-e2e-*` suite. + +--- + +## 9. Update: v2.0.0 → develop-v2.1.0 (RV64) + +The move to the `develop-v2.1.0` branch (commit `fd569c7`) is a **major migration**: +OpenVM switches the guest ISA from RV32 to RV64. What changed: + +- `Cargo.toml`: every `openvm-org/openvm.git` entry moved from `tag = "v2.0.0"` to + `branch = "develop-v2.1.0"`; the three `openvm-org/stark-backend.git` entries + stay on `tag = "v2.0.0"` (that is what openvm's own `Cargo.toml` pins on this + branch). Crate renames: `openvm-rv32im-guest`/`openvm-rv32im-transpiler` → + `openvm-riscv-guest`/`openvm-riscv-transpiler`. +- Guest toolchain: `OPENVM_RUST_TOOLCHAIN=nightly-2025-11-20` → `openvm-1.94.0` + (the openvm rust fork with the built-in `riscv64im-unknown-openvm-elf` target). + `rust-toolchain.toml` host channel → `nightly-2026-01-18` (openvm-sdk `tco` + feature); the `riscv32im-unknown-none-elf` target entry was dropped. +- `openvm.toml` (all three circuits): `[app_vm_config.rv32i]`/`rv32m` → + `rv64i`/`rv64m`. +- SDK API: `Sdk::riscv32`/`AppConfig::riscv32` → `riscv64`; `Sdk::execute*` now + takes a compiled instance (`sdk.compile_metered_cost(exe)?` then + `sdk.execute_metered_cost(&compiled, inputs)`; same for `compile`/`execute`). +- Hint stream is 8-byte granular: guest `read_witnesses_rkyv_raw` reads a `u64` + length prefix (`hint_store_u64!`) then uses `hint_buffer_chunked`. +- User public values are u16 cells (2 LE bytes per cell; `NUM_PUBLIC_VALUES` is + still 32 cells). Affected spots: guest `verify_proof` expected PVs, + `aggregated_pi_hashes` in batch/bundle circuits, fabricated + `AggregationInput.public_values` in integration utils, and the EVM branch of + `types/src/proof.rs::public_values()`. +- Guest cfg gates: `target_os = "zkvm"` → `target_os = "openvm"`. +- `crates/build-guest/src/verifier.rs`: `solidity_sdk_tag = "v2.1"`, + `verifier_path = "v2.1-deferral"`. `openvm-solidity-sdk` has no `v2.1` tag yet, + so the download fails and `auto` mode falls back to local verifier generation. +- EVM verifier workaround: the branch's Solidity template still expects 1 byte + per public value while the SDK packs u16 cells as 2 LE bytes. + `crates/build-guest/src/main.rs::patch_verifier_for_u16_public_values` + rewrites the generated wrapper (length check ×2, per-cell byte expansion) and + clears the precompiled artifact so `verifier.bin` is recompiled from the + patched source by `solc`. +- SRS: still `kzg_bn254_24.srs` (unchanged). + +Verification: `GPU=1 make test-single-chunk`, `test-multi-chunk`, +`test-e2e-batch`, `test-e2e-bundle` all pass (CUDA, RTX 3090). diff --git a/releases/dev/verifier/Halo2Verifier.sol b/releases/dev/verifier/Halo2Verifier.sol index ffe645a4..58cb0db4 100644 --- a/releases/dev/verifier/Halo2Verifier.sol +++ b/releases/dev/verifier/Halo2Verifier.sol @@ -1,3 +1,4 @@ + // SPDX-License-Identifier: MIT pragma solidity 0.8.19; @@ -23,2108 +24,1591 @@ contract Halo2Verifier { { let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_cube := - mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) - let x_cube_plus_3 := - addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) let is_affine := eq(x_cube_plus_3, y_square) valid := and(valid, is_affine) } } mstore(0xa0, mod(calldataload(0x0), f_q)) - mstore(0xc0, mod(calldataload(0x20), f_q)) - mstore(0xe0, mod(calldataload(0x40), f_q)) - mstore(0x100, mod(calldataload(0x60), f_q)) - mstore(0x120, mod(calldataload(0x80), f_q)) - mstore(0x140, mod(calldataload(0xa0), f_q)) - mstore(0x160, mod(calldataload(0xc0), f_q)) - mstore(0x180, mod(calldataload(0xe0), f_q)) - mstore(0x1a0, mod(calldataload(0x100), f_q)) - mstore(0x1c0, mod(calldataload(0x120), f_q)) - mstore(0x1e0, mod(calldataload(0x140), f_q)) - mstore(0x200, mod(calldataload(0x160), f_q)) - mstore(0x220, mod(calldataload(0x180), f_q)) - mstore(0x240, mod(calldataload(0x1a0), f_q)) - mstore(0x260, mod(calldataload(0x1c0), f_q)) - mstore(0x280, mod(calldataload(0x1e0), f_q)) - mstore(0x2a0, mod(calldataload(0x200), f_q)) - mstore(0x2c0, mod(calldataload(0x220), f_q)) - mstore(0x2e0, mod(calldataload(0x240), f_q)) - mstore(0x300, mod(calldataload(0x260), f_q)) - mstore(0x320, mod(calldataload(0x280), f_q)) - mstore(0x340, mod(calldataload(0x2a0), f_q)) - mstore(0x360, mod(calldataload(0x2c0), f_q)) - mstore(0x380, mod(calldataload(0x2e0), f_q)) - mstore(0x3a0, mod(calldataload(0x300), f_q)) - mstore(0x3c0, mod(calldataload(0x320), f_q)) - mstore(0x3e0, mod(calldataload(0x340), f_q)) - mstore(0x400, mod(calldataload(0x360), f_q)) - mstore(0x420, mod(calldataload(0x380), f_q)) - mstore(0x440, mod(calldataload(0x3a0), f_q)) - mstore(0x460, mod(calldataload(0x3c0), f_q)) - mstore(0x480, mod(calldataload(0x3e0), f_q)) - mstore(0x4a0, mod(calldataload(0x400), f_q)) - mstore(0x4c0, mod(calldataload(0x420), f_q)) - mstore(0x4e0, mod(calldataload(0x440), f_q)) - mstore(0x500, mod(calldataload(0x460), f_q)) - mstore(0x520, mod(calldataload(0x480), f_q)) - mstore(0x540, mod(calldataload(0x4a0), f_q)) - mstore(0x560, mod(calldataload(0x4c0), f_q)) - mstore(0x580, mod(calldataload(0x4e0), f_q)) - mstore(0x5a0, mod(calldataload(0x500), f_q)) - mstore(0x5c0, mod(calldataload(0x520), f_q)) - mstore(0x5e0, mod(calldataload(0x540), f_q)) - mstore(0x600, mod(calldataload(0x560), f_q)) - mstore(0x620, mod(calldataload(0x580), f_q)) - mstore(0x640, mod(calldataload(0x5a0), f_q)) - mstore(0x80, 6020310274882453454325098127953009151037386282312380019987349433040645771845) - - { - let x := calldataload(0x5c0) - mstore(0x660, x) - let y := calldataload(0x5e0) - mstore(0x680, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0x6a0, keccak256(0x80, 1568)) - { - let hash := mload(0x6a0) - mstore(0x6c0, mod(hash, f_q)) - mstore(0x6e0, hash) - } - - { - let x := calldataload(0x600) - mstore(0x700, x) - let y := calldataload(0x620) - mstore(0x720, y) - success := and(validate_ec_point(x, y), success) - } - - { - let x := calldataload(0x640) - mstore(0x740, x) - let y := calldataload(0x660) - mstore(0x760, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0x780, keccak256(0x6e0, 160)) - { - let hash := mload(0x780) - mstore(0x7a0, mod(hash, f_q)) - mstore(0x7c0, hash) - } - mstore8(2016, 1) - mstore(0x7e0, keccak256(0x7c0, 33)) - { - let hash := mload(0x7e0) - mstore(0x800, mod(hash, f_q)) - mstore(0x820, hash) - } +mstore(0xc0, mod(calldataload(0x20), f_q)) +mstore(0xe0, mod(calldataload(0x40), f_q)) +mstore(0x100, mod(calldataload(0x60), f_q)) +mstore(0x120, mod(calldataload(0x80), f_q)) +mstore(0x140, mod(calldataload(0xa0), f_q)) +mstore(0x160, mod(calldataload(0xc0), f_q)) +mstore(0x180, mod(calldataload(0xe0), f_q)) +mstore(0x1a0, mod(calldataload(0x100), f_q)) +mstore(0x1c0, mod(calldataload(0x120), f_q)) +mstore(0x1e0, mod(calldataload(0x140), f_q)) +mstore(0x200, mod(calldataload(0x160), f_q)) +mstore(0x220, mod(calldataload(0x180), f_q)) +mstore(0x240, mod(calldataload(0x1a0), f_q)) +mstore(0x260, mod(calldataload(0x1c0), f_q)) +mstore(0x280, mod(calldataload(0x1e0), f_q)) +mstore(0x2a0, mod(calldataload(0x200), f_q)) +mstore(0x2c0, mod(calldataload(0x220), f_q)) +mstore(0x2e0, mod(calldataload(0x240), f_q)) +mstore(0x300, mod(calldataload(0x260), f_q)) +mstore(0x320, mod(calldataload(0x280), f_q)) +mstore(0x340, mod(calldataload(0x2a0), f_q)) +mstore(0x360, mod(calldataload(0x2c0), f_q)) +mstore(0x380, mod(calldataload(0x2e0), f_q)) +mstore(0x3a0, mod(calldataload(0x300), f_q)) +mstore(0x3c0, mod(calldataload(0x320), f_q)) +mstore(0x3e0, mod(calldataload(0x340), f_q)) +mstore(0x400, mod(calldataload(0x360), f_q)) +mstore(0x420, mod(calldataload(0x380), f_q)) +mstore(0x440, mod(calldataload(0x3a0), f_q)) +mstore(0x460, mod(calldataload(0x3c0), f_q)) +mstore(0x480, mod(calldataload(0x3e0), f_q)) +mstore(0x4a0, mod(calldataload(0x400), f_q)) +mstore(0x4c0, mod(calldataload(0x420), f_q)) +mstore(0x4e0, mod(calldataload(0x440), f_q)) +mstore(0x500, mod(calldataload(0x460), f_q)) +mstore(0x520, mod(calldataload(0x480), f_q)) +mstore(0x540, mod(calldataload(0x4a0), f_q)) +mstore(0x560, mod(calldataload(0x4c0), f_q)) +mstore(0x580, mod(calldataload(0x4e0), f_q)) +mstore(0x5a0, mod(calldataload(0x500), f_q)) +mstore(0x5c0, mod(calldataload(0x520), f_q)) +mstore(0x5e0, mod(calldataload(0x540), f_q)) +mstore(0x600, mod(calldataload(0x560), f_q)) +mstore(0x620, mod(calldataload(0x580), f_q)) +mstore(0x640, mod(calldataload(0x5a0), f_q)) +mstore(0x80, 2479125767233137909638766696349905838230848442510599249225196178102818148724) + + { + let x := calldataload(0x5c0) + mstore(0x660, x) + let y := calldataload(0x5e0) + mstore(0x680, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x6a0, keccak256(0x80, 1568)) +{ + let hash := mload(0x6a0) + mstore(0x6c0, mod(hash, f_q)) + mstore(0x6e0, hash) + } - { - let x := calldataload(0x680) - mstore(0x840, x) - let y := calldataload(0x6a0) - mstore(0x860, y) - success := and(validate_ec_point(x, y), success) - } + { + let x := calldataload(0x600) + mstore(0x700, x) + let y := calldataload(0x620) + mstore(0x720, y) + success := and(validate_ec_point(x, y), success) + } - { - let x := calldataload(0x6c0) - mstore(0x880, x) - let y := calldataload(0x6e0) - mstore(0x8a0, y) - success := and(validate_ec_point(x, y), success) - } + { + let x := calldataload(0x640) + mstore(0x740, x) + let y := calldataload(0x660) + mstore(0x760, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x780, keccak256(0x6e0, 160)) +{ + let hash := mload(0x780) + mstore(0x7a0, mod(hash, f_q)) + mstore(0x7c0, hash) + } +mstore8(2016, 1) +mstore(0x7e0, keccak256(0x7c0, 33)) +{ + let hash := mload(0x7e0) + mstore(0x800, mod(hash, f_q)) + mstore(0x820, hash) + } - { - let x := calldataload(0x700) - mstore(0x8c0, x) - let y := calldataload(0x720) - mstore(0x8e0, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0x900, keccak256(0x820, 224)) - { - let hash := mload(0x900) - mstore(0x920, mod(hash, f_q)) - mstore(0x940, hash) - } + { + let x := calldataload(0x680) + mstore(0x840, x) + let y := calldataload(0x6a0) + mstore(0x860, y) + success := and(validate_ec_point(x, y), success) + } - { - let x := calldataload(0x740) - mstore(0x960, x) - let y := calldataload(0x760) - mstore(0x980, y) - success := and(validate_ec_point(x, y), success) - } + { + let x := calldataload(0x6c0) + mstore(0x880, x) + let y := calldataload(0x6e0) + mstore(0x8a0, y) + success := and(validate_ec_point(x, y), success) + } - { - let x := calldataload(0x780) - mstore(0x9a0, x) - let y := calldataload(0x7a0) - mstore(0x9c0, y) - success := and(validate_ec_point(x, y), success) - } + { + let x := calldataload(0x700) + mstore(0x8c0, x) + let y := calldataload(0x720) + mstore(0x8e0, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x900, keccak256(0x820, 224)) +{ + let hash := mload(0x900) + mstore(0x920, mod(hash, f_q)) + mstore(0x940, hash) + } - { - let x := calldataload(0x7c0) - mstore(0x9e0, x) - let y := calldataload(0x7e0) - mstore(0xa00, y) - success := and(validate_ec_point(x, y), success) - } + { + let x := calldataload(0x740) + mstore(0x960, x) + let y := calldataload(0x760) + mstore(0x980, y) + success := and(validate_ec_point(x, y), success) + } - { - let x := calldataload(0x800) - mstore(0xa20, x) - let y := calldataload(0x820) - mstore(0xa40, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0xa60, keccak256(0x940, 288)) - { - let hash := mload(0xa60) - mstore(0xa80, mod(hash, f_q)) - mstore(0xaa0, hash) - } - mstore(0xac0, mod(calldataload(0x840), f_q)) - mstore(0xae0, mod(calldataload(0x860), f_q)) - mstore(0xb00, mod(calldataload(0x880), f_q)) - mstore(0xb20, mod(calldataload(0x8a0), f_q)) - mstore(0xb40, mod(calldataload(0x8c0), f_q)) - mstore(0xb60, mod(calldataload(0x8e0), f_q)) - mstore(0xb80, mod(calldataload(0x900), f_q)) - mstore(0xba0, mod(calldataload(0x920), f_q)) - mstore(0xbc0, mod(calldataload(0x940), f_q)) - mstore(0xbe0, mod(calldataload(0x960), f_q)) - mstore(0xc00, mod(calldataload(0x980), f_q)) - mstore(0xc20, mod(calldataload(0x9a0), f_q)) - mstore(0xc40, mod(calldataload(0x9c0), f_q)) - mstore(0xc60, mod(calldataload(0x9e0), f_q)) - mstore(0xc80, mod(calldataload(0xa00), f_q)) - mstore(0xca0, mod(calldataload(0xa20), f_q)) - mstore(0xcc0, mod(calldataload(0xa40), f_q)) - mstore(0xce0, mod(calldataload(0xa60), f_q)) - mstore(0xd00, mod(calldataload(0xa80), f_q)) - mstore(0xd20, keccak256(0xaa0, 640)) - { - let hash := mload(0xd20) - mstore(0xd40, mod(hash, f_q)) - mstore(0xd60, hash) - } - mstore8(3456, 1) - mstore(0xd80, keccak256(0xd60, 33)) - { - let hash := mload(0xd80) - mstore(0xda0, mod(hash, f_q)) - mstore(0xdc0, hash) - } + { + let x := calldataload(0x780) + mstore(0x9a0, x) + let y := calldataload(0x7a0) + mstore(0x9c0, y) + success := and(validate_ec_point(x, y), success) + } - { - let x := calldataload(0xaa0) - mstore(0xde0, x) - let y := calldataload(0xac0) - mstore(0xe00, y) - success := and(validate_ec_point(x, y), success) - } - mstore(0xe20, keccak256(0xdc0, 96)) - { - let hash := mload(0xe20) - mstore(0xe40, mod(hash, f_q)) - mstore(0xe60, hash) - } + { + let x := calldataload(0x7c0) + mstore(0x9e0, x) + let y := calldataload(0x7e0) + mstore(0xa00, y) + success := and(validate_ec_point(x, y), success) + } - { - let x := calldataload(0xae0) - mstore(0xe80, x) - let y := calldataload(0xb00) - mstore(0xea0, y) - success := and(validate_ec_point(x, y), success) - } - { - success := and(lt(mload(0xa0), shl(88, 1)), success) - let x := mload(0xa0) - success := and(lt(mload(0xc0), shl(88, 1)), success) - x := add(x, shl(88, mload(0xc0))) - success := and(lt(mload(0xe0), shl(80, 1)), success) - x := add(x, shl(176, mload(0xe0))) - mstore(3776, x) - success := and(lt(mload(0x100), shl(88, 1)), success) - let y := mload(0x100) - success := and(lt(mload(0x120), shl(88, 1)), success) - y := add(y, shl(88, mload(0x120))) - success := and(lt(mload(0x140), shl(80, 1)), success) - y := add(y, shl(176, mload(0x140))) - mstore(3808, y) + { + let x := calldataload(0x800) + mstore(0xa20, x) + let y := calldataload(0x820) + mstore(0xa40, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xa60, keccak256(0x940, 288)) +{ + let hash := mload(0xa60) + mstore(0xa80, mod(hash, f_q)) + mstore(0xaa0, hash) + } +mstore(0xac0, mod(calldataload(0x840), f_q)) +mstore(0xae0, mod(calldataload(0x860), f_q)) +mstore(0xb00, mod(calldataload(0x880), f_q)) +mstore(0xb20, mod(calldataload(0x8a0), f_q)) +mstore(0xb40, mod(calldataload(0x8c0), f_q)) +mstore(0xb60, mod(calldataload(0x8e0), f_q)) +mstore(0xb80, mod(calldataload(0x900), f_q)) +mstore(0xba0, mod(calldataload(0x920), f_q)) +mstore(0xbc0, mod(calldataload(0x940), f_q)) +mstore(0xbe0, mod(calldataload(0x960), f_q)) +mstore(0xc00, mod(calldataload(0x980), f_q)) +mstore(0xc20, mod(calldataload(0x9a0), f_q)) +mstore(0xc40, mod(calldataload(0x9c0), f_q)) +mstore(0xc60, mod(calldataload(0x9e0), f_q)) +mstore(0xc80, mod(calldataload(0xa00), f_q)) +mstore(0xca0, mod(calldataload(0xa20), f_q)) +mstore(0xcc0, mod(calldataload(0xa40), f_q)) +mstore(0xce0, mod(calldataload(0xa60), f_q)) +mstore(0xd00, mod(calldataload(0xa80), f_q)) +mstore(0xd20, keccak256(0xaa0, 640)) +{ + let hash := mload(0xd20) + mstore(0xd40, mod(hash, f_q)) + mstore(0xd60, hash) + } +mstore8(3456, 1) +mstore(0xd80, keccak256(0xd60, 33)) +{ + let hash := mload(0xd80) + mstore(0xda0, mod(hash, f_q)) + mstore(0xdc0, hash) + } - success := and(validate_ec_point(x, y), success) - } - { - success := and(lt(mload(0x160), shl(88, 1)), success) - let x := mload(0x160) - success := and(lt(mload(0x180), shl(88, 1)), success) - x := add(x, shl(88, mload(0x180))) - success := and(lt(mload(0x1a0), shl(80, 1)), success) - x := add(x, shl(176, mload(0x1a0))) - mstore(3840, x) - success := and(lt(mload(0x1c0), shl(88, 1)), success) - let y := mload(0x1c0) - success := and(lt(mload(0x1e0), shl(88, 1)), success) - y := add(y, shl(88, mload(0x1e0))) - success := and(lt(mload(0x200), shl(80, 1)), success) - y := add(y, shl(176, mload(0x200))) - mstore(3872, y) + { + let x := calldataload(0xaa0) + mstore(0xde0, x) + let y := calldataload(0xac0) + mstore(0xe00, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xe20, keccak256(0xdc0, 96)) +{ + let hash := mload(0xe20) + mstore(0xe40, mod(hash, f_q)) + mstore(0xe60, hash) + } - success := and(validate_ec_point(x, y), success) - } - mstore(0xf40, mulmod(mload(0xa80), mload(0xa80), f_q)) - mstore(0xf60, mulmod(mload(0xf40), mload(0xf40), f_q)) - mstore(0xf80, mulmod(mload(0xf60), mload(0xf60), f_q)) - mstore(0xfa0, mulmod(mload(0xf80), mload(0xf80), f_q)) - mstore(0xfc0, mulmod(mload(0xfa0), mload(0xfa0), f_q)) - mstore(0xfe0, mulmod(mload(0xfc0), mload(0xfc0), f_q)) - mstore(0x1000, mulmod(mload(0xfe0), mload(0xfe0), f_q)) - mstore(0x1020, mulmod(mload(0x1000), mload(0x1000), f_q)) - mstore(0x1040, mulmod(mload(0x1020), mload(0x1020), f_q)) - mstore(0x1060, mulmod(mload(0x1040), mload(0x1040), f_q)) - mstore(0x1080, mulmod(mload(0x1060), mload(0x1060), f_q)) - mstore(0x10a0, mulmod(mload(0x1080), mload(0x1080), f_q)) - mstore(0x10c0, mulmod(mload(0x10a0), mload(0x10a0), f_q)) - mstore(0x10e0, mulmod(mload(0x10c0), mload(0x10c0), f_q)) - mstore(0x1100, mulmod(mload(0x10e0), mload(0x10e0), f_q)) - mstore(0x1120, mulmod(mload(0x1100), mload(0x1100), f_q)) - mstore(0x1140, mulmod(mload(0x1120), mload(0x1120), f_q)) - mstore(0x1160, mulmod(mload(0x1140), mload(0x1140), f_q)) - mstore(0x1180, mulmod(mload(0x1160), mload(0x1160), f_q)) - mstore(0x11a0, mulmod(mload(0x1180), mload(0x1180), f_q)) - mstore(0x11c0, mulmod(mload(0x11a0), mload(0x11a0), f_q)) - mstore(0x11e0, mulmod(mload(0x11c0), mload(0x11c0), f_q)) - mstore( - 0x1200, - addmod( - mload(0x11e0), - 21888242871839275222246405745257275088548364400416034343698204186575808495616, - f_q - ) - ) - mstore( - 0x1220, - mulmod( - mload(0x1200), - 21888237653275510688422624196183639687472264873923820041627027729598873448513, - f_q - ) - ) - mstore( - 0x1240, - mulmod( - mload(0x1220), - 13225785879531581993054172815365636627224369411478295502904397545373139154045, - f_q - ) - ) - mstore( - 0x1260, - addmod(mload(0xa80), 8662456992307693229192232929891638461323994988937738840793806641202669341572, f_q) - ) - mstore( - 0x1280, - mulmod( - mload(0x1220), - 10939663269433627367777756708678102241564365262857670666700619874077960926249, - f_q - ) - ) - mstore( - 0x12a0, - addmod(mload(0xa80), 10948579602405647854468649036579172846983999137558363676997584312497847569368, f_q) - ) - mstore( - 0x12c0, - mulmod( - mload(0x1220), - 11016257578652593686382655500910603527869149377564754001549454008164059876499, - f_q - ) - ) - mstore( - 0x12e0, - addmod(mload(0xa80), 10871985293186681535863750244346671560679215022851280342148750178411748619118, f_q) - ) - mstore( - 0x1300, - mulmod( - mload(0x1220), - 15402826414547299628414612080036060696555554914079673875872749760617770134879, - f_q - ) - ) - mstore( - 0x1320, - addmod(mload(0xa80), 6485416457291975593831793665221214391992809486336360467825454425958038360738, f_q) - ) - mstore( - 0x1340, - mulmod( - mload(0x1220), - 21710372849001950800533397158415938114909991150039389063546734567764856596059, - f_q - ) - ) - mstore( - 0x1360, - addmod(mload(0xa80), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q) - ) - mstore( - 0x1380, - mulmod(mload(0x1220), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q) - ) - mstore( - 0x13a0, - addmod(mload(0xa80), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q) - ) - mstore( - 0x13c0, - mulmod(mload(0x1220), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q) - ) - mstore( - 0x13e0, - addmod(mload(0xa80), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q) - ) - mstore(0x1400, mulmod(mload(0x1220), 1, f_q)) - mstore( - 0x1420, - addmod(mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q) - ) - mstore( - 0x1440, - mulmod( - mload(0x1220), - 11211301017135681023579411905410872569206244553457844956874280139879520583390, - f_q - ) - ) - mstore( - 0x1460, - addmod(mload(0xa80), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q) - ) - mstore( - 0x1480, - mulmod(mload(0x1220), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q) - ) - mstore( - 0x14a0, - addmod(mload(0xa80), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q) - ) - mstore( - 0x14c0, - mulmod( - mload(0x1220), - 12619617507853212586156872920672483948819476989779550311307282715684870266992, - f_q - ) - ) - mstore( - 0x14e0, - addmod(mload(0xa80), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q) - ) - mstore( - 0x1500, - mulmod( - mload(0x1220), - 19032961837237948602743626455740240236231119053033140765040043513661803148152, - f_q - ) - ) - mstore( - 0x1520, - addmod(mload(0xa80), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q) - ) - mstore( - 0x1540, - mulmod(mload(0x1220), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q) - ) - mstore( - 0x1560, - addmod(mload(0xa80), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q) - ) - mstore( - 0x1580, - mulmod(mload(0x1220), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q) - ) - mstore( - 0x15a0, - addmod(mload(0xa80), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q) - ) - mstore( - 0x15c0, - mulmod(mload(0x1220), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q) - ) - mstore( - 0x15e0, - addmod(mload(0xa80), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q) - ) - mstore( - 0x1600, - mulmod(mload(0x1220), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q) - ) - mstore( - 0x1620, - addmod(mload(0xa80), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q) - ) - mstore( - 0x1640, - mulmod(mload(0x1220), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q) - ) - mstore( - 0x1660, - addmod(mload(0xa80), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q) - ) - mstore( - 0x1680, - mulmod( - mload(0x1220), - 14557038802599140430182096396825290815503940951075961210638273254419942783582, - f_q - ) - ) - mstore( - 0x16a0, - addmod(mload(0xa80), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q) - ) - mstore( - 0x16c0, - mulmod( - mload(0x1220), - 13553911191894110065493137367144919847521088405945523452288398666974237857208, - f_q - ) - ) - mstore( - 0x16e0, - addmod(mload(0xa80), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q) - ) - mstore( - 0x1700, - mulmod(mload(0x1220), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q) - ) - mstore( - 0x1720, - addmod(mload(0xa80), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q) - ) - mstore( - 0x1740, - mulmod( - mload(0x1220), - 10807735674816066981985242612061336605021639643453679977988966079770672437131, - f_q - ) - ) - mstore( - 0x1760, - addmod(mload(0xa80), 11080507197023208240261163133195938483526724756962354365709238106805136058486, f_q) - ) - mstore( - 0x1780, - mulmod( - mload(0x1220), - 12459868075641381822485233712013080087763946065665469821362892189399541605692, - f_q - ) - ) - mstore( - 0x17a0, - addmod(mload(0xa80), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q) - ) - mstore( - 0x17c0, - mulmod( - mload(0x1220), - 16038300751658239075779628684257016433412502747804121525056508685985277092575, - f_q - ) - ) - mstore( - 0x17e0, - addmod(mload(0xa80), 5849942120181036146466777061000258655135861652611912818641695500590531403042, f_q) - ) - mstore( - 0x1800, - mulmod(mload(0x1220), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q) - ) - mstore( - 0x1820, - addmod(mload(0xa80), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q) - ) - mstore( - 0x1840, - mulmod( - mload(0x1220), - 13498745591877810872211159461644682954739332524336278910448604883789771736885, - f_q - ) - ) - mstore( - 0x1860, - addmod(mload(0xa80), 8389497279961464350035246283612592133809031876079755433249599302786036758732, f_q) - ) - mstore( - 0x1880, - mulmod( - mload(0x1220), - 20345677989844117909528750049476969581182118546166966482506114734614108237981, - f_q - ) - ) - mstore( - 0x18a0, - addmod(mload(0xa80), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q) - ) - mstore( - 0x18c0, - mulmod(mload(0x1220), 790608022292213379425324383664216541739009722347092850716054055768832299157, f_q) - ) - mstore( - 0x18e0, - addmod(mload(0xa80), 21097634849547061842821081361593058546809354678068941492982150130806976196460, f_q) - ) - mstore( - 0x1900, - mulmod(mload(0x1220), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q) - ) - mstore( - 0x1920, - addmod(mload(0xa80), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q) - ) - mstore( - 0x1940, - mulmod( - mload(0x1220), - 15161189183906287273290738379431332336600234154579306802151507052820126345529, - f_q - ) - ) - mstore( - 0x1960, - addmod(mload(0xa80), 6727053687932987948955667365825942751948130245836727541546697133755682150088, f_q) - ) - mstore( - 0x1980, - mulmod(mload(0x1220), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q) - ) - mstore( - 0x19a0, - addmod(mload(0xa80), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q) - ) - mstore( - 0x19c0, - mulmod( - mload(0x1220), - 16611719114775828483319365659907682366622074960672212059891361227499450055959, - f_q - ) - ) - mstore( - 0x19e0, - addmod(mload(0xa80), 5276523757063446738927040085349592721926289439743822283806842959076358439658, f_q) - ) - mstore( - 0x1a00, - mulmod(mload(0x1220), 4509404676247677387317362072810231899718070082381452255950861037254608304934, f_q) - ) - mstore( - 0x1a20, - addmod(mload(0xa80), 17378838195591597834929043672447043188830294318034582087747343149321200190683, f_q) - ) - mstore( - 0x1a40, - mulmod(mload(0x1220), 6866457077948847028333856457654941632900463970069876241424363695212127143359, f_q) - ) - mstore( - 0x1a60, - addmod(mload(0xa80), 15021785793890428193912549287602333455647900430346158102273840491363681352258, f_q) - ) - mstore( - 0x1a80, - mulmod( - mload(0x1220), - 20169013865622130318472103510465966222180994822334426398191891983290742724178, - f_q - ) - ) - mstore( - 0x1aa0, - addmod(mload(0xa80), 1719229006217144903774302234791308866367369578081607945506312203285065771439, f_q) - ) - mstore( - 0x1ac0, - mulmod( - mload(0x1220), - 14874205783542236433261764022044465911656512639684999678853651860683757650009, - f_q - ) - ) - mstore( - 0x1ae0, - addmod(mload(0xa80), 7014037088297038788984641723212809176891851760731034664844552325892050845608, f_q) - ) - mstore( - 0x1b00, - mulmod(mload(0x1220), 2579947959091681244170407980400327834520881737801886423874592072501514087543, f_q) - ) - mstore( - 0x1b20, - addmod(mload(0xa80), 19308294912747593978075997764856947254027482662614147919823612114074294408074, f_q) - ) - mstore( - 0x1b40, - mulmod( - mload(0x1220), - 17011225028452114973964561549541821925778010085385130152192105634715080939230, - f_q - ) - ) - mstore( - 0x1b60, - addmod(mload(0xa80), 4877017843387160248281844195715453162770354315030904191506098551860727556387, f_q) - ) - mstore( - 0x1b80, - mulmod(mload(0x1220), 1881761935718519990121799628252273658786792458106649887437395059872945867717, f_q) - ) - mstore( - 0x1ba0, - addmod(mload(0xa80), 20006480936120755232124606117005001429761571942309384456260809126702862627900, f_q) - ) - mstore( - 0x1bc0, - mulmod( - mload(0x1220), - 21662285561588145310352318480822402603888953131447478827940284064946709915517, - f_q - ) - ) - mstore( - 0x1be0, - addmod(mload(0xa80), 225957310251129911894087264434872484659411268968555515757920121629098580100, f_q) - ) - mstore( - 0x1c00, - mulmod( - mload(0x1220), - 21846745818185811051373434299876022191132089169516983080959277716660228899818, - f_q - ) - ) - mstore( - 0x1c20, - addmod(mload(0xa80), 41497053653464170872971445381252897416275230899051262738926469915579595799, f_q) - ) - mstore( - 0x1c40, - mulmod( - mload(0x1220), - 11770617947510597378885200406447716404126404817511323735042103519754393416137, - f_q - ) - ) - mstore( - 0x1c60, - addmod(mload(0xa80), 10117624924328677843361205338809558684421959582904710608656100666821415079480, f_q) - ) - mstore( - 0x1c80, - mulmod( - mload(0x1220), - 13018529307372270489258244406856841315962482733096074798317807775255504614069, - f_q - ) - ) - mstore( - 0x1ca0, - addmod(mload(0xa80), 8869713564467004732988161338400433772585881667319959545380396411320303881548, f_q) - ) - mstore( - 0x1cc0, - mulmod(mload(0x1220), 5276270562549512946272803945594037128265390012927669941530122528135796334063, f_q) - ) - mstore( - 0x1ce0, - addmod(mload(0xa80), 16611972309289762275973601799663237960282974387488364402168081658440012161554, f_q) - ) - mstore( - 0x1d00, - mulmod(mload(0x1220), 1459528961030896569807206253631725410868595642414057264270714861278164633285, f_q) - ) - mstore( - 0x1d20, - addmod(mload(0xa80), 20428713910808378652439199491625549677679768758001977079427489325297643862332, f_q) - ) - mstore( - 0x1d40, - mulmod(mload(0x1220), 3194789416964050406424265110350613664596286587119568977604859939037397011192, f_q) - ) - mstore( - 0x1d60, - addmod(mload(0xa80), 18693453454875224815822140634906661423952077813296465366093344247538411484425, f_q) - ) - mstore( - 0x1d80, - mulmod(mload(0x1220), 3090451643741879200285099477849831179472024364989630500355756836624424014697, f_q) - ) - mstore( - 0x1da0, - addmod(mload(0xa80), 18797791228097396021961306267407443909076340035426403843342447349951384480920, f_q) - ) - mstore( - 0x1dc0, - mulmod( - mload(0x1220), - 15927748781034921005593027077824543133423706442106451156060388409950986747549, - f_q - ) - ) - mstore( - 0x1de0, - addmod(mload(0xa80), 5960494090804354216653378667432731955124657958309583187637815776624821748068, f_q) - ) - mstore( - 0x1e00, - mulmod( - mload(0x1220), - 21594472933355353940227302948201802990541640451776958309590170926766063614527, - f_q - ) - ) - mstore( - 0x1e20, - addmod(mload(0xa80), 293769938483921282019102797055472098006723948639076034108033259809744881090, f_q) - ) - mstore( - 0x1e40, - mulmod( - mload(0x1220), - 18627493688178473377890450102960302362510276568110871848038317193719995024144, - f_q - ) - ) - mstore( - 0x1e60, - addmod(mload(0xa80), 3260749183660801844355955642296972726038087832305162495659886992855813471473, f_q) - ) - mstore( - 0x1e80, - mulmod( - mload(0x1220), - 15233875724801927436678555222002139405060841628305391430751578735629430475003, - f_q - ) - ) - mstore( - 0x1ea0, - addmod(mload(0xa80), 6654367147037347785567850523255135683487522772110642912946625450946378020614, f_q) - ) - mstore( - 0x1ec0, - mulmod( - mload(0x1220), - 12662796367122493153085459582914902083443981635312477834616629373139110863873, - f_q - ) - ) - mstore( - 0x1ee0, - addmod(mload(0xa80), 9225446504716782069160946162342373005104382765103556509081574813436697631744, f_q) - ) - mstore( - 0x1f00, - mulmod(mload(0x1220), 9228489335593836417731216695316971397516686186585289059470421738439643366942, f_q) - ) - mstore( - 0x1f20, - addmod(mload(0xa80), 12659753536245438804515189049940303691031678213830745284227782448136165128675, f_q) - ) - mstore( - 0x1f40, - mulmod(mload(0x1220), 6904960663187367776878651408524770307710353971752548687936010869699798414796, f_q) - ) - mstore( - 0x1f60, - addmod(mload(0xa80), 14983282208651907445367754336732504780838010428663485655762193316876010080821, f_q) - ) - { - let prod := mload(0x1260) + { + let x := calldataload(0xae0) + mstore(0xe80, x) + let y := calldataload(0xb00) + mstore(0xea0, y) + success := and(validate_ec_point(x, y), success) + } +{ + success := and(lt(mload(0xa0), shl(88, 1)), success) +let x := mload(0xa0) +success := and(lt(mload(0xc0), shl(88, 1)), success) +x := add(x, shl(88, mload(0xc0))) +success := and(lt(mload(0xe0), shl(80, 1)), success) +x := add(x, shl(176, mload(0xe0))) +mstore(3776, x) +success := and(lt(mload(0x100), shl(88, 1)), success) +let y := mload(0x100) +success := and(lt(mload(0x120), shl(88, 1)), success) +y := add(y, shl(88, mload(0x120))) +success := and(lt(mload(0x140), shl(80, 1)), success) +y := add(y, shl(176, mload(0x140))) +mstore(3808, y) + + success := and(validate_ec_point(x, y), success) + } +{ + success := and(lt(mload(0x160), shl(88, 1)), success) +let x := mload(0x160) +success := and(lt(mload(0x180), shl(88, 1)), success) +x := add(x, shl(88, mload(0x180))) +success := and(lt(mload(0x1a0), shl(80, 1)), success) +x := add(x, shl(176, mload(0x1a0))) +mstore(3840, x) +success := and(lt(mload(0x1c0), shl(88, 1)), success) +let y := mload(0x1c0) +success := and(lt(mload(0x1e0), shl(88, 1)), success) +y := add(y, shl(88, mload(0x1e0))) +success := and(lt(mload(0x200), shl(80, 1)), success) +y := add(y, shl(176, mload(0x200))) +mstore(3872, y) + + success := and(validate_ec_point(x, y), success) + } +mstore(0xf40, mulmod(mload(0xa80), mload(0xa80), f_q)) +mstore(0xf60, mulmod(mload(0xf40), mload(0xf40), f_q)) +mstore(0xf80, mulmod(mload(0xf60), mload(0xf60), f_q)) +mstore(0xfa0, mulmod(mload(0xf80), mload(0xf80), f_q)) +mstore(0xfc0, mulmod(mload(0xfa0), mload(0xfa0), f_q)) +mstore(0xfe0, mulmod(mload(0xfc0), mload(0xfc0), f_q)) +mstore(0x1000, mulmod(mload(0xfe0), mload(0xfe0), f_q)) +mstore(0x1020, mulmod(mload(0x1000), mload(0x1000), f_q)) +mstore(0x1040, mulmod(mload(0x1020), mload(0x1020), f_q)) +mstore(0x1060, mulmod(mload(0x1040), mload(0x1040), f_q)) +mstore(0x1080, mulmod(mload(0x1060), mload(0x1060), f_q)) +mstore(0x10a0, mulmod(mload(0x1080), mload(0x1080), f_q)) +mstore(0x10c0, mulmod(mload(0x10a0), mload(0x10a0), f_q)) +mstore(0x10e0, mulmod(mload(0x10c0), mload(0x10c0), f_q)) +mstore(0x1100, mulmod(mload(0x10e0), mload(0x10e0), f_q)) +mstore(0x1120, mulmod(mload(0x1100), mload(0x1100), f_q)) +mstore(0x1140, mulmod(mload(0x1120), mload(0x1120), f_q)) +mstore(0x1160, mulmod(mload(0x1140), mload(0x1140), f_q)) +mstore(0x1180, mulmod(mload(0x1160), mload(0x1160), f_q)) +mstore(0x11a0, mulmod(mload(0x1180), mload(0x1180), f_q)) +mstore(0x11c0, mulmod(mload(0x11a0), mload(0x11a0), f_q)) +mstore(0x11e0, mulmod(mload(0x11c0), mload(0x11c0), f_q)) +mstore(0x1200, addmod(mload(0x11e0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1220, mulmod(mload(0x1200), 21888237653275510688422624196183639687472264873923820041627027729598873448513, f_q)) +mstore(0x1240, mulmod(mload(0x1220), 13225785879531581993054172815365636627224369411478295502904397545373139154045, f_q)) +mstore(0x1260, addmod(mload(0xa80), 8662456992307693229192232929891638461323994988937738840793806641202669341572, f_q)) +mstore(0x1280, mulmod(mload(0x1220), 10939663269433627367777756708678102241564365262857670666700619874077960926249, f_q)) +mstore(0x12a0, addmod(mload(0xa80), 10948579602405647854468649036579172846983999137558363676997584312497847569368, f_q)) +mstore(0x12c0, mulmod(mload(0x1220), 11016257578652593686382655500910603527869149377564754001549454008164059876499, f_q)) +mstore(0x12e0, addmod(mload(0xa80), 10871985293186681535863750244346671560679215022851280342148750178411748619118, f_q)) +mstore(0x1300, mulmod(mload(0x1220), 15402826414547299628414612080036060696555554914079673875872749760617770134879, f_q)) +mstore(0x1320, addmod(mload(0xa80), 6485416457291975593831793665221214391992809486336360467825454425958038360738, f_q)) +mstore(0x1340, mulmod(mload(0x1220), 21710372849001950800533397158415938114909991150039389063546734567764856596059, f_q)) +mstore(0x1360, addmod(mload(0xa80), 177870022837324421713008586841336973638373250376645280151469618810951899558, f_q)) +mstore(0x1380, mulmod(mload(0x1220), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +mstore(0x13a0, addmod(mload(0xa80), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q)) +mstore(0x13c0, mulmod(mload(0x1220), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) +mstore(0x13e0, addmod(mload(0xa80), 13154116519010929542673167886091370382741775939114889923107781597533678454429, f_q)) +mstore(0x1400, mulmod(mload(0x1220), 1, f_q)) +mstore(0x1420, addmod(mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1440, mulmod(mload(0x1220), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +mstore(0x1460, addmod(mload(0xa80), 10676941854703594198666993839846402519342119846958189386823924046696287912227, f_q)) +mstore(0x1480, mulmod(mload(0x1220), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x14a0, addmod(mload(0xa80), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q)) +mstore(0x14c0, mulmod(mload(0x1220), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q)) +mstore(0x14e0, addmod(mload(0xa80), 9268625363986062636089532824584791139728887410636484032390921470890938228625, f_q)) +mstore(0x1500, mulmod(mload(0x1220), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +mstore(0x1520, addmod(mload(0xa80), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q)) +mstore(0x1540, mulmod(mload(0x1220), 915149353520972163646494413843788069594022902357002628455555785223409501882, f_q)) +mstore(0x1560, addmod(mload(0xa80), 20973093518318303058599911331413487018954341498059031715242648401352398993735, f_q)) +mstore(0x1580, mulmod(mload(0x1220), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +mstore(0x15a0, addmod(mload(0xa80), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q)) +mstore(0x15c0, mulmod(mload(0x1220), 4245441013247250116003069945606352967193023389718465410501109428393342802981, f_q)) +mstore(0x15e0, addmod(mload(0xa80), 17642801858592025106243335799650922121355341010697568933197094758182465692636, f_q)) +mstore(0x1600, mulmod(mload(0x1220), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q)) +mstore(0x1620, addmod(mload(0xa80), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q)) +mstore(0x1640, mulmod(mload(0x1220), 5980488956150442207659150513163747165544364597008566989111579977672498964212, f_q)) +mstore(0x1660, addmod(mload(0xa80), 15907753915688833014587255232093527923003999803407467354586624208903309531405, f_q)) +mstore(0x1680, mulmod(mload(0x1220), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q)) +mstore(0x16a0, addmod(mload(0xa80), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q)) +mstore(0x16c0, mulmod(mload(0x1220), 13553911191894110065493137367144919847521088405945523452288398666974237857208, f_q)) +mstore(0x16e0, addmod(mload(0xa80), 8334331679945165156753268378112355241027275994470510891409805519601570638409, f_q)) +mstore(0x1700, mulmod(mload(0x1220), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q)) +mstore(0x1720, addmod(mload(0xa80), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q)) +mstore(0x1740, mulmod(mload(0x1220), 10807735674816066981985242612061336605021639643453679977988966079770672437131, f_q)) +mstore(0x1760, addmod(mload(0xa80), 11080507197023208240261163133195938483526724756962354365709238106805136058486, f_q)) +mstore(0x1780, mulmod(mload(0x1220), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q)) +mstore(0x17a0, addmod(mload(0xa80), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q)) +mstore(0x17c0, mulmod(mload(0x1220), 16038300751658239075779628684257016433412502747804121525056508685985277092575, f_q)) +mstore(0x17e0, addmod(mload(0xa80), 5849942120181036146466777061000258655135861652611912818641695500590531403042, f_q)) +mstore(0x1800, mulmod(mload(0x1220), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q)) +mstore(0x1820, addmod(mload(0xa80), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q)) +mstore(0x1840, mulmod(mload(0x1220), 13498745591877810872211159461644682954739332524336278910448604883789771736885, f_q)) +mstore(0x1860, addmod(mload(0xa80), 8389497279961464350035246283612592133809031876079755433249599302786036758732, f_q)) +mstore(0x1880, mulmod(mload(0x1220), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q)) +mstore(0x18a0, addmod(mload(0xa80), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q)) +mstore(0x18c0, mulmod(mload(0x1220), 790608022292213379425324383664216541739009722347092850716054055768832299157, f_q)) +mstore(0x18e0, addmod(mload(0xa80), 21097634849547061842821081361593058546809354678068941492982150130806976196460, f_q)) +mstore(0x1900, mulmod(mload(0x1220), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q)) +mstore(0x1920, addmod(mload(0xa80), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q)) +mstore(0x1940, mulmod(mload(0x1220), 15161189183906287273290738379431332336600234154579306802151507052820126345529, f_q)) +mstore(0x1960, addmod(mload(0xa80), 6727053687932987948955667365825942751948130245836727541546697133755682150088, f_q)) +mstore(0x1980, mulmod(mload(0x1220), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q)) +mstore(0x19a0, addmod(mload(0xa80), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q)) +mstore(0x19c0, mulmod(mload(0x1220), 16611719114775828483319365659907682366622074960672212059891361227499450055959, f_q)) +mstore(0x19e0, addmod(mload(0xa80), 5276523757063446738927040085349592721926289439743822283806842959076358439658, f_q)) +mstore(0x1a00, mulmod(mload(0x1220), 4509404676247677387317362072810231899718070082381452255950861037254608304934, f_q)) +mstore(0x1a20, addmod(mload(0xa80), 17378838195591597834929043672447043188830294318034582087747343149321200190683, f_q)) +mstore(0x1a40, mulmod(mload(0x1220), 6866457077948847028333856457654941632900463970069876241424363695212127143359, f_q)) +mstore(0x1a60, addmod(mload(0xa80), 15021785793890428193912549287602333455647900430346158102273840491363681352258, f_q)) +mstore(0x1a80, mulmod(mload(0x1220), 20169013865622130318472103510465966222180994822334426398191891983290742724178, f_q)) +mstore(0x1aa0, addmod(mload(0xa80), 1719229006217144903774302234791308866367369578081607945506312203285065771439, f_q)) +mstore(0x1ac0, mulmod(mload(0x1220), 14874205783542236433261764022044465911656512639684999678853651860683757650009, f_q)) +mstore(0x1ae0, addmod(mload(0xa80), 7014037088297038788984641723212809176891851760731034664844552325892050845608, f_q)) +mstore(0x1b00, mulmod(mload(0x1220), 2579947959091681244170407980400327834520881737801886423874592072501514087543, f_q)) +mstore(0x1b20, addmod(mload(0xa80), 19308294912747593978075997764856947254027482662614147919823612114074294408074, f_q)) +mstore(0x1b40, mulmod(mload(0x1220), 17011225028452114973964561549541821925778010085385130152192105634715080939230, f_q)) +mstore(0x1b60, addmod(mload(0xa80), 4877017843387160248281844195715453162770354315030904191506098551860727556387, f_q)) +mstore(0x1b80, mulmod(mload(0x1220), 1881761935718519990121799628252273658786792458106649887437395059872945867717, f_q)) +mstore(0x1ba0, addmod(mload(0xa80), 20006480936120755232124606117005001429761571942309384456260809126702862627900, f_q)) +mstore(0x1bc0, mulmod(mload(0x1220), 21662285561588145310352318480822402603888953131447478827940284064946709915517, f_q)) +mstore(0x1be0, addmod(mload(0xa80), 225957310251129911894087264434872484659411268968555515757920121629098580100, f_q)) +mstore(0x1c00, mulmod(mload(0x1220), 21846745818185811051373434299876022191132089169516983080959277716660228899818, f_q)) +mstore(0x1c20, addmod(mload(0xa80), 41497053653464170872971445381252897416275230899051262738926469915579595799, f_q)) +mstore(0x1c40, mulmod(mload(0x1220), 11770617947510597378885200406447716404126404817511323735042103519754393416137, f_q)) +mstore(0x1c60, addmod(mload(0xa80), 10117624924328677843361205338809558684421959582904710608656100666821415079480, f_q)) +mstore(0x1c80, mulmod(mload(0x1220), 13018529307372270489258244406856841315962482733096074798317807775255504614069, f_q)) +mstore(0x1ca0, addmod(mload(0xa80), 8869713564467004732988161338400433772585881667319959545380396411320303881548, f_q)) +mstore(0x1cc0, mulmod(mload(0x1220), 5276270562549512946272803945594037128265390012927669941530122528135796334063, f_q)) +mstore(0x1ce0, addmod(mload(0xa80), 16611972309289762275973601799663237960282974387488364402168081658440012161554, f_q)) +mstore(0x1d00, mulmod(mload(0x1220), 1459528961030896569807206253631725410868595642414057264270714861278164633285, f_q)) +mstore(0x1d20, addmod(mload(0xa80), 20428713910808378652439199491625549677679768758001977079427489325297643862332, f_q)) +mstore(0x1d40, mulmod(mload(0x1220), 3194789416964050406424265110350613664596286587119568977604859939037397011192, f_q)) +mstore(0x1d60, addmod(mload(0xa80), 18693453454875224815822140634906661423952077813296465366093344247538411484425, f_q)) +mstore(0x1d80, mulmod(mload(0x1220), 3090451643741879200285099477849831179472024364989630500355756836624424014697, f_q)) +mstore(0x1da0, addmod(mload(0xa80), 18797791228097396021961306267407443909076340035426403843342447349951384480920, f_q)) +mstore(0x1dc0, mulmod(mload(0x1220), 15927748781034921005593027077824543133423706442106451156060388409950986747549, f_q)) +mstore(0x1de0, addmod(mload(0xa80), 5960494090804354216653378667432731955124657958309583187637815776624821748068, f_q)) +mstore(0x1e00, mulmod(mload(0x1220), 21594472933355353940227302948201802990541640451776958309590170926766063614527, f_q)) +mstore(0x1e20, addmod(mload(0xa80), 293769938483921282019102797055472098006723948639076034108033259809744881090, f_q)) +mstore(0x1e40, mulmod(mload(0x1220), 18627493688178473377890450102960302362510276568110871848038317193719995024144, f_q)) +mstore(0x1e60, addmod(mload(0xa80), 3260749183660801844355955642296972726038087832305162495659886992855813471473, f_q)) +mstore(0x1e80, mulmod(mload(0x1220), 15233875724801927436678555222002139405060841628305391430751578735629430475003, f_q)) +mstore(0x1ea0, addmod(mload(0xa80), 6654367147037347785567850523255135683487522772110642912946625450946378020614, f_q)) +mstore(0x1ec0, mulmod(mload(0x1220), 12662796367122493153085459582914902083443981635312477834616629373139110863873, f_q)) +mstore(0x1ee0, addmod(mload(0xa80), 9225446504716782069160946162342373005104382765103556509081574813436697631744, f_q)) +mstore(0x1f00, mulmod(mload(0x1220), 9228489335593836417731216695316971397516686186585289059470421738439643366942, f_q)) +mstore(0x1f20, addmod(mload(0xa80), 12659753536245438804515189049940303691031678213830745284227782448136165128675, f_q)) +mstore(0x1f40, mulmod(mload(0x1220), 6904960663187367776878651408524770307710353971752548687936010869699798414796, f_q)) +mstore(0x1f60, addmod(mload(0xa80), 14983282208651907445367754336732504780838010428663485655762193316876010080821, f_q)) +{ + let prod := mload(0x1260) prod := mulmod(mload(0x12a0), prod, f_q) mstore(0x1f80, prod) - + prod := mulmod(mload(0x12e0), prod, f_q) mstore(0x1fa0, prod) - + prod := mulmod(mload(0x1320), prod, f_q) mstore(0x1fc0, prod) - + prod := mulmod(mload(0x1360), prod, f_q) mstore(0x1fe0, prod) - + prod := mulmod(mload(0x13a0), prod, f_q) mstore(0x2000, prod) - + prod := mulmod(mload(0x13e0), prod, f_q) mstore(0x2020, prod) - + prod := mulmod(mload(0x1420), prod, f_q) mstore(0x2040, prod) - + prod := mulmod(mload(0x1460), prod, f_q) mstore(0x2060, prod) - + prod := mulmod(mload(0x14a0), prod, f_q) mstore(0x2080, prod) - + prod := mulmod(mload(0x14e0), prod, f_q) mstore(0x20a0, prod) - + prod := mulmod(mload(0x1520), prod, f_q) mstore(0x20c0, prod) - + prod := mulmod(mload(0x1560), prod, f_q) mstore(0x20e0, prod) - + prod := mulmod(mload(0x15a0), prod, f_q) mstore(0x2100, prod) - + prod := mulmod(mload(0x15e0), prod, f_q) mstore(0x2120, prod) - + prod := mulmod(mload(0x1620), prod, f_q) mstore(0x2140, prod) - + prod := mulmod(mload(0x1660), prod, f_q) mstore(0x2160, prod) - + prod := mulmod(mload(0x16a0), prod, f_q) mstore(0x2180, prod) - + prod := mulmod(mload(0x16e0), prod, f_q) mstore(0x21a0, prod) - + prod := mulmod(mload(0x1720), prod, f_q) mstore(0x21c0, prod) - + prod := mulmod(mload(0x1760), prod, f_q) mstore(0x21e0, prod) - + prod := mulmod(mload(0x17a0), prod, f_q) mstore(0x2200, prod) - + prod := mulmod(mload(0x17e0), prod, f_q) mstore(0x2220, prod) - + prod := mulmod(mload(0x1820), prod, f_q) mstore(0x2240, prod) - + prod := mulmod(mload(0x1860), prod, f_q) mstore(0x2260, prod) - + prod := mulmod(mload(0x18a0), prod, f_q) mstore(0x2280, prod) - + prod := mulmod(mload(0x18e0), prod, f_q) mstore(0x22a0, prod) - + prod := mulmod(mload(0x1920), prod, f_q) mstore(0x22c0, prod) - + prod := mulmod(mload(0x1960), prod, f_q) mstore(0x22e0, prod) - + prod := mulmod(mload(0x19a0), prod, f_q) mstore(0x2300, prod) - + prod := mulmod(mload(0x19e0), prod, f_q) mstore(0x2320, prod) - + prod := mulmod(mload(0x1a20), prod, f_q) mstore(0x2340, prod) - + prod := mulmod(mload(0x1a60), prod, f_q) mstore(0x2360, prod) - + prod := mulmod(mload(0x1aa0), prod, f_q) mstore(0x2380, prod) - + prod := mulmod(mload(0x1ae0), prod, f_q) mstore(0x23a0, prod) - + prod := mulmod(mload(0x1b20), prod, f_q) mstore(0x23c0, prod) - + prod := mulmod(mload(0x1b60), prod, f_q) mstore(0x23e0, prod) - + prod := mulmod(mload(0x1ba0), prod, f_q) mstore(0x2400, prod) - + prod := mulmod(mload(0x1be0), prod, f_q) mstore(0x2420, prod) - + prod := mulmod(mload(0x1c20), prod, f_q) mstore(0x2440, prod) - + prod := mulmod(mload(0x1c60), prod, f_q) mstore(0x2460, prod) - + prod := mulmod(mload(0x1ca0), prod, f_q) mstore(0x2480, prod) - + prod := mulmod(mload(0x1ce0), prod, f_q) mstore(0x24a0, prod) - + prod := mulmod(mload(0x1d20), prod, f_q) mstore(0x24c0, prod) - + prod := mulmod(mload(0x1d60), prod, f_q) mstore(0x24e0, prod) - + prod := mulmod(mload(0x1da0), prod, f_q) mstore(0x2500, prod) - + prod := mulmod(mload(0x1de0), prod, f_q) mstore(0x2520, prod) - + prod := mulmod(mload(0x1e20), prod, f_q) mstore(0x2540, prod) - + prod := mulmod(mload(0x1e60), prod, f_q) mstore(0x2560, prod) - + prod := mulmod(mload(0x1ea0), prod, f_q) mstore(0x2580, prod) - + prod := mulmod(mload(0x1ee0), prod, f_q) mstore(0x25a0, prod) - + prod := mulmod(mload(0x1f20), prod, f_q) mstore(0x25c0, prod) - + prod := mulmod(mload(0x1f60), prod, f_q) mstore(0x25e0, prod) - + prod := mulmod(mload(0x1200), prod, f_q) mstore(0x2600, prod) - } - mstore(0x2640, 32) - mstore(0x2660, 32) - mstore(0x2680, 32) - mstore(0x26a0, mload(0x2600)) - mstore(0x26c0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x26e0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x2640, 0xc0, 0x2620, 0x20), 1), success) - { - let inv := mload(0x2620) - let v - - v := mload(0x1200) - mstore(4608, mulmod(mload(0x25e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1f60) - mstore(8032, mulmod(mload(0x25c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1f20) - mstore(7968, mulmod(mload(0x25a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ee0) - mstore(7904, mulmod(mload(0x2580), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ea0) - mstore(7840, mulmod(mload(0x2560), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1e60) - mstore(7776, mulmod(mload(0x2540), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1e20) - mstore(7712, mulmod(mload(0x2520), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1de0) - mstore(7648, mulmod(mload(0x2500), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1da0) - mstore(7584, mulmod(mload(0x24e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1d60) - mstore(7520, mulmod(mload(0x24c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1d20) - mstore(7456, mulmod(mload(0x24a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ce0) - mstore(7392, mulmod(mload(0x2480), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ca0) - mstore(7328, mulmod(mload(0x2460), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1c60) - mstore(7264, mulmod(mload(0x2440), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1c20) - mstore(7200, mulmod(mload(0x2420), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1be0) - mstore(7136, mulmod(mload(0x2400), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ba0) - mstore(7072, mulmod(mload(0x23e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1b60) - mstore(7008, mulmod(mload(0x23c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1b20) - mstore(6944, mulmod(mload(0x23a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1ae0) - mstore(6880, mulmod(mload(0x2380), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1aa0) - mstore(6816, mulmod(mload(0x2360), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1a60) - mstore(6752, mulmod(mload(0x2340), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1a20) - mstore(6688, mulmod(mload(0x2320), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x19e0) - mstore(6624, mulmod(mload(0x2300), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x19a0) - mstore(6560, mulmod(mload(0x22e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1960) - mstore(6496, mulmod(mload(0x22c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1920) - mstore(6432, mulmod(mload(0x22a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x18e0) - mstore(6368, mulmod(mload(0x2280), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x18a0) - mstore(6304, mulmod(mload(0x2260), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1860) - mstore(6240, mulmod(mload(0x2240), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1820) - mstore(6176, mulmod(mload(0x2220), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x17e0) - mstore(6112, mulmod(mload(0x2200), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x17a0) - mstore(6048, mulmod(mload(0x21e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1760) - mstore(5984, mulmod(mload(0x21c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1720) - mstore(5920, mulmod(mload(0x21a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x16e0) - mstore(5856, mulmod(mload(0x2180), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x16a0) - mstore(5792, mulmod(mload(0x2160), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1660) - mstore(5728, mulmod(mload(0x2140), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1620) - mstore(5664, mulmod(mload(0x2120), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x15e0) - mstore(5600, mulmod(mload(0x2100), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x15a0) - mstore(5536, mulmod(mload(0x20e0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1560) - mstore(5472, mulmod(mload(0x20c0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1520) - mstore(5408, mulmod(mload(0x20a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x14e0) - mstore(5344, mulmod(mload(0x2080), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x14a0) - mstore(5280, mulmod(mload(0x2060), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1460) - mstore(5216, mulmod(mload(0x2040), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1420) - mstore(5152, mulmod(mload(0x2020), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x13e0) - mstore(5088, mulmod(mload(0x2000), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x13a0) - mstore(5024, mulmod(mload(0x1fe0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1360) - mstore(4960, mulmod(mload(0x1fc0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1320) - mstore(4896, mulmod(mload(0x1fa0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x12e0) - mstore(4832, mulmod(mload(0x1f80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x12a0) - mstore(4768, mulmod(mload(0x1260), inv, f_q)) - inv := mulmod(v, inv, f_q) + + } +mstore(0x2640, 32) +mstore(0x2660, 32) +mstore(0x2680, 32) +mstore(0x26a0, mload(0x2600)) +mstore(0x26c0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x26e0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x2640, 0xc0, 0x2620, 0x20), 1), success) +{ + + let inv := mload(0x2620) + let v + + v := mload(0x1200) + mstore(4608, mulmod(mload(0x25e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1f60) + mstore(8032, mulmod(mload(0x25c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1f20) + mstore(7968, mulmod(mload(0x25a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ee0) + mstore(7904, mulmod(mload(0x2580), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ea0) + mstore(7840, mulmod(mload(0x2560), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1e60) + mstore(7776, mulmod(mload(0x2540), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1e20) + mstore(7712, mulmod(mload(0x2520), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1de0) + mstore(7648, mulmod(mload(0x2500), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1da0) + mstore(7584, mulmod(mload(0x24e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1d60) + mstore(7520, mulmod(mload(0x24c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1d20) + mstore(7456, mulmod(mload(0x24a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ce0) + mstore(7392, mulmod(mload(0x2480), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ca0) + mstore(7328, mulmod(mload(0x2460), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1c60) + mstore(7264, mulmod(mload(0x2440), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1c20) + mstore(7200, mulmod(mload(0x2420), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1be0) + mstore(7136, mulmod(mload(0x2400), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ba0) + mstore(7072, mulmod(mload(0x23e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1b60) + mstore(7008, mulmod(mload(0x23c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1b20) + mstore(6944, mulmod(mload(0x23a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1ae0) + mstore(6880, mulmod(mload(0x2380), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1aa0) + mstore(6816, mulmod(mload(0x2360), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1a60) + mstore(6752, mulmod(mload(0x2340), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1a20) + mstore(6688, mulmod(mload(0x2320), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x19e0) + mstore(6624, mulmod(mload(0x2300), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x19a0) + mstore(6560, mulmod(mload(0x22e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1960) + mstore(6496, mulmod(mload(0x22c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1920) + mstore(6432, mulmod(mload(0x22a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x18e0) + mstore(6368, mulmod(mload(0x2280), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x18a0) + mstore(6304, mulmod(mload(0x2260), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1860) + mstore(6240, mulmod(mload(0x2240), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1820) + mstore(6176, mulmod(mload(0x2220), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x17e0) + mstore(6112, mulmod(mload(0x2200), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x17a0) + mstore(6048, mulmod(mload(0x21e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1760) + mstore(5984, mulmod(mload(0x21c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1720) + mstore(5920, mulmod(mload(0x21a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x16e0) + mstore(5856, mulmod(mload(0x2180), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x16a0) + mstore(5792, mulmod(mload(0x2160), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1660) + mstore(5728, mulmod(mload(0x2140), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1620) + mstore(5664, mulmod(mload(0x2120), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x15e0) + mstore(5600, mulmod(mload(0x2100), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x15a0) + mstore(5536, mulmod(mload(0x20e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1560) + mstore(5472, mulmod(mload(0x20c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1520) + mstore(5408, mulmod(mload(0x20a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x14e0) + mstore(5344, mulmod(mload(0x2080), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x14a0) + mstore(5280, mulmod(mload(0x2060), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1460) + mstore(5216, mulmod(mload(0x2040), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1420) + mstore(5152, mulmod(mload(0x2020), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x13e0) + mstore(5088, mulmod(mload(0x2000), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x13a0) + mstore(5024, mulmod(mload(0x1fe0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1360) + mstore(4960, mulmod(mload(0x1fc0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1320) + mstore(4896, mulmod(mload(0x1fa0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x12e0) + mstore(4832, mulmod(mload(0x1f80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x12a0) + mstore(4768, mulmod(mload(0x1260), inv, f_q)) + inv := mulmod(v, inv, f_q) mstore(0x1260, inv) - } - mstore(0x2700, mulmod(mload(0x1240), mload(0x1260), f_q)) - mstore(0x2720, mulmod(mload(0x1280), mload(0x12a0), f_q)) - mstore(0x2740, mulmod(mload(0x12c0), mload(0x12e0), f_q)) - mstore(0x2760, mulmod(mload(0x1300), mload(0x1320), f_q)) - mstore(0x2780, mulmod(mload(0x1340), mload(0x1360), f_q)) - mstore(0x27a0, mulmod(mload(0x1380), mload(0x13a0), f_q)) - mstore(0x27c0, mulmod(mload(0x13c0), mload(0x13e0), f_q)) - mstore(0x27e0, mulmod(mload(0x1400), mload(0x1420), f_q)) - mstore(0x2800, mulmod(mload(0x1440), mload(0x1460), f_q)) - mstore(0x2820, mulmod(mload(0x1480), mload(0x14a0), f_q)) - mstore(0x2840, mulmod(mload(0x14c0), mload(0x14e0), f_q)) - mstore(0x2860, mulmod(mload(0x1500), mload(0x1520), f_q)) - mstore(0x2880, mulmod(mload(0x1540), mload(0x1560), f_q)) - mstore(0x28a0, mulmod(mload(0x1580), mload(0x15a0), f_q)) - mstore(0x28c0, mulmod(mload(0x15c0), mload(0x15e0), f_q)) - mstore(0x28e0, mulmod(mload(0x1600), mload(0x1620), f_q)) - mstore(0x2900, mulmod(mload(0x1640), mload(0x1660), f_q)) - mstore(0x2920, mulmod(mload(0x1680), mload(0x16a0), f_q)) - mstore(0x2940, mulmod(mload(0x16c0), mload(0x16e0), f_q)) - mstore(0x2960, mulmod(mload(0x1700), mload(0x1720), f_q)) - mstore(0x2980, mulmod(mload(0x1740), mload(0x1760), f_q)) - mstore(0x29a0, mulmod(mload(0x1780), mload(0x17a0), f_q)) - mstore(0x29c0, mulmod(mload(0x17c0), mload(0x17e0), f_q)) - mstore(0x29e0, mulmod(mload(0x1800), mload(0x1820), f_q)) - mstore(0x2a00, mulmod(mload(0x1840), mload(0x1860), f_q)) - mstore(0x2a20, mulmod(mload(0x1880), mload(0x18a0), f_q)) - mstore(0x2a40, mulmod(mload(0x18c0), mload(0x18e0), f_q)) - mstore(0x2a60, mulmod(mload(0x1900), mload(0x1920), f_q)) - mstore(0x2a80, mulmod(mload(0x1940), mload(0x1960), f_q)) - mstore(0x2aa0, mulmod(mload(0x1980), mload(0x19a0), f_q)) - mstore(0x2ac0, mulmod(mload(0x19c0), mload(0x19e0), f_q)) - mstore(0x2ae0, mulmod(mload(0x1a00), mload(0x1a20), f_q)) - mstore(0x2b00, mulmod(mload(0x1a40), mload(0x1a60), f_q)) - mstore(0x2b20, mulmod(mload(0x1a80), mload(0x1aa0), f_q)) - mstore(0x2b40, mulmod(mload(0x1ac0), mload(0x1ae0), f_q)) - mstore(0x2b60, mulmod(mload(0x1b00), mload(0x1b20), f_q)) - mstore(0x2b80, mulmod(mload(0x1b40), mload(0x1b60), f_q)) - mstore(0x2ba0, mulmod(mload(0x1b80), mload(0x1ba0), f_q)) - mstore(0x2bc0, mulmod(mload(0x1bc0), mload(0x1be0), f_q)) - mstore(0x2be0, mulmod(mload(0x1c00), mload(0x1c20), f_q)) - mstore(0x2c00, mulmod(mload(0x1c40), mload(0x1c60), f_q)) - mstore(0x2c20, mulmod(mload(0x1c80), mload(0x1ca0), f_q)) - mstore(0x2c40, mulmod(mload(0x1cc0), mload(0x1ce0), f_q)) - mstore(0x2c60, mulmod(mload(0x1d00), mload(0x1d20), f_q)) - mstore(0x2c80, mulmod(mload(0x1d40), mload(0x1d60), f_q)) - mstore(0x2ca0, mulmod(mload(0x1d80), mload(0x1da0), f_q)) - mstore(0x2cc0, mulmod(mload(0x1dc0), mload(0x1de0), f_q)) - mstore(0x2ce0, mulmod(mload(0x1e00), mload(0x1e20), f_q)) - mstore(0x2d00, mulmod(mload(0x1e40), mload(0x1e60), f_q)) - mstore(0x2d20, mulmod(mload(0x1e80), mload(0x1ea0), f_q)) - mstore(0x2d40, mulmod(mload(0x1ec0), mload(0x1ee0), f_q)) - mstore(0x2d60, mulmod(mload(0x1f00), mload(0x1f20), f_q)) - mstore(0x2d80, mulmod(mload(0x1f40), mload(0x1f60), f_q)) - { - let result := mulmod(mload(0x27e0), mload(0xa0), f_q) - result := addmod(mulmod(mload(0x2800), mload(0xc0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2820), mload(0xe0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2840), mload(0x100), f_q), result, f_q) - result := addmod(mulmod(mload(0x2860), mload(0x120), f_q), result, f_q) - result := addmod(mulmod(mload(0x2880), mload(0x140), f_q), result, f_q) - result := addmod(mulmod(mload(0x28a0), mload(0x160), f_q), result, f_q) - result := addmod(mulmod(mload(0x28c0), mload(0x180), f_q), result, f_q) - result := addmod(mulmod(mload(0x28e0), mload(0x1a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2900), mload(0x1c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2920), mload(0x1e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2940), mload(0x200), f_q), result, f_q) - result := addmod(mulmod(mload(0x2960), mload(0x220), f_q), result, f_q) - result := addmod(mulmod(mload(0x2980), mload(0x240), f_q), result, f_q) - result := addmod(mulmod(mload(0x29a0), mload(0x260), f_q), result, f_q) - result := addmod(mulmod(mload(0x29c0), mload(0x280), f_q), result, f_q) - result := addmod(mulmod(mload(0x29e0), mload(0x2a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a00), mload(0x2c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a20), mload(0x2e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a40), mload(0x300), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a60), mload(0x320), f_q), result, f_q) - result := addmod(mulmod(mload(0x2a80), mload(0x340), f_q), result, f_q) - result := addmod(mulmod(mload(0x2aa0), mload(0x360), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ac0), mload(0x380), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ae0), mload(0x3a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b00), mload(0x3c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b20), mload(0x3e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b40), mload(0x400), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b60), mload(0x420), f_q), result, f_q) - result := addmod(mulmod(mload(0x2b80), mload(0x440), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ba0), mload(0x460), f_q), result, f_q) - result := addmod(mulmod(mload(0x2bc0), mload(0x480), f_q), result, f_q) - result := addmod(mulmod(mload(0x2be0), mload(0x4a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c00), mload(0x4c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c20), mload(0x4e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c40), mload(0x500), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c60), mload(0x520), f_q), result, f_q) - result := addmod(mulmod(mload(0x2c80), mload(0x540), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ca0), mload(0x560), f_q), result, f_q) - result := addmod(mulmod(mload(0x2cc0), mload(0x580), f_q), result, f_q) - result := addmod(mulmod(mload(0x2ce0), mload(0x5a0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d00), mload(0x5c0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d20), mload(0x5e0), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d40), mload(0x600), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d60), mload(0x620), f_q), result, f_q) - result := addmod(mulmod(mload(0x2d80), mload(0x640), f_q), result, f_q) - mstore(11680, result) - } - mstore(0x2dc0, mulmod(mload(0xb00), mload(0xae0), f_q)) - mstore(0x2de0, addmod(mload(0xac0), mload(0x2dc0), f_q)) - mstore(0x2e00, addmod(mload(0x2de0), sub(f_q, mload(0xb20)), f_q)) - mstore(0x2e20, mulmod(mload(0x2e00), mload(0xb80), f_q)) - mstore(0x2e40, mulmod(mload(0x920), mload(0x2e20), f_q)) - mstore(0x2e60, addmod(1, sub(f_q, mload(0xc40)), f_q)) - mstore(0x2e80, mulmod(mload(0x2e60), mload(0x27e0), f_q)) - mstore(0x2ea0, addmod(mload(0x2e40), mload(0x2e80), f_q)) - mstore(0x2ec0, mulmod(mload(0x920), mload(0x2ea0), f_q)) - mstore(0x2ee0, mulmod(mload(0xc40), mload(0xc40), f_q)) - mstore(0x2f00, addmod(mload(0x2ee0), sub(f_q, mload(0xc40)), f_q)) - mstore(0x2f20, mulmod(mload(0x2f00), mload(0x2700), f_q)) - mstore(0x2f40, addmod(mload(0x2ec0), mload(0x2f20), f_q)) - mstore(0x2f60, mulmod(mload(0x920), mload(0x2f40), f_q)) - mstore(0x2f80, addmod(1, sub(f_q, mload(0x2700)), f_q)) - mstore(0x2fa0, addmod(mload(0x2720), mload(0x2740), f_q)) - mstore(0x2fc0, addmod(mload(0x2fa0), mload(0x2760), f_q)) - mstore(0x2fe0, addmod(mload(0x2fc0), mload(0x2780), f_q)) - mstore(0x3000, addmod(mload(0x2fe0), mload(0x27a0), f_q)) - mstore(0x3020, addmod(mload(0x3000), mload(0x27c0), f_q)) - mstore(0x3040, addmod(mload(0x2f80), sub(f_q, mload(0x3020)), f_q)) - mstore(0x3060, mulmod(mload(0xbe0), mload(0x7a0), f_q)) - mstore(0x3080, addmod(mload(0xb40), mload(0x3060), f_q)) - mstore(0x30a0, addmod(mload(0x3080), mload(0x800), f_q)) - mstore(0x30c0, mulmod(mload(0xc00), mload(0x7a0), f_q)) - mstore(0x30e0, addmod(mload(0xac0), mload(0x30c0), f_q)) - mstore(0x3100, addmod(mload(0x30e0), mload(0x800), f_q)) - mstore(0x3120, mulmod(mload(0x3100), mload(0x30a0), f_q)) - mstore(0x3140, mulmod(mload(0xc20), mload(0x7a0), f_q)) - mstore(0x3160, addmod(mload(0x2da0), mload(0x3140), f_q)) - mstore(0x3180, addmod(mload(0x3160), mload(0x800), f_q)) - mstore(0x31a0, mulmod(mload(0x3180), mload(0x3120), f_q)) - mstore(0x31c0, mulmod(mload(0x31a0), mload(0xc60), f_q)) - mstore(0x31e0, mulmod(1, mload(0x7a0), f_q)) - mstore(0x3200, mulmod(mload(0xa80), mload(0x31e0), f_q)) - mstore(0x3220, addmod(mload(0xb40), mload(0x3200), f_q)) - mstore(0x3240, addmod(mload(0x3220), mload(0x800), f_q)) - mstore( - 0x3260, - mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x7a0), f_q) - ) - mstore(0x3280, mulmod(mload(0xa80), mload(0x3260), f_q)) - mstore(0x32a0, addmod(mload(0xac0), mload(0x3280), f_q)) - mstore(0x32c0, addmod(mload(0x32a0), mload(0x800), f_q)) - mstore(0x32e0, mulmod(mload(0x32c0), mload(0x3240), f_q)) - mstore( - 0x3300, - mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x7a0), f_q) - ) - mstore(0x3320, mulmod(mload(0xa80), mload(0x3300), f_q)) - mstore(0x3340, addmod(mload(0x2da0), mload(0x3320), f_q)) - mstore(0x3360, addmod(mload(0x3340), mload(0x800), f_q)) - mstore(0x3380, mulmod(mload(0x3360), mload(0x32e0), f_q)) - mstore(0x33a0, mulmod(mload(0x3380), mload(0xc40), f_q)) - mstore(0x33c0, addmod(mload(0x31c0), sub(f_q, mload(0x33a0)), f_q)) - mstore(0x33e0, mulmod(mload(0x33c0), mload(0x3040), f_q)) - mstore(0x3400, addmod(mload(0x2f60), mload(0x33e0), f_q)) - mstore(0x3420, mulmod(mload(0x920), mload(0x3400), f_q)) - mstore(0x3440, addmod(1, sub(f_q, mload(0xc80)), f_q)) - mstore(0x3460, mulmod(mload(0x3440), mload(0x27e0), f_q)) - mstore(0x3480, addmod(mload(0x3420), mload(0x3460), f_q)) - mstore(0x34a0, mulmod(mload(0x920), mload(0x3480), f_q)) - mstore(0x34c0, mulmod(mload(0xc80), mload(0xc80), f_q)) - mstore(0x34e0, addmod(mload(0x34c0), sub(f_q, mload(0xc80)), f_q)) - mstore(0x3500, mulmod(mload(0x34e0), mload(0x2700), f_q)) - mstore(0x3520, addmod(mload(0x34a0), mload(0x3500), f_q)) - mstore(0x3540, mulmod(mload(0x920), mload(0x3520), f_q)) - mstore(0x3560, addmod(mload(0xcc0), mload(0x7a0), f_q)) - mstore(0x3580, mulmod(mload(0x3560), mload(0xca0), f_q)) - mstore(0x35a0, addmod(mload(0xd00), mload(0x800), f_q)) - mstore(0x35c0, mulmod(mload(0x35a0), mload(0x3580), f_q)) - mstore(0x35e0, mulmod(mload(0xac0), mload(0xba0), f_q)) - mstore(0x3600, addmod(mload(0x35e0), mload(0x7a0), f_q)) - mstore(0x3620, mulmod(mload(0x3600), mload(0xc80), f_q)) - mstore(0x3640, addmod(mload(0xb60), mload(0x800), f_q)) - mstore(0x3660, mulmod(mload(0x3640), mload(0x3620), f_q)) - mstore(0x3680, addmod(mload(0x35c0), sub(f_q, mload(0x3660)), f_q)) - mstore(0x36a0, mulmod(mload(0x3680), mload(0x3040), f_q)) - mstore(0x36c0, addmod(mload(0x3540), mload(0x36a0), f_q)) - mstore(0x36e0, mulmod(mload(0x920), mload(0x36c0), f_q)) - mstore(0x3700, addmod(mload(0xcc0), sub(f_q, mload(0xd00)), f_q)) - mstore(0x3720, mulmod(mload(0x3700), mload(0x27e0), f_q)) - mstore(0x3740, addmod(mload(0x36e0), mload(0x3720), f_q)) - mstore(0x3760, mulmod(mload(0x920), mload(0x3740), f_q)) - mstore(0x3780, mulmod(mload(0x3700), mload(0x3040), f_q)) - mstore(0x37a0, addmod(mload(0xcc0), sub(f_q, mload(0xce0)), f_q)) - mstore(0x37c0, mulmod(mload(0x37a0), mload(0x3780), f_q)) - mstore(0x37e0, addmod(mload(0x3760), mload(0x37c0), f_q)) - mstore(0x3800, mulmod(mload(0x11e0), mload(0x11e0), f_q)) - mstore(0x3820, mulmod(mload(0x3800), mload(0x11e0), f_q)) - mstore(0x3840, mulmod(mload(0x3820), mload(0x11e0), f_q)) - mstore(0x3860, mulmod(1, mload(0x11e0), f_q)) - mstore(0x3880, mulmod(1, mload(0x3800), f_q)) - mstore(0x38a0, mulmod(1, mload(0x3820), f_q)) - mstore(0x38c0, mulmod(mload(0x37e0), mload(0x1200), f_q)) - mstore(0x38e0, mulmod(mload(0xf40), mload(0xa80), f_q)) - mstore(0x3900, mulmod(mload(0x38e0), mload(0xa80), f_q)) - mstore( - 0x3920, - mulmod(mload(0xa80), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q) - ) - mstore(0x3940, addmod(mload(0xe40), sub(f_q, mload(0x3920)), f_q)) - mstore(0x3960, mulmod(mload(0xa80), 1, f_q)) - mstore(0x3980, addmod(mload(0xe40), sub(f_q, mload(0x3960)), f_q)) - mstore( - 0x39a0, - mulmod(mload(0xa80), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q) - ) - mstore(0x39c0, addmod(mload(0xe40), sub(f_q, mload(0x39a0)), f_q)) - mstore( - 0x39e0, - mulmod(mload(0xa80), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q) - ) - mstore(0x3a00, addmod(mload(0xe40), sub(f_q, mload(0x39e0)), f_q)) - mstore( - 0x3a20, - mulmod(mload(0xa80), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q) - ) - mstore(0x3a40, addmod(mload(0xe40), sub(f_q, mload(0x3a20)), f_q)) - mstore( - 0x3a60, - mulmod(3544324119167359571073009690693121464267965232733679586767649244433889388945, mload(0x38e0), f_q) - ) - mstore(0x3a80, mulmod(mload(0x3a60), 1, f_q)) - { - let result := mulmod(mload(0xe40), mload(0x3a60), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3a80)), f_q), result, f_q) - mstore(15008, result) - } - mstore( - 0x3ac0, - mulmod(3860370625838117017501327045244227871206764201116468958063324100051382735289, mload(0x38e0), f_q) - ) - mstore( - 0x3ae0, - mulmod( - mload(0x3ac0), - 11211301017135681023579411905410872569206244553457844956874280139879520583390, - f_q - ) - ) - { - let result := mulmod(mload(0xe40), mload(0x3ac0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ae0)), f_q), result, f_q) - mstore(15104, result) - } - mstore( - 0x3b20, - mulmod( - 21616901807277407275624036604424346159916096890712898844034238973395610537327, - mload(0x38e0), - f_q - ) - ) - mstore( - 0x3b40, - mulmod(mload(0x3b20), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q) - ) - { - let result := mulmod(mload(0xe40), mload(0x3b20), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b40)), f_q), result, f_q) - mstore(15200, result) - } - mstore( - 0x3b80, - mulmod(3209408481237076479025468386201293941554240476766691830436732310949352383503, mload(0x38e0), f_q) - ) - mstore( - 0x3ba0, - mulmod( - mload(0x3b80), - 12619617507853212586156872920672483948819476989779550311307282715684870266992, - f_q - ) - ) - { - let result := mulmod(mload(0xe40), mload(0x3b80), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ba0)), f_q), result, f_q) - mstore(15296, result) - } - mstore(0x3be0, mulmod(1, mload(0x3980), f_q)) - mstore(0x3c00, mulmod(mload(0x3be0), mload(0x39c0), f_q)) - mstore(0x3c20, mulmod(mload(0x3c00), mload(0x3a00), f_q)) - mstore(0x3c40, mulmod(mload(0x3c20), mload(0x3a40), f_q)) - mstore( - 0x3c60, - mulmod(10676941854703594198666993839846402519342119846958189386823924046696287912228, mload(0xa80), f_q) - ) - mstore(0x3c80, mulmod(mload(0x3c60), 1, f_q)) - { - let result := mulmod(mload(0xe40), mload(0x3c60), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3c80)), f_q), result, f_q) - mstore(15520, result) - } - mstore( - 0x3cc0, - mulmod(11211301017135681023579411905410872569206244553457844956874280139879520583389, mload(0xa80), f_q) - ) - mstore( - 0x3ce0, - mulmod( - mload(0x3cc0), - 11211301017135681023579411905410872569206244553457844956874280139879520583390, - f_q - ) - ) - { - let result := mulmod(mload(0xe40), mload(0x3cc0), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ce0)), f_q), result, f_q) - mstore(15616, result) - } - mstore( - 0x3d20, - mulmod(13154116519010929542673167886091370382741775939114889923107781597533678454430, mload(0xa80), f_q) - ) - mstore(0x3d40, mulmod(mload(0x3d20), 1, f_q)) - { - let result := mulmod(mload(0xe40), mload(0x3d20), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d40)), f_q), result, f_q) - mstore(15712, result) - } - mstore( - 0x3d80, - mulmod(8734126352828345679573237859165904705806588461301144420590422589042130041187, mload(0xa80), f_q) - ) - mstore( - 0x3da0, - mulmod(mload(0x3d80), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q) - ) - { - let result := mulmod(mload(0xe40), mload(0x3d80), f_q) - result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3da0)), f_q), result, f_q) - mstore(15808, result) - } - mstore(0x3de0, mulmod(mload(0x3be0), mload(0x3940), f_q)) - { - let result := mulmod(mload(0xe40), 1, f_q) - result := addmod( - mulmod( - mload(0xa80), - 21888242871839275222246405745257275088548364400416034343698204186575808495616, - f_q - ), - result, - f_q - ) - mstore(15872, result) - } - { - let prod := mload(0x3aa0) + + } +mstore(0x2700, mulmod(mload(0x1240), mload(0x1260), f_q)) +mstore(0x2720, mulmod(mload(0x1280), mload(0x12a0), f_q)) +mstore(0x2740, mulmod(mload(0x12c0), mload(0x12e0), f_q)) +mstore(0x2760, mulmod(mload(0x1300), mload(0x1320), f_q)) +mstore(0x2780, mulmod(mload(0x1340), mload(0x1360), f_q)) +mstore(0x27a0, mulmod(mload(0x1380), mload(0x13a0), f_q)) +mstore(0x27c0, mulmod(mload(0x13c0), mload(0x13e0), f_q)) +mstore(0x27e0, mulmod(mload(0x1400), mload(0x1420), f_q)) +mstore(0x2800, mulmod(mload(0x1440), mload(0x1460), f_q)) +mstore(0x2820, mulmod(mload(0x1480), mload(0x14a0), f_q)) +mstore(0x2840, mulmod(mload(0x14c0), mload(0x14e0), f_q)) +mstore(0x2860, mulmod(mload(0x1500), mload(0x1520), f_q)) +mstore(0x2880, mulmod(mload(0x1540), mload(0x1560), f_q)) +mstore(0x28a0, mulmod(mload(0x1580), mload(0x15a0), f_q)) +mstore(0x28c0, mulmod(mload(0x15c0), mload(0x15e0), f_q)) +mstore(0x28e0, mulmod(mload(0x1600), mload(0x1620), f_q)) +mstore(0x2900, mulmod(mload(0x1640), mload(0x1660), f_q)) +mstore(0x2920, mulmod(mload(0x1680), mload(0x16a0), f_q)) +mstore(0x2940, mulmod(mload(0x16c0), mload(0x16e0), f_q)) +mstore(0x2960, mulmod(mload(0x1700), mload(0x1720), f_q)) +mstore(0x2980, mulmod(mload(0x1740), mload(0x1760), f_q)) +mstore(0x29a0, mulmod(mload(0x1780), mload(0x17a0), f_q)) +mstore(0x29c0, mulmod(mload(0x17c0), mload(0x17e0), f_q)) +mstore(0x29e0, mulmod(mload(0x1800), mload(0x1820), f_q)) +mstore(0x2a00, mulmod(mload(0x1840), mload(0x1860), f_q)) +mstore(0x2a20, mulmod(mload(0x1880), mload(0x18a0), f_q)) +mstore(0x2a40, mulmod(mload(0x18c0), mload(0x18e0), f_q)) +mstore(0x2a60, mulmod(mload(0x1900), mload(0x1920), f_q)) +mstore(0x2a80, mulmod(mload(0x1940), mload(0x1960), f_q)) +mstore(0x2aa0, mulmod(mload(0x1980), mload(0x19a0), f_q)) +mstore(0x2ac0, mulmod(mload(0x19c0), mload(0x19e0), f_q)) +mstore(0x2ae0, mulmod(mload(0x1a00), mload(0x1a20), f_q)) +mstore(0x2b00, mulmod(mload(0x1a40), mload(0x1a60), f_q)) +mstore(0x2b20, mulmod(mload(0x1a80), mload(0x1aa0), f_q)) +mstore(0x2b40, mulmod(mload(0x1ac0), mload(0x1ae0), f_q)) +mstore(0x2b60, mulmod(mload(0x1b00), mload(0x1b20), f_q)) +mstore(0x2b80, mulmod(mload(0x1b40), mload(0x1b60), f_q)) +mstore(0x2ba0, mulmod(mload(0x1b80), mload(0x1ba0), f_q)) +mstore(0x2bc0, mulmod(mload(0x1bc0), mload(0x1be0), f_q)) +mstore(0x2be0, mulmod(mload(0x1c00), mload(0x1c20), f_q)) +mstore(0x2c00, mulmod(mload(0x1c40), mload(0x1c60), f_q)) +mstore(0x2c20, mulmod(mload(0x1c80), mload(0x1ca0), f_q)) +mstore(0x2c40, mulmod(mload(0x1cc0), mload(0x1ce0), f_q)) +mstore(0x2c60, mulmod(mload(0x1d00), mload(0x1d20), f_q)) +mstore(0x2c80, mulmod(mload(0x1d40), mload(0x1d60), f_q)) +mstore(0x2ca0, mulmod(mload(0x1d80), mload(0x1da0), f_q)) +mstore(0x2cc0, mulmod(mload(0x1dc0), mload(0x1de0), f_q)) +mstore(0x2ce0, mulmod(mload(0x1e00), mload(0x1e20), f_q)) +mstore(0x2d00, mulmod(mload(0x1e40), mload(0x1e60), f_q)) +mstore(0x2d20, mulmod(mload(0x1e80), mload(0x1ea0), f_q)) +mstore(0x2d40, mulmod(mload(0x1ec0), mload(0x1ee0), f_q)) +mstore(0x2d60, mulmod(mload(0x1f00), mload(0x1f20), f_q)) +mstore(0x2d80, mulmod(mload(0x1f40), mload(0x1f60), f_q)) +{ + let result := mulmod(mload(0x27e0), mload(0xa0), f_q) +result := addmod(mulmod(mload(0x2800), mload(0xc0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2820), mload(0xe0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2840), mload(0x100), f_q), result, f_q) +result := addmod(mulmod(mload(0x2860), mload(0x120), f_q), result, f_q) +result := addmod(mulmod(mload(0x2880), mload(0x140), f_q), result, f_q) +result := addmod(mulmod(mload(0x28a0), mload(0x160), f_q), result, f_q) +result := addmod(mulmod(mload(0x28c0), mload(0x180), f_q), result, f_q) +result := addmod(mulmod(mload(0x28e0), mload(0x1a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2900), mload(0x1c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2920), mload(0x1e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2940), mload(0x200), f_q), result, f_q) +result := addmod(mulmod(mload(0x2960), mload(0x220), f_q), result, f_q) +result := addmod(mulmod(mload(0x2980), mload(0x240), f_q), result, f_q) +result := addmod(mulmod(mload(0x29a0), mload(0x260), f_q), result, f_q) +result := addmod(mulmod(mload(0x29c0), mload(0x280), f_q), result, f_q) +result := addmod(mulmod(mload(0x29e0), mload(0x2a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a00), mload(0x2c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a20), mload(0x2e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a40), mload(0x300), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a60), mload(0x320), f_q), result, f_q) +result := addmod(mulmod(mload(0x2a80), mload(0x340), f_q), result, f_q) +result := addmod(mulmod(mload(0x2aa0), mload(0x360), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ac0), mload(0x380), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ae0), mload(0x3a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b00), mload(0x3c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b20), mload(0x3e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b40), mload(0x400), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b60), mload(0x420), f_q), result, f_q) +result := addmod(mulmod(mload(0x2b80), mload(0x440), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ba0), mload(0x460), f_q), result, f_q) +result := addmod(mulmod(mload(0x2bc0), mload(0x480), f_q), result, f_q) +result := addmod(mulmod(mload(0x2be0), mload(0x4a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c00), mload(0x4c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c20), mload(0x4e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c40), mload(0x500), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c60), mload(0x520), f_q), result, f_q) +result := addmod(mulmod(mload(0x2c80), mload(0x540), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ca0), mload(0x560), f_q), result, f_q) +result := addmod(mulmod(mload(0x2cc0), mload(0x580), f_q), result, f_q) +result := addmod(mulmod(mload(0x2ce0), mload(0x5a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d00), mload(0x5c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d20), mload(0x5e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d40), mload(0x600), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d60), mload(0x620), f_q), result, f_q) +result := addmod(mulmod(mload(0x2d80), mload(0x640), f_q), result, f_q) +mstore(11680, result) + } +mstore(0x2dc0, mulmod(mload(0xb00), mload(0xae0), f_q)) +mstore(0x2de0, addmod(mload(0xac0), mload(0x2dc0), f_q)) +mstore(0x2e00, addmod(mload(0x2de0), sub(f_q, mload(0xb20)), f_q)) +mstore(0x2e20, mulmod(mload(0x2e00), mload(0xb80), f_q)) +mstore(0x2e40, mulmod(mload(0x920), mload(0x2e20), f_q)) +mstore(0x2e60, addmod(1, sub(f_q, mload(0xc40)), f_q)) +mstore(0x2e80, mulmod(mload(0x2e60), mload(0x27e0), f_q)) +mstore(0x2ea0, addmod(mload(0x2e40), mload(0x2e80), f_q)) +mstore(0x2ec0, mulmod(mload(0x920), mload(0x2ea0), f_q)) +mstore(0x2ee0, mulmod(mload(0xc40), mload(0xc40), f_q)) +mstore(0x2f00, addmod(mload(0x2ee0), sub(f_q, mload(0xc40)), f_q)) +mstore(0x2f20, mulmod(mload(0x2f00), mload(0x2700), f_q)) +mstore(0x2f40, addmod(mload(0x2ec0), mload(0x2f20), f_q)) +mstore(0x2f60, mulmod(mload(0x920), mload(0x2f40), f_q)) +mstore(0x2f80, addmod(1, sub(f_q, mload(0x2700)), f_q)) +mstore(0x2fa0, addmod(mload(0x2720), mload(0x2740), f_q)) +mstore(0x2fc0, addmod(mload(0x2fa0), mload(0x2760), f_q)) +mstore(0x2fe0, addmod(mload(0x2fc0), mload(0x2780), f_q)) +mstore(0x3000, addmod(mload(0x2fe0), mload(0x27a0), f_q)) +mstore(0x3020, addmod(mload(0x3000), mload(0x27c0), f_q)) +mstore(0x3040, addmod(mload(0x2f80), sub(f_q, mload(0x3020)), f_q)) +mstore(0x3060, mulmod(mload(0xbe0), mload(0x7a0), f_q)) +mstore(0x3080, addmod(mload(0xb40), mload(0x3060), f_q)) +mstore(0x30a0, addmod(mload(0x3080), mload(0x800), f_q)) +mstore(0x30c0, mulmod(mload(0xc00), mload(0x7a0), f_q)) +mstore(0x30e0, addmod(mload(0xac0), mload(0x30c0), f_q)) +mstore(0x3100, addmod(mload(0x30e0), mload(0x800), f_q)) +mstore(0x3120, mulmod(mload(0x3100), mload(0x30a0), f_q)) +mstore(0x3140, mulmod(mload(0xc20), mload(0x7a0), f_q)) +mstore(0x3160, addmod(mload(0x2da0), mload(0x3140), f_q)) +mstore(0x3180, addmod(mload(0x3160), mload(0x800), f_q)) +mstore(0x31a0, mulmod(mload(0x3180), mload(0x3120), f_q)) +mstore(0x31c0, mulmod(mload(0x31a0), mload(0xc60), f_q)) +mstore(0x31e0, mulmod(1, mload(0x7a0), f_q)) +mstore(0x3200, mulmod(mload(0xa80), mload(0x31e0), f_q)) +mstore(0x3220, addmod(mload(0xb40), mload(0x3200), f_q)) +mstore(0x3240, addmod(mload(0x3220), mload(0x800), f_q)) +mstore(0x3260, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x7a0), f_q)) +mstore(0x3280, mulmod(mload(0xa80), mload(0x3260), f_q)) +mstore(0x32a0, addmod(mload(0xac0), mload(0x3280), f_q)) +mstore(0x32c0, addmod(mload(0x32a0), mload(0x800), f_q)) +mstore(0x32e0, mulmod(mload(0x32c0), mload(0x3240), f_q)) +mstore(0x3300, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x7a0), f_q)) +mstore(0x3320, mulmod(mload(0xa80), mload(0x3300), f_q)) +mstore(0x3340, addmod(mload(0x2da0), mload(0x3320), f_q)) +mstore(0x3360, addmod(mload(0x3340), mload(0x800), f_q)) +mstore(0x3380, mulmod(mload(0x3360), mload(0x32e0), f_q)) +mstore(0x33a0, mulmod(mload(0x3380), mload(0xc40), f_q)) +mstore(0x33c0, addmod(mload(0x31c0), sub(f_q, mload(0x33a0)), f_q)) +mstore(0x33e0, mulmod(mload(0x33c0), mload(0x3040), f_q)) +mstore(0x3400, addmod(mload(0x2f60), mload(0x33e0), f_q)) +mstore(0x3420, mulmod(mload(0x920), mload(0x3400), f_q)) +mstore(0x3440, addmod(1, sub(f_q, mload(0xc80)), f_q)) +mstore(0x3460, mulmod(mload(0x3440), mload(0x27e0), f_q)) +mstore(0x3480, addmod(mload(0x3420), mload(0x3460), f_q)) +mstore(0x34a0, mulmod(mload(0x920), mload(0x3480), f_q)) +mstore(0x34c0, mulmod(mload(0xc80), mload(0xc80), f_q)) +mstore(0x34e0, addmod(mload(0x34c0), sub(f_q, mload(0xc80)), f_q)) +mstore(0x3500, mulmod(mload(0x34e0), mload(0x2700), f_q)) +mstore(0x3520, addmod(mload(0x34a0), mload(0x3500), f_q)) +mstore(0x3540, mulmod(mload(0x920), mload(0x3520), f_q)) +mstore(0x3560, addmod(mload(0xcc0), mload(0x7a0), f_q)) +mstore(0x3580, mulmod(mload(0x3560), mload(0xca0), f_q)) +mstore(0x35a0, addmod(mload(0xd00), mload(0x800), f_q)) +mstore(0x35c0, mulmod(mload(0x35a0), mload(0x3580), f_q)) +mstore(0x35e0, mulmod(mload(0xac0), mload(0xba0), f_q)) +mstore(0x3600, addmod(mload(0x35e0), mload(0x7a0), f_q)) +mstore(0x3620, mulmod(mload(0x3600), mload(0xc80), f_q)) +mstore(0x3640, addmod(mload(0xb60), mload(0x800), f_q)) +mstore(0x3660, mulmod(mload(0x3640), mload(0x3620), f_q)) +mstore(0x3680, addmod(mload(0x35c0), sub(f_q, mload(0x3660)), f_q)) +mstore(0x36a0, mulmod(mload(0x3680), mload(0x3040), f_q)) +mstore(0x36c0, addmod(mload(0x3540), mload(0x36a0), f_q)) +mstore(0x36e0, mulmod(mload(0x920), mload(0x36c0), f_q)) +mstore(0x3700, addmod(mload(0xcc0), sub(f_q, mload(0xd00)), f_q)) +mstore(0x3720, mulmod(mload(0x3700), mload(0x27e0), f_q)) +mstore(0x3740, addmod(mload(0x36e0), mload(0x3720), f_q)) +mstore(0x3760, mulmod(mload(0x920), mload(0x3740), f_q)) +mstore(0x3780, mulmod(mload(0x3700), mload(0x3040), f_q)) +mstore(0x37a0, addmod(mload(0xcc0), sub(f_q, mload(0xce0)), f_q)) +mstore(0x37c0, mulmod(mload(0x37a0), mload(0x3780), f_q)) +mstore(0x37e0, addmod(mload(0x3760), mload(0x37c0), f_q)) +mstore(0x3800, mulmod(mload(0x11e0), mload(0x11e0), f_q)) +mstore(0x3820, mulmod(mload(0x3800), mload(0x11e0), f_q)) +mstore(0x3840, mulmod(mload(0x3820), mload(0x11e0), f_q)) +mstore(0x3860, mulmod(1, mload(0x11e0), f_q)) +mstore(0x3880, mulmod(1, mload(0x3800), f_q)) +mstore(0x38a0, mulmod(1, mload(0x3820), f_q)) +mstore(0x38c0, mulmod(mload(0x37e0), mload(0x1200), f_q)) +mstore(0x38e0, mulmod(mload(0xf40), mload(0xa80), f_q)) +mstore(0x3900, mulmod(mload(0x38e0), mload(0xa80), f_q)) +mstore(0x3920, mulmod(mload(0xa80), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) +mstore(0x3940, addmod(mload(0xe40), sub(f_q, mload(0x3920)), f_q)) +mstore(0x3960, mulmod(mload(0xa80), 1, f_q)) +mstore(0x3980, addmod(mload(0xe40), sub(f_q, mload(0x3960)), f_q)) +mstore(0x39a0, mulmod(mload(0xa80), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +mstore(0x39c0, addmod(mload(0xe40), sub(f_q, mload(0x39a0)), f_q)) +mstore(0x39e0, mulmod(mload(0xa80), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x3a00, addmod(mload(0xe40), sub(f_q, mload(0x39e0)), f_q)) +mstore(0x3a20, mulmod(mload(0xa80), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q)) +mstore(0x3a40, addmod(mload(0xe40), sub(f_q, mload(0x3a20)), f_q)) +mstore(0x3a60, mulmod(3544324119167359571073009690693121464267965232733679586767649244433889388945, mload(0x38e0), f_q)) +mstore(0x3a80, mulmod(mload(0x3a60), 1, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3a60), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3a80)), f_q), result, f_q) +mstore(15008, result) + } +mstore(0x3ac0, mulmod(3860370625838117017501327045244227871206764201116468958063324100051382735289, mload(0x38e0), f_q)) +mstore(0x3ae0, mulmod(mload(0x3ac0), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3ac0), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ae0)), f_q), result, f_q) +mstore(15104, result) + } +mstore(0x3b20, mulmod(21616901807277407275624036604424346159916096890712898844034238973395610537327, mload(0x38e0), f_q)) +mstore(0x3b40, mulmod(mload(0x3b20), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3b20), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3b40)), f_q), result, f_q) +mstore(15200, result) + } +mstore(0x3b80, mulmod(3209408481237076479025468386201293941554240476766691830436732310949352383503, mload(0x38e0), f_q)) +mstore(0x3ba0, mulmod(mload(0x3b80), 12619617507853212586156872920672483948819476989779550311307282715684870266992, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3b80), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ba0)), f_q), result, f_q) +mstore(15296, result) + } +mstore(0x3be0, mulmod(1, mload(0x3980), f_q)) +mstore(0x3c00, mulmod(mload(0x3be0), mload(0x39c0), f_q)) +mstore(0x3c20, mulmod(mload(0x3c00), mload(0x3a00), f_q)) +mstore(0x3c40, mulmod(mload(0x3c20), mload(0x3a40), f_q)) +mstore(0x3c60, mulmod(10676941854703594198666993839846402519342119846958189386823924046696287912228, mload(0xa80), f_q)) +mstore(0x3c80, mulmod(mload(0x3c60), 1, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3c60), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3c80)), f_q), result, f_q) +mstore(15520, result) + } +mstore(0x3cc0, mulmod(11211301017135681023579411905410872569206244553457844956874280139879520583389, mload(0xa80), f_q)) +mstore(0x3ce0, mulmod(mload(0x3cc0), 11211301017135681023579411905410872569206244553457844956874280139879520583390, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3cc0), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3ce0)), f_q), result, f_q) +mstore(15616, result) + } +mstore(0x3d20, mulmod(13154116519010929542673167886091370382741775939114889923107781597533678454430, mload(0xa80), f_q)) +mstore(0x3d40, mulmod(mload(0x3d20), 1, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3d20), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3d40)), f_q), result, f_q) +mstore(15712, result) + } +mstore(0x3d80, mulmod(8734126352828345679573237859165904705806588461301144420590422589042130041187, mload(0xa80), f_q)) +mstore(0x3da0, mulmod(mload(0x3d80), 8734126352828345679573237859165904705806588461301144420590422589042130041188, f_q)) +{ + let result := mulmod(mload(0xe40), mload(0x3d80), f_q) +result := addmod(mulmod(mload(0xa80), sub(f_q, mload(0x3da0)), f_q), result, f_q) +mstore(15808, result) + } +mstore(0x3de0, mulmod(mload(0x3be0), mload(0x3940), f_q)) +{ + let result := mulmod(mload(0xe40), 1, f_q) +result := addmod(mulmod(mload(0xa80), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) +mstore(15872, result) + } +{ + let prod := mload(0x3aa0) prod := mulmod(mload(0x3b00), prod, f_q) mstore(0x3e20, prod) - + prod := mulmod(mload(0x3b60), prod, f_q) mstore(0x3e40, prod) - + prod := mulmod(mload(0x3bc0), prod, f_q) mstore(0x3e60, prod) - + prod := mulmod(mload(0x3ca0), prod, f_q) mstore(0x3e80, prod) - + prod := mulmod(mload(0x3d00), prod, f_q) mstore(0x3ea0, prod) - + prod := mulmod(mload(0x3c00), prod, f_q) mstore(0x3ec0, prod) - + prod := mulmod(mload(0x3d60), prod, f_q) mstore(0x3ee0, prod) - + prod := mulmod(mload(0x3dc0), prod, f_q) mstore(0x3f00, prod) - + prod := mulmod(mload(0x3de0), prod, f_q) mstore(0x3f20, prod) - + prod := mulmod(mload(0x3e00), prod, f_q) mstore(0x3f40, prod) - + prod := mulmod(mload(0x3be0), prod, f_q) mstore(0x3f60, prod) - } - mstore(0x3fa0, 32) - mstore(0x3fc0, 32) - mstore(0x3fe0, 32) - mstore(0x4000, mload(0x3f60)) - mstore(0x4020, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x4040, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x3fa0, 0xc0, 0x3f80, 0x20), 1), success) - { - let inv := mload(0x3f80) - let v - - v := mload(0x3be0) - mstore(15328, mulmod(mload(0x3f40), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3e00) - mstore(15872, mulmod(mload(0x3f20), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3de0) - mstore(15840, mulmod(mload(0x3f00), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3dc0) - mstore(15808, mulmod(mload(0x3ee0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3d60) - mstore(15712, mulmod(mload(0x3ec0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3c00) - mstore(15360, mulmod(mload(0x3ea0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3d00) - mstore(15616, mulmod(mload(0x3e80), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3ca0) - mstore(15520, mulmod(mload(0x3e60), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3bc0) - mstore(15296, mulmod(mload(0x3e40), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3b60) - mstore(15200, mulmod(mload(0x3e20), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x3b00) - mstore(15104, mulmod(mload(0x3aa0), inv, f_q)) - inv := mulmod(v, inv, f_q) + + } +mstore(0x3fa0, 32) +mstore(0x3fc0, 32) +mstore(0x3fe0, 32) +mstore(0x4000, mload(0x3f60)) +mstore(0x4020, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x4040, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x3fa0, 0xc0, 0x3f80, 0x20), 1), success) +{ + + let inv := mload(0x3f80) + let v + + v := mload(0x3be0) + mstore(15328, mulmod(mload(0x3f40), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3e00) + mstore(15872, mulmod(mload(0x3f20), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3de0) + mstore(15840, mulmod(mload(0x3f00), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3dc0) + mstore(15808, mulmod(mload(0x3ee0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3d60) + mstore(15712, mulmod(mload(0x3ec0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3c00) + mstore(15360, mulmod(mload(0x3ea0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3d00) + mstore(15616, mulmod(mload(0x3e80), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3ca0) + mstore(15520, mulmod(mload(0x3e60), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3bc0) + mstore(15296, mulmod(mload(0x3e40), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3b60) + mstore(15200, mulmod(mload(0x3e20), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3b00) + mstore(15104, mulmod(mload(0x3aa0), inv, f_q)) + inv := mulmod(v, inv, f_q) mstore(0x3aa0, inv) - } - { - let result := mload(0x3aa0) - result := addmod(mload(0x3b00), result, f_q) - result := addmod(mload(0x3b60), result, f_q) - result := addmod(mload(0x3bc0), result, f_q) - mstore(16480, result) - } - mstore(0x4080, mulmod(mload(0x3c40), mload(0x3c00), f_q)) - { - let result := mload(0x3ca0) - result := addmod(mload(0x3d00), result, f_q) - mstore(16544, result) - } - mstore(0x40c0, mulmod(mload(0x3c40), mload(0x3de0), f_q)) - { - let result := mload(0x3d60) - result := addmod(mload(0x3dc0), result, f_q) - mstore(16608, result) - } - mstore(0x4100, mulmod(mload(0x3c40), mload(0x3be0), f_q)) - { - let result := mload(0x3e00) - mstore(16672, result) - } - { - let prod := mload(0x4060) + + } +{ + let result := mload(0x3aa0) +result := addmod(mload(0x3b00), result, f_q) +result := addmod(mload(0x3b60), result, f_q) +result := addmod(mload(0x3bc0), result, f_q) +mstore(16480, result) + } +mstore(0x4080, mulmod(mload(0x3c40), mload(0x3c00), f_q)) +{ + let result := mload(0x3ca0) +result := addmod(mload(0x3d00), result, f_q) +mstore(16544, result) + } +mstore(0x40c0, mulmod(mload(0x3c40), mload(0x3de0), f_q)) +{ + let result := mload(0x3d60) +result := addmod(mload(0x3dc0), result, f_q) +mstore(16608, result) + } +mstore(0x4100, mulmod(mload(0x3c40), mload(0x3be0), f_q)) +{ + let result := mload(0x3e00) +mstore(16672, result) + } +{ + let prod := mload(0x4060) prod := mulmod(mload(0x40a0), prod, f_q) mstore(0x4140, prod) - + prod := mulmod(mload(0x40e0), prod, f_q) mstore(0x4160, prod) - + prod := mulmod(mload(0x4120), prod, f_q) mstore(0x4180, prod) - } - mstore(0x41c0, 32) - mstore(0x41e0, 32) - mstore(0x4200, 32) - mstore(0x4220, mload(0x4180)) - mstore(0x4240, 21888242871839275222246405745257275088548364400416034343698204186575808495615) - mstore(0x4260, 21888242871839275222246405745257275088548364400416034343698204186575808495617) - success := and(eq(staticcall(gas(), 0x5, 0x41c0, 0xc0, 0x41a0, 0x20), 1), success) - { - let inv := mload(0x41a0) - let v - - v := mload(0x4120) - mstore(16672, mulmod(mload(0x4160), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x40e0) - mstore(16608, mulmod(mload(0x4140), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x40a0) - mstore(16544, mulmod(mload(0x4060), inv, f_q)) - inv := mulmod(v, inv, f_q) + + } +mstore(0x41c0, 32) +mstore(0x41e0, 32) +mstore(0x4200, 32) +mstore(0x4220, mload(0x4180)) +mstore(0x4240, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x4260, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x41c0, 0xc0, 0x41a0, 0x20), 1), success) +{ + + let inv := mload(0x41a0) + let v + + v := mload(0x4120) + mstore(16672, mulmod(mload(0x4160), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x40e0) + mstore(16608, mulmod(mload(0x4140), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x40a0) + mstore(16544, mulmod(mload(0x4060), inv, f_q)) + inv := mulmod(v, inv, f_q) mstore(0x4060, inv) - } - mstore(0x4280, mulmod(mload(0x4080), mload(0x40a0), f_q)) - mstore(0x42a0, mulmod(mload(0x40c0), mload(0x40e0), f_q)) - mstore(0x42c0, mulmod(mload(0x4100), mload(0x4120), f_q)) - mstore(0x42e0, mulmod(mload(0xd40), mload(0xd40), f_q)) - mstore(0x4300, mulmod(mload(0x42e0), mload(0xd40), f_q)) - mstore(0x4320, mulmod(mload(0x4300), mload(0xd40), f_q)) - mstore(0x4340, mulmod(mload(0x4320), mload(0xd40), f_q)) - mstore(0x4360, mulmod(mload(0x4340), mload(0xd40), f_q)) - mstore(0x4380, mulmod(mload(0x4360), mload(0xd40), f_q)) - mstore(0x43a0, mulmod(mload(0x4380), mload(0xd40), f_q)) - mstore(0x43c0, mulmod(mload(0x43a0), mload(0xd40), f_q)) - mstore(0x43e0, mulmod(mload(0x43c0), mload(0xd40), f_q)) - mstore(0x4400, mulmod(mload(0xda0), mload(0xda0), f_q)) - mstore(0x4420, mulmod(mload(0x4400), mload(0xda0), f_q)) - mstore(0x4440, mulmod(mload(0x4420), mload(0xda0), f_q)) - { - let result := mulmod(mload(0xac0), mload(0x3aa0), f_q) - result := addmod(mulmod(mload(0xae0), mload(0x3b00), f_q), result, f_q) - result := addmod(mulmod(mload(0xb00), mload(0x3b60), f_q), result, f_q) - result := addmod(mulmod(mload(0xb20), mload(0x3bc0), f_q), result, f_q) - mstore(17504, result) - } - mstore(0x4480, mulmod(mload(0x4460), mload(0x4060), f_q)) - mstore(0x44a0, mulmod(sub(f_q, mload(0x4480)), 1, f_q)) - mstore(0x44c0, mulmod(mload(0x44a0), 1, f_q)) - mstore(0x44e0, mulmod(1, mload(0x4080), f_q)) - { - let result := mulmod(mload(0xc40), mload(0x3ca0), f_q) - result := addmod(mulmod(mload(0xc60), mload(0x3d00), f_q), result, f_q) - mstore(17664, result) - } - mstore(0x4520, mulmod(mload(0x4500), mload(0x4280), f_q)) - mstore(0x4540, mulmod(sub(f_q, mload(0x4520)), 1, f_q)) - mstore(0x4560, mulmod(mload(0x44e0), 1, f_q)) - { - let result := mulmod(mload(0xc80), mload(0x3ca0), f_q) - result := addmod(mulmod(mload(0xca0), mload(0x3d00), f_q), result, f_q) - mstore(17792, result) - } - mstore(0x45a0, mulmod(mload(0x4580), mload(0x4280), f_q)) - mstore(0x45c0, mulmod(sub(f_q, mload(0x45a0)), mload(0xd40), f_q)) - mstore(0x45e0, mulmod(mload(0x44e0), mload(0xd40), f_q)) - mstore(0x4600, addmod(mload(0x4540), mload(0x45c0), f_q)) - mstore(0x4620, mulmod(mload(0x4600), mload(0xda0), f_q)) - mstore(0x4640, mulmod(mload(0x4560), mload(0xda0), f_q)) - mstore(0x4660, mulmod(mload(0x45e0), mload(0xda0), f_q)) - mstore(0x4680, addmod(mload(0x44c0), mload(0x4620), f_q)) - mstore(0x46a0, mulmod(1, mload(0x40c0), f_q)) - { - let result := mulmod(mload(0xcc0), mload(0x3d60), f_q) - result := addmod(mulmod(mload(0xce0), mload(0x3dc0), f_q), result, f_q) - mstore(18112, result) - } - mstore(0x46e0, mulmod(mload(0x46c0), mload(0x42a0), f_q)) - mstore(0x4700, mulmod(sub(f_q, mload(0x46e0)), 1, f_q)) - mstore(0x4720, mulmod(mload(0x46a0), 1, f_q)) - mstore(0x4740, mulmod(mload(0x4700), mload(0x4400), f_q)) - mstore(0x4760, mulmod(mload(0x4720), mload(0x4400), f_q)) - mstore(0x4780, addmod(mload(0x4680), mload(0x4740), f_q)) - mstore(0x47a0, mulmod(1, mload(0x4100), f_q)) - { - let result := mulmod(mload(0xd00), mload(0x3e00), f_q) - mstore(18368, result) - } - mstore(0x47e0, mulmod(mload(0x47c0), mload(0x42c0), f_q)) - mstore(0x4800, mulmod(sub(f_q, mload(0x47e0)), 1, f_q)) - mstore(0x4820, mulmod(mload(0x47a0), 1, f_q)) - { - let result := mulmod(mload(0xb40), mload(0x3e00), f_q) - mstore(18496, result) - } - mstore(0x4860, mulmod(mload(0x4840), mload(0x42c0), f_q)) - mstore(0x4880, mulmod(sub(f_q, mload(0x4860)), mload(0xd40), f_q)) - mstore(0x48a0, mulmod(mload(0x47a0), mload(0xd40), f_q)) - mstore(0x48c0, addmod(mload(0x4800), mload(0x4880), f_q)) - { - let result := mulmod(mload(0xb60), mload(0x3e00), f_q) - mstore(18656, result) - } - mstore(0x4900, mulmod(mload(0x48e0), mload(0x42c0), f_q)) - mstore(0x4920, mulmod(sub(f_q, mload(0x4900)), mload(0x42e0), f_q)) - mstore(0x4940, mulmod(mload(0x47a0), mload(0x42e0), f_q)) - mstore(0x4960, addmod(mload(0x48c0), mload(0x4920), f_q)) - { - let result := mulmod(mload(0xb80), mload(0x3e00), f_q) - mstore(18816, result) - } - mstore(0x49a0, mulmod(mload(0x4980), mload(0x42c0), f_q)) - mstore(0x49c0, mulmod(sub(f_q, mload(0x49a0)), mload(0x4300), f_q)) - mstore(0x49e0, mulmod(mload(0x47a0), mload(0x4300), f_q)) - mstore(0x4a00, addmod(mload(0x4960), mload(0x49c0), f_q)) - { - let result := mulmod(mload(0xba0), mload(0x3e00), f_q) - mstore(18976, result) - } - mstore(0x4a40, mulmod(mload(0x4a20), mload(0x42c0), f_q)) - mstore(0x4a60, mulmod(sub(f_q, mload(0x4a40)), mload(0x4320), f_q)) - mstore(0x4a80, mulmod(mload(0x47a0), mload(0x4320), f_q)) - mstore(0x4aa0, addmod(mload(0x4a00), mload(0x4a60), f_q)) - { - let result := mulmod(mload(0xbe0), mload(0x3e00), f_q) - mstore(19136, result) - } - mstore(0x4ae0, mulmod(mload(0x4ac0), mload(0x42c0), f_q)) - mstore(0x4b00, mulmod(sub(f_q, mload(0x4ae0)), mload(0x4340), f_q)) - mstore(0x4b20, mulmod(mload(0x47a0), mload(0x4340), f_q)) - mstore(0x4b40, addmod(mload(0x4aa0), mload(0x4b00), f_q)) - { - let result := mulmod(mload(0xc00), mload(0x3e00), f_q) - mstore(19296, result) - } - mstore(0x4b80, mulmod(mload(0x4b60), mload(0x42c0), f_q)) - mstore(0x4ba0, mulmod(sub(f_q, mload(0x4b80)), mload(0x4360), f_q)) - mstore(0x4bc0, mulmod(mload(0x47a0), mload(0x4360), f_q)) - mstore(0x4be0, addmod(mload(0x4b40), mload(0x4ba0), f_q)) - { - let result := mulmod(mload(0xc20), mload(0x3e00), f_q) - mstore(19456, result) - } - mstore(0x4c20, mulmod(mload(0x4c00), mload(0x42c0), f_q)) - mstore(0x4c40, mulmod(sub(f_q, mload(0x4c20)), mload(0x4380), f_q)) - mstore(0x4c60, mulmod(mload(0x47a0), mload(0x4380), f_q)) - mstore(0x4c80, addmod(mload(0x4be0), mload(0x4c40), f_q)) - mstore(0x4ca0, mulmod(mload(0x3860), mload(0x4100), f_q)) - mstore(0x4cc0, mulmod(mload(0x3880), mload(0x4100), f_q)) - mstore(0x4ce0, mulmod(mload(0x38a0), mload(0x4100), f_q)) - { - let result := mulmod(mload(0x38c0), mload(0x3e00), f_q) - mstore(19712, result) - } - mstore(0x4d20, mulmod(mload(0x4d00), mload(0x42c0), f_q)) - mstore(0x4d40, mulmod(sub(f_q, mload(0x4d20)), mload(0x43a0), f_q)) - mstore(0x4d60, mulmod(mload(0x47a0), mload(0x43a0), f_q)) - mstore(0x4d80, mulmod(mload(0x4ca0), mload(0x43a0), f_q)) - mstore(0x4da0, mulmod(mload(0x4cc0), mload(0x43a0), f_q)) - mstore(0x4dc0, mulmod(mload(0x4ce0), mload(0x43a0), f_q)) - mstore(0x4de0, addmod(mload(0x4c80), mload(0x4d40), f_q)) - { - let result := mulmod(mload(0xbc0), mload(0x3e00), f_q) - mstore(19968, result) - } - mstore(0x4e20, mulmod(mload(0x4e00), mload(0x42c0), f_q)) - mstore(0x4e40, mulmod(sub(f_q, mload(0x4e20)), mload(0x43c0), f_q)) - mstore(0x4e60, mulmod(mload(0x47a0), mload(0x43c0), f_q)) - mstore(0x4e80, addmod(mload(0x4de0), mload(0x4e40), f_q)) - mstore(0x4ea0, mulmod(mload(0x4e80), mload(0x4420), f_q)) - mstore(0x4ec0, mulmod(mload(0x4820), mload(0x4420), f_q)) - mstore(0x4ee0, mulmod(mload(0x48a0), mload(0x4420), f_q)) - mstore(0x4f00, mulmod(mload(0x4940), mload(0x4420), f_q)) - mstore(0x4f20, mulmod(mload(0x49e0), mload(0x4420), f_q)) - mstore(0x4f40, mulmod(mload(0x4a80), mload(0x4420), f_q)) - mstore(0x4f60, mulmod(mload(0x4b20), mload(0x4420), f_q)) - mstore(0x4f80, mulmod(mload(0x4bc0), mload(0x4420), f_q)) - mstore(0x4fa0, mulmod(mload(0x4c60), mload(0x4420), f_q)) - mstore(0x4fc0, mulmod(mload(0x4d60), mload(0x4420), f_q)) - mstore(0x4fe0, mulmod(mload(0x4d80), mload(0x4420), f_q)) - mstore(0x5000, mulmod(mload(0x4da0), mload(0x4420), f_q)) - mstore(0x5020, mulmod(mload(0x4dc0), mload(0x4420), f_q)) - mstore(0x5040, mulmod(mload(0x4e60), mload(0x4420), f_q)) - mstore(0x5060, addmod(mload(0x4780), mload(0x4ea0), f_q)) - mstore(0x5080, mulmod(1, mload(0x3c40), f_q)) - mstore(0x50a0, mulmod(1, mload(0xe40), f_q)) - mstore(0x50c0, 0x0000000000000000000000000000000000000000000000000000000000000001) - mstore(0x50e0, 0x0000000000000000000000000000000000000000000000000000000000000002) - mstore(0x5100, mload(0x5060)) - success := and(eq(staticcall(gas(), 0x7, 0x50c0, 0x60, 0x50c0, 0x40), 1), success) - mstore(0x5120, mload(0x50c0)) - mstore(0x5140, mload(0x50e0)) - mstore(0x5160, mload(0x660)) - mstore(0x5180, mload(0x680)) - success := and(eq(staticcall(gas(), 0x6, 0x5120, 0x80, 0x5120, 0x40), 1), success) - mstore(0x51a0, mload(0x840)) - mstore(0x51c0, mload(0x860)) - mstore(0x51e0, mload(0x4640)) - success := and(eq(staticcall(gas(), 0x7, 0x51a0, 0x60, 0x51a0, 0x40), 1), success) - mstore(0x5200, mload(0x5120)) - mstore(0x5220, mload(0x5140)) - mstore(0x5240, mload(0x51a0)) - mstore(0x5260, mload(0x51c0)) - success := and(eq(staticcall(gas(), 0x6, 0x5200, 0x80, 0x5200, 0x40), 1), success) - mstore(0x5280, mload(0x880)) - mstore(0x52a0, mload(0x8a0)) - mstore(0x52c0, mload(0x4660)) - success := and(eq(staticcall(gas(), 0x7, 0x5280, 0x60, 0x5280, 0x40), 1), success) - mstore(0x52e0, mload(0x5200)) - mstore(0x5300, mload(0x5220)) - mstore(0x5320, mload(0x5280)) - mstore(0x5340, mload(0x52a0)) - success := and(eq(staticcall(gas(), 0x6, 0x52e0, 0x80, 0x52e0, 0x40), 1), success) - mstore(0x5360, mload(0x700)) - mstore(0x5380, mload(0x720)) - mstore(0x53a0, mload(0x4760)) - success := and(eq(staticcall(gas(), 0x7, 0x5360, 0x60, 0x5360, 0x40), 1), success) - mstore(0x53c0, mload(0x52e0)) - mstore(0x53e0, mload(0x5300)) - mstore(0x5400, mload(0x5360)) - mstore(0x5420, mload(0x5380)) - success := and(eq(staticcall(gas(), 0x6, 0x53c0, 0x80, 0x53c0, 0x40), 1), success) - mstore(0x5440, mload(0x740)) - mstore(0x5460, mload(0x760)) - mstore(0x5480, mload(0x4ec0)) - success := and(eq(staticcall(gas(), 0x7, 0x5440, 0x60, 0x5440, 0x40), 1), success) - mstore(0x54a0, mload(0x53c0)) - mstore(0x54c0, mload(0x53e0)) - mstore(0x54e0, mload(0x5440)) - mstore(0x5500, mload(0x5460)) - success := and(eq(staticcall(gas(), 0x6, 0x54a0, 0x80, 0x54a0, 0x40), 1), success) - mstore(0x5520, 0x213cf40011f8738900198c599b174deea636c934734af4175066ca297f6aee32) - mstore(0x5540, 0x1551f2933d6608d18f1e2a1109615b45127e58443760b02d78fcb4f974b3e3ce) - mstore(0x5560, mload(0x4ee0)) - success := and(eq(staticcall(gas(), 0x7, 0x5520, 0x60, 0x5520, 0x40), 1), success) - mstore(0x5580, mload(0x54a0)) - mstore(0x55a0, mload(0x54c0)) - mstore(0x55c0, mload(0x5520)) - mstore(0x55e0, mload(0x5540)) - success := and(eq(staticcall(gas(), 0x6, 0x5580, 0x80, 0x5580, 0x40), 1), success) - mstore(0x5600, 0x21c6ea7d6dbcd767ffb9d9beeb4f9c2f8243bc65290f2d75a59aea4f65ba8f3d) - mstore(0x5620, 0x24d0a0acb031c9a5687da08cdaf96650aae5c60435739bda8bbd574eb962622c) - mstore(0x5640, mload(0x4f00)) - success := and(eq(staticcall(gas(), 0x7, 0x5600, 0x60, 0x5600, 0x40), 1), success) - mstore(0x5660, mload(0x5580)) - mstore(0x5680, mload(0x55a0)) - mstore(0x56a0, mload(0x5600)) - mstore(0x56c0, mload(0x5620)) - success := and(eq(staticcall(gas(), 0x6, 0x5660, 0x80, 0x5660, 0x40), 1), success) - mstore(0x56e0, 0x1b17b25aa929dcad654497848acfba2fc23c687717f4e6437765014649c6ee15) - mstore(0x5700, 0x1b73aa6e3e6bc14b25ca8373a4d01a79c62903f91fcb76d095ffb6ac9c692049) - mstore(0x5720, mload(0x4f20)) - success := and(eq(staticcall(gas(), 0x7, 0x56e0, 0x60, 0x56e0, 0x40), 1), success) - mstore(0x5740, mload(0x5660)) - mstore(0x5760, mload(0x5680)) - mstore(0x5780, mload(0x56e0)) - mstore(0x57a0, mload(0x5700)) - success := and(eq(staticcall(gas(), 0x6, 0x5740, 0x80, 0x5740, 0x40), 1), success) - mstore(0x57c0, 0x25d0a5ef48f837d14233ce2f0961acb9ea1aecc12db0d3056c898cc9e5af5032) - mstore(0x57e0, 0x16f5118c4e2170b94e6137b7eca44571aabe677276a76ea0739b73f04bc853d2) - mstore(0x5800, mload(0x4f40)) - success := and(eq(staticcall(gas(), 0x7, 0x57c0, 0x60, 0x57c0, 0x40), 1), success) - mstore(0x5820, mload(0x5740)) - mstore(0x5840, mload(0x5760)) - mstore(0x5860, mload(0x57c0)) - mstore(0x5880, mload(0x57e0)) - success := and(eq(staticcall(gas(), 0x6, 0x5820, 0x80, 0x5820, 0x40), 1), success) - mstore(0x58a0, 0x1300f711a49a47d1cc1e27868541625117f9280a357c0c2b8ff0b13d790af07e) - mstore(0x58c0, 0x1496bd40d661139862d6a21270441c823a376eceed145dd6c2e3fa1772cda2e6) - mstore(0x58e0, mload(0x4f60)) - success := and(eq(staticcall(gas(), 0x7, 0x58a0, 0x60, 0x58a0, 0x40), 1), success) - mstore(0x5900, mload(0x5820)) - mstore(0x5920, mload(0x5840)) - mstore(0x5940, mload(0x58a0)) - mstore(0x5960, mload(0x58c0)) - success := and(eq(staticcall(gas(), 0x6, 0x5900, 0x80, 0x5900, 0x40), 1), success) - mstore(0x5980, 0x2796a29f6addcfdaef342d7f8d985a5c979587ef95d818d223c6d4e714d6c47c) - mstore(0x59a0, 0x0796ed448832f14fa093a077b57b5f6f0ec7536b3012777973a0456806821d54) - mstore(0x59c0, mload(0x4f80)) - success := and(eq(staticcall(gas(), 0x7, 0x5980, 0x60, 0x5980, 0x40), 1), success) - mstore(0x59e0, mload(0x5900)) - mstore(0x5a00, mload(0x5920)) - mstore(0x5a20, mload(0x5980)) - mstore(0x5a40, mload(0x59a0)) - success := and(eq(staticcall(gas(), 0x6, 0x59e0, 0x80, 0x59e0, 0x40), 1), success) - mstore(0x5a60, 0x261ab0f335502b5ba92ab4fff6f7a02112a6b9c5e281ae4d61d2883e5a245f2e) - mstore(0x5a80, 0x22b7d8c7bd000ddcabc27ad346fe991bf62cb53131a912201e57da270c061af1) - mstore(0x5aa0, mload(0x4fa0)) - success := and(eq(staticcall(gas(), 0x7, 0x5a60, 0x60, 0x5a60, 0x40), 1), success) - mstore(0x5ac0, mload(0x59e0)) - mstore(0x5ae0, mload(0x5a00)) - mstore(0x5b00, mload(0x5a60)) - mstore(0x5b20, mload(0x5a80)) - success := and(eq(staticcall(gas(), 0x6, 0x5ac0, 0x80, 0x5ac0, 0x40), 1), success) - mstore(0x5b40, mload(0x960)) - mstore(0x5b60, mload(0x980)) - mstore(0x5b80, mload(0x4fc0)) - success := and(eq(staticcall(gas(), 0x7, 0x5b40, 0x60, 0x5b40, 0x40), 1), success) - mstore(0x5ba0, mload(0x5ac0)) - mstore(0x5bc0, mload(0x5ae0)) - mstore(0x5be0, mload(0x5b40)) - mstore(0x5c00, mload(0x5b60)) - success := and(eq(staticcall(gas(), 0x6, 0x5ba0, 0x80, 0x5ba0, 0x40), 1), success) - mstore(0x5c20, mload(0x9a0)) - mstore(0x5c40, mload(0x9c0)) - mstore(0x5c60, mload(0x4fe0)) - success := and(eq(staticcall(gas(), 0x7, 0x5c20, 0x60, 0x5c20, 0x40), 1), success) - mstore(0x5c80, mload(0x5ba0)) - mstore(0x5ca0, mload(0x5bc0)) - mstore(0x5cc0, mload(0x5c20)) - mstore(0x5ce0, mload(0x5c40)) - success := and(eq(staticcall(gas(), 0x6, 0x5c80, 0x80, 0x5c80, 0x40), 1), success) - mstore(0x5d00, mload(0x9e0)) - mstore(0x5d20, mload(0xa00)) - mstore(0x5d40, mload(0x5000)) - success := and(eq(staticcall(gas(), 0x7, 0x5d00, 0x60, 0x5d00, 0x40), 1), success) - mstore(0x5d60, mload(0x5c80)) - mstore(0x5d80, mload(0x5ca0)) - mstore(0x5da0, mload(0x5d00)) - mstore(0x5dc0, mload(0x5d20)) - success := and(eq(staticcall(gas(), 0x6, 0x5d60, 0x80, 0x5d60, 0x40), 1), success) - mstore(0x5de0, mload(0xa20)) - mstore(0x5e00, mload(0xa40)) - mstore(0x5e20, mload(0x5020)) - success := and(eq(staticcall(gas(), 0x7, 0x5de0, 0x60, 0x5de0, 0x40), 1), success) - mstore(0x5e40, mload(0x5d60)) - mstore(0x5e60, mload(0x5d80)) - mstore(0x5e80, mload(0x5de0)) - mstore(0x5ea0, mload(0x5e00)) - success := and(eq(staticcall(gas(), 0x6, 0x5e40, 0x80, 0x5e40, 0x40), 1), success) - mstore(0x5ec0, mload(0x8c0)) - mstore(0x5ee0, mload(0x8e0)) - mstore(0x5f00, mload(0x5040)) - success := and(eq(staticcall(gas(), 0x7, 0x5ec0, 0x60, 0x5ec0, 0x40), 1), success) - mstore(0x5f20, mload(0x5e40)) - mstore(0x5f40, mload(0x5e60)) - mstore(0x5f60, mload(0x5ec0)) - mstore(0x5f80, mload(0x5ee0)) - success := and(eq(staticcall(gas(), 0x6, 0x5f20, 0x80, 0x5f20, 0x40), 1), success) - mstore(0x5fa0, mload(0xde0)) - mstore(0x5fc0, mload(0xe00)) - mstore(0x5fe0, sub(f_q, mload(0x5080))) - success := and(eq(staticcall(gas(), 0x7, 0x5fa0, 0x60, 0x5fa0, 0x40), 1), success) - mstore(0x6000, mload(0x5f20)) - mstore(0x6020, mload(0x5f40)) - mstore(0x6040, mload(0x5fa0)) - mstore(0x6060, mload(0x5fc0)) - success := and(eq(staticcall(gas(), 0x6, 0x6000, 0x80, 0x6000, 0x40), 1), success) - mstore(0x6080, mload(0xe80)) - mstore(0x60a0, mload(0xea0)) - mstore(0x60c0, mload(0x50a0)) - success := and(eq(staticcall(gas(), 0x7, 0x6080, 0x60, 0x6080, 0x40), 1), success) - mstore(0x60e0, mload(0x6000)) - mstore(0x6100, mload(0x6020)) - mstore(0x6120, mload(0x6080)) - mstore(0x6140, mload(0x60a0)) - success := and(eq(staticcall(gas(), 0x6, 0x60e0, 0x80, 0x60e0, 0x40), 1), success) - mstore(0x6160, mload(0x60e0)) - mstore(0x6180, mload(0x6100)) - mstore(0x61a0, mload(0xe80)) - mstore(0x61c0, mload(0xea0)) - mstore(0x61e0, mload(0xec0)) - mstore(0x6200, mload(0xee0)) - mstore(0x6220, mload(0xf00)) - mstore(0x6240, mload(0xf20)) - mstore(0x6260, keccak256(0x6160, 256)) - mstore(25216, mod(mload(25184), f_q)) - mstore(0x62a0, mulmod(mload(0x6280), mload(0x6280), f_q)) - mstore(0x62c0, mulmod(1, mload(0x6280), f_q)) - mstore(0x62e0, mload(0x61e0)) - mstore(0x6300, mload(0x6200)) - mstore(0x6320, mload(0x62c0)) - success := and(eq(staticcall(gas(), 0x7, 0x62e0, 0x60, 0x62e0, 0x40), 1), success) - mstore(0x6340, mload(0x6160)) - mstore(0x6360, mload(0x6180)) - mstore(0x6380, mload(0x62e0)) - mstore(0x63a0, mload(0x6300)) - success := and(eq(staticcall(gas(), 0x6, 0x6340, 0x80, 0x6340, 0x40), 1), success) - mstore(0x63c0, mload(0x6220)) - mstore(0x63e0, mload(0x6240)) - mstore(0x6400, mload(0x62c0)) - success := and(eq(staticcall(gas(), 0x7, 0x63c0, 0x60, 0x63c0, 0x40), 1), success) - mstore(0x6420, mload(0x61a0)) - mstore(0x6440, mload(0x61c0)) - mstore(0x6460, mload(0x63c0)) - mstore(0x6480, mload(0x63e0)) - success := and(eq(staticcall(gas(), 0x6, 0x6420, 0x80, 0x6420, 0x40), 1), success) - mstore(0x64a0, mload(0x6340)) - mstore(0x64c0, mload(0x6360)) - mstore(0x64e0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) + + } +mstore(0x4280, mulmod(mload(0x4080), mload(0x40a0), f_q)) +mstore(0x42a0, mulmod(mload(0x40c0), mload(0x40e0), f_q)) +mstore(0x42c0, mulmod(mload(0x4100), mload(0x4120), f_q)) +mstore(0x42e0, mulmod(mload(0xd40), mload(0xd40), f_q)) +mstore(0x4300, mulmod(mload(0x42e0), mload(0xd40), f_q)) +mstore(0x4320, mulmod(mload(0x4300), mload(0xd40), f_q)) +mstore(0x4340, mulmod(mload(0x4320), mload(0xd40), f_q)) +mstore(0x4360, mulmod(mload(0x4340), mload(0xd40), f_q)) +mstore(0x4380, mulmod(mload(0x4360), mload(0xd40), f_q)) +mstore(0x43a0, mulmod(mload(0x4380), mload(0xd40), f_q)) +mstore(0x43c0, mulmod(mload(0x43a0), mload(0xd40), f_q)) +mstore(0x43e0, mulmod(mload(0x43c0), mload(0xd40), f_q)) +mstore(0x4400, mulmod(mload(0xda0), mload(0xda0), f_q)) +mstore(0x4420, mulmod(mload(0x4400), mload(0xda0), f_q)) +mstore(0x4440, mulmod(mload(0x4420), mload(0xda0), f_q)) +{ + let result := mulmod(mload(0xac0), mload(0x3aa0), f_q) +result := addmod(mulmod(mload(0xae0), mload(0x3b00), f_q), result, f_q) +result := addmod(mulmod(mload(0xb00), mload(0x3b60), f_q), result, f_q) +result := addmod(mulmod(mload(0xb20), mload(0x3bc0), f_q), result, f_q) +mstore(17504, result) + } +mstore(0x4480, mulmod(mload(0x4460), mload(0x4060), f_q)) +mstore(0x44a0, mulmod(sub(f_q, mload(0x4480)), 1, f_q)) +mstore(0x44c0, mulmod(mload(0x44a0), 1, f_q)) +mstore(0x44e0, mulmod(1, mload(0x4080), f_q)) +{ + let result := mulmod(mload(0xc40), mload(0x3ca0), f_q) +result := addmod(mulmod(mload(0xc60), mload(0x3d00), f_q), result, f_q) +mstore(17664, result) + } +mstore(0x4520, mulmod(mload(0x4500), mload(0x4280), f_q)) +mstore(0x4540, mulmod(sub(f_q, mload(0x4520)), 1, f_q)) +mstore(0x4560, mulmod(mload(0x44e0), 1, f_q)) +{ + let result := mulmod(mload(0xc80), mload(0x3ca0), f_q) +result := addmod(mulmod(mload(0xca0), mload(0x3d00), f_q), result, f_q) +mstore(17792, result) + } +mstore(0x45a0, mulmod(mload(0x4580), mload(0x4280), f_q)) +mstore(0x45c0, mulmod(sub(f_q, mload(0x45a0)), mload(0xd40), f_q)) +mstore(0x45e0, mulmod(mload(0x44e0), mload(0xd40), f_q)) +mstore(0x4600, addmod(mload(0x4540), mload(0x45c0), f_q)) +mstore(0x4620, mulmod(mload(0x4600), mload(0xda0), f_q)) +mstore(0x4640, mulmod(mload(0x4560), mload(0xda0), f_q)) +mstore(0x4660, mulmod(mload(0x45e0), mload(0xda0), f_q)) +mstore(0x4680, addmod(mload(0x44c0), mload(0x4620), f_q)) +mstore(0x46a0, mulmod(1, mload(0x40c0), f_q)) +{ + let result := mulmod(mload(0xcc0), mload(0x3d60), f_q) +result := addmod(mulmod(mload(0xce0), mload(0x3dc0), f_q), result, f_q) +mstore(18112, result) + } +mstore(0x46e0, mulmod(mload(0x46c0), mload(0x42a0), f_q)) +mstore(0x4700, mulmod(sub(f_q, mload(0x46e0)), 1, f_q)) +mstore(0x4720, mulmod(mload(0x46a0), 1, f_q)) +mstore(0x4740, mulmod(mload(0x4700), mload(0x4400), f_q)) +mstore(0x4760, mulmod(mload(0x4720), mload(0x4400), f_q)) +mstore(0x4780, addmod(mload(0x4680), mload(0x4740), f_q)) +mstore(0x47a0, mulmod(1, mload(0x4100), f_q)) +{ + let result := mulmod(mload(0xd00), mload(0x3e00), f_q) +mstore(18368, result) + } +mstore(0x47e0, mulmod(mload(0x47c0), mload(0x42c0), f_q)) +mstore(0x4800, mulmod(sub(f_q, mload(0x47e0)), 1, f_q)) +mstore(0x4820, mulmod(mload(0x47a0), 1, f_q)) +{ + let result := mulmod(mload(0xb40), mload(0x3e00), f_q) +mstore(18496, result) + } +mstore(0x4860, mulmod(mload(0x4840), mload(0x42c0), f_q)) +mstore(0x4880, mulmod(sub(f_q, mload(0x4860)), mload(0xd40), f_q)) +mstore(0x48a0, mulmod(mload(0x47a0), mload(0xd40), f_q)) +mstore(0x48c0, addmod(mload(0x4800), mload(0x4880), f_q)) +{ + let result := mulmod(mload(0xb60), mload(0x3e00), f_q) +mstore(18656, result) + } +mstore(0x4900, mulmod(mload(0x48e0), mload(0x42c0), f_q)) +mstore(0x4920, mulmod(sub(f_q, mload(0x4900)), mload(0x42e0), f_q)) +mstore(0x4940, mulmod(mload(0x47a0), mload(0x42e0), f_q)) +mstore(0x4960, addmod(mload(0x48c0), mload(0x4920), f_q)) +{ + let result := mulmod(mload(0xb80), mload(0x3e00), f_q) +mstore(18816, result) + } +mstore(0x49a0, mulmod(mload(0x4980), mload(0x42c0), f_q)) +mstore(0x49c0, mulmod(sub(f_q, mload(0x49a0)), mload(0x4300), f_q)) +mstore(0x49e0, mulmod(mload(0x47a0), mload(0x4300), f_q)) +mstore(0x4a00, addmod(mload(0x4960), mload(0x49c0), f_q)) +{ + let result := mulmod(mload(0xba0), mload(0x3e00), f_q) +mstore(18976, result) + } +mstore(0x4a40, mulmod(mload(0x4a20), mload(0x42c0), f_q)) +mstore(0x4a60, mulmod(sub(f_q, mload(0x4a40)), mload(0x4320), f_q)) +mstore(0x4a80, mulmod(mload(0x47a0), mload(0x4320), f_q)) +mstore(0x4aa0, addmod(mload(0x4a00), mload(0x4a60), f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x3e00), f_q) +mstore(19136, result) + } +mstore(0x4ae0, mulmod(mload(0x4ac0), mload(0x42c0), f_q)) +mstore(0x4b00, mulmod(sub(f_q, mload(0x4ae0)), mload(0x4340), f_q)) +mstore(0x4b20, mulmod(mload(0x47a0), mload(0x4340), f_q)) +mstore(0x4b40, addmod(mload(0x4aa0), mload(0x4b00), f_q)) +{ + let result := mulmod(mload(0xc00), mload(0x3e00), f_q) +mstore(19296, result) + } +mstore(0x4b80, mulmod(mload(0x4b60), mload(0x42c0), f_q)) +mstore(0x4ba0, mulmod(sub(f_q, mload(0x4b80)), mload(0x4360), f_q)) +mstore(0x4bc0, mulmod(mload(0x47a0), mload(0x4360), f_q)) +mstore(0x4be0, addmod(mload(0x4b40), mload(0x4ba0), f_q)) +{ + let result := mulmod(mload(0xc20), mload(0x3e00), f_q) +mstore(19456, result) + } +mstore(0x4c20, mulmod(mload(0x4c00), mload(0x42c0), f_q)) +mstore(0x4c40, mulmod(sub(f_q, mload(0x4c20)), mload(0x4380), f_q)) +mstore(0x4c60, mulmod(mload(0x47a0), mload(0x4380), f_q)) +mstore(0x4c80, addmod(mload(0x4be0), mload(0x4c40), f_q)) +mstore(0x4ca0, mulmod(mload(0x3860), mload(0x4100), f_q)) +mstore(0x4cc0, mulmod(mload(0x3880), mload(0x4100), f_q)) +mstore(0x4ce0, mulmod(mload(0x38a0), mload(0x4100), f_q)) +{ + let result := mulmod(mload(0x38c0), mload(0x3e00), f_q) +mstore(19712, result) + } +mstore(0x4d20, mulmod(mload(0x4d00), mload(0x42c0), f_q)) +mstore(0x4d40, mulmod(sub(f_q, mload(0x4d20)), mload(0x43a0), f_q)) +mstore(0x4d60, mulmod(mload(0x47a0), mload(0x43a0), f_q)) +mstore(0x4d80, mulmod(mload(0x4ca0), mload(0x43a0), f_q)) +mstore(0x4da0, mulmod(mload(0x4cc0), mload(0x43a0), f_q)) +mstore(0x4dc0, mulmod(mload(0x4ce0), mload(0x43a0), f_q)) +mstore(0x4de0, addmod(mload(0x4c80), mload(0x4d40), f_q)) +{ + let result := mulmod(mload(0xbc0), mload(0x3e00), f_q) +mstore(19968, result) + } +mstore(0x4e20, mulmod(mload(0x4e00), mload(0x42c0), f_q)) +mstore(0x4e40, mulmod(sub(f_q, mload(0x4e20)), mload(0x43c0), f_q)) +mstore(0x4e60, mulmod(mload(0x47a0), mload(0x43c0), f_q)) +mstore(0x4e80, addmod(mload(0x4de0), mload(0x4e40), f_q)) +mstore(0x4ea0, mulmod(mload(0x4e80), mload(0x4420), f_q)) +mstore(0x4ec0, mulmod(mload(0x4820), mload(0x4420), f_q)) +mstore(0x4ee0, mulmod(mload(0x48a0), mload(0x4420), f_q)) +mstore(0x4f00, mulmod(mload(0x4940), mload(0x4420), f_q)) +mstore(0x4f20, mulmod(mload(0x49e0), mload(0x4420), f_q)) +mstore(0x4f40, mulmod(mload(0x4a80), mload(0x4420), f_q)) +mstore(0x4f60, mulmod(mload(0x4b20), mload(0x4420), f_q)) +mstore(0x4f80, mulmod(mload(0x4bc0), mload(0x4420), f_q)) +mstore(0x4fa0, mulmod(mload(0x4c60), mload(0x4420), f_q)) +mstore(0x4fc0, mulmod(mload(0x4d60), mload(0x4420), f_q)) +mstore(0x4fe0, mulmod(mload(0x4d80), mload(0x4420), f_q)) +mstore(0x5000, mulmod(mload(0x4da0), mload(0x4420), f_q)) +mstore(0x5020, mulmod(mload(0x4dc0), mload(0x4420), f_q)) +mstore(0x5040, mulmod(mload(0x4e60), mload(0x4420), f_q)) +mstore(0x5060, addmod(mload(0x4780), mload(0x4ea0), f_q)) +mstore(0x5080, mulmod(1, mload(0x3c40), f_q)) +mstore(0x50a0, mulmod(1, mload(0xe40), f_q)) +mstore(0x50c0, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(0x50e0, 0x0000000000000000000000000000000000000000000000000000000000000002) +mstore(0x5100, mload(0x5060)) +success := and(eq(staticcall(gas(), 0x7, 0x50c0, 0x60, 0x50c0, 0x40), 1), success) +mstore(0x5120, mload(0x50c0)) + mstore(0x5140, mload(0x50e0)) +mstore(0x5160, mload(0x660)) + mstore(0x5180, mload(0x680)) +success := and(eq(staticcall(gas(), 0x6, 0x5120, 0x80, 0x5120, 0x40), 1), success) +mstore(0x51a0, mload(0x840)) + mstore(0x51c0, mload(0x860)) +mstore(0x51e0, mload(0x4640)) +success := and(eq(staticcall(gas(), 0x7, 0x51a0, 0x60, 0x51a0, 0x40), 1), success) +mstore(0x5200, mload(0x5120)) + mstore(0x5220, mload(0x5140)) +mstore(0x5240, mload(0x51a0)) + mstore(0x5260, mload(0x51c0)) +success := and(eq(staticcall(gas(), 0x6, 0x5200, 0x80, 0x5200, 0x40), 1), success) +mstore(0x5280, mload(0x880)) + mstore(0x52a0, mload(0x8a0)) +mstore(0x52c0, mload(0x4660)) +success := and(eq(staticcall(gas(), 0x7, 0x5280, 0x60, 0x5280, 0x40), 1), success) +mstore(0x52e0, mload(0x5200)) + mstore(0x5300, mload(0x5220)) +mstore(0x5320, mload(0x5280)) + mstore(0x5340, mload(0x52a0)) +success := and(eq(staticcall(gas(), 0x6, 0x52e0, 0x80, 0x52e0, 0x40), 1), success) +mstore(0x5360, mload(0x700)) + mstore(0x5380, mload(0x720)) +mstore(0x53a0, mload(0x4760)) +success := and(eq(staticcall(gas(), 0x7, 0x5360, 0x60, 0x5360, 0x40), 1), success) +mstore(0x53c0, mload(0x52e0)) + mstore(0x53e0, mload(0x5300)) +mstore(0x5400, mload(0x5360)) + mstore(0x5420, mload(0x5380)) +success := and(eq(staticcall(gas(), 0x6, 0x53c0, 0x80, 0x53c0, 0x40), 1), success) +mstore(0x5440, mload(0x740)) + mstore(0x5460, mload(0x760)) +mstore(0x5480, mload(0x4ec0)) +success := and(eq(staticcall(gas(), 0x7, 0x5440, 0x60, 0x5440, 0x40), 1), success) +mstore(0x54a0, mload(0x53c0)) + mstore(0x54c0, mload(0x53e0)) +mstore(0x54e0, mload(0x5440)) + mstore(0x5500, mload(0x5460)) +success := and(eq(staticcall(gas(), 0x6, 0x54a0, 0x80, 0x54a0, 0x40), 1), success) +mstore(0x5520, 0x0b1b66f975ddca0acbfb7616fdfb45b58fa2e61370d8050b1db3f63da1d620a9) + mstore(0x5540, 0x19a35018fbf062d680f5f4dd5a9ddc3027e4cb5d14c71a750c30ca098ca90b35) +mstore(0x5560, mload(0x4ee0)) +success := and(eq(staticcall(gas(), 0x7, 0x5520, 0x60, 0x5520, 0x40), 1), success) +mstore(0x5580, mload(0x54a0)) + mstore(0x55a0, mload(0x54c0)) +mstore(0x55c0, mload(0x5520)) + mstore(0x55e0, mload(0x5540)) +success := and(eq(staticcall(gas(), 0x6, 0x5580, 0x80, 0x5580, 0x40), 1), success) +mstore(0x5600, 0x21c6ea7d6dbcd767ffb9d9beeb4f9c2f8243bc65290f2d75a59aea4f65ba8f3d) + mstore(0x5620, 0x24d0a0acb031c9a5687da08cdaf96650aae5c60435739bda8bbd574eb962622c) +mstore(0x5640, mload(0x4f00)) +success := and(eq(staticcall(gas(), 0x7, 0x5600, 0x60, 0x5600, 0x40), 1), success) +mstore(0x5660, mload(0x5580)) + mstore(0x5680, mload(0x55a0)) +mstore(0x56a0, mload(0x5600)) + mstore(0x56c0, mload(0x5620)) +success := and(eq(staticcall(gas(), 0x6, 0x5660, 0x80, 0x5660, 0x40), 1), success) +mstore(0x56e0, 0x1b17b25aa929dcad654497848acfba2fc23c687717f4e6437765014649c6ee15) + mstore(0x5700, 0x1b73aa6e3e6bc14b25ca8373a4d01a79c62903f91fcb76d095ffb6ac9c692049) +mstore(0x5720, mload(0x4f20)) +success := and(eq(staticcall(gas(), 0x7, 0x56e0, 0x60, 0x56e0, 0x40), 1), success) +mstore(0x5740, mload(0x5660)) + mstore(0x5760, mload(0x5680)) +mstore(0x5780, mload(0x56e0)) + mstore(0x57a0, mload(0x5700)) +success := and(eq(staticcall(gas(), 0x6, 0x5740, 0x80, 0x5740, 0x40), 1), success) +mstore(0x57c0, 0x25d0a5ef48f837d14233ce2f0961acb9ea1aecc12db0d3056c898cc9e5af5032) + mstore(0x57e0, 0x16f5118c4e2170b94e6137b7eca44571aabe677276a76ea0739b73f04bc853d2) +mstore(0x5800, mload(0x4f40)) +success := and(eq(staticcall(gas(), 0x7, 0x57c0, 0x60, 0x57c0, 0x40), 1), success) +mstore(0x5820, mload(0x5740)) + mstore(0x5840, mload(0x5760)) +mstore(0x5860, mload(0x57c0)) + mstore(0x5880, mload(0x57e0)) +success := and(eq(staticcall(gas(), 0x6, 0x5820, 0x80, 0x5820, 0x40), 1), success) +mstore(0x58a0, 0x1253193b69dc358c09220c36b04a3c026b8b9912dcd40b8671634fcdb50657c1) + mstore(0x58c0, 0x1d936da500b58a7118360c92841b2f8f0e636245f8b5ec34db6235b56dc25848) +mstore(0x58e0, mload(0x4f60)) +success := and(eq(staticcall(gas(), 0x7, 0x58a0, 0x60, 0x58a0, 0x40), 1), success) +mstore(0x5900, mload(0x5820)) + mstore(0x5920, mload(0x5840)) +mstore(0x5940, mload(0x58a0)) + mstore(0x5960, mload(0x58c0)) +success := and(eq(staticcall(gas(), 0x6, 0x5900, 0x80, 0x5900, 0x40), 1), success) +mstore(0x5980, 0x28b5b520d4b614165e1aa123b55428806f77327c2b3a4d8c467a323f4b4f7b43) + mstore(0x59a0, 0x0d4825d9ce7cd6f2efe68b77dc1fc56d7b4cb9d52224c14ccfcb75b76fc6b1fc) +mstore(0x59c0, mload(0x4f80)) +success := and(eq(staticcall(gas(), 0x7, 0x5980, 0x60, 0x5980, 0x40), 1), success) +mstore(0x59e0, mload(0x5900)) + mstore(0x5a00, mload(0x5920)) +mstore(0x5a20, mload(0x5980)) + mstore(0x5a40, mload(0x59a0)) +success := and(eq(staticcall(gas(), 0x6, 0x59e0, 0x80, 0x59e0, 0x40), 1), success) +mstore(0x5a60, 0x261ab0f335502b5ba92ab4fff6f7a02112a6b9c5e281ae4d61d2883e5a245f2e) + mstore(0x5a80, 0x22b7d8c7bd000ddcabc27ad346fe991bf62cb53131a912201e57da270c061af1) +mstore(0x5aa0, mload(0x4fa0)) +success := and(eq(staticcall(gas(), 0x7, 0x5a60, 0x60, 0x5a60, 0x40), 1), success) +mstore(0x5ac0, mload(0x59e0)) + mstore(0x5ae0, mload(0x5a00)) +mstore(0x5b00, mload(0x5a60)) + mstore(0x5b20, mload(0x5a80)) +success := and(eq(staticcall(gas(), 0x6, 0x5ac0, 0x80, 0x5ac0, 0x40), 1), success) +mstore(0x5b40, mload(0x960)) + mstore(0x5b60, mload(0x980)) +mstore(0x5b80, mload(0x4fc0)) +success := and(eq(staticcall(gas(), 0x7, 0x5b40, 0x60, 0x5b40, 0x40), 1), success) +mstore(0x5ba0, mload(0x5ac0)) + mstore(0x5bc0, mload(0x5ae0)) +mstore(0x5be0, mload(0x5b40)) + mstore(0x5c00, mload(0x5b60)) +success := and(eq(staticcall(gas(), 0x6, 0x5ba0, 0x80, 0x5ba0, 0x40), 1), success) +mstore(0x5c20, mload(0x9a0)) + mstore(0x5c40, mload(0x9c0)) +mstore(0x5c60, mload(0x4fe0)) +success := and(eq(staticcall(gas(), 0x7, 0x5c20, 0x60, 0x5c20, 0x40), 1), success) +mstore(0x5c80, mload(0x5ba0)) + mstore(0x5ca0, mload(0x5bc0)) +mstore(0x5cc0, mload(0x5c20)) + mstore(0x5ce0, mload(0x5c40)) +success := and(eq(staticcall(gas(), 0x6, 0x5c80, 0x80, 0x5c80, 0x40), 1), success) +mstore(0x5d00, mload(0x9e0)) + mstore(0x5d20, mload(0xa00)) +mstore(0x5d40, mload(0x5000)) +success := and(eq(staticcall(gas(), 0x7, 0x5d00, 0x60, 0x5d00, 0x40), 1), success) +mstore(0x5d60, mload(0x5c80)) + mstore(0x5d80, mload(0x5ca0)) +mstore(0x5da0, mload(0x5d00)) + mstore(0x5dc0, mload(0x5d20)) +success := and(eq(staticcall(gas(), 0x6, 0x5d60, 0x80, 0x5d60, 0x40), 1), success) +mstore(0x5de0, mload(0xa20)) + mstore(0x5e00, mload(0xa40)) +mstore(0x5e20, mload(0x5020)) +success := and(eq(staticcall(gas(), 0x7, 0x5de0, 0x60, 0x5de0, 0x40), 1), success) +mstore(0x5e40, mload(0x5d60)) + mstore(0x5e60, mload(0x5d80)) +mstore(0x5e80, mload(0x5de0)) + mstore(0x5ea0, mload(0x5e00)) +success := and(eq(staticcall(gas(), 0x6, 0x5e40, 0x80, 0x5e40, 0x40), 1), success) +mstore(0x5ec0, mload(0x8c0)) + mstore(0x5ee0, mload(0x8e0)) +mstore(0x5f00, mload(0x5040)) +success := and(eq(staticcall(gas(), 0x7, 0x5ec0, 0x60, 0x5ec0, 0x40), 1), success) +mstore(0x5f20, mload(0x5e40)) + mstore(0x5f40, mload(0x5e60)) +mstore(0x5f60, mload(0x5ec0)) + mstore(0x5f80, mload(0x5ee0)) +success := and(eq(staticcall(gas(), 0x6, 0x5f20, 0x80, 0x5f20, 0x40), 1), success) +mstore(0x5fa0, mload(0xde0)) + mstore(0x5fc0, mload(0xe00)) +mstore(0x5fe0, sub(f_q, mload(0x5080))) +success := and(eq(staticcall(gas(), 0x7, 0x5fa0, 0x60, 0x5fa0, 0x40), 1), success) +mstore(0x6000, mload(0x5f20)) + mstore(0x6020, mload(0x5f40)) +mstore(0x6040, mload(0x5fa0)) + mstore(0x6060, mload(0x5fc0)) +success := and(eq(staticcall(gas(), 0x6, 0x6000, 0x80, 0x6000, 0x40), 1), success) +mstore(0x6080, mload(0xe80)) + mstore(0x60a0, mload(0xea0)) +mstore(0x60c0, mload(0x50a0)) +success := and(eq(staticcall(gas(), 0x7, 0x6080, 0x60, 0x6080, 0x40), 1), success) +mstore(0x60e0, mload(0x6000)) + mstore(0x6100, mload(0x6020)) +mstore(0x6120, mload(0x6080)) + mstore(0x6140, mload(0x60a0)) +success := and(eq(staticcall(gas(), 0x6, 0x60e0, 0x80, 0x60e0, 0x40), 1), success) +mstore(0x6160, mload(0x60e0)) + mstore(0x6180, mload(0x6100)) +mstore(0x61a0, mload(0xe80)) + mstore(0x61c0, mload(0xea0)) +mstore(0x61e0, mload(0xec0)) + mstore(0x6200, mload(0xee0)) +mstore(0x6220, mload(0xf00)) + mstore(0x6240, mload(0xf20)) +mstore(0x6260, keccak256(0x6160, 256)) +mstore(25216, mod(mload(25184), f_q)) +mstore(0x62a0, mulmod(mload(0x6280), mload(0x6280), f_q)) +mstore(0x62c0, mulmod(1, mload(0x6280), f_q)) +mstore(0x62e0, mload(0x61e0)) + mstore(0x6300, mload(0x6200)) +mstore(0x6320, mload(0x62c0)) +success := and(eq(staticcall(gas(), 0x7, 0x62e0, 0x60, 0x62e0, 0x40), 1), success) +mstore(0x6340, mload(0x6160)) + mstore(0x6360, mload(0x6180)) +mstore(0x6380, mload(0x62e0)) + mstore(0x63a0, mload(0x6300)) +success := and(eq(staticcall(gas(), 0x6, 0x6340, 0x80, 0x6340, 0x40), 1), success) +mstore(0x63c0, mload(0x6220)) + mstore(0x63e0, mload(0x6240)) +mstore(0x6400, mload(0x62c0)) +success := and(eq(staticcall(gas(), 0x7, 0x63c0, 0x60, 0x63c0, 0x40), 1), success) +mstore(0x6420, mload(0x61a0)) + mstore(0x6440, mload(0x61c0)) +mstore(0x6460, mload(0x63c0)) + mstore(0x6480, mload(0x63e0)) +success := and(eq(staticcall(gas(), 0x6, 0x6420, 0x80, 0x6420, 0x40), 1), success) +mstore(0x64a0, mload(0x6340)) + mstore(0x64c0, mload(0x6360)) +mstore(0x64e0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) mstore(0x6500, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) mstore(0x6520, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) mstore(0x6540, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) - mstore(0x6560, mload(0x6420)) - mstore(0x6580, mload(0x6440)) - mstore(0x65a0, 0x172aa93c41f16e1e04d62ac976a5d945f4be0acab990c6dc19ac4a7cf68bf77b) +mstore(0x6560, mload(0x6420)) + mstore(0x6580, mload(0x6440)) +mstore(0x65a0, 0x172aa93c41f16e1e04d62ac976a5d945f4be0acab990c6dc19ac4a7cf68bf77b) mstore(0x65c0, 0x2ae0c8c3a090f7200ff398ee9845bbae8f8c1445ae7b632212775f60a0e21600) mstore(0x65e0, 0x190fa476a5b352809ed41d7a0d7fe12b8f685e3c12a6d83855dba27aaf469643) mstore(0x6600, 0x1c0a500618907df9e4273d5181e31088deb1f05132de037cbfe73888f97f77c9) - success := and(eq(staticcall(gas(), 0x8, 0x64a0, 0x180, 0x64a0, 0x20), 1), success) - success := and(eq(mload(0x64a0), 1), success) +success := and(eq(staticcall(gas(), 0x8, 0x64a0, 0x180, 0x64a0, 0x20), 1), success) +success := and(eq(mload(0x64a0), 1), success) // Revert if anything fails if iszero(success) { revert(0, 0) } // Return empty bytes on success return(0, 0) + } } } + \ No newline at end of file diff --git a/releases/dev/verifier/verifier.bin b/releases/dev/verifier/verifier.bin index e43ee5e5326f8d74bd4dd4b7aaa6a5d280acaf71..258670f3f3b443299799a3ff84291d7791298490 100644 GIT binary patch delta 1083 zcmY*Xe{2(V6z{iPr=tVM){U}e+gTu+E`tdSCy0!UlIz_8w~BXz!{+EV=NdqLyYp5#zh4-N5yv?j`(u#a_{qb zpLg$l-}mYenjS)i7xBZz51o{|H}FZ98?PP_J8w3A@z%BRw)%~i^?kGTDesUooqRjJ z-qo`y=b&Lll%?-&J~KgGAg@qidHFfsH#glfq1^pz zYVWDZ+RC3tU-f=n+MQoJl9#yPsY_44RP78FzPx->+hkoLFOa|CQ|3kI8^=!;PL6x@ zuGU>+R<3x3G=CJ9%gpxk4(nK#Z$o}6=3mplq_rhDWBt1Rhn704{i|l$#9PH+m1R-m zpLjS` zudgQ8PA+h$VY@61KOo$5f@CMURY=s$NT_Dje=v5C&>+sy^!Ew389EM~P7DN#7jbBA~@l0L60Dq>dP8oo)IL2w~^mqswHH{6Ly6e16R*~GA;vC+3D>pMT^z$ z{hKfqW*JjnUjJCZG(J}BoL888nCGXvI-2C+=NFxB?NJu;0Sq zDbNU#2K#PM;T}C}&k{4juyUvlj0y||3>(OvOFRzqaXjelon)k_ZpRp6oQ-*2LuS%Q zxssqYi@BObH-H%kuIU%u_v2?fi>~YC--x}7Z{HVA?LXAF@GIn^f@o~;YgBr?wpFZi_$4?Em`ix%1Q*237+jMb1Jll1N zm5cV7=6pRm>2`*PZZmO3cgA>Eew_dpQZBF2`5jFwihZ=(JT|Tm6m9Wab8|AmiL}kX zPPK2W|8T#)b$V))EkPHFJ6t>a(Oq*&xj(zWX=)$ccVcP()ZMLh)3)?&-3oICcqjaNVXG`a7EKO>MW*iwSwgDYP>c-fMX=H0n>@sd3? z6)iQ-hct}1@uZ1tyjBVqNiJ{iU~|s43E$?0P^kEHN&Y&+&H1aw#}{w$glx-Wl;I2N ze`PO-A?XfY1eBkI_7VYDonAmYjp&MGSBU zeT>1aVpsKdQ>ewBLYR=rkrwL?sE|3!i%7O44U`8#hg*=e^6xHN9-<`22a+kFa8PXekh$bn@9dv(Bpa(bXJ!Ft)XX;)dC>oN$xV)@8Fm^SM87Kzv)Td Ql|s+D)k|mUViR= BN254_SCALAR_MODULUS) revert InvalidAppExeCommit(appExeCommit); if (uint256(appVmCommit) >= BN254_SCALAR_MODULUS) revert InvalidAppVmCommit(appVmCommit); @@ -72,7 +67,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { // Other than the fallback() in `Halo2Verifier`, there is only one // function selector on the external ABI: `verify(..)`, which has // selector 0x24270d54. If `proofData` ever began with 0x24270d54, this - // function would be called again instead of hitting the fallback. + // function would be called again instead of hitting the fallback. // // If a valid proof ever began with 0x24270d54, it would fail to verify. // However, `snark-verifier`'s proof structure guarantees that the first @@ -119,12 +114,11 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { /// /// @return proofPtr Memory pointer to the beginning of the constructed /// proof. This pointer does not follow `bytes memory` semantics. - function _constructProof( - bytes calldata publicValues, - bytes calldata proofData, - bytes32 appExeCommit, - bytes32 appVmCommit - ) internal pure returns (MemoryPointer proofPtr) { + function _constructProof(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) + internal + pure + returns (MemoryPointer proofPtr) + { uint256 fullProofLength = FULL_PROOF_LENGTH; // The expected proof format using hex offsets: @@ -158,11 +152,14 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH)) calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560) - // Copy each byte of the public values into the proof. It copies the - // most significant bytes of public values first. + // Copy each u16 public value cell into its own bytes32 word. The + // calldata packs each cell as 2 little-endian bytes; the word is + // big-endian, so the low byte lands at offset 0x1f and the high + // byte at 0x1e of each word. let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { - calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01) + calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, shl(1, i)), 0x01) + calldatacopy(sub(add(publicValuesMemOffset, shl(5, i)), 1), add(add(publicValues.offset, shl(1, i)), 1), 0x01) } } } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c6357706..e822dc9f 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,5 @@ [toolchain] -channel = "nightly-2025-11-20" -targets = ["riscv32im-unknown-none-elf", "x86_64-unknown-linux-gnu"] +# Nightly required by the openvm-sdk "tco" feature (see openvm's rust-toolchain.toml). +channel = "nightly-2026-01-18" +targets = ["x86_64-unknown-linux-gnu"] components = ["llvm-tools", "rustc-dev"] From 1a5cd7d90655eac5def147587a0056b97019659a Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 16 Jul 2026 15:01:17 +0800 Subject: [PATCH 03/15] chore: upgrade openvm to develop-v2.1.0 latest (d193688d) - Update Cargo.lock openvm entries to d193688d - Adapt save_stdin_as_json to new Vec StdIn buffer - Cache SdkCachedProvingKey instead of AggProvingKey for new SDK builder - Use circuit-specific app_config in tester_execute - Regenerate guest assets and commitments --- Cargo.lock | 175 +++++++++--------- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- crates/integration/src/lib.rs | 16 +- crates/prover/src/utils/mod.rs | 9 +- crates/types/Cargo.toml | 1 + crates/types/src/zkvm.rs | 22 ++- crates/verifier/src/verifier.rs | 2 +- 12 files changed, 127 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7afa416..254c0215 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -721,7 +721,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -732,7 +732,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2273,7 +2273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2722,8 +2722,8 @@ dependencies = [ [[package]] name = "halo2-axiom" -version = "0.5.1" -source = "git+https://github.com/axiom-crypto/halo2.git?tag=v0.5.1#c9e642dd14561274de4f6f11625aa3ae73ea74d0" +version = "0.5.2" +source = "git+https://github.com/axiom-crypto/halo2.git?tag=v0.5.2#1eed471495b64ec1edf22f0661bbc65d0e4381d5" dependencies = [ "blake2b_simd", "crossbeam", @@ -2744,7 +2744,7 @@ dependencies = [ [[package]] name = "halo2-base" version = "0.5.4" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.4#6522c1c5fd98daf92cba36f97fecd00e59d5ad70" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.4#a69fdee77f41bdd48ad658b69673dea5a0815db4" dependencies = [ "getset", "halo2-axiom", @@ -2764,7 +2764,7 @@ dependencies = [ [[package]] name = "halo2-ecc" version = "0.5.4" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.4#6522c1c5fd98daf92cba36f97fecd00e59d5ad70" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.4#a69fdee77f41bdd48ad658b69673dea5a0815db4" dependencies = [ "halo2-base", "itertools 0.11.0", @@ -3367,7 +3367,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "ecdsa", "elliptic-curve", @@ -3746,7 +3746,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3884,7 +3884,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.110", @@ -4092,7 +4092,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4107,7 +4107,7 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "blstrs", "cfg-if", @@ -4129,6 +4129,7 @@ dependencies = [ "openvm-cuda-common", "openvm-instructions", "openvm-mod-circuit-builder", + "openvm-platform", "openvm-riscv-adapters", "openvm-riscv-circuit", "openvm-stark-backend", @@ -4142,7 +4143,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-macros-common", "quote", @@ -4152,7 +4153,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "halo2curves-axiom 0.7.3", "num-bigint", @@ -4168,7 +4169,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "num-bigint", "num-prime", @@ -4180,7 +4181,7 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-algebra-guest", "openvm-decoder", @@ -4194,7 +4195,7 @@ dependencies = [ [[package]] name = "openvm-algebra-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "num-bigint", "num-traits", @@ -4204,7 +4205,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "clap", "eyre", @@ -4217,7 +4218,6 @@ dependencies = [ "openvm-stark-sdk", "openvm-transpiler", "openvm-verify-stark-host", - "p3-field", "rand_chacha 0.3.1", "tiny-keccak", "tracing", @@ -4227,7 +4227,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4241,7 +4241,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4268,7 +4268,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4277,7 +4277,7 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-bigint-guest", "openvm-decoder", @@ -4292,7 +4292,7 @@ dependencies = [ [[package]] name = "openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4304,7 +4304,7 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "backtrace", "bytesize", @@ -4326,6 +4326,7 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", + "openvm-platform", "openvm-poseidon2-air", "openvm-stark-backend", "openvm-stark-sdk", @@ -4344,7 +4345,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4355,7 +4356,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4375,7 +4376,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4397,7 +4398,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "cfg-if", "derivative", @@ -4411,6 +4412,7 @@ dependencies = [ "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-common", + "openvm-instructions", "openvm-poseidon2-air", "openvm-recursion-circuit", "openvm-recursion-circuit-derive", @@ -4503,7 +4505,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "proc-macro2", "quote", @@ -4513,12 +4515,12 @@ dependencies = [ [[package]] name = "openvm-decoder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" [[package]] name = "openvm-deferral-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "cfg-if", "dashmap", @@ -4548,7 +4550,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4557,7 +4559,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4573,7 +4575,7 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "blstrs", "cfg-if", @@ -4595,6 +4597,7 @@ dependencies = [ "openvm-ecc-transpiler", "openvm-instructions", "openvm-mod-circuit-builder", + "openvm-platform", "openvm-riscv-adapters", "openvm-riscv-circuit", "openvm-stark-backend", @@ -4608,7 +4611,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "ecdsa", "elliptic-curve", @@ -4627,7 +4630,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-macros-common", "quote", @@ -4637,7 +4640,7 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-decoder", "openvm-ecc-guest", @@ -4651,7 +4654,7 @@ dependencies = [ [[package]] name = "openvm-instructions" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4668,7 +4671,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "quote", "syn 2.0.110", @@ -4677,7 +4680,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4686,7 +4689,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4714,7 +4717,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-platform", ] @@ -4722,7 +4725,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4736,7 +4739,7 @@ dependencies = [ [[package]] name = "openvm-macros-common" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "syn 2.0.110", ] @@ -4744,7 +4747,7 @@ dependencies = [ [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4762,7 +4765,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.3", @@ -4786,7 +4789,7 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4818,7 +4821,7 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "blstrs", "halo2curves-axiom 0.7.3", @@ -4839,7 +4842,7 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4852,7 +4855,7 @@ dependencies = [ [[package]] name = "openvm-platform" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "libm", "openvm-custom-insn", @@ -4862,7 +4865,7 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "derivative", "lazy_static", @@ -4880,7 +4883,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4908,7 +4911,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "quote", "syn 2.0.110", @@ -4917,7 +4920,7 @@ dependencies = [ [[package]] name = "openvm-riscv-adapters" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4934,7 +4937,7 @@ dependencies = [ [[package]] name = "openvm-riscv-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4951,6 +4954,7 @@ dependencies = [ "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", + "openvm-platform", "openvm-riscv-transpiler", "openvm-stark-backend", "openvm-stark-sdk", @@ -4963,7 +4967,7 @@ dependencies = [ [[package]] name = "openvm-riscv-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4972,7 +4976,7 @@ dependencies = [ [[package]] name = "openvm-riscv-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4988,7 +4992,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "alloy-sol-types", "bitcode", @@ -5027,7 +5031,7 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "bon", "cfg-if", @@ -5063,7 +5067,7 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-sha2-guest", "sha2 0.10.9", @@ -5072,7 +5076,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "ndarray", "num_enum", @@ -5086,7 +5090,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5115,7 +5119,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-platform", ] @@ -5123,7 +5127,7 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -5201,7 +5205,7 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "halo2-base", "itertools 0.14.0", @@ -5225,7 +5229,7 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "elf", "eyre", @@ -5240,7 +5244,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "bitcode", "cfg-if", @@ -5270,7 +5274,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-deferral-guest", ] @@ -5278,7 +5282,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "bitcode", "eyre", @@ -5317,7 +5321,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "ecdsa", "elliptic-curve", @@ -7598,7 +7602,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7631,14 +7635,12 @@ dependencies = [ [[package]] name = "rvr-openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "openvm-instructions", "openvm-platform", "openvm-riscv-guest", - "openvm-stark-backend", "rvr-openvm-build", - "rvr-openvm-ext-ffi-common", "rvr-openvm-ir", "rvr-openvm-lift", "thiserror 1.0.69", @@ -7647,21 +7649,12 @@ dependencies = [ [[package]] name = "rvr-openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" - -[[package]] -name = "rvr-openvm-ext-ffi-common" -version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" -dependencies = [ - "openvm-instructions", - "openvm-platform", -] +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" [[package]] name = "rvr-openvm-ir" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "serde", ] @@ -7669,13 +7662,12 @@ dependencies = [ [[package]] name = "rvr-openvm-lift" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fd569c743c802a95c066d9d86d5d6e3a07517d5b" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" dependencies = [ "libloading", "openvm-instructions", "openvm-riscv-transpiler", "openvm-stark-backend", - "rvr-openvm-ext-ffi-common", "rvr-openvm-ir", "thiserror 1.0.69", ] @@ -8060,6 +8052,7 @@ dependencies = [ "once_cell", "openvm-circuit", "openvm-sdk", + "openvm-sdk-config", "openvm-stark-sdk", "openvm-static-verifier", "openvm-verify-stark-host", @@ -8545,7 +8538,7 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "snark-verifier" version = "0.2.6" -source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.6#89abe4719d54c68ba07480a1b2204d736cdf0fec" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.6#364e82654c746b063aff528d8cb660890908278a" dependencies = [ "halo2-base", "halo2-ecc", @@ -8566,7 +8559,7 @@ dependencies = [ [[package]] name = "snark-verifier-sdk" version = "0.2.6" -source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.6#89abe4719d54c68ba07480a1b2204d736cdf0fec" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.6#364e82654c746b063aff528d8cb660890908278a" dependencies = [ "ark-std 0.3.0", "bincode 1.3.3", @@ -8839,7 +8832,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 8ea0752d..2af03321 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [484008805, 495385384, 580625652, 1256154140, 344157297, 193294640, 204686231, 1298907128]; +pub const COMMIT: [u32; 8] = [255390656, 841614202, 723072685, 428945948, 1058935670, 1172523134, 659659239, 1036669295]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index e194b577..69c5e497 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1294116814, 1474253328, 1120614043, 965568099, 1164275634, 1855860028, 258237225, 196946449]; +pub const COMMIT: [u32; 8] = [1987114624, 804141507, 1994569689, 1169568751, 1595734354, 237628733, 186189138, 793815735]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 1c7c9692..a2d366d1 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1443277551, 653435895, 1375066366, 326410668, 1121253390, 342859750, 1593789325, 668948641]; +pub const COMMIT: [u32; 8] = [1203227948, 673590627, 566821506, 1414543696, 1000030357, 1132953155, 1921276173, 1587256891]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index e0c1c65f..49b7b44d 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [307979900, 1253096756, 1500738532, 1272243460, 647335365, 313600294, 213468467, 466651622]; +pub const COMMIT: [u32; 8] = [1730948446, 592379163, 30730427, 1108807042, 587065798, 698750563, 1595566218, 1990233667]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 6f07e05b..f6a71591 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [908836225, 991040821, 1510474027, 1845433726, 1048440467, 1276051553, 1035576080, 1258921324]; +pub const COMMIT: [u32; 8] = [267779200, 272736994, 569255966, 1032674134, 1018200325, 1908782056, 1594495174, 1244019586]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index efbbb3d1..03687fbf 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [177016299, 1080091031, 1310488645, 1551948772, 1390988486, 911933392, 1165989125, 952863336]; +pub const COMMIT: [u32; 8] = [88949024, 1187928366, 385523892, 1823125618, 165562023, 109824935, 183750709, 663351380]; diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index 70f218e9..5771d41f 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -1,8 +1,12 @@ use cargo_metadata::MetadataCommand; use once_cell::sync::OnceCell; use openvm_circuit::arch::deferral::DeferralState; +use openvm_sdk::config::AggregationSystemParams; use openvm_sdk::{DeferralInput, Sdk, StdIn}; use openvm_stark_sdk::openvm_stark_backend::codec::Decode; +use openvm_stark_sdk::config::{ + internal_params_with_100_bits_security, leaf_params_with_100_bits_security, +}; use openvm_verify_stark_circuit::extension::{get_deferral_state, get_raw_deferral_results}; use openvm_verify_stark_host::{ VmStarkProof, @@ -20,7 +24,7 @@ use scroll_zkvm_types::{ types_agg::ProgramCommitment, utils::serialize_vk, }; -use scroll_zkvm_verifier::verifier::{AGG_STARK_PROVING_KEY, UniversalVerifier}; +use scroll_zkvm_verifier::verifier::UniversalVerifier; use std::collections::HashMap; use std::{ io::Cursor, @@ -403,10 +407,16 @@ pub fn tester_execute( .map(|p| p.as_stark_proof().expect("must be stark proof")), )?; - let _app_vm_config = app_config.app_vm_config.clone(); + // Use the circuit-specific app config so the executor supports all required + // extensions (keccak, ecc, pairing, etc.). Aggregation params are only needed + // to satisfy the SDK builder; key generation is lazy and never triggered by + // the execution-only test path. let sdk = Sdk::builder() .app_config(app_config) - .agg_pk(AGG_STARK_PROVING_KEY.clone()) + .agg_params(AggregationSystemParams { + leaf: leaf_params_with_100_bits_security(), + internal: internal_params_with_100_bits_security(), + }) .build() .map_err(|e| eyre::eyre!("sdk build failed: {e}"))?; let ret = scroll_zkvm_prover::utils::vm::execute_guest(&sdk, app_exe, &stdin)?; diff --git a/crates/prover/src/utils/mod.rs b/crates/prover/src/utils/mod.rs index ddc48a04..c6407e9c 100644 --- a/crates/prover/src/utils/mod.rs +++ b/crates/prover/src/utils/mod.rs @@ -76,11 +76,12 @@ pub fn save_stdin_as_json(stdin: &openvm_sdk::StdIn, filename: &str) { let mut json: serde_json::Value = serde_json::from_str("{\"input\":[]}").unwrap(); let json_input = json["input"].as_array_mut().unwrap(); for item in &stdin.buffer { - use openvm_stark_sdk::openvm_stark_backend::p3_field::PrimeField32; let mut bytes: Vec = vec![0x02]; - for f in item { - let u32_bytes = f.as_canonical_u32().to_le_bytes(); - bytes.extend_from_slice(&u32_bytes); + for b in item { + // The new OpenVM SDK stores stdin as raw bytes; keep the historical + // 0x02 (little-endian u32 word) serialization so the dumped JSON is + // still accepted by `cargo openvm`. + bytes.extend_from_slice(&[*b, 0, 0, 0]); } json_input.push(serde_json::Value::String(format!( "0x{}", diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml index 518da567..34a31ce4 100644 --- a/crates/types/Cargo.toml +++ b/crates/types/Cargo.toml @@ -14,6 +14,7 @@ types-batch = { path = "batch", package = "scroll-zkvm-types-batch", features = types-bundle = { path = "bundle", package = "scroll-zkvm-types-bundle" } openvm-sdk = { workspace = true } +openvm-sdk-config = { workspace = true } openvm-verify-stark-host = { workspace = true } openvm-static-verifier = { workspace = true } openvm-circuit = { workspace = true } diff --git a/crates/types/src/zkvm.rs b/crates/types/src/zkvm.rs index fb4e9522..63490e42 100644 --- a/crates/types/src/zkvm.rs +++ b/crates/types/src/zkvm.rs @@ -1,21 +1,33 @@ use once_cell::sync::Lazy; use openvm_sdk::Sdk; use openvm_sdk::config::AggregationSystemParams; -use openvm_sdk::keygen::AggProvingKey; +use openvm_sdk::keygen::SdkCachedProvingKey; +use openvm_sdk_config::SdkVmConfig; use openvm_stark_sdk::config::{ MAX_APP_LOG_STACKED_HEIGHT, app_params_with_100_bits_security, internal_params_with_100_bits_security, leaf_params_with_100_bits_security, }; -/// Proving key for STARK aggregation. Primarily used to aggregate +/// Cached proving keys for STARK aggregation. Primarily used to aggregate /// [continuation proofs][openvm_sdk::prover::vm::ContinuationVmProof]. -pub static AGG_STARK_PROVING_KEY: Lazy = Lazy::new(build_agg_pk); +/// +/// Starting with OpenVM develop-v2.1.0, the SDK builder requires both `app_pk` +/// and `agg_pk` to be supplied together when seeding with pre-generated keys, +/// so we cache the full [`SdkCachedProvingKey`] instead of only `AggProvingKey`. +pub static AGG_STARK_PROVING_KEY: Lazy> = Lazy::new(build_agg_pk); -fn build_agg_pk() -> AggProvingKey { +fn build_agg_pk() -> SdkCachedProvingKey { let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); let agg_params = AggregationSystemParams { leaf: leaf_params_with_100_bits_security(), internal: internal_params_with_100_bits_security(), }; - Sdk::riscv64(app_params, agg_params).agg_pk().clone() + let sdk = Sdk::riscv64(app_params, agg_params); + SdkCachedProvingKey { + app_pk: sdk.app_pk().clone(), + agg_pk: sdk.agg_pk(), + deferral_pk: None, + deferral_agg_pk: None, + root_pk: None, + } } diff --git a/crates/verifier/src/verifier.rs b/crates/verifier/src/verifier.rs index f321279e..16c0732c 100644 --- a/crates/verifier/src/verifier.rs +++ b/crates/verifier/src/verifier.rs @@ -98,7 +98,7 @@ impl UniversalVerifier { let loaded_mvk = openvm_sdk::fs::read_object_from_file(path_agg_vk).unwrap_or_else(|_| { tracing::warn!("root_verifier_vk not found on disk, computing on-the-fly (slow)..."); - AGG_STARK_PROVING_KEY.internal_recursive.get_vk().clone() + AGG_STARK_PROVING_KEY.agg_pk.internal_recursive.get_vk().clone() }); Ok(Self { From 251667431aa4b5f28b75d28292d51af31293dd10 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Fri, 17 Jul 2026 14:55:31 +0800 Subject: [PATCH 04/15] chore: bump openvm to develop-v2.1.0 latest (10371132) --- Cargo.lock | 130 ++++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 254c0215..059270c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3367,7 +3367,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "ecdsa", "elliptic-curve", @@ -4092,7 +4092,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4107,7 +4107,7 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "blstrs", "cfg-if", @@ -4143,7 +4143,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-macros-common", "quote", @@ -4153,7 +4153,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "halo2curves-axiom 0.7.3", "num-bigint", @@ -4169,7 +4169,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "num-bigint", "num-prime", @@ -4181,7 +4181,7 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-algebra-guest", "openvm-decoder", @@ -4195,7 +4195,7 @@ dependencies = [ [[package]] name = "openvm-algebra-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "num-bigint", "num-traits", @@ -4205,7 +4205,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "clap", "eyre", @@ -4227,7 +4227,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4241,7 +4241,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4268,7 +4268,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4277,7 +4277,7 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-bigint-guest", "openvm-decoder", @@ -4292,7 +4292,7 @@ dependencies = [ [[package]] name = "openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4304,7 +4304,7 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "backtrace", "bytesize", @@ -4345,7 +4345,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4356,7 +4356,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4376,7 +4376,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4398,7 +4398,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "cfg-if", "derivative", @@ -4505,7 +4505,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "proc-macro2", "quote", @@ -4515,12 +4515,12 @@ dependencies = [ [[package]] name = "openvm-decoder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" [[package]] name = "openvm-deferral-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "cfg-if", "dashmap", @@ -4550,7 +4550,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4559,7 +4559,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4575,7 +4575,7 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "blstrs", "cfg-if", @@ -4611,7 +4611,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "ecdsa", "elliptic-curve", @@ -4630,7 +4630,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-macros-common", "quote", @@ -4640,7 +4640,7 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-decoder", "openvm-ecc-guest", @@ -4654,7 +4654,7 @@ dependencies = [ [[package]] name = "openvm-instructions" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4671,7 +4671,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "quote", "syn 2.0.110", @@ -4680,7 +4680,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4689,7 +4689,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4717,7 +4717,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-platform", ] @@ -4725,7 +4725,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4739,7 +4739,7 @@ dependencies = [ [[package]] name = "openvm-macros-common" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "syn 2.0.110", ] @@ -4747,7 +4747,7 @@ dependencies = [ [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4765,7 +4765,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.3", @@ -4789,7 +4789,7 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4821,7 +4821,7 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "blstrs", "halo2curves-axiom 0.7.3", @@ -4842,7 +4842,7 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4855,7 +4855,7 @@ dependencies = [ [[package]] name = "openvm-platform" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "libm", "openvm-custom-insn", @@ -4865,7 +4865,7 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "derivative", "lazy_static", @@ -4883,7 +4883,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4911,7 +4911,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "quote", "syn 2.0.110", @@ -4920,7 +4920,7 @@ dependencies = [ [[package]] name = "openvm-riscv-adapters" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4937,7 +4937,7 @@ dependencies = [ [[package]] name = "openvm-riscv-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4967,7 +4967,7 @@ dependencies = [ [[package]] name = "openvm-riscv-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4976,7 +4976,7 @@ dependencies = [ [[package]] name = "openvm-riscv-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4992,7 +4992,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "alloy-sol-types", "bitcode", @@ -5031,7 +5031,7 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "bon", "cfg-if", @@ -5067,7 +5067,7 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-sha2-guest", "sha2 0.10.9", @@ -5076,7 +5076,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "ndarray", "num_enum", @@ -5090,7 +5090,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5119,7 +5119,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-platform", ] @@ -5127,7 +5127,7 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -5205,7 +5205,7 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "halo2-base", "itertools 0.14.0", @@ -5229,7 +5229,7 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "elf", "eyre", @@ -5244,7 +5244,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "bitcode", "cfg-if", @@ -5274,7 +5274,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-deferral-guest", ] @@ -5282,7 +5282,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "bitcode", "eyre", @@ -5321,7 +5321,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "ecdsa", "elliptic-curve", @@ -7635,7 +7635,7 @@ dependencies = [ [[package]] name = "rvr-openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "openvm-instructions", "openvm-platform", @@ -7649,12 +7649,12 @@ dependencies = [ [[package]] name = "rvr-openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" [[package]] name = "rvr-openvm-ir" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "serde", ] @@ -7662,7 +7662,7 @@ dependencies = [ [[package]] name = "rvr-openvm-lift" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#d193688d7d7af90dd7ce9a4a49e3e820cd8c23f7" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" dependencies = [ "libloading", "openvm-instructions", From 83c6c375f0bde012597706a46ae67d5179c47704 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Wed, 22 Jul 2026 08:31:53 +0800 Subject: [PATCH 05/15] chore: upgrade openvm to develop-v2.1.0 latest (fc1a0001) - Bump openvm (and stark-backend/sdk) to branch develop-v2.1.0 latest. - Bump snark-verifier-sdk to branch develop-v2.1.0 to avoid duplicate snark-verifier / halo2-base / halo2-ecc versions in Cargo.lock. - Rebuild guest assets and refresh commitment files. - Verified: cargo check, test-single-chunk, test-e2e-bundle all pass. --- Cargo.lock | 154 +++++++++--------- Cargo.toml | 8 +- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- 8 files changed, 87 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 059270c4..493e5fff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2744,7 +2744,7 @@ dependencies = [ [[package]] name = "halo2-base" version = "0.5.4" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.4#a69fdee77f41bdd48ad658b69673dea5a0815db4" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=develop-v2.1.0#d59f41ac884d18a985025090a227fa6733398ae8" dependencies = [ "getset", "halo2-axiom", @@ -2764,7 +2764,7 @@ dependencies = [ [[package]] name = "halo2-ecc" version = "0.5.4" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.4#a69fdee77f41bdd48ad658b69673dea5a0815db4" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=develop-v2.1.0#d59f41ac884d18a985025090a227fa6733398ae8" dependencies = [ "halo2-base", "itertools 0.11.0", @@ -3367,7 +3367,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "ecdsa", "elliptic-curve", @@ -3884,7 +3884,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate 3.4.0", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.110", @@ -4092,7 +4092,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4107,7 +4107,7 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "blstrs", "cfg-if", @@ -4143,7 +4143,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-macros-common", "quote", @@ -4153,7 +4153,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "halo2curves-axiom 0.7.3", "num-bigint", @@ -4169,7 +4169,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "num-bigint", "num-prime", @@ -4181,7 +4181,7 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-algebra-guest", "openvm-decoder", @@ -4195,7 +4195,7 @@ dependencies = [ [[package]] name = "openvm-algebra-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "num-bigint", "num-traits", @@ -4205,7 +4205,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "clap", "eyre", @@ -4227,7 +4227,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4241,7 +4241,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4268,7 +4268,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4277,7 +4277,7 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-bigint-guest", "openvm-decoder", @@ -4292,7 +4292,7 @@ dependencies = [ [[package]] name = "openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4304,7 +4304,7 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "backtrace", "bytesize", @@ -4345,7 +4345,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4356,7 +4356,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4376,7 +4376,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4387,7 +4387,7 @@ dependencies = [ [[package]] name = "openvm-codec-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", @@ -4398,7 +4398,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "cfg-if", "derivative", @@ -4430,7 +4430,7 @@ dependencies = [ [[package]] name = "openvm-cpu-backend" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" dependencies = [ "cfg-if", "derive-new 0.7.0", @@ -4455,7 +4455,7 @@ dependencies = [ [[package]] name = "openvm-cuda-backend" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" dependencies = [ "derive-new 0.7.0", "getset", @@ -4482,7 +4482,7 @@ dependencies = [ [[package]] name = "openvm-cuda-builder" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" dependencies = [ "cc", "glob", @@ -4491,7 +4491,7 @@ dependencies = [ [[package]] name = "openvm-cuda-common" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" dependencies = [ "bytesize", "ctor", @@ -4505,7 +4505,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "proc-macro2", "quote", @@ -4515,12 +4515,12 @@ dependencies = [ [[package]] name = "openvm-decoder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" [[package]] name = "openvm-deferral-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "cfg-if", "dashmap", @@ -4550,7 +4550,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4559,7 +4559,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4575,7 +4575,7 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "blstrs", "cfg-if", @@ -4611,7 +4611,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "ecdsa", "elliptic-curve", @@ -4630,7 +4630,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-macros-common", "quote", @@ -4640,7 +4640,7 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-decoder", "openvm-ecc-guest", @@ -4654,7 +4654,7 @@ dependencies = [ [[package]] name = "openvm-instructions" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4671,7 +4671,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "quote", "syn 2.0.110", @@ -4680,7 +4680,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4689,7 +4689,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4717,7 +4717,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-platform", ] @@ -4725,7 +4725,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4739,7 +4739,7 @@ dependencies = [ [[package]] name = "openvm-macros-common" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "syn 2.0.110", ] @@ -4747,7 +4747,7 @@ dependencies = [ [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4765,7 +4765,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.3", @@ -4789,7 +4789,7 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4821,7 +4821,7 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "blstrs", "halo2curves-axiom 0.7.3", @@ -4842,7 +4842,7 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4855,7 +4855,7 @@ dependencies = [ [[package]] name = "openvm-platform" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "libm", "openvm-custom-insn", @@ -4865,7 +4865,7 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "derivative", "lazy_static", @@ -4883,7 +4883,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4911,7 +4911,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "quote", "syn 2.0.110", @@ -4920,7 +4920,7 @@ dependencies = [ [[package]] name = "openvm-riscv-adapters" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4937,7 +4937,7 @@ dependencies = [ [[package]] name = "openvm-riscv-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -4967,7 +4967,7 @@ dependencies = [ [[package]] name = "openvm-riscv-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4976,7 +4976,7 @@ dependencies = [ [[package]] name = "openvm-riscv-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4992,7 +4992,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "alloy-sol-types", "bitcode", @@ -5031,7 +5031,7 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "bon", "cfg-if", @@ -5067,7 +5067,7 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-sha2-guest", "sha2 0.10.9", @@ -5076,7 +5076,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "ndarray", "num_enum", @@ -5090,7 +5090,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "cfg-if", "derive-new 0.6.0", @@ -5119,7 +5119,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-platform", ] @@ -5127,7 +5127,7 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -5141,7 +5141,7 @@ dependencies = [ [[package]] name = "openvm-stark-backend" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" dependencies = [ "cfg-if", "derivative", @@ -5174,7 +5174,7 @@ dependencies = [ [[package]] name = "openvm-stark-sdk" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" dependencies = [ "dashmap", "derive-new 0.7.0", @@ -5205,7 +5205,7 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "halo2-base", "itertools 0.14.0", @@ -5229,7 +5229,7 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "elf", "eyre", @@ -5244,7 +5244,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "bitcode", "cfg-if", @@ -5274,7 +5274,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-deferral-guest", ] @@ -5282,7 +5282,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "bitcode", "eyre", @@ -5321,7 +5321,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "ecdsa", "elliptic-curve", @@ -7635,7 +7635,7 @@ dependencies = [ [[package]] name = "rvr-openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "openvm-instructions", "openvm-platform", @@ -7649,12 +7649,12 @@ dependencies = [ [[package]] name = "rvr-openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" [[package]] name = "rvr-openvm-ir" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "serde", ] @@ -7662,7 +7662,7 @@ dependencies = [ [[package]] name = "rvr-openvm-lift" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#103711322ca7bb7142e1455eb9f288b2b58b743f" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" dependencies = [ "libloading", "openvm-instructions", @@ -8538,7 +8538,7 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "snark-verifier" version = "0.2.6" -source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.6#364e82654c746b063aff528d8cb660890908278a" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?branch=develop-v2.1.0#369f98ff87dbdde689ec576aa9c5fd2609599481" dependencies = [ "halo2-base", "halo2-ecc", @@ -8559,7 +8559,7 @@ dependencies = [ [[package]] name = "snark-verifier-sdk" version = "0.2.6" -source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.6#364e82654c746b063aff528d8cb660890908278a" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?branch=develop-v2.1.0#369f98ff87dbdde689ec576aa9c5fd2609599481" dependencies = [ "ark-std 0.3.0", "bincode 1.3.3", diff --git a/Cargo.toml b/Cargo.toml index 89eb3004..f8e334cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ openvm-recursion-circuit = { git = "https://github.com/openvm-org/openvm.git", b openvm-verify-stark-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } openvm-deferral-circuit = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } -openvm-cuda-backend = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v2.0.0", default-features = false } +openvm-cuda-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2.1.0", default-features = false } openvm-deferral-guest = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } openvm-riscv-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false, features = [ @@ -72,8 +72,8 @@ openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", branch = "devel openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } # more openvm related libs -openvm-stark-backend = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v2.0.0", default-features = false } -openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v2.0.0", default-features = false } +openvm-stark-backend = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2.1.0", default-features = false } +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", branch = "develop-v2.1.0", default-features = false } sbv-core = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2" } sbv-helpers = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2", features = ["dev"] } @@ -120,7 +120,7 @@ serde = { version = "1", default-features = false, features = ["derive"] } serde_json = { version = "1.0" } serde_with = "3.11.0" base64 = "0.22" -snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.2.6", default-features = false, features = [ +snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", branch = "develop-v2.1.0", default-features = false, features = [ "loader_halo2", "display", "revm", diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 2af03321..dd45b669 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [255390656, 841614202, 723072685, 428945948, 1058935670, 1172523134, 659659239, 1036669295]; +pub const COMMIT: [u32; 8] = [115157132, 393572845, 557417739, 79486268, 660343404, 1592314737, 1861383675, 999759017]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index 69c5e497..e79ba768 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1987114624, 804141507, 1994569689, 1169568751, 1595734354, 237628733, 186189138, 793815735]; +pub const COMMIT: [u32; 8] = [384198920, 946911614, 1945276966, 1066991198, 120879595, 1218478975, 1310787160, 671783010]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index a2d366d1..21e88298 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1203227948, 673590627, 566821506, 1414543696, 1000030357, 1132953155, 1921276173, 1587256891]; +pub const COMMIT: [u32; 8] = [1038112378, 124292610, 1512008632, 1365978245, 475241295, 1067078051, 1243399125, 388021491]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index 49b7b44d..17f9a6ba 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1730948446, 592379163, 30730427, 1108807042, 587065798, 698750563, 1595566218, 1990233667]; +pub const COMMIT: [u32; 8] = [1433592467, 651964155, 869916513, 230031791, 1891226614, 1483632017, 1684572596, 1430668087]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index f6a71591..909735cd 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [267779200, 272736994, 569255966, 1032674134, 1018200325, 1908782056, 1594495174, 1244019586]; +pub const COMMIT: [u32; 8] = [676054146, 1044310886, 566210658, 1542994098, 353929751, 556241164, 1828048797, 1104766936]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index 03687fbf..fad8201b 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [88949024, 1187928366, 385523892, 1823125618, 165562023, 109824935, 183750709, 663351380]; +pub const COMMIT: [u32; 8] = [1278216950, 615031465, 469053169, 1209049901, 1697168163, 663367631, 113121555, 917336839]; From 59167b1798c0d6c3321faad0cff8e01ef0f6ffb3 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Mon, 27 Jul 2026 05:09:07 +0000 Subject: [PATCH 06/15] chore: rebuild guest assets and fix v2.1 guest build setup - Rebuild chunk/batch/bundle guest assets against openvm fc1a0001 (previous assets were stale: 'Executor not found for opcode 544'), refreshing exe commitment files. - Dockerfile: install nightly-2026-01-18 host toolchain and cargo-openvm (pinned rev fc1a0001) with the openvm-1.94.1 RV64 guest toolchain; symlink cargo into the custom toolchain (rustup >= 1.29 no longer falls back to the default toolchain's cargo for linked toolchains). - Makefile/AGENTS.md: default OPENVM_RUST_TOOLCHAIN openvm-1.94.0 -> openvm-1.94.1 (what cargo-openvm currently installs). --- AGENTS.md | 12 ++++++------ Dockerfile | 16 +++++++++++----- Makefile | 2 +- .../circuits/batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/bundle-circuit/bundle_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_exe_commit.rs | 2 +- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index df22e4b7..321d348f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,8 +25,8 @@ This project uses **OpenVM `develop-v2.1.0` branch** (RV64 guest toolchain) as i Compared to v2.0.0, the `develop-v2.1.0` branch changes: -- Guest target is now `riscv64im-unknown-openvm-elf` (built into the `openvm-1.94.0` - rust fork toolchain). Guest builds MUST use `OPENVM_RUST_TOOLCHAIN=openvm-1.94.0` +- Guest target is now `riscv64im-unknown-openvm-elf` (built into the `openvm-1.94.1` + rust fork toolchain). Guest builds MUST use `OPENVM_RUST_TOOLCHAIN=openvm-1.94.1` (the default in the Makefile and in `openvm-build`). The old `riscv32im-risc0-zkvm-elf` / `nightly-2025-11-20` combination is gone. - Crate renames: `openvm-rv32im-{guest,transpiler,circuit}` → `openvm-riscv-{guest,transpiler,circuit}`. @@ -72,10 +72,10 @@ To move to a newer OpenVM ref, retarget every `openvm-org/openvm.git` entry in ` 2. **Force-rebuild ALL guest assets** (auto mode skips existing files): ```bash # Local build - OPENVM_RUST_TOOLCHAIN=openvm-1.94.0 cargo run --release -p scroll-zkvm-build-guest -- --mode force + OPENVM_RUST_TOOLCHAIN=openvm-1.94.1 cargo run --release -p scroll-zkvm-build-guest -- --mode force # Docker build (matches CI) - OPENVM_RUST_TOOLCHAIN=openvm-1.94.0 make build-guest + OPENVM_RUST_TOOLCHAIN=openvm-1.94.1 make build-guest ``` This regenerates: `app.elf`, `app.vmexe`, commitment `.rs` files, `agg_vk.bin`, `openVmVk.json`, and the EVM verifier (`verifier.sol` + `verifier.bin`). @@ -134,7 +134,7 @@ This happens when: **Fix**: Regenerate with: ```bash -OPENVM_RUST_TOOLCHAIN=openvm-1.94.0 cargo run --release -p scroll-zkvm-build-guest -- --mode force +OPENVM_RUST_TOOLCHAIN=openvm-1.94.1 cargo run --release -p scroll-zkvm-build-guest -- --mode force ``` (The default `auto` mode will fall back to local generation if the download fails; use `RECOMPUTE_MODE=yes` to force local generation immediately.) @@ -186,7 +186,7 @@ Do **not** reintroduce `sdk.prover()` / `sdk.agg_vk()` calls in read-only (verif # Force rebuild all guest assets (required after OpenVM upgrade). # Default RECOMPUTE_MODE=auto falls back to local generation if the download fails. # Use RECOMPUTE_MODE=yes to skip the download and force local generation. -OPENVM_RUST_TOOLCHAIN=openvm-1.94.0 cargo run --release -p scroll-zkvm-build-guest -- --mode force +OPENVM_RUST_TOOLCHAIN=openvm-1.94.1 cargo run --release -p scroll-zkvm-build-guest -- --mode force # Run end-to-end tests (ALWAYS use make, never raw cargo test) GPU=1 make test-e2e-bundle diff --git a/Dockerfile b/Dockerfile index dff929ec..f28a405d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,11 +2,17 @@ FROM rust:1.93 WORKDIR /app -# Install the nightly toolchain used by openvm-build for guest programs, -# plus the RISC-V target and rust-src needed for -Z build-std. -RUN rustup toolchain install nightly-2025-11-20 && \ - rustup target add --toolchain nightly-2025-11-20 riscv32im-unknown-none-elf && \ - rustup component add --toolchain nightly-2025-11-20 rust-src llvm-tools rustc-dev +# Host toolchain required by rust-toolchain.toml (openvm-sdk "tco" feature). +RUN rustup toolchain install nightly-2026-01-18 && \ + rustup component add --toolchain nightly-2026-01-18 llvm-tools rustc-dev + +# cargo-openvm CLI from the pinned OpenVM rev, plus the RV64 guest toolchain +# (installs the `openvm-1.94.1` rustup toolchain used by openvm-build). +RUN cargo install --locked --git https://github.com/openvm-org/openvm.git --rev fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce cargo-openvm && \ + cargo openvm toolchain install && \ + ln -s "$(rustup which cargo)" "$(dirname "$(rustup +openvm-1.94.1 which rustc)")/cargo" + +ENV OPENVM_RUST_TOOLCHAIN=openvm-1.94.1 RUN wget https://github.com/ethereum/solc-bin/raw/refs/heads/gh-pages/linux-amd64/solc-linux-amd64-v0.8.19+commit.7dd6d404 -O /usr/local/bin/solc && \ chmod +x /usr/local/bin/solc diff --git a/Makefile b/Makefile index cf937ec8..35c805b9 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ export RUST_BACKTRACE RUST_LOG ?= off,scroll_zkvm_integration=debug,scroll_zkvm_verifier=debug,scroll_zkvm_prover=debug,p3_fri=warn,p3_dft=warn,openvm_circuit=warn export RUST_LOG -OPENVM_RUST_TOOLCHAIN ?= openvm-1.94.0 +OPENVM_RUST_TOOLCHAIN ?= openvm-1.94.1 export OPENVM_RUST_TOOLCHAIN # Set GPU config if GPU=1 is set diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index dd45b669..01281358 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [115157132, 393572845, 557417739, 79486268, 660343404, 1592314737, 1861383675, 999759017]; +pub const COMMIT: [u32; 8] = [489474824, 200779855, 2004723502, 648032708, 1886949501, 1969061570, 587725836, 813210780]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 21e88298..7b2bed94 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1038112378, 124292610, 1512008632, 1365978245, 475241295, 1067078051, 1243399125, 388021491]; +pub const COMMIT: [u32; 8] = [720267250, 951746208, 1115812520, 149247792, 56768113, 781771991, 8710599, 1047779014]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 909735cd..c0480c9b 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [676054146, 1044310886, 566210658, 1542994098, 353929751, 556241164, 1828048797, 1104766936]; +pub const COMMIT: [u32; 8] = [824638038, 1065949766, 533757489, 39260798, 286314453, 1346905579, 324834474, 290220891]; From 02bb5a7815962c41fad31fdd2834ba1f5b416481 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Wed, 12 Aug 2026 13:01:53 +0800 Subject: [PATCH 07/15] chore: upgrade openvm to develop-v2.1.0 (b3c95cd0) Pin openvm/stark-backend to develop-v2.1.0 commit b3c95cd0. The true latest (a935d8b3d) is not usable yet: its new "sparse initial memory snapshot and GPU Merkle build" asserts on DEFERRAL_AS being touched with num_cells=0 during the bundle root/SNARK stage, because the SDK's compute_root_proof_heights builds a deferral=None root config whose apply_optimizations zeroes DEFERRAL_AS. b3c95cd0 is the newest commit that passes the full GPU suite. Changes needed for this range of develop-v2.1.0: - Add patches/openvm-mem override (via [patch] on the openvm git source). Upstream openvm-mem copy_forward/copy_backward use 64-byte aggregate copies (load::<64>/store::<64>) that LLVM lowers back into memmove calls, making memmove recurse until the guest stack wraps ("upper 4 bytes must be zero"). The override does block copies with 8x u64 loads-then-stores. - Upstream restored byte-sized user public values (1 byte per cell). Update verify_proof, pi_hash_to_public_values, and aggregated_pi_hashes in batch/bundle circuits to match, and drop the now-obsolete patch_verifier_for_u16_public_values workaround. - setup.rs: VmExe gained cfg_block_starts; default it in the old-format fallback path. - Rebuild guest assets, commitments, and EVM verifier. Verified on GPU: test-execute-chunk, test-single-chunk, test-e2e-bundle all pass. --- AGENTS.md | 59 ++- Cargo.lock | 168 +++++---- Cargo.toml | 6 + crates/build-guest/src/main.rs | 58 +-- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- crates/circuits/batch-circuit/src/circuit.rs | 10 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- crates/circuits/bundle-circuit/src/circuit.rs | 10 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- crates/integration/src/utils/mod.rs | 9 +- crates/prover/src/setup.rs | 1 + crates/types/circuit/src/lib.rs | 11 +- patches/openvm-mem/Cargo.toml | 7 + patches/openvm-mem/src/lib.rs | 344 ++++++++++++++++++ patches/openvm-mem/src/tests.rs | 124 +++++++ releases/dev/verifier/verifier.bin | Bin 19824 -> 19781 bytes releases/dev/verifier/verifier.sol | 11 +- 20 files changed, 650 insertions(+), 180 deletions(-) create mode 100644 patches/openvm-mem/Cargo.toml create mode 100644 patches/openvm-mem/src/lib.rs create mode 100644 patches/openvm-mem/src/tests.rs diff --git a/AGENTS.md b/AGENTS.md index 321d348f..11933ac9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,18 +36,11 @@ Compared to v2.0.0, the `develop-v2.1.0` branch changes: first, then `sdk.execute(&compiled, ...)` / `sdk.execute_metered_cost(&compiled, ...)`. - Hint stream words are 8 bytes: `hint_store_u32!` → `hint_store_u64!` / `hint_buffer_chunked`, and the hint-stream length prefix is a `u64`. -- User public values are **u16 cells** (2 little-endian bytes per cell) instead of - 1 byte per u32 cell. `NUM_PUBLIC_VALUES` is still 32 cells (= 64 bytes); the - 32-byte pi hash fills the first 16 cells. +- User public values are **single bytes** (1 byte per cell, stored in the low byte + of a u32 field element). `NUM_PUBLIC_VALUES` is 32 cells (= 32 bytes); the + 32-byte pi hash fills all 32 cells. (Earlier v2.1.0 snapshots used u16 cells; + upstream restored byte-sized public values in commit `b3c95cd00`.) - Guest cfg gates: `target_os = "zkvm"` → `target_os = "openvm"`. -- ⚠️ **EVM verifier template bug on this branch**: the SDK packs user public - values as 2 LE bytes per u16 cell in `verifier_calldata`, but the Solidity - template (`crates/sdk/contracts/template/OpenVmHalo2Verifier.sol`) still - expects 1 byte per PV, causing `InvalidPublicValuesLength` reverts. - `crates/build-guest/src/main.rs::patch_verifier_for_u16_public_values` - rewrites the locally generated wrapper to accept 2 bytes per cell. If that - function errors with "template fragment not found", upstream has changed the - template — review whether the patch is still needed. - Host toolchain: `rust-toolchain.toml` uses `nightly-2026-01-18` (required by the openvm-sdk `tco` feature). @@ -146,6 +139,36 @@ OPENVM_RUST_TOOLCHAIN=openvm-1.94.1 cargo run --release -p scroll-zkvm-build-gue ### Docker build fails with stale CID The `build-guest.sh` script may fail if a stale `build-guest.cid` file exists. Use local build (`cargo run -p scroll-zkvm-build-guest`) as fallback. +### Guest crashes with `upper 4 bytes must be zero` (TryFromIntError) in store/addi +**Symptoms**: `test-execute-chunk` / proving panics in `openvm_riscv_circuit` with a +register holding `0xfffffffffffffe60` (=-416) or similar sign-extended garbage, and the +stack pointer walks down by a fixed stride (e.g. 416) until it wraps. +**Cause**: Upstream `openvm-mem` (introduced in commit `d664effb1`, "use rust native +memory intrinsics") implements `copy_forward`/`copy_backward` with 64-byte aggregate +copies (`load::<64>`/`store::<64>`). LLVM lowers those aggregate copies into calls to +`memmove`, which makes `memmove` recursively call itself and overflow the guest stack. +**Fix**: We ship a local override at `patches/openvm-mem` (wired via +`[patch."https://github.com/openvm-org/openvm.git"]` in `Cargo.toml`) that does the +block copies with 8× `u64` loads-then-stores instead of one 64-byte aggregate. If you +bump OpenVM and upstream fixes `openvm-mem`, delete the `[patch]` entry and the +`patches/openvm-mem` directory. + +### `subtree size exceeds the address space's configured leaf count` (bundle root/SNARK) +**Symptoms**: `test-e2e-bundle` fails during `gen_proof_snark` (the Halo2 wrap of the +bundle root proof) with this assert from +`crates/vm/src/system/cuda/merkle_tree/mod.rs`, for `DEFERRAL_AS` (address space 4) +with `num_cells=0`. +**Cause**: OpenVM commit `a935d8b3d` ("perf: sparse initial memory snapshot and GPU +Merkle build") added a strict leaf-count assert. The SDK's `compute_root_proof_heights` +builds the root config from a default `AppConfig::riscv64` (which has `deferral=None`), +so `apply_optimizations` zeroes `DEFERRAL_AS.num_cells` — but deferral is actually +active and the root proof touches that address space. This is an upstream SDK +inconsistency the new assert exposes. +**Fix**: We currently pin OpenVM to `b3c95cd00` (the commit just before `a935d8b3d`), +which does not have the GPU Merkle build. To move to `a935d8b3d` or later you must patch +`openvm-sdk` so the root-prover config keeps `DEFERRAL_AS` allocated (or wait for an +upstream fix). + ## GPU Features Two levels of GPU acceleration exist, wired as cargo features: @@ -208,6 +231,20 @@ can waste hours of CPU time. Always run it as: cargo test --release -p scroll-zkvm-build-guest test_verifier ``` +### RVR native execution toolchain (currently disabled) + +The optional `rvr` feature of `openvm-sdk` compiles guest code to native C at runtime for +faster execution. It is **not** enabled in `Cargo.toml` by default (the default path uses +the interpreter, which is slower but well-tested). If you enable it, you need +**LLVM clang-22 + lld-22** on the host: + +- Set `RVR_CC=clang-22` and `RVR_LD=lld` (or `RVR_LD=ld.lld`) when running tests. +- If the system clang is older, install clang-22/lld-22 via conda-forge and put it on `PATH`: + ```bash + mamba install -y -c conda-forge clang=22 lld=22 llvm=22 + PATH="/home/scroll/miniforge3/bin:$PATH" RVR_CC=clang-22 RVR_LD=lld GPU=1 make test-single-chunk + ``` + ## Deferral Model (OpenVM v2+) OpenVM v2 replaces the traditional root-verifier recursion with a **deferred compute model**: diff --git a/Cargo.lock b/Cargo.lock index 132c1f0a..f82b7513 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3490,7 +3490,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "ecdsa", "elliptic-curve", @@ -4007,7 +4007,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "syn 2.0.110", @@ -4215,13 +4215,14 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "bytemuck", "getrandom 0.2.16", "getrandom 0.3.4", "num-bigint", "openvm-custom-insn", + "openvm-mem", "openvm-platform", "openvm-riscv-guest", "serde", @@ -4230,7 +4231,7 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "blstrs", "cfg-if 1.0.4", @@ -4249,6 +4250,7 @@ dependencies = [ "openvm-circuit-primitives-derive", "openvm-cpu-backend", "openvm-cuda-backend", + "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", "openvm-mod-circuit-builder", @@ -4266,7 +4268,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-macros-common", "quote", @@ -4276,7 +4278,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "halo2curves-axiom 0.7.3", "num-bigint", @@ -4292,7 +4294,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "num-bigint", "num-prime", @@ -4304,7 +4306,7 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-algebra-guest", "openvm-decoder", @@ -4318,7 +4320,7 @@ dependencies = [ [[package]] name = "openvm-algebra-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "num-bigint", "num-traits", @@ -4328,7 +4330,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "clap", "eyre", @@ -4350,7 +4352,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4364,7 +4366,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "cfg-if 1.0.4", "derive-new 0.6.0", @@ -4391,7 +4393,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4400,7 +4402,7 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-bigint-guest", "openvm-decoder", @@ -4415,7 +4417,7 @@ dependencies = [ [[package]] name = "openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4427,9 +4429,10 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "backtrace", + "bytemuck", "bytesize", "cfg-if 1.0.4", "dashmap", @@ -4458,6 +4461,7 @@ dependencies = [ "rand 0.9.4", "rustc-hash 2.1.1", "rvr-openvm", + "rvr-state", "serde", "serde-big-array", "static_assertions", @@ -4468,7 +4472,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4479,7 +4483,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4499,7 +4503,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4510,7 +4514,7 @@ dependencies = [ [[package]] name = "openvm-codec-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#be2b6983cbd70976b37acbb72ceb1b3593dc67ae" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", @@ -4521,7 +4525,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "cfg-if 1.0.4", "derivative", @@ -4553,7 +4557,7 @@ dependencies = [ [[package]] name = "openvm-cpu-backend" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#be2b6983cbd70976b37acbb72ceb1b3593dc67ae" dependencies = [ "cfg-if 1.0.4", "derive-new 0.7.0", @@ -4578,7 +4582,7 @@ dependencies = [ [[package]] name = "openvm-cuda-backend" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#be2b6983cbd70976b37acbb72ceb1b3593dc67ae" dependencies = [ "derive-new 0.7.0", "getset", @@ -4605,7 +4609,7 @@ dependencies = [ [[package]] name = "openvm-cuda-builder" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#be2b6983cbd70976b37acbb72ceb1b3593dc67ae" dependencies = [ "cc", "glob", @@ -4614,7 +4618,7 @@ dependencies = [ [[package]] name = "openvm-cuda-common" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#be2b6983cbd70976b37acbb72ceb1b3593dc67ae" dependencies = [ "bytesize", "ctor", @@ -4628,7 +4632,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "proc-macro2", "quote", @@ -4638,12 +4642,12 @@ dependencies = [ [[package]] name = "openvm-decoder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" [[package]] name = "openvm-deferral-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "cfg-if 1.0.4", "dashmap", @@ -4673,7 +4677,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4682,7 +4686,7 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "eyre", "openvm-deferral-guest", @@ -4698,7 +4702,7 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "blstrs", "cfg-if 1.0.4", @@ -4734,7 +4738,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "ecdsa", "elliptic-curve", @@ -4753,7 +4757,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-macros-common", "quote", @@ -4763,7 +4767,7 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-decoder", "openvm-ecc-guest", @@ -4777,7 +4781,7 @@ dependencies = [ [[package]] name = "openvm-instructions" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4794,7 +4798,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "quote", "syn 2.0.110", @@ -4803,7 +4807,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4812,7 +4816,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4840,7 +4844,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-platform", ] @@ -4848,7 +4852,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4862,22 +4866,25 @@ dependencies = [ [[package]] name = "openvm-macros-common" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "syn 2.0.110", ] +[[package]] +name = "openvm-mem" +version = "2.0.0" + [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "itertools 0.14.0", "num-bigint", "num-traits", "openvm-circuit", "openvm-circuit-primitives", - "openvm-instructions", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.8.6", @@ -4888,7 +4895,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.3", @@ -4912,7 +4919,7 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "cfg-if 1.0.4", "derive-new 0.6.0", @@ -4944,9 +4951,9 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ - "blstrs", + "blst", "halo2curves-axiom 0.7.3", "hex-literal 1.1.0", "itertools 0.14.0", @@ -4965,7 +4972,7 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -4978,7 +4985,7 @@ dependencies = [ [[package]] name = "openvm-platform" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "libm", "openvm-custom-insn", @@ -4988,7 +4995,7 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "derivative", "lazy_static", @@ -5006,7 +5013,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5034,7 +5041,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "quote", "syn 2.0.110", @@ -5043,7 +5050,7 @@ dependencies = [ [[package]] name = "openvm-riscv-adapters" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5060,7 +5067,7 @@ dependencies = [ [[package]] name = "openvm-riscv-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "cfg-if 1.0.4", "derive-new 0.6.0", @@ -5090,7 +5097,7 @@ dependencies = [ [[package]] name = "openvm-riscv-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -5099,7 +5106,7 @@ dependencies = [ [[package]] name = "openvm-riscv-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -5115,7 +5122,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "alloy-sol-types", "bitcode", @@ -5154,7 +5161,7 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "bon", "cfg-if 1.0.4", @@ -5185,12 +5192,13 @@ dependencies = [ "openvm-verify-stark-circuit", "serde", "toml", + "tracing", ] [[package]] name = "openvm-sha2" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-sha2-guest", "sha2 0.10.9", @@ -5199,7 +5207,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "ndarray", "num_enum", @@ -5213,7 +5221,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "cfg-if 1.0.4", "derive-new 0.6.0", @@ -5242,7 +5250,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-platform", ] @@ -5250,7 +5258,7 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-decoder", "openvm-instructions", @@ -5264,7 +5272,7 @@ dependencies = [ [[package]] name = "openvm-stark-backend" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#be2b6983cbd70976b37acbb72ceb1b3593dc67ae" dependencies = [ "cfg-if 1.0.4", "derivative", @@ -5297,7 +5305,7 @@ dependencies = [ [[package]] name = "openvm-stark-sdk" version = "2.0.0" -source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#7a425b64a7f037da3ee642f0dc7128494e2f458b" +source = "git+https://github.com/openvm-org/stark-backend.git?branch=develop-v2.1.0#be2b6983cbd70976b37acbb72ceb1b3593dc67ae" dependencies = [ "dashmap", "derive-new 0.7.0", @@ -5328,7 +5336,7 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "halo2-base", "itertools 0.14.0", @@ -5352,7 +5360,7 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "elf", "eyre", @@ -5367,7 +5375,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "bitcode", "cfg-if 1.0.4", @@ -5397,7 +5405,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-deferral-guest", ] @@ -5405,7 +5413,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "bitcode", "eyre", @@ -5444,7 +5452,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "ecdsa", "elliptic-curve", @@ -7787,26 +7795,26 @@ dependencies = [ [[package]] name = "rvr-openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "openvm-instructions", "openvm-platform", - "openvm-riscv-guest", "rvr-openvm-build", "rvr-openvm-ir", "rvr-openvm-lift", + "rvr-state", "thiserror 1.0.69", ] [[package]] name = "rvr-openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" [[package]] name = "rvr-openvm-ir" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "serde", ] @@ -7814,16 +7822,22 @@ dependencies = [ [[package]] name = "rvr-openvm-lift" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#fc1a0001e63d5685fb40c1ffb10c6ce0d55677ce" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" dependencies = [ "libloading", "openvm-instructions", - "openvm-riscv-transpiler", "openvm-stark-backend", + "rustc-hash 2.1.1", "rvr-openvm-ir", "thiserror 1.0.69", + "tracing", ] +[[package]] +name = "rvr-state" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" + [[package]] name = "ryu" version = "1.0.20" diff --git a/Cargo.toml b/Cargo.toml index f8e334cd..9fb6cc16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -162,6 +162,12 @@ revm-precompile = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v revm-primitives = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" } revm-state = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" } +# openvm-mem's copy_forward/copy_backward use 64-byte aggregate copies that LLVM lowers +# into `memmove` calls, making `memmove` recurse until the guest stack overflows. +# Override with a local copy that uses u64 chunks instead. See patches/openvm-mem. +[patch."https://github.com/openvm-org/openvm.git"] +openvm-mem = { path = "patches/openvm-mem" } + [profile.maxperf] inherits = "release" lto = "fat" diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index 17973bec..4b6f40d8 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -485,62 +485,14 @@ pub fn build_evm_verifier( let app_params = app_params_with_100_bits_security(MAX_APP_LOG_STACKED_HEIGHT); let agg_params = default_agg_params(); let sdk = build_recompute_sdk(release_output_dir, &app_params, &agg_params)?; - let mut verifier = sdk.generate_halo2_verifier_solidity()?; - verifier.openvm_verifier_code = - patch_verifier_for_u16_public_values(&verifier.openvm_verifier_code)?; - // The SDK compiled the artifact bytecode from the *unpatched* source. - // Clear it so `write_evm_verifier_artifacts` recompiles with solc from - // the patched verifier.sol written to disk. - verifier.artifact.bytecode = Vec::new(); + let verifier = sdk.generate_halo2_verifier_solidity()?; + // NOTE: as of openvm develop-v2.1.0 (commit b3c95cd00 "restore byte-sized + // public values"), user public values are single bytes again, matching the + // SDK's Solidity template. The previous u16-cell workaround + // (patch_verifier_for_u16_public_values) is no longer applied. Ok((sdk, verifier)) } -/// Patch the locally generated `OpenVmHalo2Verifier.sol` for u16 public values. -/// -/// On the `develop-v2.1.0` branch, user public values are u16 cells (2 bytes -/// each), and the SDK packs them as 2 little-endian bytes per cell in -/// `EvmProof::verifier_calldata`. The Solidity template on this branch still -/// expects 1 byte per public value, so the generated wrapper reverts with -/// `InvalidPublicValuesLength`. Until upstream updates the template, rewrite -/// the generated wrapper to: -/// -/// - accept `2 * PUBLIC_VALUES_LENGTH` calldata bytes, and -/// - expand each u16 cell (little-endian in calldata) into a big-endian -/// `bytes32` word. -/// -/// Fails loudly if the expected template fragments are not found, so we notice -/// when upstream changes the template (e.g. ships a proper u16 fix). -fn patch_verifier_for_u16_public_values(sol_code: &str) -> Result { - const OLD_LEN_CHECK: &str = "if (publicValues.length != PUBLIC_VALUES_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length);"; - const NEW_LEN_CHECK: &str = "if (publicValues.length != PUBLIC_VALUES_LENGTH * 2) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH * 2, publicValues.length);"; - const OLD_LOOP: &str = " // Copy each byte of the public values into the proof. It copies the - // most significant bytes of public values first. - let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) - for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { - calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01) - }"; - const NEW_LOOP: &str = " // Copy each u16 public value cell into its own bytes32 word. The - // calldata packs each cell as 2 little-endian bytes; the word is - // big-endian, so the low byte lands at offset 0x1f and the high - // byte at 0x1e of each word. - let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) - for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { - calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, shl(1, i)), 0x01) - calldatacopy(sub(add(publicValuesMemOffset, shl(5, i)), 1), add(add(publicValues.offset, shl(1, i)), 1), 0x01) - }"; - - let mut patched = sol_code.to_string(); - for (old, new) in [(OLD_LEN_CHECK, NEW_LEN_CHECK), (OLD_LOOP, NEW_LOOP)] { - if !patched.contains(old) { - return Err(eyre::eyre!( - "verifier template fragment not found; upstream may have changed the OpenVmHalo2Verifier template (u16 public values patch needs review)" - )); - } - patched = patched.replace(old, new); - } - Ok(patched) -} - fn write_evm_verifier_artifacts( verifier_output_dir: &Path, verifier: &openvm_sdk::types::EvmHalo2Verifier, diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 01281358..e8a10c3b 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [489474824, 200779855, 2004723502, 648032708, 1886949501, 1969061570, 587725836, 813210780]; +pub const COMMIT: [u32; 8] = [139929666, 753896685, 1853904564, 1388310222, 487550726, 758710732, 1810988145, 429452358]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index e79ba768..9c520f01 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [384198920, 946911614, 1945276966, 1066991198, 120879595, 1218478975, 1310787160, 671783010]; +pub const COMMIT: [u32; 8] = [746377549, 1162918801, 1051540790, 1928041030, 152070805, 1113647181, 1968697469, 1593844187]; diff --git a/crates/circuits/batch-circuit/src/circuit.rs b/crates/circuits/batch-circuit/src/circuit.rs index 4e93351f..3ef4a6b1 100644 --- a/crates/circuits/batch-circuit/src/circuit.rs +++ b/crates/circuits/batch-circuit/src/circuit.rs @@ -86,17 +86,13 @@ impl AggCircuit for BatchCircuit { proofs .iter() .map(|proof| { - // Each public value is a u16 cell (2 bytes, little-endian); the - // pi hash occupies the first 32 bytes (16 cells). + // Each public value cell is a single byte; the pi hash occupies all + // 32 cells. let transformed = proof .public_values .iter() - .flat_map(|&val| { - u16::try_from(val) - .expect("public value fits in u16") - .to_le_bytes() - }) .take(32) + .map(|&val| val as u8) .collect::>(); B256::from_slice(transformed.as_slice()) }) diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 7b2bed94..ac926dfc 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [720267250, 951746208, 1115812520, 149247792, 56768113, 781771991, 8710599, 1047779014]; +pub const COMMIT: [u32; 8] = [1517974075, 589154344, 1786735536, 153963703, 1152034845, 1004578779, 1107563189, 1187609870]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index 17f9a6ba..59906747 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1433592467, 651964155, 869916513, 230031791, 1891226614, 1483632017, 1684572596, 1430668087]; +pub const COMMIT: [u32; 8] = [210058995, 1094759752, 632338706, 1021800370, 639104907, 1560970220, 929526493, 1399681357]; diff --git a/crates/circuits/bundle-circuit/src/circuit.rs b/crates/circuits/bundle-circuit/src/circuit.rs index 00b17cfc..721b6516 100644 --- a/crates/circuits/bundle-circuit/src/circuit.rs +++ b/crates/circuits/bundle-circuit/src/circuit.rs @@ -79,17 +79,13 @@ impl AggCircuit for BundleCircuit { proofs .iter() .map(|proof| { - // Each public value is a u16 cell (2 bytes, little-endian); the - // pi hash occupies the first 32 bytes (16 cells). + // Each public value cell is a single byte; the pi hash occupies all + // 32 cells. let transformed = proof .public_values .iter() - .flat_map(|&val| { - u16::try_from(val) - .expect("public value fits in u16") - .to_le_bytes() - }) .take(32) + .map(|&val| val as u8) .collect::>(); B256::from_slice(transformed.as_slice()) }) diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index c0480c9b..8858c6ea 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [824638038, 1065949766, 533757489, 39260798, 286314453, 1346905579, 324834474, 290220891]; +pub const COMMIT: [u32; 8] = [36604511, 758201064, 1447719550, 1099084240, 611083294, 1279007169, 1209336150, 1688379479]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index fad8201b..c4c2cdfa 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1278216950, 615031465, 469053169, 1209049901, 1697168163, 663367631, 113121555, 917336839]; +pub const COMMIT: [u32; 8] = [1968976531, 846168655, 1173672047, 1954338880, 1456456415, 656306742, 1613486240, 941152904]; diff --git a/crates/integration/src/utils/mod.rs b/crates/integration/src/utils/mod.rs index bc94393c..10da355e 100644 --- a/crates/integration/src/utils/mod.rs +++ b/crates/integration/src/utils/mod.rs @@ -40,14 +40,13 @@ fn blks_tx_bytes<'a>(blks: impl Iterator) -> Vec { }) } -/// Encode a 32-byte pi hash as OpenVM public values: each public value is a -/// u16 cell (2 little-endian bytes), so the hash fills the first 16 cells and -/// the remaining cells (up to `NUM_PUBLIC_VALUES`) are zero. +/// Encode a 32-byte pi hash as OpenVM public values: each public value cell is a +/// single byte, so the 32-byte hash fills all `NUM_PUBLIC_VALUES` (32) cells. pub(crate) fn pi_hash_to_public_values(pi_hash: &B256) -> Vec { let mut public_values = pi_hash .as_slice() - .chunks_exact(2) - .map(|c| u16::from_le_bytes([c[0], c[1]]) as u32) + .iter() + .map(|&b| b as u32) .collect::>(); public_values.resize(scroll_zkvm_types::types_agg::NUM_PUBLIC_VALUES, 0); public_values diff --git a/crates/prover/src/setup.rs b/crates/prover/src/setup.rs index 4187cb70..4e80d953 100644 --- a/crates/prover/src/setup.rs +++ b/crates/prover/src/setup.rs @@ -80,6 +80,7 @@ pub fn read_app_exe>(path: P) -> Result, Error> { }) .collect(), fn_bounds: old_exe.fn_bounds, + cfg_block_starts: Default::default(), }; Ok(exe) } diff --git a/crates/types/circuit/src/lib.rs b/crates/types/circuit/src/lib.rs index 30f9e9ca..0ae9195e 100644 --- a/crates/types/circuit/src/lib.rs +++ b/crates/types/circuit/src/lib.rs @@ -142,16 +142,13 @@ fn verify_proof(commitment: &ProgramCommitment, public_inputs: &[u32], input_com // Sanity check for the number of public-input values. assert_eq!(public_inputs.len(), NUM_PUBLIC_VALUES); - // OpenVM stores each user public value as a u16 cell in a 32-bit field - // element; the verify-stark guest helper collapses them back to dense - // bytes (2 little-endian bytes per cell). + // OpenVM stores each user public value as a single byte in the low byte of a + // 32-bit field element; the verify-stark guest helper collapses them back to + // dense bytes (1 byte per cell). let expected = ProofOutput { app_exe_commit: u32_array_to_commit(&commitment.exe), app_vm_commit: u32_array_to_commit(&commitment.vm), - user_public_values: public_inputs - .iter() - .flat_map(|&w| (w as u16).to_le_bytes()) - .collect(), + user_public_values: public_inputs.iter().map(|&w| w as u8).collect(), }; verify_stark::<0>(input_commit, &expected); diff --git a/patches/openvm-mem/Cargo.toml b/patches/openvm-mem/Cargo.toml new file mode 100644 index 00000000..c23190ac --- /dev/null +++ b/patches/openvm-mem/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "openvm-mem" +description = "libc memory intrinsics (memcpy, memset, memmove, memcmp, bcmp) for OpenVM guest programs." +version = "2.0.0" +edition = "2021" + +[lints] diff --git a/patches/openvm-mem/src/lib.rs b/patches/openvm-mem/src/lib.rs new file mode 100644 index 00000000..ec1f16dd --- /dev/null +++ b/patches/openvm-mem/src/lib.rs @@ -0,0 +1,344 @@ +//! libc memory intrinsics for OpenVM guest programs. +//! +//! OpenVM costs a misaligned load or store the same as an aligned one, and the guest target +//! enables `+unaligned-scalar-mem`. A conventional libc spends most of its complexity avoiding +//! misaligned access, and all of that is wasted work here, so these implementations do no +//! alignment work at all: they issue 8-byte accesses at whatever address they are given and cover +//! short runs with overlapping moves rather than byte loops. +//! +//! `#![no_builtins]` keeps LLVM's loop-idiom pass from lowering the loops here back into calls to +//! the very symbols they define. It is scoped to this crate so the rest of the guest still gets +//! normal libcall recognition. + +#![cfg(any(test, openvm_intrinsics, target_os = "openvm"))] +#![no_std] +#![no_builtins] + +/// Bytes moved per iteration of the bulk loops. +const BLOCK: usize = 64; + +#[inline(always)] +unsafe fn load(src: *const u8) -> [u8; N] { + (src as *const [u8; N]).read() +} + +#[inline(always)] +unsafe fn store(dest: *mut u8, val: [u8; N]) { + (dest as *mut [u8; N]).write(val) +} + +/// Scalar accessors. Values are kept in registers, unlike byte arrays wide enough to spill. +macro_rules! scalar_accessors { + ($read:ident, $write:ident, $t:ty) => { + #[inline(always)] + unsafe fn $read(src: *const u8) -> $t { + <$t>::from_ne_bytes(load::<{ core::mem::size_of::<$t>() }>(src)) + } + #[inline(always)] + unsafe fn $write(dest: *mut u8, val: $t) { + store::<{ core::mem::size_of::<$t>() }>(dest, val.to_ne_bytes()) + } + }; +} +scalar_accessors!(read_u64, write_u64, u64); +scalar_accessors!(read_u32, write_u32, u32); +scalar_accessors!(read_u16, write_u16, u16); + +/// Copies the first and last `WORDS * 8` bytes of an `n`-byte range, which together cover it when +/// `n <= WORDS * 16`. +/// +/// Every load is issued before any store, so this stays correct when the ranges overlap: the two +/// runs together read exactly the bytes they go on to write. `WORDS` is a constant, so the loops +/// unroll and the values stay in registers. +#[inline(always)] +unsafe fn copy_overlapping(dest: *mut u8, src: *const u8, n: usize) { + let back = n - WORDS * 8; + let mut head = [0u64; WORDS]; + let mut tail = [0u64; WORDS]; + let mut i = 0; + while i < WORDS { + head[i] = read_u64(src.add(i * 8)); + tail[i] = read_u64(src.add(back + i * 8)); + i += 1; + } + i = 0; + while i < WORDS { + write_u64(dest.add(i * 8), head[i]); + write_u64(dest.add(back + i * 8), tail[i]); + i += 1; + } +} + +/// Copies `n < BLOCK` bytes using two overlapping runs of same-width moves. +#[inline(always)] +unsafe fn copy_tail(dest: *mut u8, src: *const u8, n: usize) { + if n >= 32 { + copy_overlapping::<4>(dest, src, n); + } else if n >= 16 { + copy_overlapping::<2>(dest, src, n); + } else if n >= 8 { + copy_overlapping::<1>(dest, src, n); + } else if n >= 4 { + let (a, b) = (read_u32(src), read_u32(src.add(n - 4))); + write_u32(dest, a); + write_u32(dest.add(n - 4), b); + } else if n >= 2 { + let (a, b) = (read_u16(src), read_u16(src.add(n - 2))); + write_u16(dest, a); + write_u16(dest.add(n - 2), b); + } else if n == 1 { + *dest = *src; + } +} + +/// Copies low addresses first. +/// +/// # Safety +/// +/// `src` must be valid for reads of `n` bytes and `dest` valid for writes of `n` bytes. The +/// ranges may overlap only when `dest <= src`. +#[inline(always)] +unsafe fn copy_forward(dest: *mut u8, src: *const u8, n: usize) { + let (mut dest, mut src, mut rem) = (dest, src, n); + while rem >= BLOCK { + // Load all words into registers before storing, matching the original + // load-then-store ordering. u64 accesses avoid LLVM lowering the 64-byte + // aggregate copy into a `memmove` call (which would recurse into us). + let mut buf = [0u64; BLOCK / 8]; + let mut i = 0; + while i < BLOCK / 8 { + buf[i] = read_u64(src.add(i * 8)); + i += 1; + } + i = 0; + while i < BLOCK / 8 { + write_u64(dest.add(i * 8), buf[i]); + i += 1; + } + dest = dest.add(BLOCK); + src = src.add(BLOCK); + rem -= BLOCK; + } + copy_tail(dest, src, rem); +} + +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[no_mangle] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + copy_forward(dest, src, n); + dest +} + +/// Copies high addresses first. +/// +/// # Safety +/// +/// `src` must be valid for reads of `n` bytes and `dest` valid for writes of `n` bytes. The +/// ranges may overlap only when `dest >= src`; use [`copy_forward`] otherwise. +#[inline(always)] +unsafe fn copy_backward(dest: *mut u8, src: *const u8, n: usize) { + let mut rem = n; + while rem >= BLOCK { + rem -= BLOCK; + // See copy_forward: keep loads before stores with u64 accesses to avoid an + // aggregate-copy-to-`memmove` lowering that would recurse. + let mut buf = [0u64; BLOCK / 8]; + let mut i = 0; + while i < BLOCK / 8 { + buf[i] = read_u64(src.add(rem + i * 8)); + i += 1; + } + i = 0; + while i < BLOCK / 8 { + write_u64(dest.add(rem + i * 8), buf[i]); + i += 1; + } + } + // Everything still unwritten lives below `rem`, and `copy_tail` loads before it stores. + copy_tail(dest, src, rem); +} + +/// Copies `n` bytes, choosing a direction that tolerates overlap. +/// +/// # Safety +/// +/// `src` must be valid for reads of `n` bytes and `dest` valid for writes of `n` bytes. +#[inline(always)] +unsafe fn move_bytes(dest: *mut u8, src: *const u8, n: usize) { + // Copying upwards is safe unless `dest` starts inside the source range. The wrapping + // subtraction folds `dest < src` into the same comparison: it underflows past any real `n`. + if (dest as usize).wrapping_sub(src as usize) >= n { + copy_forward(dest, src, n); + } else { + copy_backward(dest, src, n); + } +} + +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[no_mangle] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + move_bytes(dest, src, n); + dest +} + +/// Writes `WORDS` words at `dest` and `WORDS` more ending at `dest + n`. +#[inline(always)] +unsafe fn set_overlapping(dest: *mut u8, word: u64, n: usize) { + let back = n - WORDS * 8; + let mut i = 0; + while i < WORDS { + write_u64(dest.add(i * 8), word); + write_u64(dest.add(back + i * 8), word); + i += 1; + } +} + +/// Writes `n < BLOCK` copies of `word`'s low byte using two overlapping runs of stores. +/// +/// Overlapping stores of the same value are idempotent, so no ordering care is needed. +#[inline(always)] +unsafe fn set_tail(dest: *mut u8, word: u64, n: usize) { + if n >= 32 { + set_overlapping::<4>(dest, word, n); + } else if n >= 16 { + set_overlapping::<2>(dest, word, n); + } else if n >= 8 { + set_overlapping::<1>(dest, word, n); + } else if n >= 4 { + write_u32(dest, word as u32); + write_u32(dest.add(n - 4), word as u32); + } else if n >= 2 { + write_u16(dest, word as u16); + write_u16(dest.add(n - 2), word as u16); + } else if n == 1 { + *dest = word as u8; + } +} + +/// Fills `n` bytes with `val`. +/// +/// # Safety +/// +/// `dest` must be valid for writes of `n` bytes. +#[inline(always)] +unsafe fn set_bytes(dest: *mut u8, val: u8, n: usize) { + let word = u64::from_ne_bytes([val; 8]); + let (mut dest, mut rem) = (dest, n); + while rem >= BLOCK { + let mut i = 0; + while i < BLOCK / 8 { + write_u64(dest.add(i * 8), word); + i += 1; + } + dest = dest.add(BLOCK); + rem -= BLOCK; + } + set_tail(dest, word, rem); +} + +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[no_mangle] +pub unsafe extern "C" fn memset(dest: *mut u8, val: core::ffi::c_int, n: usize) -> *mut u8 { + set_bytes(dest, val as u8, n); + dest +} + +const WORD: usize = core::mem::size_of::(); + +/// Reads a word with byte 0 in the low bits, so bit order matches address order. +#[inline(always)] +unsafe fn read_word(src: *const u8) -> u64 { + u64::from_le_bytes(load::(src)) +} + +/// Difference of the lowest-addressed byte on which `a` and `b` disagree. `a != b` required. +#[inline(always)] +fn byte_ordering(a: u64, b: u64) -> i32 { + let shift = (a ^ b).trailing_zeros() & !7; + (((a >> shift) & 0xff) as i32) - (((b >> shift) & 0xff) as i32) +} + +/// Compares `n` bytes, returning a value whose sign matches the first differing byte. +/// +/// # Safety +/// +/// `a` and `b` must be valid for reads of `n` bytes. +#[inline(always)] +unsafe fn compare_bytes(a: *const u8, b: *const u8, n: usize) -> i32 { + if n >= WORD { + // Advancing the pointers keeps the loop one instruction shorter than indexing off a base. + let (mut a, mut b, mut rem) = (a, b, n); + while rem >= WORD { + let (x, y) = (read_word(a), read_word(b)); + if x != y { + return byte_ordering(x, y); + } + a = a.add(WORD); + b = b.add(WORD); + rem -= WORD; + } + if rem != 0 { + // Overlapping final word. Everything before it already matched, so the first + // difference within it is also the first difference overall. + let (x, y) = (read_word(a.sub(WORD - rem)), read_word(b.sub(WORD - rem))); + if x != y { + return byte_ordering(x, y); + } + } + return 0; + } + // Under a word there is nothing to widen into; at most seven iterations. + let mut i = 0; + while i < n { + let (x, y) = (*a.add(i), *b.add(i)); + if x != y { + return x as i32 - y as i32; + } + i += 1; + } + 0 +} + +/// Reports whether `n` bytes differ, without ordering them. +/// +/// # Safety +/// +/// `a` and `b` must be valid for reads of `n` bytes. +#[inline(always)] +unsafe fn bytes_differ(a: *const u8, b: *const u8, n: usize) -> bool { + if n >= WORD { + let (mut a, mut b, mut rem) = (a, b, n); + while rem >= WORD { + if read_word(a) != read_word(b) { + return true; + } + a = a.add(WORD); + b = b.add(WORD); + rem -= WORD; + } + return rem != 0 && read_word(a.sub(WORD - rem)) != read_word(b.sub(WORD - rem)); + } + let mut i = 0; + while i < n { + if *a.add(i) != *b.add(i) { + return true; + } + i += 1; + } + false +} + +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[no_mangle] +pub unsafe extern "C" fn memcmp(a: *const u8, b: *const u8, n: usize) -> core::ffi::c_int { + compare_bytes(a, b, n) +} + +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[no_mangle] +pub unsafe extern "C" fn bcmp(a: *const u8, b: *const u8, n: usize) -> core::ffi::c_int { + bytes_differ(a, b, n) as core::ffi::c_int +} + +#[cfg(test)] +mod tests; diff --git a/patches/openvm-mem/src/tests.rs b/patches/openvm-mem/src/tests.rs new file mode 100644 index 00000000..6bf96db5 --- /dev/null +++ b/patches/openvm-mem/src/tests.rs @@ -0,0 +1,124 @@ +extern crate std; + +use std::{vec, vec::Vec}; + +use super::*; + +const PAD: u8 = 0xAA; +/// Every source/destination offset within a memory block, plus one past it. +const OFFSETS: usize = 9; +/// Exercises both bulk-loop iterations and every `copy_tail` arm. +const MAX_LEN: usize = 200; + +fn pattern(len: usize) -> Vec { + (0..len) + .map(|i| (i as u8).wrapping_mul(31).wrapping_add(7)) + .collect() +} + +#[test] +fn compare_bytes_matches_slice_cmp() { + let a = pattern(MAX_LEN + 2 * OFFSETS); + for n in 0..=MAX_LEN { + for a_off in 0..OFFSETS { + for b_off in 0..OFFSETS { + // Flip one byte at a time so every position is the first difference in turn, + // including positions only the overlapping final word can reach. + for flip in (0..n).chain([usize::MAX]) { + let mut b = a.clone(); + if flip != usize::MAX { + b[b_off + flip] ^= 0x80; + } + let got = + unsafe { compare_bytes(a.as_ptr().add(a_off), b.as_ptr().add(b_off), n) }; + let want = a[a_off..a_off + n].cmp(&b[b_off..b_off + n]); + assert_eq!( + got.signum(), + match want { + std::cmp::Ordering::Less => -1, + std::cmp::Ordering::Equal => 0, + std::cmp::Ordering::Greater => 1, + }, + "n={n} a_off={a_off} b_off={b_off} flip={flip}" + ); + let differ = + unsafe { bytes_differ(a.as_ptr().add(a_off), b.as_ptr().add(b_off), n) }; + assert_eq!(differ, want != std::cmp::Ordering::Equal); + } + } + } + } +} + +/// Overlap distances that straddle the bulk-loop stride in both copy directions. +const MAX_DELTA: usize = BLOCK + OFFSETS; + +#[test] +fn move_bytes_matches_copy_within() { + let base = pattern(MAX_LEN + 2 * MAX_DELTA); + let mut buf = base.clone(); + let mut expected = base.clone(); + for n in 0..=MAX_LEN { + for delta in 0..=MAX_DELTA { + // `dest` above `src` forces the backward copy, below it the forward one. + for (src_off, dest_off) in [ + (MAX_DELTA, MAX_DELTA + delta), + (MAX_DELTA + delta, MAX_DELTA), + ] { + buf.copy_from_slice(&base); + expected.copy_from_slice(&base); + expected.copy_within(src_off..src_off + n, dest_off); + unsafe { move_bytes(buf.as_mut_ptr().add(dest_off), buf.as_ptr().add(src_off), n) }; + assert_eq!(buf, expected, "n={n} delta={delta} dest_off={dest_off}"); + } + } + } +} + +#[test] +fn set_bytes_matches_fill() { + for n in 0..=MAX_LEN { + for dest_off in 0..OFFSETS { + let mut dest = vec![PAD; MAX_LEN + 2 * OFFSETS]; + unsafe { set_bytes(dest.as_mut_ptr().add(dest_off), 0x5C, n) }; + assert!( + dest[dest_off..dest_off + n].iter().all(|&b| b == 0x5C), + "n={n} dest_off={dest_off}" + ); + assert!( + dest[..dest_off].iter().all(|&b| b == PAD) + && dest[dest_off + n..].iter().all(|&b| b == PAD), + "wrote outside the destination range: n={n} dest_off={dest_off}" + ); + } + } +} + +#[test] +fn copy_forward_matches_slice_copy() { + let src = pattern(MAX_LEN + 2 * OFFSETS); + for n in 0..=MAX_LEN { + for src_off in 0..OFFSETS { + for dest_off in 0..OFFSETS { + let mut dest = vec![PAD; MAX_LEN + 2 * OFFSETS]; + unsafe { + copy_forward( + dest.as_mut_ptr().add(dest_off), + src.as_ptr().add(src_off), + n, + ) + }; + assert_eq!( + &dest[dest_off..dest_off + n], + &src[src_off..src_off + n], + "n={n} src_off={src_off} dest_off={dest_off}" + ); + assert!( + dest[..dest_off].iter().all(|&b| b == PAD) + && dest[dest_off + n..].iter().all(|&b| b == PAD), + "wrote outside the destination range: n={n} dest_off={dest_off}" + ); + } + } + } +} diff --git a/releases/dev/verifier/verifier.bin b/releases/dev/verifier/verifier.bin index 258670f3f3b443299799a3ff84291d7791298490..25efe4f909068937dfaa47ddb4344e6069889ffa 100644 GIT binary patch delta 692 zcmYL{%WD%+6o+$bBE@2SCB|AQ)2Ngp;v)(x$M-wu+%xlYj=Y&8 zJV1_?gBRogt?4F{vH_5%4Hk{37>x(TvMfnS&Lp1W%u7IdhD`Ufx%#BAnu zW*&m_S~nq`&|1SU~}#p+!%$>5^7LItq%_4B?iF7+|0j+JS@MRf#%#tt}2W$IbW6H#f7hFQ>?tDdNTn zn@Jo}GPGCcpd1lt5eB-T^J*NFy9OxvWyC+N^!7NOTXRK}fYzyVF_15N5x2>qb>7DO zIRlXrzxHF&pUEZtlF|}$T;$y9vcxz0w{Emzkn1x{nf$GmZI#KfkXevr75o8cdvz`o zTTD!J{9-P<{U0nsked)u%ee{KVeB|J?SXbl=cPYrvQQzkDGs?=10A$?*dq$w*8&4| zht6Flk5D-A0F9RN9jfus_zoGS%+C;P< zwuw-an`XFdC2T8Njdy|;Gthy)#=#q?(Yb~D9x(A9?Ub`r+ybr~t0Q9~lSYPSf^(@> zaXyWqUhbsHZAZoeV-duRS;Y6;M#Mv{pU|>v=a73-lBX72!%K-V&B#7} zKNvZGL9dDiPSH|`A^WXLRBV(5@o*4|S I?g;h&1-$Y%Pyhe` diff --git a/releases/dev/verifier/verifier.sol b/releases/dev/verifier/verifier.sol index ba22de7e..61169af2 100644 --- a/releases/dev/verifier/verifier.sol +++ b/releases/dev/verifier/verifier.sol @@ -59,7 +59,7 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { /// is being verified. /// @param appVmCommit The commitment to the VM configuration. function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view { - if (publicValues.length != PUBLIC_VALUES_LENGTH * 2) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH * 2, publicValues.length); + if (publicValues.length != PUBLIC_VALUES_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length); if (proofData.length != PROOF_DATA_LENGTH) revert InvalidProofDataLength(PROOF_DATA_LENGTH, proofData.length); if (uint256(appExeCommit) >= BN254_SCALAR_MODULUS) revert InvalidAppExeCommit(appExeCommit); if (uint256(appVmCommit) >= BN254_SCALAR_MODULUS) revert InvalidAppVmCommit(appVmCommit); @@ -152,14 +152,11 @@ contract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier { let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH)) calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560) - // Copy each u16 public value cell into its own bytes32 word. The - // calldata packs each cell as 2 little-endian bytes; the word is - // big-endian, so the low byte lands at offset 0x1f and the high - // byte at 0x1e of each word. + // Copy each byte of the public values into the proof. It copies the + // most significant bytes of public values first. let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f) for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } { - calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, shl(1, i)), 0x01) - calldatacopy(sub(add(publicValuesMemOffset, shl(5, i)), 1), add(add(publicValues.offset, shl(1, i)), 1), 0x01) + calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01) } } } From 87d02870eaa37bcc123b9f3aded6979598f37d23 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Fri, 21 Aug 2026 01:26:31 +0000 Subject: [PATCH 08/15] chore: upgrade openvm to develop-v2.1.0 (29fc511e) Includes upstream fix 46709d24 (#3118) for the DEFERRAL_AS root-keygen leaf-count assert that blocked test-e2e-bundle, plus #3112 sparse memory snapshot and #3109 field-independent instructions (VmExe/Program/ Instruction are now non-generic; app.vmexe format changed). - adapt host code to non-generic VmExe; drop legacy exe format shim - rebuild all guest assets and the EVM verifier - mount host SRS params in build-guest.sh for local verifier generation - update AGENTS.md (fix landed upstream; openvm-mem patch still needed) Verified: GPU=1 make test-single-chunk / test-e2e-batch / test-e2e-bundle --- AGENTS.md | 19 ++- Cargo.lock | 145 ++++++++---------- build-guest.sh | 7 +- crates/build-guest/src/main.rs | 4 +- .../batch-circuit/batch_exe_commit.rs | 2 +- .../circuits/batch-circuit/batch_vm_commit.rs | 2 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../bundle-circuit/bundle_vm_commit.rs | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- .../circuits/chunk-circuit/chunk_vm_commit.rs | 2 +- crates/prover/src/prover/mod.rs | 4 +- crates/prover/src/setup.rs | 82 +--------- 12 files changed, 102 insertions(+), 171 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 11933ac9..0f876f1d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -162,12 +162,19 @@ with `num_cells=0`. Merkle build") added a strict leaf-count assert. The SDK's `compute_root_proof_heights` builds the root config from a default `AppConfig::riscv64` (which has `deferral=None`), so `apply_optimizations` zeroes `DEFERRAL_AS.num_cells` — but deferral is actually -active and the root proof touches that address space. This is an upstream SDK -inconsistency the new assert exposes. -**Fix**: We currently pin OpenVM to `b3c95cd00` (the commit just before `a935d8b3d`), -which does not have the GPU Merkle build. To move to `a935d8b3d` or later you must patch -`openvm-sdk` so the root-prover config keeps `DEFERRAL_AS` allocated (or wait for an -upstream fix). +active and the root proof touches that address space. +**Fix**: Fixed upstream by `46709d24` ("fix: keep the dummy root-keygen app config +self-consistent", #3118), which re-runs `apply_optimizations()` in +`compute_root_proof_heights` so the dummy root-keygen config keeps `DEFERRAL_AS` +allocated. We track `develop-v2.1.0` HEAD (`29fc511e`), which includes the fix. If you +ever need to pin between `a935d8b3d` and `46709d24`, this assert will come back. + +### Field-independent instructions (#3109) +As of `29fc511e` ("refactor(v2.1): make program instructions field-independent"), +`Instruction` / `Program` / `VmExe` are **non-generic** (no ``); operands are +`InstructionOperand(i32)` restricted to the signed 30-bit domain. This changes the +`app.vmexe` serialization format, so any OpenVM bump across this commit requires a +full force rebuild of guest assets. ## GPU Features diff --git a/Cargo.lock b/Cargo.lock index f82b7513..ab620dc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3490,7 +3490,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "ecdsa", "elliptic-curve", @@ -4215,7 +4215,7 @@ dependencies = [ [[package]] name = "openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "bytemuck", "getrandom 0.2.16", @@ -4231,7 +4231,7 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "blstrs", "cfg-if 1.0.4", @@ -4268,7 +4268,7 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-macros-common", "quote", @@ -4278,7 +4278,7 @@ dependencies = [ [[package]] name = "openvm-algebra-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "halo2curves-axiom 0.7.3", "num-bigint", @@ -4294,7 +4294,7 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "num-bigint", "num-prime", @@ -4306,13 +4306,12 @@ dependencies = [ [[package]] name = "openvm-algebra-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-algebra-guest", "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", - "openvm-stark-backend", "openvm-transpiler", "strum 0.26.3", ] @@ -4320,7 +4319,7 @@ dependencies = [ [[package]] name = "openvm-algebra-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "num-bigint", "num-traits", @@ -4330,7 +4329,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-prove" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "clap", "eyre", @@ -4352,7 +4351,7 @@ dependencies = [ [[package]] name = "openvm-benchmarks-utils" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "cargo_metadata 0.18.1", "clap", @@ -4366,7 +4365,7 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "cfg-if 1.0.4", "derive-new 0.6.0", @@ -4393,7 +4392,7 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4402,14 +4401,13 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-bigint-guest", "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-riscv-transpiler", - "openvm-stark-backend", "openvm-transpiler", "strum 0.26.3", ] @@ -4417,7 +4415,7 @@ dependencies = [ [[package]] name = "openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "cargo_metadata 0.18.1", "eyre", @@ -4429,7 +4427,7 @@ dependencies = [ [[package]] name = "openvm-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "backtrace", "bytemuck", @@ -4472,7 +4470,7 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4483,7 +4481,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -4503,7 +4501,7 @@ dependencies = [ [[package]] name = "openvm-circuit-primitives-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -4525,7 +4523,7 @@ dependencies = [ [[package]] name = "openvm-continuations" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "cfg-if 1.0.4", "derivative", @@ -4632,7 +4630,7 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "proc-macro2", "quote", @@ -4642,12 +4640,12 @@ dependencies = [ [[package]] name = "openvm-decoder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" [[package]] name = "openvm-deferral-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "cfg-if 1.0.4", "dashmap", @@ -4677,7 +4675,7 @@ dependencies = [ [[package]] name = "openvm-deferral-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -4686,14 +4684,13 @@ dependencies = [ [[package]] name = "openvm-deferral-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "eyre", "openvm-deferral-guest", "openvm-instructions", "openvm-instructions-derive", "openvm-transpiler", - "p3-field", "rrs-lib", "serde", "strum 0.26.3", @@ -4702,7 +4699,7 @@ dependencies = [ [[package]] name = "openvm-ecc-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "blstrs", "cfg-if 1.0.4", @@ -4738,7 +4735,7 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "ecdsa", "elliptic-curve", @@ -4757,7 +4754,7 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-macros-common", "quote", @@ -4767,13 +4764,12 @@ dependencies = [ [[package]] name = "openvm-ecc-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-decoder", "openvm-ecc-guest", "openvm-instructions", "openvm-instructions-derive", - "openvm-stark-backend", "openvm-transpiler", "strum 0.26.3", ] @@ -4781,7 +4777,7 @@ dependencies = [ [[package]] name = "openvm-instructions" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -4789,7 +4785,6 @@ dependencies = [ "num-bigint", "num-traits", "openvm-instructions-derive", - "openvm-stark-backend", "serde", "strum 0.26.3", "strum_macros 0.26.4", @@ -4798,7 +4793,7 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "quote", "syn 2.0.110", @@ -4807,7 +4802,7 @@ dependencies = [ [[package]] name = "openvm-keccak256" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-keccak256-guest", "spin 0.10.0", @@ -4816,7 +4811,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "derive-new 0.6.0", "derive_more 1.0.0", @@ -4844,7 +4839,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-platform", ] @@ -4852,13 +4847,12 @@ dependencies = [ [[package]] name = "openvm-keccak256-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-keccak256-guest", - "openvm-stark-backend", "openvm-transpiler", "strum 0.26.3", ] @@ -4866,7 +4860,7 @@ dependencies = [ [[package]] name = "openvm-macros-common" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "syn 2.0.110", ] @@ -4878,7 +4872,7 @@ version = "2.0.0" [[package]] name = "openvm-mod-circuit-builder" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "itertools 0.14.0", "num-bigint", @@ -4895,7 +4889,7 @@ dependencies = [ [[package]] name = "openvm-pairing" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.3", @@ -4919,7 +4913,7 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "cfg-if 1.0.4", "derive-new 0.6.0", @@ -4951,7 +4945,7 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "blst", "halo2curves-axiom 0.7.3", @@ -4972,12 +4966,11 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-decoder", "openvm-instructions", "openvm-pairing-guest", - "openvm-stark-backend", "openvm-transpiler", "strum 0.26.3", ] @@ -4985,8 +4978,9 @@ dependencies = [ [[package]] name = "openvm-platform" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ + "critical-section", "libm", "openvm-custom-insn", "openvm-riscv-guest", @@ -4995,7 +4989,7 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "derivative", "lazy_static", @@ -5013,7 +5007,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5041,7 +5035,7 @@ dependencies = [ [[package]] name = "openvm-recursion-circuit-derive" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "quote", "syn 2.0.110", @@ -5050,7 +5044,7 @@ dependencies = [ [[package]] name = "openvm-riscv-adapters" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5067,7 +5061,7 @@ dependencies = [ [[package]] name = "openvm-riscv-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "cfg-if 1.0.4", "derive-new 0.6.0", @@ -5097,7 +5091,7 @@ dependencies = [ [[package]] name = "openvm-riscv-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-custom-insn", "strum_macros 0.26.4", @@ -5106,13 +5100,12 @@ dependencies = [ [[package]] name = "openvm-riscv-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-riscv-guest", - "openvm-stark-backend", "openvm-transpiler", "serde", "strum 0.26.3", @@ -5122,7 +5115,7 @@ dependencies = [ [[package]] name = "openvm-sdk" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "alloy-sol-types", "bitcode", @@ -5161,7 +5154,7 @@ dependencies = [ [[package]] name = "openvm-sdk-config" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "bon", "cfg-if 1.0.4", @@ -5198,7 +5191,7 @@ dependencies = [ [[package]] name = "openvm-sha2" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-sha2-guest", "sha2 0.10.9", @@ -5207,7 +5200,7 @@ dependencies = [ [[package]] name = "openvm-sha2-air" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "ndarray", "num_enum", @@ -5221,7 +5214,7 @@ dependencies = [ [[package]] name = "openvm-sha2-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "cfg-if 1.0.4", "derive-new 0.6.0", @@ -5250,7 +5243,7 @@ dependencies = [ [[package]] name = "openvm-sha2-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-platform", ] @@ -5258,13 +5251,12 @@ dependencies = [ [[package]] name = "openvm-sha2-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-decoder", "openvm-instructions", "openvm-instructions-derive", "openvm-sha2-guest", - "openvm-stark-backend", "openvm-transpiler", "strum 0.26.3", ] @@ -5336,7 +5328,7 @@ dependencies = [ [[package]] name = "openvm-static-verifier" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "halo2-base", "itertools 0.14.0", @@ -5360,14 +5352,13 @@ dependencies = [ [[package]] name = "openvm-transpiler" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "elf", "eyre", "openvm-decoder", "openvm-instructions", "openvm-platform", - "openvm-stark-backend", "rustc-demangle", "thiserror 1.0.69", ] @@ -5375,7 +5366,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-circuit" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "bitcode", "cfg-if 1.0.4", @@ -5405,7 +5396,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-deferral-guest", ] @@ -5413,7 +5404,7 @@ dependencies = [ [[package]] name = "openvm-verify-stark-host" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "bitcode", "eyre", @@ -5452,7 +5443,7 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "ecdsa", "elliptic-curve", @@ -7795,7 +7786,7 @@ dependencies = [ [[package]] name = "rvr-openvm" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-instructions", "openvm-platform", @@ -7809,12 +7800,12 @@ dependencies = [ [[package]] name = "rvr-openvm-build" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" [[package]] name = "rvr-openvm-ir" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "serde", ] @@ -7822,7 +7813,7 @@ dependencies = [ [[package]] name = "rvr-openvm-lift" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "libloading", "openvm-instructions", @@ -7836,7 +7827,7 @@ dependencies = [ [[package]] name = "rvr-state" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#b3c95cd00e8162dcb3d220e22bb57c9ebda357c5" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" [[package]] name = "ryu" @@ -9726,7 +9717,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/build-guest.sh b/build-guest.sh index 7c1b5239..169dd979 100755 --- a/build-guest.sh +++ b/build-guest.sh @@ -20,8 +20,11 @@ cleanup() { # set trap to cleanup on exit trap cleanup EXIT -# run docker image -docker run --cidfile ./build-guest.cid --platform linux/amd64 build-guest:local make build-guest-local +# run docker image (mount host SRS params: local EVM verifier generation needs them) +mkdir -p "$HOME/.openvm/params" +docker run --cidfile ./build-guest.cid --platform linux/amd64 \ + -v "$HOME/.openvm/params:/root/.openvm/params:ro" \ + build-guest:local make build-guest-local container_id=$(cat ./build-guest.cid) # copy vm commitments from container to local diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index 4b6f40d8..ef6ad58f 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -40,7 +40,7 @@ use openvm_continuations::CommitBytes; use openvm_instructions::exe::VmExe; use openvm_recursion_circuit::batch_constraint::commit_child_vk; use openvm_sdk::{ - F, Sdk, + Sdk, config::{AggregationConfig, AggregationSystemParams, AggregationTreeConfig, AppConfig}, fs::write_object_to_file, prover::MultiDeferralCircuitProver, @@ -310,7 +310,7 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re println!("{LOG_PREFIX} elf written to {path_app_elf:?}"); // 2. Transpile ELF to VM Executable - let app_exe: VmExe = (*sdk.convert_to_exe(elf)?).clone(); + let app_exe: VmExe = (*sdk.convert_to_exe(elf)?).clone(); // Write exe to disc. let path_app_exe: PathBuf = path_assets.join("app.vmexe"); diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index e8a10c3b..28f79045 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [139929666, 753896685, 1853904564, 1388310222, 487550726, 758710732, 1810988145, 429452358]; +pub const COMMIT: [u32; 8] = [1435303184, 1278916743, 1567053108, 357182736, 1859551511, 1164766284, 717059677, 936378388]; diff --git a/crates/circuits/batch-circuit/batch_vm_commit.rs b/crates/circuits/batch-circuit/batch_vm_commit.rs index 9c520f01..9c3722b8 100644 --- a/crates/circuits/batch-circuit/batch_vm_commit.rs +++ b/crates/circuits/batch-circuit/batch_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [746377549, 1162918801, 1051540790, 1928041030, 152070805, 1113647181, 1968697469, 1593844187]; +pub const COMMIT: [u32; 8] = [628643739, 1391655643, 612908973, 1977999238, 335322123, 1575930128, 1995361175, 572648692]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index ac926dfc..482e9848 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1517974075, 589154344, 1786735536, 153963703, 1152034845, 1004578779, 1107563189, 1187609870]; +pub const COMMIT: [u32; 8] = [1096401504, 229560942, 1241164728, 64742493, 1896387437, 936717747, 436295168, 132807200]; diff --git a/crates/circuits/bundle-circuit/bundle_vm_commit.rs b/crates/circuits/bundle-circuit/bundle_vm_commit.rs index 59906747..8457738a 100644 --- a/crates/circuits/bundle-circuit/bundle_vm_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [210058995, 1094759752, 632338706, 1021800370, 639104907, 1560970220, 929526493, 1399681357]; +pub const COMMIT: [u32; 8] = [1473077767, 915340244, 1015753118, 931874796, 1629597349, 1264003766, 1595028109, 54844257]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 8858c6ea..3b746b5a 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [36604511, 758201064, 1447719550, 1099084240, 611083294, 1279007169, 1209336150, 1688379479]; +pub const COMMIT: [u32; 8] = [198887705, 1164914482, 18333845, 198791779, 827337688, 209274783, 1299008267, 1889595312]; diff --git a/crates/circuits/chunk-circuit/chunk_vm_commit.rs b/crates/circuits/chunk-circuit/chunk_vm_commit.rs index c4c2cdfa..a9bced4b 100644 --- a/crates/circuits/chunk-circuit/chunk_vm_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_vm_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1968976531, 846168655, 1173672047, 1954338880, 1456456415, 656306742, 1613486240, 941152904]; +pub const COMMIT: [u32; 8] = [322604582, 189444280, 87460111, 1707829116, 1997509938, 1357280705, 319517109, 1974772180]; diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index a6945d14..41168508 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -10,7 +10,7 @@ use openvm_sdk::config::{ AggregationConfig, AggregationSystemParams, AggregationTreeConfig, AppConfig, }; use openvm_sdk::prover::{DeferralAggProver, MultiDeferralCircuitProver}; -use openvm_sdk::{F, SC, Sdk, StdIn}; +use openvm_sdk::{SC, Sdk, StdIn}; use openvm_sdk_config::{SdkVmConfig, deferral::SupportedDeferral}; use openvm_stark_backend::StarkEngine; use openvm_stark_sdk::{ @@ -69,7 +69,7 @@ pub struct Prover { /// Prover name pub prover_name: String, /// The program exe. - pub app_exe: Arc>, + pub app_exe: Arc, /// Prover configuration. pub config: ProverConfig, /// SDKConfig diff --git a/crates/prover/src/setup.rs b/crates/prover/src/setup.rs index 4e80d953..d9e9ce19 100644 --- a/crates/prover/src/setup.rs +++ b/crates/prover/src/setup.rs @@ -1,88 +1,18 @@ -use std::{collections::BTreeMap, fs::read_to_string, path::Path}; +use std::{fs::read_to_string, path::Path}; -use openvm_circuit::arch::instructions::{ - exe::{FnBounds, VmExe}, - instruction::{DebugInfo, Instruction}, - program::Program, -}; -use openvm_sdk::F; +use openvm_circuit::arch::instructions::exe::VmExe; use openvm_sdk::config::AppConfig; use openvm_sdk::fs::read_object_from_file; use openvm_sdk_config::SdkVmConfig; use crate::Error; -/// Wrapper around [`openvm_sdk::fs::read_exe_from_file`]. -pub fn read_app_exe>(path: P) -> Result, Error> { - if let Ok(r) = read_object_from_file(&path) { - return Ok(r); - } - - println!("loading vmexe failed, trying old format.."); - - /// Executable program for OpenVM. - #[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)] - #[serde(bound(serialize = "F: Serialize", deserialize = "F: Deserialize<'de>"))] - pub struct OldProgram { - #[serde(deserialize_with = "deserialize_instructions_and_debug_infos")] - pub instructions_and_debug_infos: Vec, Option)>>, - pub step: u32, - pub pc_base: u32, - } - #[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)] - #[serde(bound( - serialize = "F: serde::Serialize", - deserialize = "F: std::cmp::Ord + serde::Deserialize<'de>" - ))] - pub struct OldVmExe { - /// Program to execute. - pub program: OldProgram, - /// Start address of pc. - pub pc_start: u32, - /// Initial memory image. - pub init_memory: BTreeMap<(u32, u32), F>, - /// Starting + ending bounds for each function. - pub fn_bounds: FnBounds, - } - use serde::{Deserialize, Deserializer, Serialize}; - - #[allow(clippy::type_complexity)] - fn deserialize_instructions_and_debug_infos<'de, F: Deserialize<'de>, D: Deserializer<'de>>( - deserializer: D, - ) -> Result, Option)>>, D::Error> { - let (inst_data, total_len): (Vec<(Instruction, u32)>, u32) = - Deserialize::deserialize(deserializer)?; - let mut ret: Vec, Option)>> = Vec::new(); - ret.resize_with(total_len as usize, || None); - for (inst, i) in inst_data { - ret[i as usize] = Some((inst, None)); - } - Ok(ret) - } - - let old_exe: OldVmExe = read_object_from_file(&path).map_err(|e| Error::Setup { +/// Read and deserialize [`VmExe`] from the given path. +pub fn read_app_exe>(path: P) -> Result { + read_object_from_file(&path).map_err(|e| Error::Setup { path: path.as_ref().into(), src: e.to_string(), - })?; - use openvm_stark_sdk::openvm_stark_backend::p3_field::{PrimeField32, integers::QuotientMap}; - let exe = VmExe:: { - program: Program:: { - instructions_and_debug_infos: old_exe.program.instructions_and_debug_infos, - pc_base: old_exe.program.pc_base, - }, - pc_start: old_exe.pc_start, - init_memory: old_exe - .init_memory - .into_iter() - .map(|(k, v)| { - assert!(v < F::from_int(256u32)); - (k, v.as_canonical_u32() as u8) - }) - .collect(), - fn_bounds: old_exe.fn_bounds, - cfg_block_starts: Default::default(), - }; - Ok(exe) + }) } /// Read and deserialize [`openvm_sdk::config::AppConfig`] from the given path to the TOML config. From 1884e760e42ba02d78aa2e4300bc847fa94fd913 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 22 Sep 2026 06:55:09 +0000 Subject: [PATCH 09/15] fix: regenerate chunk exe commitment for openvm 29fc511e The committed value was stale (built at b3c95cd0). The 29fc511e bump made instructions field-independent (#3109), changing the vmexe format; rebuilt guest assets produce a different app exe commitment. --- crates/circuits/chunk-circuit/chunk_exe_commit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 3b746b5a..37f12f0d 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [198887705, 1164914482, 18333845, 198791779, 827337688, 209274783, 1299008267, 1889595312]; +pub const COMMIT: [u32; 8] = [1192406321, 1007067640, 1433639583, 1891545475, 903990723, 621677400, 1106027141, 1005293682]; From 3ed8ea1330db87cc2c145997a17927af2a6db163 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 22 Sep 2026 06:55:19 +0000 Subject: [PATCH 10/15] docs: document openvm-1.94.1 toolchain install and glibc>=2.39 requirement The prebuilt guest toolchain cannot run on Ubuntu 22.04 (glibc 2.35). Document the install path (~/.openvm/toolchains + rustup symlink) and an Ubuntu 24.04 container workaround with the required mounts, plus the OPENVM_GUEST_LOGFILE tip for capturing inner build output. --- AGENTS.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 0f876f1d..35f9535e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,6 +29,10 @@ Compared to v2.0.0, the `develop-v2.1.0` branch changes: rust fork toolchain). Guest builds MUST use `OPENVM_RUST_TOOLCHAIN=openvm-1.94.1` (the default in the Makefile and in `openvm-build`). The old `riscv32im-risc0-zkvm-elf` / `nightly-2025-11-20` combination is gone. + The toolchain is installed via `cargo openvm toolchain install` (see Dockerfile; it + extracts to `~/.openvm/toolchains/openvm-1.94.1` and symlinks it from + `~/.rustup/toolchains/`). The prebuilt binaries require **glibc ≥ 2.39** + (Ubuntu 24.04+); on older hosts see the glibc failure pattern below. - Crate renames: `openvm-rv32im-{guest,transpiler,circuit}` → `openvm-riscv-{guest,transpiler,circuit}`. - `openvm.toml`: `[app_vm_config.rv32i]`/`rv32m` → `rv64i`/`rv64m`. - SDK API: `Sdk::riscv32`/`AppConfig::riscv32` → `riscv64`; `Sdk::execute*` now @@ -139,6 +143,39 @@ OPENVM_RUST_TOOLCHAIN=openvm-1.94.1 cargo run --release -p scroll-zkvm-build-gue ### Docker build fails with stale CID The `build-guest.sh` script may fail if a stale `build-guest.cid` file exists. Use local build (`cargo run -p scroll-zkvm-build-guest`) as fallback. +### Guest build fails: `GLIBC_2.3x' not found` / `GLIBCXX_3.4.32' not found` +**Symptoms**: `scroll-zkvm-build-guest` fails during the RV64 guest build with +`rustc: /lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.39' not found (required by +.../openvm-1.94.1/lib/librustc_driver-*.so)`. +**Cause**: The prebuilt `openvm-1.94.1` toolchain installed by `cargo openvm toolchain +install` requires glibc ≥ 2.39 (Ubuntu 24.04+). Older hosts (e.g. Ubuntu 22.04, glibc +2.35) cannot run it. +**Fix**: Run the guest build inside an Ubuntu 24.04 container with the repo and the +rustup/cargo/openvm dirs mounted (host-compiled binaries run fine inside; glibc is +forward-compatible): +```bash +cat > /tmp/Dockerfile.guest2404 <<'EOF' +FROM ubuntu:24.04 +RUN apt-get update && apt-get install -y --no-install-recommends build-essential ca-certificates git && rm -rf /var/lib/apt/lists/* +EOF +docker build -t guest-build-2404:local -f /tmp/Dockerfile.guest2404 /tmp + +docker run --rm --user $(id -u):$(id -g) \ + -e HOME="$HOME" -e RUSTUP_HOME="$HOME/.rustup" -e CARGO_HOME="$HOME/.cargo" \ + -e OPENVM_RUST_TOOLCHAIN=openvm-1.94.1 \ + -e PATH="$HOME/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \ + -v "$PWD:$PWD" -v "$HOME/.rustup:$HOME/.rustup" -v "$HOME/.cargo:$HOME/.cargo" \ + -v "$HOME/.openvm:$HOME/.openvm" -w "$PWD" \ + guest-build-2404:local \ + "$HOME/.cargo/bin/cargo" run --release -p scroll-zkvm-build-guest -- --mode force +``` +⚠️ The `~/.openvm` mount is **required**: the toolchain really lives at +`~/.openvm/toolchains/openvm-1.94.1` and is only symlinked from +`~/.rustup/toolchains/`; without the mount rustup reports +`override toolchain 'openvm-1.94.1' is not installed` (dangling symlink → ENOENT). +Tip: set `OPENVM_GUEST_LOGFILE=` to capture the inner guest cargo output — it +defaults to `/dev/tty`, which is invisible in containers/CI. + ### Guest crashes with `upper 4 bytes must be zero` (TryFromIntError) in store/addi **Symptoms**: `test-execute-chunk` / proving panics in `openvm_riscv_circuit` with a register holding `0xfffffffffffffe60` (=-416) or similar sign-extended garbage, and the From 2301a47301daaeffc64960011484ce20396833f1 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 24 Sep 2026 13:43:25 +0000 Subject: [PATCH 11/15] perf: replace vm-zstd with ruzstd decode, drop vm-zstd entirely Guest-side zstd decoding in the batch circuit now uses the standard pure-Rust ruzstd crate instead of the in-house vm-zstd decoder. Batch e2e total cycles drop 31.4% (12,989,579 -> 8,905,075), STARK proving time ~5.66s -> ~4.85s on RTX 4090. The scroll envelope stores a zstd frame without the 4-byte magic number, so the magic is prepended zero-copy before decoding. vm-zstd is removed from the dependency graph completely: its only remaining use was host-side test encoding in the integration crate, where zstd_encode was a thin wrapper around da-codec's encoder-standard. Depend on encoder-standard directly (same locked commit, byte-identical output) and inline the wrapper. Cargo.lock edited by hand (adds ruzstd 0.9.0 + twox-hash 2.1.4, removes vm-zstd and orphaned bitstream-io/strum 0.25/strum_macros 0.25/heck 0.4.1) and validated with cargo metadata --locked to avoid a global re-resolve bumping revm. --- Cargo.lock | 74 ++++++------------- Cargo.toml | 2 +- .../batch-circuit/batch_exe_commit.rs | 2 +- crates/integration/Cargo.toml | 2 +- crates/integration/src/utils/mod.rs | 19 ++++- crates/types/batch/Cargo.toml | 2 +- crates/types/batch/src/payload/mod.rs | 19 +++++ crates/types/batch/src/payload/v6.rs | 4 +- crates/types/batch/src/payload/v7.rs | 4 +- 9 files changed, 65 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab620dc1..debd99d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -537,7 +537,7 @@ checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" dependencies = [ "alloy-sol-macro-input", "const-hex", - "heck 0.5.0", + "heck", "indexmap 2.12.0", "proc-macro-error2", "proc-macro2", @@ -555,7 +555,7 @@ checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ "const-hex", "dunce", - "heck 0.5.0", + "heck", "macro-string", "proc-macro2", "quote", @@ -1259,12 +1259,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "bitstream-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" - [[package]] name = "bitvec" version = "1.0.1" @@ -1606,7 +1600,7 @@ version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.110", @@ -2990,12 +2984,6 @@ dependencies = [ "serde", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -7783,6 +7771,15 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "ruzstd" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a252f5e20f038fe7b4ea53e073e65398d652c864cc162fc77c56c2f13717b888" +dependencies = [ + "twox-hash", +] + [[package]] name = "rvr-openvm" version = "2.0.0" @@ -8129,6 +8126,7 @@ dependencies = [ "clap", "csv", "dotenvy", + "encoder-standard", "eyre", "futures", "glob", @@ -8162,7 +8160,6 @@ dependencies = [ "tracing", "tracing-subscriber 0.3.20", "url", - "vm-zstd", ] [[package]] @@ -8248,10 +8245,10 @@ dependencies = [ "openvm-pairing", "openvm-pairing-guest", "openvm-sha2", + "ruzstd", "sbv-primitives", "scroll-zkvm-types-base", "serde", - "vm-zstd", ] [[package]] @@ -8840,12 +8837,6 @@ dependencies = [ "syn 2.0.110", ] -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" - [[package]] name = "strum" version = "0.26.3" @@ -8864,26 +8855,13 @@ dependencies = [ "strum_macros 0.27.2", ] -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.110", -] - [[package]] name = "strum_macros" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", @@ -8896,7 +8874,7 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.110", @@ -9434,6 +9412,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "twox-hash" +version = "2.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5283634e518fe9e82c7b20520bb4bc209009fd16c82077c802f8111ecbb0117a" + [[package]] name = "typenum" version = "1.19.0" @@ -9556,20 +9540,6 @@ version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" -[[package]] -name = "vm-zstd" -version = "0.1.1" -source = "git+https://github.com/scroll-tech/rust-zstd-decompressor.git?rev=b027327#b0273278316245fef733df54cc29ee3baa3d7382" -dependencies = [ - "anyhow", - "bitstream-io", - "encoder-standard", - "itertools 0.11.0", - "serde", - "strum 0.25.0", - "strum_macros 0.25.3", -] - [[package]] name = "wait-timeout" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 9fb6cc16..42a4f0f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -128,7 +128,7 @@ snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git tiny-keccak = "2.0" thiserror = "2" tracing = "0.1" -vm-zstd = { git = "https://github.com/scroll-tech/rust-zstd-decompressor.git", rev = "b027327" } +encoder-standard = { git = "https://github.com/scroll-tech/da-codec.git" } toml = "0.8.14" tracing-subscriber = "0.3" sysinfo = { version = "0.35", default-features = false } diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 28f79045..61db46d4 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1435303184, 1278916743, 1567053108, 357182736, 1859551511, 1164766284, 717059677, 936378388]; +pub const COMMIT: [u32; 8] = [260182314, 1280890024, 529127170, 916766546, 895907952, 1406126257, 12172159, 1952507758]; diff --git a/crates/integration/Cargo.toml b/crates/integration/Cargo.toml index 9118616d..c9e76d64 100644 --- a/crates/integration/Cargo.toml +++ b/crates/integration/Cargo.toml @@ -45,7 +45,7 @@ eyre.workspace = true rayon.workspace = true serde.workspace = true futures.workspace = true -vm-zstd = { workspace = true, features = ["zstd"] } +encoder-standard = { workspace = true } tokio = { workspace = true, features = ["full"] } hex.workspace = true diff --git a/crates/integration/src/utils/mod.rs b/crates/integration/src/utils/mod.rs index 10da355e..fd311bd6 100644 --- a/crates/integration/src/utils/mod.rs +++ b/crates/integration/src/utils/mod.rs @@ -17,7 +17,24 @@ use scroll_zkvm_types::{ utils::{keccak256, point_eval, serialize_vk}, }; use std::env; -use vm_zstd::zstd_encode; +use std::io::Write; + +/// Encode payload bytes into a single zstd frame without the 4-byte magic number, +/// matching the scroll envelope format (see `zstd_decode` in scroll-zkvm-types-batch). +fn zstd_encode(raw_input_bytes: &[u8]) -> Vec { + use encoder_standard::{N_BLOCK_SIZE_TARGET, init_zstd_encoder}; + + // compression level = 0 defaults to using level=3, which is zstd's default. + let mut encoder = init_zstd_encoder(N_BLOCK_SIZE_TARGET); + + // set source length, which will be reflected in the frame header. + encoder + .set_pledged_src_size(Some(raw_input_bytes.len() as u64)) + .unwrap(); + + encoder.write_all(raw_input_bytes).unwrap(); + encoder.finish().unwrap() +} #[allow(dead_code)] fn final_l1_index(blk: &BlockWitness) -> u64 { diff --git a/crates/types/batch/Cargo.toml b/crates/types/batch/Cargo.toml index e2836f22..fa46497e 100644 --- a/crates/types/batch/Cargo.toml +++ b/crates/types/batch/Cargo.toml @@ -11,7 +11,7 @@ version.workspace = true alloy-primitives = { workspace = true } serde.workspace = true itertools.workspace = true -vm-zstd = { workspace = true } +ruzstd = "0.9" types-base = { path = "../base", package = "scroll-zkvm-types-base" } openvm = { workspace = true, features = ["std"] } diff --git a/crates/types/batch/src/payload/mod.rs b/crates/types/batch/src/payload/mod.rs index 9e258e69..84fb9eb7 100644 --- a/crates/types/batch/src/payload/mod.rs +++ b/crates/types/batch/src/payload/mod.rs @@ -30,6 +30,25 @@ pub trait Envelope { } } +/// Decode zstd-compressed payload bytes using the standard pure-Rust decoder. +/// +/// The scroll envelope stores a single zstd frame without the 4-byte magic number, +/// so the magic is prepended (zero-copy) before handing the stream to the decoder. +pub(crate) fn zstd_decode(src: &[u8]) -> Vec { + use ruzstd::decoding::StreamingDecoder; + use ruzstd::io::Read; + + const ZSTD_MAGIC: [u8; 4] = [0x28, 0xB5, 0x2F, 0xFD]; + let mut stream = ZSTD_MAGIC.as_slice().chain(src); + let mut decoder = + StreamingDecoder::new(&mut stream).expect("zstd decoder init should succeed"); + let mut decoded = Vec::new(); + decoder + .read_to_end(&mut decoded) + .expect("zstd decode should succeed"); + decoded +} + pub trait Payload { type BatchHeader: BatchHeader; diff --git a/crates/types/batch/src/payload/v6.rs b/crates/types/batch/src/payload/v6.rs index 0a3ad2f1..302ecfd0 100644 --- a/crates/types/batch/src/payload/v6.rs +++ b/crates/types/batch/src/payload/v6.rs @@ -80,9 +80,7 @@ impl Payload for PayloadV6 { fn from_envelope(envelope: &Self::Envelope) -> Self { // Decode the payload bytes from the envelope bytes. let payload_bytes = if envelope.is_encoded { - vm_zstd::process(envelope.envelope_bytes.as_slice()) - .expect("envelope to payload v6 should succeed zstd-decoding") - .decoded_data + super::zstd_decode(envelope.envelope_bytes.as_slice()) } else { envelope.envelope_bytes.to_vec() }; diff --git a/crates/types/batch/src/payload/v7.rs b/crates/types/batch/src/payload/v7.rs index 80c78d6c..ee0be727 100644 --- a/crates/types/batch/src/payload/v7.rs +++ b/crates/types/batch/src/payload/v7.rs @@ -144,9 +144,7 @@ impl super::Payload for GenericPayloadV7 { fn from_envelope(envelope: &Self::Envelope) -> Self { // Conditionally decode depending on the flag set in the envelope. let payload_bytes = if envelope.is_encoded & 1 == 1 { - vm_zstd::process(&envelope.unpadded_bytes) - .expect("zstd decode should succeed") - .decoded_data + super::zstd_decode(&envelope.unpadded_bytes) } else { envelope.unpadded_bytes.to_vec() }; From 3e1f42ef71ce59153ead8e9e365f59d5c4206c55 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Fri, 25 Sep 2026 13:52:38 +0000 Subject: [PATCH 12/15] perf: cut batch/bundle guest cycles; add cycle-profiling infra Optimizations (driven by new per-function cycle profiles): - batch: 8,905,075 -> 5,397,474 cycles (-39.4%); STARK prove 4.7-4.9s -> 4.44s on RTX 4090. * BatchWitness.blob_bytes: serde helper that decodes bincode byte arrays in one shot (length prefix + bulk copy) instead of element-by-element (same wire format). Was 26% of batch cycles. * BlobPolynomial::new: pack 31-byte coefficients with chunked copies instead of a byte-at-a-time loop. Was 17%. * builder/v7: borrow witness blob bytes when already padded instead of copying into a fresh 126KB buffer. - bundle: 61,613 -> 18,200 cycles (-70.5%): link openvm-keccak256 (provides the native_keccak256 extern) and enable alloy-primitives/native-keccak, mirroring batch-circuit. Previously bundle guest fell back to software tiny-keccak (63% of its cycles in keccakf). - chunk: profiled but unchanged this round; hotspots are upstream (risc0-ethereum-trie node RLP decode ~30%, memcpy 15%, revm bytecode analysis ~6-11%, interpreter ops). See AGENTS.md. Profiling infrastructure: - New perf-metrics feature chain (build-guest/prover/integration) wiring openvm-sdk/perf-metrics: guests built with the feature carry fn_bounds + a demangled guest.symbols table (build-guest sets GUEST_SYMBOLS_PATH and inserts a synthetic bound for entry PCs to avoid an openvm unwrap panic). - scroll-zkvm-prover installs a DebuggingRecorder when PROFILE_METRICS_DIR is set and dumps per-proof counter deltas as metrics JSON after every proof (gen_proof_stark / gen_proof_snark). - scripts/profile_top.py: aggregates the JSON into top functions / spans. - AGENTS.md: profiling how-to + the native_keccak256 link failure pattern. Cargo.lock hand-edited (metrics/metrics-util into prover deps, bundle-circuit keccak dep swap) and validated with cargo metadata --locked. --- AGENTS.md | 49 ++++++++ Cargo.lock | 4 +- crates/build-guest/Cargo.toml | 2 + crates/build-guest/src/main.rs | 40 +++++- .../batch-circuit/batch_exe_commit.rs | 2 +- crates/circuits/bundle-circuit/Cargo.toml | 4 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- crates/circuits/bundle-circuit/src/circuit.rs | 2 +- crates/integration/Cargo.toml | 2 +- crates/prover/Cargo.toml | 5 + crates/prover/src/prover/mod.rs | 106 ++++++++++++++++ .../types/batch/src/blob_consistency/mod.rs | 7 +- crates/types/batch/src/builder/v7.rs | 21 ++-- crates/types/batch/src/witness.rs | 46 +++++++ scripts/profile_top.py | 117 ++++++++++++++++++ 15 files changed, 390 insertions(+), 19 deletions(-) create mode 100644 scripts/profile_top.py diff --git a/AGENTS.md b/AGENTS.md index 35f9535e..10cb23f7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -106,6 +106,55 @@ To move to a newer OpenVM ref, retarget every `openvm-org/openvm.git` entry in ` ``` Integration tests reuse cached proofs by default. Stale proofs from a previous OpenVM version will cause failures. +### Guest ELF link fails with `undefined symbol: native_keccak256` +**Cause**: The circuit crate enabled `alloy-primitives/native-keccak` (so `alloy_primitives::keccak256` +calls the `native_keccak256` extern) but links the wrong provider crate. The extern is defined in +**`openvm-keccak256`** (guest-libs, also exports `native_keccakf`/`native_xorin`), NOT in +`openvm-keccak256-guest` (extensions — only defines `native_xorin`/`native_keccakf`). +**Fix**: depend on `openvm-keccak256` and import it in `circuit.rs` (`use openvm_keccak256;`), +mirroring `batch-circuit`. Check the actual keccak backend per circuit with +`cargo tree -p --prefix none -f "{p} {f}" | grep ^alloy-primitives`: +the guest graph must show `native-keccak` and must NOT show `tiny-keccak` (a software fallback — +the bundle circuit once spent 63% of its cycles in `tiny_keccak::keccakf` because of this). + +## Guest Cycle Profiling + +Function-level cycle attribution is available via openvm's `perf-metrics` feature (function +spans from ELF symbol bounds + a metrics recorder in the prover): + +1. **Build guests with profiling metadata** (adds `fn_bounds` + `guest.symbols` to the assets; + exe commitments are unaffected): + ```bash + # in the guest-build container, like a normal force build but with the feature + BUILD_PROJECT=chunk,batch,bundle OPENVM_BUILD_LOCKED=1 \ + cargo run --release --locked -p scroll-zkvm-build-guest \ + --features scroll-zkvm-build-guest/perf-metrics -- --mode force + ``` + (The transpiler requires `GUEST_SYMBOLS_PATH` when `function-span` is on; build-guest sets it + per project to `releases/dev//guest.symbols`. build-guest also inserts a synthetic + `[0, first_fn)` fn bound — without it openvm's `update_current_fn` panics on entry-trampoline PCs.) + +2. **Run any proving test** with the prover-side feature and an output dir: + ```bash + PROFILE_METRICS_DIR=/tmp/prof GPU=1 cargo test --release --locked \ + --features scroll-zkvm-integration/cuda,scroll-zkvm-integration/perf-metrics \ + -p scroll-zkvm-integration --test batch_circuit e2e -- --exact --nocapture + ``` + Every proof writes `/-.json` (per-proof counter deltas) in the + `scripts/flamegraph.py` metrics format. + +3. **Analyze** with `scripts/profile_top.py --symbols releases/dev//guest.symbols` + (top functions by executed instructions, inclusive span stacks). `scripts/flamegraph.py` + `--guest-symbols` works on the same files for SVG flamegraphs. + +Caveats: +- The profile counts *executed instructions* per function. On the GPU proving path the + per-AIR `cells_used` metrics are NOT emitted (CPU prove only), and the instruction replay + inflates wall-clock proving time ~4x — never compare wall times from a `perf-metrics` build + against a clean build. +- The recorder accumulates per process; the prover writes per-proof deltas, so each JSON holds + exactly one proof's profile even when a test proves many circuits (e2e bundle). + ## Common Failure Patterns ### `NativeHintSliceSubEx` assertion failure diff --git a/Cargo.lock b/Cargo.lock index debd99d0..13bb9219 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8083,7 +8083,7 @@ dependencies = [ "alloy-primitives", "bincode 2.0.1", "openvm", - "openvm-keccak256-guest", + "openvm-keccak256", "scroll-zkvm-types-bundle", "scroll-zkvm-types-circuit", ] @@ -8172,6 +8172,8 @@ dependencies = [ "eyre", "git-version", "hex", + "metrics", + "metrics-util", "openvm-circuit", "openvm-continuations", "openvm-cuda-backend", diff --git a/crates/build-guest/Cargo.toml b/crates/build-guest/Cargo.toml index 5fec3fda..e36681dc 100644 --- a/crates/build-guest/Cargo.toml +++ b/crates/build-guest/Cargo.toml @@ -31,3 +31,5 @@ clap = { version = "4.0", features = ["derive"] } [features] default = ["scroll"] scroll = ["scroll-zkvm-types/scroll"] +# Bake function bounds into .vmexe files for guest cycle profiling. +perf-metrics = ["openvm-sdk/perf-metrics"] diff --git a/crates/build-guest/src/main.rs b/crates/build-guest/src/main.rs index ef6ad58f..de4b6115 100644 --- a/crates/build-guest/src/main.rs +++ b/crates/build-guest/src/main.rs @@ -267,6 +267,21 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re // 1. Build ELF + // Create the assets dir if not already present. + let path_assets = Path::new(release_output_dir).join(project_name); + fs::create_dir_all(&path_assets)?; + + // With `perf-metrics`, the transpiler records function bounds in the exe and + // requires GUEST_SYMBOLS_PATH to dump the demangled symbol table (consumed by + // scripts/flamegraph.py --guest-symbols). `sdk.build` already decodes the ELF, + // so this must be set before it. + #[cfg(feature = "perf-metrics")] + { + let guest_symbols_path = path_assets.join("guest.symbols"); + println!("{LOG_PREFIX} GUEST_SYMBOLS_PATH={guest_symbols_path:?}"); + std::env::set_var("GUEST_SYMBOLS_PATH", &guest_symbols_path); + } + // Store current directory and change to project directory let original_dir = env::current_dir()?; env::set_current_dir(&project_path)?; @@ -297,9 +312,6 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re original_dir.display() ); - // Create the assets dir if not already present. - let path_assets = Path::new(release_output_dir).join(project_name); - fs::create_dir_all(&path_assets)?; let elf_src = workspace_dir .join("target") .join("riscv64im-unknown-openvm-elf") @@ -312,6 +324,28 @@ fn generate_app_assets(workspace_dir: &Path, release_output_dir: &PathBuf) -> Re // 2. Transpile ELF to VM Executable let app_exe: VmExe = (*sdk.convert_to_exe(elf)?).clone(); + // openvm's `update_current_fn` unwraps the greatest function bound <= pc, + // which panics if execution touches a pc below the first STT_FUNC symbol + // (entry trampolines etc.). Cover that range with a synthetic bound whose + // name is offset 0 in the symbols string table (the empty string). + #[cfg(feature = "perf-metrics")] + let app_exe = { + let mut app_exe = app_exe; + if let Some((&min_start, _)) = app_exe.fn_bounds.iter().next() { + if min_start > 0 { + app_exe.fn_bounds.insert( + 0, + openvm_instructions::exe::FnBound { + start: 0, + end: min_start - 1, + name: "0".to_string(), + }, + ); + } + } + app_exe + }; + // Write exe to disc. let path_app_exe: PathBuf = path_assets.join("app.vmexe"); write_object_to_file(&path_app_exe, app_exe.clone())?; diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 61db46d4..e5495f4b 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [260182314, 1280890024, 529127170, 916766546, 895907952, 1406126257, 12172159, 1952507758]; +pub const COMMIT: [u32; 8] = [236400959, 1921678370, 1681141574, 435295083, 1495503815, 21325623, 212114691, 392953574]; diff --git a/crates/circuits/bundle-circuit/Cargo.toml b/crates/circuits/bundle-circuit/Cargo.toml index 9319ec41..fcee2adc 100644 --- a/crates/circuits/bundle-circuit/Cargo.toml +++ b/crates/circuits/bundle-circuit/Cargo.toml @@ -11,9 +11,9 @@ scroll-zkvm-types-circuit.workspace = true scroll-zkvm-types-bundle.workspace = true openvm = { workspace = true, features = ["std"] } -openvm-keccak256-guest.workspace = true +openvm-keccak256 = { workspace = true } -alloy-primitives = { workspace = true } +alloy-primitives = { workspace = true, features = ["native-keccak"] } [features] default = [] diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 482e9848..80971976 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1096401504, 229560942, 1241164728, 64742493, 1896387437, 936717747, 436295168, 132807200]; +pub const COMMIT: [u32; 8] = [159067914, 70283829, 1094250858, 1695200420, 1766304820, 1211651143, 955692376, 2323832]; diff --git a/crates/circuits/bundle-circuit/src/circuit.rs b/crates/circuits/bundle-circuit/src/circuit.rs index 721b6516..38978b54 100644 --- a/crates/circuits/bundle-circuit/src/circuit.rs +++ b/crates/circuits/bundle-circuit/src/circuit.rs @@ -15,7 +15,7 @@ use scroll_zkvm_types_circuit::{ use crate::child_commitments; #[allow(unused_imports, clippy::single_component_path_imports)] -use openvm_keccak256_guest; +use openvm_keccak256; // trigger extern native-keccak256 #[derive(Default)] pub struct BundleCircuit; diff --git a/crates/integration/Cargo.toml b/crates/integration/Cargo.toml index c9e76d64..4b6554a7 100644 --- a/crates/integration/Cargo.toml +++ b/crates/integration/Cargo.toml @@ -75,4 +75,4 @@ cuda = ["scroll-zkvm-prover/cuda"] # halo2 (SNARK) proving on GPU; implies cuda. VRAM-heavy, see scroll-zkvm-prover. halo2-gpu = ["scroll-zkvm-prover/halo2-gpu"] limit-logs = [] -perf-metrics = ["openvm-sdk/perf-metrics"] +perf-metrics = ["openvm-sdk/perf-metrics", "scroll-zkvm-prover/perf-metrics"] diff --git a/crates/prover/Cargo.toml b/crates/prover/Cargo.toml index 7876b554..64a75825 100644 --- a/crates/prover/Cargo.toml +++ b/crates/prover/Cargo.toml @@ -35,6 +35,8 @@ thiserror.workspace = true toml = "0.8" cudarc = { version = "0.9", optional = true } +metrics = { version = "0.23", optional = true } +metrics-util = { version = "0.17", optional = true } [dev-dependencies] @@ -44,5 +46,8 @@ cuda = ["openvm-sdk/cuda", "dep:cudarc", "openvm-verify-stark-circuit/cuda", "de # GPU acceleration for the halo2 (SNARK) prover on top of `cuda`. Needs much # more VRAM than STARK proving; enable only on 24 GB-class GPUs. halo2-gpu = ["cuda", "openvm-sdk/halo2-gpu"] +# Per-function guest cycle profiling. Dumps a metrics JSON (flamegraph.py +# format) at the path in env PROFILE_METRICS_JSON after each proof. +perf-metrics = ["openvm-sdk/perf-metrics", "dep:metrics", "dep:metrics-util"] diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index 41168508..41440759 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -43,6 +43,104 @@ type SdkAppConfig = AppConfig; // Re-export from openvm_sdk. pub use openvm_sdk::{self}; +/// Dumps guest profiling counters (per-function cycles, cells used) recorded +/// by openvm's `perf-metrics` feature into JSON files in the format that +/// `scripts/flamegraph.py` consumes. Enabled by setting PROFILE_METRICS_DIR to +/// an output directory. Every proof writes `-.json` holding the +/// counter *delta* since the previous proof in this process, so each file +/// contains exactly one proof's guest profile. +#[cfg(feature = "perf-metrics")] +mod profile_dump { + use std::collections::HashMap; + use std::sync::{Mutex, OnceLock}; + + static SNAPSHOTTER: OnceLock> = OnceLock::new(); + static PREV: Mutex>> = Mutex::new(None); + static NEXT_IDX: Mutex> = + Mutex::new(std::collections::BTreeMap::new()); + + fn snapshotter() -> Option<&'static metrics_util::debugging::Snapshotter> { + std::env::var_os("PROFILE_METRICS_DIR")?; + SNAPSHOTTER + .get_or_init(|| { + let recorder = metrics_util::debugging::DebuggingRecorder::new(); + let snapshotter = recorder.snapshotter(); + metrics::set_global_recorder(recorder) + .ok() + .map(|_| snapshotter) + }) + .as_ref() + } + + pub fn install() { + let _ = snapshotter(); + } + + pub fn dump(prover_name: &str) { + let Some(snapshotter) = snapshotter() else { + return; + }; + let dir = std::env::var("PROFILE_METRICS_DIR").expect("checked by snapshotter()"); + + #[derive(serde::Serialize)] + struct Entry { + metric: String, + labels: Vec<(String, String)>, + value: u64, + } + + // Current absolute counter values, keyed by a stable serialization. + let mut entries = HashMap::)>::new(); + let mut cur = HashMap::::new(); + for (key, _unit, _desc, value) in snapshotter.snapshot().into_vec() { + if key.kind() != metrics_util::MetricKind::Counter { + continue; + } + let metrics_util::debugging::DebugValue::Counter(value) = value else { + continue; + }; + let key = key.key(); + let labels: Vec<(String, String)> = key + .labels() + .map(|l| (l.key().to_string(), l.value().to_string())) + .collect(); + let id = format!("{}\0{:?}", key.name(), labels); + entries.insert(id.clone(), (key.name().to_string(), labels)); + cur.insert(id, value); + } + + let mut prev = PREV.lock().unwrap(); + let prev_map = prev.get_or_insert_with(HashMap::new); + let mut delta_entries = Vec::new(); + for (id, value) in &cur { + let delta = value.saturating_sub(prev_map.get(id).copied().unwrap_or(0)); + if delta == 0 { + continue; + } + let (metric, labels) = &entries[id]; + delta_entries.push(Entry { + metric: metric.clone(), + labels: labels.clone(), + value: delta, + }); + } + *prev_map = cur; + drop(prev); + + let mut idx_map = NEXT_IDX.lock().unwrap(); + let idx = idx_map.entry(prover_name.to_string()).or_insert(0); + let path = format!("{dir}/{prover_name}-{idx}.json"); + *idx += 1; + drop(idx_map); + + let json = serde_json::json!({ "counter": delta_entries }); + match std::fs::write(&path, serde_json::to_string(&json).unwrap()) { + Ok(()) => tracing::info!("profile metrics written to {path}"), + Err(err) => tracing::warn!("failed to write profile metrics to {path}: {err}"), + } + } +} + /// Default aggregation parameters shared by all provers. fn default_agg_params() -> AggregationSystemParams { AggregationSystemParams { @@ -351,10 +449,14 @@ impl Prover { let execution_time_mills = t.elapsed().as_millis() as u64; let t = std::time::Instant::now(); + #[cfg(feature = "perf-metrics")] + profile_dump::install(); let sdk = self.get_sdk()?; let (vm_stark_proof, baseline) = sdk .prove(self.app_exe.clone(), stdin, def_inputs) .map_err(|e| Error::GenProof(e.to_string()))?; + #[cfg(feature = "perf-metrics")] + profile_dump::dump(&self.prover_name); let proving_time_mills = t.elapsed().as_millis() as u64; let proving_time_s = proving_time_mills as f32 / 1000.0f32; let prove_speed = (total_cycles as f32 / 1_000_000.0f32) / proving_time_s; // MHz @@ -423,10 +525,14 @@ impl Prover { ) -> Result { self.execute_and_check(&stdin)?; + #[cfg(feature = "perf-metrics")] + profile_dump::install(); let sdk = self.get_sdk()?; let evm_proof = sdk .prove_evm(self.app_exe.clone(), stdin, def_inputs) .map_err(|e| Error::GenProof(format!("{}", e)))?; + #[cfg(feature = "perf-metrics")] + profile_dump::dump(&self.prover_name); Ok(evm_proof) } diff --git a/crates/types/batch/src/blob_consistency/mod.rs b/crates/types/batch/src/blob_consistency/mod.rs index a6498d47..fba44da7 100644 --- a/crates/types/batch/src/blob_consistency/mod.rs +++ b/crates/types/batch/src/blob_consistency/mod.rs @@ -42,8 +42,11 @@ impl BlobPolynomial { "too many bytes in batch data" ); - for (i, &byte) in blob_bytes.iter().enumerate() { - coefficients[i / 31][1 + (i % 31)] = byte; + for (coefficient, bytes) in coefficients + .iter_mut() + .zip(blob_bytes.chunks(N_DATA_BYTES_PER_COEFFICIENT)) + { + coefficient[1..1 + bytes.len()].copy_from_slice(bytes); } Self(coefficients.map(|coeff| U256::from_be_bytes(coeff))) diff --git a/crates/types/batch/src/builder/v7.rs b/crates/types/batch/src/builder/v7.rs index b2e69930..04d7ee94 100644 --- a/crates/types/batch/src/builder/v7.rs +++ b/crates/types/batch/src/builder/v7.rs @@ -79,14 +79,21 @@ impl super::BatchInfoBuilder for GenericBatchInfoBuilderV7

{ "blob-envelope bigger than allowed", ); - let envelope_bytes = { - let mut padded = args.blob_bytes.to_vec(); - padded.resize(N_BLOB_BYTES, 0); - padded + // Blob bytes from the witness are already padded to N_BLOB_BYTES; only + // fall back to local padding for shorter (e.g. hand-crafted) inputs. + let envelope_bytes_storage; + let envelope_bytes: &[u8] = if args.blob_bytes.len() == N_BLOB_BYTES { + args.blob_bytes.as_slice() + } else { + envelope_bytes_storage = { + let mut padded = args.blob_bytes.to_vec(); + padded.resize(N_BLOB_BYTES, 0); + padded + }; + &envelope_bytes_storage }; - let envelope = <::Envelope as Envelope>::from_slice( - envelope_bytes.as_slice(), - ); + let envelope = + <::Envelope as Envelope>::from_slice(envelope_bytes); let payload = Self::Payload::from_envelope(&envelope); let blob_versioned_hash = args.header.blob_versioned_hash(); diff --git a/crates/types/batch/src/witness.rs b/crates/types/batch/src/witness.rs index fb7e569c..220ed64f 100644 --- a/crates/types/batch/src/witness.rs +++ b/crates/types/batch/src/witness.rs @@ -94,6 +94,7 @@ pub struct BatchWitness { /// Chunk infos. pub chunk_infos: Vec, /// Blob bytes. + #[serde(with = "bytes_vec")] pub blob_bytes: Vec, /// Witness for point evaluation. /// @@ -112,6 +113,51 @@ impl ProofCarryingWitness for BatchWitness { } } +/// Serde helper for large byte vectors. The wire format stays identical to +/// bincode's default `Vec` encoding (length prefix + raw bytes), but +/// deserialization claims the whole slice in one shot instead of decoding +/// element by element. +mod bytes_vec { + use serde::{Deserializer, Serializer}; + + pub fn serialize(bytes: &[u8], serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(bytes) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + struct Visitor; + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = Vec; + + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("a byte array") + } + + fn visit_bytes(self, v: &[u8]) -> Result { + Ok(v.to_vec()) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut out = Vec::with_capacity(seq.size_hint().unwrap_or(0)); + while let Some(b) = seq.next_element()? { + out.push(b); + } + Ok(out) + } + } + deserializer.deserialize_bytes(Visitor) + } +} + impl From<&BatchWitness> for BatchInfo { fn from(witness: &BatchWitness) -> Self { let chunk_infos = witness.chunk_infos.to_vec(); diff --git a/scripts/profile_top.py b/scripts/profile_top.py new file mode 100644 index 00000000..5e63a87e --- /dev/null +++ b/scripts/profile_top.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +"""Aggregate guest profiling metrics JSON (dumped by scroll-zkvm-prover's +`perf-metrics` feature via PROFILE_METRICS_DIR) into human-readable tops: + + - top functions by executed instructions ("frequency"), self-attribution + (leaf frame of the cycle tracker span stack) + - top inclusive span stacks (flamegraph-style), also written as .stacks + - top AIRs by cells used ("cells_used") + +Function spans are decimal offsets into the guest symbols string table +(dumped by build-guest as guest.symbols when built with `perf-metrics`). + +Usage: profile_top.py metrics.json [--symbols guest.symbols] [--top 30] +""" + +import argparse +import json +import sys +from collections import defaultdict + + +def load_symbols(path): + if not path: + return None + with open(path, "rb") as f: + return f.read() + + +def resolve(name, symbols): + """Resolve a span frame: decimal offset into the string table, or a plain name.""" + if symbols is None or not name or not name.isdigit(): + return name + offset = int(name) + end = symbols.find(b"\0", offset) + if end == -1 or offset >= len(symbols): + return name + return symbols[offset:end].decode(errors="replace") + + +def shorten(name, maxlen=110): + """Collapse verbose Rust paths: keep the last meaningful segments.""" + if len(name) <= maxlen: + return name + # strip generic args for readability + out = [] + depth = 0 + for ch in name: + if ch == "<": + depth += 1 + elif ch == ">": + depth -= 1 + elif depth == 0: + out.append(ch) + name = "".join(out) + if len(name) > maxlen: + name = "..." + name[-maxlen:] + return name + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("metrics_json") + ap.add_argument("--symbols", default=None) + ap.add_argument("--top", type=int, default=30) + args = ap.parse_args() + + with open(args.metrics_json) as f: + data = json.load(f) + + symbols = load_symbols(args.symbols) + + instr_self = defaultdict(int) # leaf function -> instructions + instr_inclusive = defaultdict(int) # full stack -> instructions + cells_air = defaultdict(int) # air name -> cells + cells_span_air = defaultdict(int) # (span leaf fn, air) -> cells + + for entry in data.get("counter", []): + metric = entry["metric"] + labels = dict(entry["labels"]) + value = int(entry["value"]) + span = labels.get("cycle_tracker_span", "") + frames = [resolve(f, symbols) for f in span.split(";") if f != ""] + leaf = frames[-1] if frames else "" + + if metric == "frequency": + instr_self[leaf] += value + instr_inclusive[";".join(frames)] += value + elif metric == "cells_used": + air = labels.get("air_name", "?") + cells_air[air] += value + cells_span_air[(leaf, air)] += value + + total_instr = sum(instr_self.values()) + total_cells = sum(cells_air.values()) + + print(f"== total guest instructions (frequency): {total_instr:,}") + print(f"== total trace cells (cells_used): {total_cells:,}") + print() + print(f"-- top {args.top} functions by instructions (self) --") + for name, v in sorted(instr_self.items(), key=lambda kv: -kv[1])[: args.top]: + print(f"{v:>14,} {100.0*v/max(total_instr,1):5.1f}% {shorten(name)}") + print() + print(f"-- top {args.top} AIRs by cells used --") + for name, v in sorted(cells_air.items(), key=lambda kv: -kv[1])[: args.top]: + print(f"{v:>14,} {100.0*v/max(total_cells,1):5.1f}% {name}") + print() + print(f"-- top {args.top} (function, AIR) by cells used --") + for (fn, air), v in sorted(cells_span_air.items(), key=lambda kv: -kv[1])[: args.top]: + print(f"{v:>14,} {100.0*v/max(total_cells,1):5.1f}% {air} <- {shorten(fn, 80)}") + print() + print(f"-- top {args.top} inclusive span stacks by instructions --") + for stack, v in sorted(instr_inclusive.items(), key=lambda kv: -kv[1])[: args.top]: + print(f"{v:>14,} {100.0*v/max(total_instr,1):5.1f}% {shorten(stack, 160)}") + + +if __name__ == "__main__": + main() From 430b7acc0db86927a0d27e2a37de0bcc2e2d46ee Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sat, 26 Sep 2026 03:27:51 +0000 Subject: [PATCH 13/15] perf: cut chunk guest cycles 12.1% via MPT decode + keccak absorb fast paths Two local patch crates (see AGENTS.md 'Local patch crates'): - patches/risc0-ethereum-trie: hand-written MPT node parser replacing the alloy-rlp PayloadView based decoder (no per-list Vec alloc, single-copy compact-path decode), plus an inline fast path for 33-byte digest children. Per chunk the witness MPTs contain ~11.5k real nodes but ~111k digest children, so skipping the generic recursion for digests is the biggest win. - patches/openvm-keccak256-guest: native_xorin stages unaligned input in an aligned zero-padded stack buffer instead of heap AlignedBuf round-trips (27% of the 87k absorbs per chunk take it). Also keeps an execute-path profiling hook: tester_execute honors PROFILE_METRICS_DIR under the perf-metrics feature, and profile_dump is pub. AGENTS.md documents that the GPU-prove replay profile truncates after ~26% of the execution (use a CPU prove for a full-execution profile). chunk circuit (GalileoV2 preset, 6 blocks / 630 txs / 35.2M gas): cycles 202,969,694 -> 178,400,161 (-12.1%) e2e STARK prove 44.15s -> 41.40s (-6.2%, RTX 4090) batch circuit: 5,397,474 -> 5,394,332 cycles (keccak patch only) pi hashes unchanged; test_execute + e2e chunk/batch/bundle all pass; risc0-ethereum-trie unit tests (17) pass; jumpdest analysis was fuzzed against revm's analyze_legacy for equivalence during development. --- .gitignore | 3 + AGENTS.md | 39 + Cargo.lock | 2 - Cargo.toml | 13 + .../batch-circuit/batch_exe_commit.rs | 2 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- crates/integration/src/lib.rs | 6 +- crates/prover/src/lib.rs | 2 +- crates/prover/src/prover/mod.rs | 2 +- patches/openvm-keccak256-guest/Cargo.toml | 16 + patches/openvm-keccak256-guest/src/lib.rs | 145 +++ patches/risc0-ethereum-trie/Cargo.toml | 34 + patches/risc0-ethereum-trie/README.md | 3 + patches/risc0-ethereum-trie/src/lib.rs | 24 + .../risc0-ethereum-trie/src/mpt/children.rs | 197 ++++ .../risc0-ethereum-trie/src/mpt/memoize.rs | 53 + patches/risc0-ethereum-trie/src/mpt/mod.rs | 919 ++++++++++++++++++ .../risc0-ethereum-trie/src/mpt/nibbles.rs | 115 +++ patches/risc0-ethereum-trie/src/mpt/node.rs | 291 ++++++ patches/risc0-ethereum-trie/src/mpt/orphan.rs | 330 +++++++ patches/risc0-ethereum-trie/src/mpt/rkyv.rs | 189 ++++ patches/risc0-ethereum-trie/src/mpt/rlp.rs | 654 +++++++++++++ patches/risc0-ethereum-trie/src/mpt/serde.rs | 116 +++ 24 files changed, 3151 insertions(+), 8 deletions(-) create mode 100644 patches/openvm-keccak256-guest/Cargo.toml create mode 100644 patches/openvm-keccak256-guest/src/lib.rs create mode 100644 patches/risc0-ethereum-trie/Cargo.toml create mode 100644 patches/risc0-ethereum-trie/README.md create mode 100644 patches/risc0-ethereum-trie/src/lib.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/children.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/memoize.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/mod.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/nibbles.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/node.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/orphan.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/rkyv.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/rlp.rs create mode 100644 patches/risc0-ethereum-trie/src/mpt/serde.rs diff --git a/.gitignore b/.gitignore index b80edca8..a3bbc762 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ verifier.bin .vscode/ .env + +# standalone test runs inside patch crates generate their own lockfiles +patches/*/Cargo.lock diff --git a/AGENTS.md b/AGENTS.md index 10cb23f7..a74231cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -152,9 +152,48 @@ Caveats: per-AIR `cells_used` metrics are NOT emitted (CPU prove only), and the instruction replay inflates wall-clock proving time ~4x — never compare wall times from a `perf-metrics` build against a clean build. +- **GPU prove replay is truncated**: the GPU postflight program log only covers the first + ~26% of a chunk-sized execution (53.4M of 203M instructions — verify against the + `execute_metered_insns` counter or `total_cycles`; if `frequency` totals are much lower, + the sample is partial). Witness-processing phases sit early in the execution, so a + truncated sample over-weights them vs EVM execution. For a full-execution profile, run the + prove on CPU (no `cuda` feature): the CPU replay covers every segment. +- The execute-only path (`tester_execute`, e.g. `test-execute-chunk`) also honors + `PROFILE_METRICS_DIR` and writes `execute-0.json`, but the metered-cost executor emits no + function-span counters there — it is only useful for total cycle counts. - The recorder accumulates per process; the prover writes per-proof deltas, so each JSON holds exactly one proof's profile even when a test proves many circuits (e2e bundle). +## Local patch crates (`patches/`) + +Dependencies patched to local sources via `[patch]` in the root `Cargo.toml`: + +- `patches/openvm-mem` — memmove recursion fix (see failure patterns). +- `patches/openvm-keccak256-guest` — `native_xorin` gains an aligned-stack staging fast path + for unaligned inputs/lengths (the common case for trie-node and digest hashing), avoiding + 2 heap allocations + 3 copies per call. ~27% of the chunk circuit's 87k keccak absorbs take + this path. Revert by deleting the `[patch]` entry and directory. +- `patches/risc0-ethereum-trie` — hand-written MPT node decoder replacing the + alloy-rlp `PayloadView` based one (no per-list `Vec` allocation, single-copy path + decoding), plus an inline fast path for the 33-byte digest children that dominate + branch nodes (~111k per chunk vs ~11.5k real nodes — skipping the generic decoder + recursion for them was the single biggest chunk win, −8%). The original + implementation is kept as `decode_node_orig`/`decode_path_orig` behind + `const FAST_DECODE` for A/B measurement; the crate's own unit tests + (`cargo test` inside the directory) cover the parser. + +Rules of engagement when editing `[patch]` tables here: + +- **Never** run a bare `cargo update` or a plain `cargo metadata` after changing patches — + unpinned git deps (`risc0-ethereum` by branch HEAD, `da-codec`, ...) float to the newest + fetched commit and `alloy-evm`'s `revm` req re-resolves to registry `30.2.0`, breaking the + build with duplicate-revm type mismatches. Instead hand-edit `Cargo.lock` to the minimal + diff (for a path patch: delete the package's `source =` line, adjust its dep list), then + verify with `cargo metadata --locked` (must print nothing / exit 0 without touching the lock). +- A `[patch]` cannot intercept *path* deps inside a git dependency (e.g. `revm-interpreter`'s + dep on `revm-bytecode` inside the scroll-revm repo) — patching individual crates out of such + a repo requires vendoring the whole repo, which we avoid. + ## Common Failure Patterns ### `NativeHintSliceSubEx` assertion failure diff --git a/Cargo.lock b/Cargo.lock index 13bb9219..9f3062a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4827,7 +4827,6 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0" -source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-platform", ] @@ -7582,7 +7581,6 @@ dependencies = [ [[package]] name = "risc0-ethereum-trie" version = "0.1.0" -source = "git+https://github.com/risc0/risc0-ethereum#c1ddb41a44dc0730da883bbfa9fbe75ad335df1b" dependencies = [ "alloy-primitives", "alloy-rlp", diff --git a/Cargo.toml b/Cargo.toml index 42a4f0f8..7c3d7d6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -165,8 +165,21 @@ revm-state = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" } # openvm-mem's copy_forward/copy_backward use 64-byte aggregate copies that LLVM lowers # into `memmove` calls, making `memmove` recurse until the guest stack overflows. # Override with a local copy that uses u64 chunks instead. See patches/openvm-mem. +# openvm-keccak256-guest: local fork adds an unaligned-input fast path for native_xorin +# (avoids 2 heap allocs + 3 memcpys per keccak256 call). See patches/openvm-keccak256-guest. [patch."https://github.com/openvm-org/openvm.git"] openvm-mem = { path = "patches/openvm-mem" } +openvm-keccak256-guest = { path = "patches/openvm-keccak256-guest" } + +# (An sbv-trie fork for bytecode-analysis dedup was tried and rejected: witness +# codes are already deduplicated host-side in ChunkWitness::new, and a SWAR +# jumpdest scan loses to the byte-wise loop since ~83% of 8-byte words in real +# bytecode contain a PUSH opcode byte.) + +# Experimental local fork for guest cycle optimization (hand-written MPT node parser). +# Same code as c1ddb41 otherwise; delete this section to disable. +[patch."https://github.com/risc0/risc0-ethereum"] +risc0-ethereum-trie = { path = "patches/risc0-ethereum-trie" } [profile.maxperf] inherits = "release" diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index e5495f4b..4542ae03 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [236400959, 1921678370, 1681141574, 435295083, 1495503815, 21325623, 212114691, 392953574]; +pub const COMMIT: [u32; 8] = [269629868, 11304576, 863701181, 1150881528, 59510026, 134705669, 876257829, 347575516]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index 80971976..a0478042 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [159067914, 70283829, 1094250858, 1695200420, 1766304820, 1211651143, 955692376, 2323832]; +pub const COMMIT: [u32; 8] = [377119168, 119635917, 112852172, 128935761, 622071650, 982588409, 1749410501, 766274532]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index 37f12f0d..de609822 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1192406321, 1007067640, 1433639583, 1891545475, 903990723, 621677400, 1106027141, 1005293682]; +pub const COMMIT: [u32; 8] = [1811353780, 763823461, 692493179, 1468603078, 466259603, 1427628903, 1282295217, 627556282]; diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index 41f2939b..9cc3b564 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -3,10 +3,10 @@ use once_cell::sync::OnceCell; use openvm_circuit::arch::deferral::DeferralState; use openvm_sdk::config::AggregationSystemParams; use openvm_sdk::{DeferralInput, Sdk, StdIn}; -use openvm_stark_sdk::openvm_stark_backend::codec::Decode; use openvm_stark_sdk::config::{ internal_params_with_100_bits_security, leaf_params_with_100_bits_security, }; +use openvm_stark_sdk::openvm_stark_backend::codec::Decode; use openvm_verify_stark_circuit::extension::{get_deferral_state, get_raw_deferral_results}; use openvm_verify_stark_host::{ VmStarkProof, @@ -425,7 +425,11 @@ pub fn tester_execute( }) .build() .map_err(|e| eyre::eyre!("sdk build failed: {e}"))?; + #[cfg(feature = "perf-metrics")] + scroll_zkvm_prover::prover::profile_dump::install(); let ret = scroll_zkvm_prover::utils::vm::execute_guest(&sdk, app_exe, &stdin)?; + #[cfg(feature = "perf-metrics")] + scroll_zkvm_prover::prover::profile_dump::dump("execute"); Ok(ret) } diff --git a/crates/prover/src/lib.rs b/crates/prover/src/lib.rs index a5776558..e10295ee 100644 --- a/crates/prover/src/lib.rs +++ b/crates/prover/src/lib.rs @@ -3,7 +3,7 @@ mod error; pub use error::Error; -mod prover; +pub mod prover; pub use prover::{Prover, ProverConfig}; pub mod setup; diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index 41440759..976bf066 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -50,7 +50,7 @@ pub use openvm_sdk::{self}; /// counter *delta* since the previous proof in this process, so each file /// contains exactly one proof's guest profile. #[cfg(feature = "perf-metrics")] -mod profile_dump { +pub mod profile_dump { use std::collections::HashMap; use std::sync::{Mutex, OnceLock}; diff --git a/patches/openvm-keccak256-guest/Cargo.toml b/patches/openvm-keccak256-guest/Cargo.toml new file mode 100644 index 00000000..8de69183 --- /dev/null +++ b/patches/openvm-keccak256-guest/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "openvm-keccak256-guest" +description = "OpenVM guest library for keccak256" +version = "2.0.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +# Local experimental fork of openvm `develop-v2.1.0` (29fc511e) keccak256 guest +# crate for zkVM cycle optimization. See patches/ notes in AGENTS.md. + +[dependencies] +openvm-platform = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } + +[features] +default = [] + diff --git a/patches/openvm-keccak256-guest/src/lib.rs b/patches/openvm-keccak256-guest/src/lib.rs new file mode 100644 index 00000000..75d490e0 --- /dev/null +++ b/patches/openvm-keccak256-guest/src/lib.rs @@ -0,0 +1,145 @@ +#![no_std] + +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +use openvm_platform::alloc::AlignedBuf; + +pub const OPCODE: u8 = 0x0b; +pub const KECCAKF_FUNCT3: u8 = 0b100; +pub const KECCAKF_FUNCT7: u8 = 0; +pub const XORIN_FUNCT3: u8 = 0b100; +pub const XORIN_FUNCT7: u8 = 1; + +pub const KECCAK_WIDTH_BYTES: usize = 200; +pub const KECCAK_RATE: usize = 136; +pub const KECCAK_OUTPUT_SIZE: usize = 32; +pub const MIN_ALIGN: usize = 8; + +/// Compile-time toggle: `false` disables the aligned-stack staging fast path in +/// `native_xorin` (for A/B cycle measurement). +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +const FAST_XORIN: bool = true; + +/// XOR `len` bytes from `input` into `buffer` using the native XORIN instruction. +/// +/// # Panics +/// +/// Panics if `len > KECCAK_RATE` (136): the XORIN circuit absorbs at most `KECCAK_RATE` bytes +/// per instruction, so a larger length would execute but fail to prove. +/// +/// # Safety +/// +/// - `buffer` must point to a buffer of at least `len` bytes. +/// - `input` must point to a buffer of at least `len` bytes. +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[no_mangle] +pub unsafe extern "C" fn native_xorin(buffer: *mut u8, input: *const u8, len: usize) { + assert!( + len <= KECCAK_RATE, + "native_xorin: len exceeds the XORIN circuit's maximum rate of {} bytes", + KECCAK_RATE + ); + if len == 0 { + return; + } + unsafe { + let buffer_aligned = buffer as usize % MIN_ALIGN == 0; + let input_aligned = input as usize % MIN_ALIGN == 0; + let len_aligned = len % MIN_ALIGN == 0; + let all_aligned = buffer_aligned && input_aligned && len_aligned; + + if all_aligned { + __native_xorin(buffer, input, len); + } else if buffer_aligned && FAST_XORIN { + // Fast path: stage the (possibly unaligned) input in an aligned stack + // buffer. The XORIN instruction consumes a whole number of 8-byte + // words, so zero the tail padding to leave those state words + // unchanged (x ^ 0 = x). This avoids two heap allocations and the + // buffer copy round-trip of the generic path below. + #[repr(align(8))] + struct Stage([u8; KECCAK_RATE]); + + let adjusted_len = len.next_multiple_of(MIN_ALIGN); + let mut stage = core::mem::MaybeUninit::::uninit(); + let stage_ptr = stage.as_mut_ptr() as *mut u8; + core::ptr::copy_nonoverlapping(input, stage_ptr, len); + core::ptr::write_bytes(stage_ptr.add(len), 0, adjusted_len - len); + __native_xorin(buffer, stage_ptr, adjusted_len); + } else { + let adjusted_len = len.next_multiple_of(MIN_ALIGN); + let aligned_buffer; + let aligned_input; + + let actual_buffer = if buffer_aligned && len_aligned { + buffer + } else { + aligned_buffer = AlignedBuf::uninit(adjusted_len, MIN_ALIGN); + core::ptr::copy_nonoverlapping(buffer, aligned_buffer.ptr, len); + aligned_buffer.ptr + }; + + let actual_input = if input_aligned && len_aligned { + input + } else { + aligned_input = AlignedBuf::uninit(adjusted_len, MIN_ALIGN); + core::ptr::copy_nonoverlapping(input, aligned_input.ptr, len); + aligned_input.ptr + }; + + __native_xorin(actual_buffer, actual_input, adjusted_len); + + if !buffer_aligned || !len_aligned { + core::ptr::copy_nonoverlapping(actual_buffer as *const u8, buffer, len); + } + } + } +} + +/// Apply the Keccak-f\[1600\] permutation to the 200-byte state buffer. +/// +/// # Safety +/// +/// - `buffer` must point to a buffer of at least `KECCAK_WIDTH_BYTES` (200) bytes. +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[no_mangle] +pub unsafe extern "C" fn native_keccakf(buffer: *mut u8) { + unsafe { + if buffer as usize % MIN_ALIGN == 0 { + __native_keccakf(buffer); + } else { + let aligned_buffer = AlignedBuf::new(buffer, KECCAK_WIDTH_BYTES, MIN_ALIGN); + __native_keccakf(aligned_buffer.ptr); + core::ptr::copy_nonoverlapping( + aligned_buffer.ptr as *const u8, + buffer, + KECCAK_WIDTH_BYTES, + ); + } + } +} + +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[inline(always)] +fn __native_xorin(mut buffer: *mut u8, input: *const u8, len: usize) { + openvm_platform::custom_insn_r!( + opcode = OPCODE, + funct3 = XORIN_FUNCT3, + funct7 = XORIN_FUNCT7, + rd = InOut buffer, + rs1 = In input, + rs2 = In len + ); +} + +#[cfg(any(openvm_intrinsics, target_os = "openvm"))] +#[inline(always)] +fn __native_keccakf(mut buffer: *mut u8) { + openvm_platform::custom_insn_r!( + opcode = OPCODE, + funct3 = KECCAKF_FUNCT3, + funct7 = KECCAKF_FUNCT7, + rd = InOut buffer, + rs1 = Const "x0", + rs2 = Const "x0", + ); +} + diff --git a/patches/risc0-ethereum-trie/Cargo.toml b/patches/risc0-ethereum-trie/Cargo.toml new file mode 100644 index 00000000..0dd69554 --- /dev/null +++ b/patches/risc0-ethereum-trie/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "risc0-ethereum-trie" +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/risc0/risc0-ethereum" + +# Local experimental fork of risc0-ethereum-trie @ c1ddb41 for zkVM cycle +# optimization. See patches/ notes in AGENTS.md. + +[dependencies] +alloy-primitives = { version = "1.3", features = ["map"] } +alloy-rlp = { version = "0.3.8", features = ["arrayvec"] } +alloy-trie = { version = "0.8" } +arrayvec = "0.7" +bincode = { version = "1.3", optional = true } +itertools = "0.14" +rkyv = { version = "0.8", optional = true } +serde = { version = "1.0", optional = true } +thiserror = "2.0" + +[features] +default = [] +rkyv = ["dep:rkyv"] +serde = ["dep:serde", "dep:bincode", "alloy-primitives/serde", "alloy-trie/serde"] +rlp_serialize = [] +orphan = [] + +[dev-dependencies] +alloy-trie = { version = "0.8", features = ["ethereum"] } +serde_json = "1.0" + + +[workspace] diff --git a/patches/risc0-ethereum-trie/README.md b/patches/risc0-ethereum-trie/README.md new file mode 100644 index 00000000..688ff1f7 --- /dev/null +++ b/patches/risc0-ethereum-trie/README.md @@ -0,0 +1,3 @@ +# risc0-ethereum-trie + +Fast Merkle-Patricia Trie (MPT) implementation. diff --git a/patches/risc0-ethereum-trie/src/lib.rs b/patches/risc0-ethereum-trie/src/lib.rs new file mode 100644 index 00000000..4942184f --- /dev/null +++ b/patches/risc0-ethereum-trie/src/lib.rs @@ -0,0 +1,24 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![doc = include_str!("../README.md")] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +mod mpt; + +#[cfg(feature = "orphan")] +pub use mpt::orphan; +pub use mpt::{CachedTrie, EMPTY_ROOT_HASH, Trie}; + +pub use alloy_trie::Nibbles; diff --git a/patches/risc0-ethereum-trie/src/mpt/children.rs b/patches/risc0-ethereum-trie/src/mpt/children.rs new file mode 100644 index 00000000..563c1016 --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/children.rs @@ -0,0 +1,197 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{ + memoize::Memoization, + node::{Child, Node}, +}; +use std::slice::Iter; + +/// Implements a helper wrapper for the children of a Branch node. +/// +/// This wrapper offers various convenience features and assures that there is never a Null child. +#[derive(Debug, Clone)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(transparent), + serde(bound(serialize = "Node: serde::Serialize")), + serde(bound(deserialize = "Node: serde::Deserialize<'de>")) +)] +#[cfg_attr( + feature = "rkyv", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + rkyv(bytecheck(bounds(__C: rkyv::validation::ArchiveContext, __C::Error: rkyv::rancor::Source))), + rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, __S::Error: rkyv::rancor::Source)), + rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source, M: Default)) +)] +pub(super) struct Children( + #[cfg_attr(feature = "rkyv", rkyv(omit_bounds))] [Option>>; 16], +); + +impl Default for Children { + fn default() -> Self { + Self(Default::default()) + } +} + +impl PartialEq for Children { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for Children where Node: Eq {} + +/// A view into a single entry in a children map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`Children::entry`] method. +pub(super) enum Entry<'a, M> { + Vacant(VacantEntry<'a, M>), + Occupied(OccupiedEntry<'a, M>), +} + +/// A view into a vacant entry in a children map. +/// It is part of the [`Entry`] enum. +pub(super) struct VacantEntry<'a, M> { + child: &'a mut Option>, +} + +/// A view into an occupied entry in a children map. +/// It is part of the [`Entry`] enum. +pub(super) struct OccupiedEntry<'a, M> { + child: &'a mut Option>, +} + +impl Drop for OccupiedEntry<'_, M> { + fn drop(&mut self) { + if matches!(self.get(), Node::Null) { + *self.child = None; + } + } +} + +impl<'a, M> Entry<'a, M> { + #[inline] + const fn new(child: &'a mut Option>) -> Self { + match child { + None => Entry::Vacant(VacantEntry { child }), + Some(_) => Entry::Occupied(OccupiedEntry { child }), + } + } +} + +impl VacantEntry<'_, M> { + /// Sets the child of the entry with the `VacantEntry`'s index, and returns a mutable reference + /// to it. + #[inline] + pub(super) fn insert(self, child: Child) { + assert!(!matches!(child.as_ref(), Node::Null)); + *self.child = Some(child) + } +} + +impl OccupiedEntry<'_, M> { + /// Gets a reference to the child node in the entry. + #[inline] + pub(super) fn get(&self) -> &Node { + // SAFETY: an OccupiedEntry is only created for a child that is not `None` + unsafe { self.child.as_deref().unwrap_unchecked() } + } + + /// Gets a mutable reference to the child node in the entry. + #[inline] + pub(super) fn get_mut(&mut self) -> &mut Node { + // SAFETY: an OccupiedEntry is only created for a child that is not `None` + unsafe { self.child.as_deref_mut().unwrap_unchecked() } + } +} + +#[allow(dead_code)] +impl Children { + #[inline] + pub(super) fn get(&self, idx: u8) -> Option<&Node> { + self.0[idx as usize].as_deref() + } + + #[inline] + pub(super) unsafe fn get_unchecked(&self, idx: u8) -> Option<&Node> { + self.0.get_unchecked(idx as usize).as_deref() + } + + #[inline] + pub(super) const fn entry(&mut self, idx: u8) -> Entry<'_, M> { + Entry::new(&mut self.0[idx as usize]) + } + + #[inline] + pub(super) fn insert(&mut self, idx: u8, child: Child) { + assert!(!matches!(child.as_ref(), Node::Null)); + self.0[idx as usize] = Some(child); + } + + #[inline] + pub(super) fn len(&self) -> usize { + self.0.iter().flatten().count() + } + + pub(super) fn take_single_child(&mut self) -> Option<(u8, Child)> { + let mut child_idx = None; + for (i, child) in self.0.iter().enumerate() { + if child.is_some() { + if child_idx.is_some() { + return None; // more than one child found + } + child_idx = Some(i); + } + } + // SAFETY: if `child_idx` is only set when the corresponding child is `Some` + child_idx.map(|i| (i as u8, unsafe { self.0[i].take().unwrap_unchecked() })) + } + + #[inline] + pub(super) fn iter(&self) -> Iter<'_, Option>> { + self.0.iter() + } + + #[inline] + pub(super) fn into_iter(self) -> impl Iterator>> { + self.0.into_iter() + } + + #[inline] + pub(super) fn entries(&mut self) -> impl Iterator> { + self.0.iter_mut().map(Entry::new) + } +} + +impl Children { + #[inline] + pub(super) fn memoize(&mut self) { + self.0 + .iter_mut() + .flatten() + .for_each(|child| child.memoize()) + } +} + +impl>, const N: usize> From<[(u8, C); N]> for Children { + fn from(arr: [(u8, C); N]) -> Self { + let mut children = Children::default(); + for (idx, child) in arr { + children.insert(idx, child.into()); + } + children + } +} diff --git a/patches/risc0-ethereum-trie/src/mpt/memoize.rs b/patches/risc0-ethereum-trie/src/mpt/memoize.rs new file mode 100644 index 00000000..dd450898 --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/memoize.rs @@ -0,0 +1,53 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::rlp::RlpNode; + +pub(super) trait Memoization: Default { + fn clear(&mut self); + fn get(&self) -> Option<&RlpNode>; + fn set(&mut self, rlp_node: RlpNode); +} + +#[derive(Debug, Clone, Copy, Default)] +pub(super) struct NoCache; + +impl Memoization for NoCache { + #[inline] + fn clear(&mut self) {} + #[inline] + fn get(&self) -> Option<&RlpNode> { + None + } + #[inline] + fn set(&mut self, _: RlpNode) {} +} + +#[derive(Debug, Clone, Default)] +pub(super) struct Cache(Option); + +impl Memoization for Cache { + #[inline] + fn clear(&mut self) { + self.0 = None + } + #[inline] + fn get(&self) -> Option<&RlpNode> { + self.0.as_ref() + } + #[inline] + fn set(&mut self, rlp_node: RlpNode) { + self.0 = Some(rlp_node) + } +} diff --git a/patches/risc0-ethereum-trie/src/mpt/mod.rs b/patches/risc0-ethereum-trie/src/mpt/mod.rs new file mode 100644 index 00000000..9de415ee --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/mod.rs @@ -0,0 +1,919 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A sparse Merkle Patricia trie implementation. + +use alloy_primitives::{B256, Bytes, keccak256, map::B256Map}; +use alloy_trie::Nibbles; +use children::Children; +use memoize::{Cache, NoCache}; +use nibbles::NibbleSlice; +use node::Node; +use std::{cmp::PartialEq, fmt::Debug}; + +mod children; + +mod memoize; +mod nibbles; +mod node; +#[cfg(feature = "orphan")] +pub mod orphan; +#[cfg(feature = "rkyv")] +mod rkyv; +mod rlp; +#[cfg(feature = "serde")] +mod serde; + +pub use alloy_trie::EMPTY_ROOT_HASH; + +/// A sparse Merkle Patricia trie storing byte values. +#[derive(Debug, Clone, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[cfg_attr( + feature = "rkyv", + derive(::rkyv::Archive, ::rkyv::Serialize, ::rkyv::Deserialize) +)] +pub struct Trie(Node); + +impl Trie { + /// Retrieves the value associated with a given key. + /// + /// # Panics + /// + /// It panics when neither inclusion nor exclusion of the key can be guaranteed. + #[inline] + pub fn get(&self, key: impl AsRef<[u8]>) -> Option<&[u8]> { + self.0 + .get(NibbleSlice::from(&Nibbles::unpack(key))) + .map(|b| b.as_ref()) + } + + /// Inserts a key-value pair into the trie. + /// + /// # Panics + /// + /// This method may panic under the following conditions: + /// + /// * If the insertion would result in a value being stored directly in a branch node, which is + /// not allowed in this trie implementation. + /// * If the key to be inserted corresponds to a part of the trie that has not been resolved + /// (i.e., the node is represented by a digest and the full node is not available). + #[inline] + pub fn insert(&mut self, key: impl AsRef<[u8]>, value: impl Into) { + self.0 + .insert(NibbleSlice::from(&Nibbles::unpack(key)), value.into()); + } + + /// Removes a key-value pair from the trie. + /// + /// If the key exists in the trie, it is removed along with its associated value, and the method + /// returns `true`. If the key does not exist, the trie remains unchanged, and the method + /// returns `false`. + /// + /// # Panics + /// + /// This method may panic under the following conditions: + /// + /// * When neither the inclusion nor exclusion of the key can be guaranteed. + /// * If the removal of the key leads to a branch node having only a single, non-resolved child. + /// In such cases, the correct pruning of the trie cannot be guaranteed, indicating a + /// potential issue with the trie's construction. + #[inline] + pub fn remove(&mut self, key: impl AsRef<[u8]>) -> bool { + self.0.remove(NibbleSlice::from(&Nibbles::unpack(key))) + } + + /// Returns the number of full nodes in the trie. + /// + /// A full node is a node that needs to be fully encoded to compute the root hash. + #[inline] + pub fn size(&self) -> usize { + self.0.size() + } + + /// Computes and returns the hash of the trie's root node. + #[inline] + pub fn hash_slow(&self) -> B256 { + self.0.hash() + } + + /// Clears the trie, removing all key-value pairs. + #[inline] + pub fn clear(&mut self) { + self.0 = Node::Null + } + + /// Resolves currently unresolved nodes within the trie using the provided RLP-encoded nodes. + /// + /// This method iterates through the provided RLP-encoded nodes, computes the Keccak-256 hash of + /// each node, and attempts to replace any internal `Node::Digest` entries matching that hash + /// with the decoded node. + /// + /// # Errors + /// + /// This function returns an error if it encounters any issues during the decoding of RLP + /// encoded nodes or if the provided nodes result in an invalid trie structure. + pub fn hydrate_from_rlp>( + &mut self, + nodes: impl IntoIterator, + ) -> alloy_rlp::Result<()> { + let rlp_by_digest = nodes + .into_iter() + .map(|rlp| (keccak256(&rlp), rlp)) + .collect(); + self.0.resolve_digests(&rlp_by_digest) + } + + /// Converts the trie into a [CachedTrie]. + pub fn into_cached(self) -> CachedTrie { + fn rec(root: Node) -> Node { + match root { + Node::Null => Node::Null, + Node::Leaf(prefix, value, _) => Node::Leaf(prefix, value, Cache::default()), + Node::Extension(prefix, child, _) => { + Node::Extension(prefix, rec(*child).into(), Cache::default()) + } + Node::Branch(children, _) => { + let mut cached_children = Children::default(); + for (i, child) in children.into_iter().enumerate() { + if let Some(child) = child { + cached_children.insert(i as u8, rec(*child).into()); + } + } + Node::Branch(cached_children, Cache::default()) + } + Node::Digest(digest) => Node::Digest(digest), + } + } + + CachedTrie { + inner: rec(self.0), + hash: None, + } + } + + /// Returns the RLP-encoded nodes of the trie in preorder. It may return duplicate nodes. + /// + /// Each value but the first, represents a node with RLP-length >= 32, while shorter nodes are + /// included inline. + #[inline] + pub fn rlp_nodes(&self) -> Vec { + self.0.rlp_nodes() + } + + /// Creates a new trie that only contains a digest of the root. + #[inline] + pub const fn from_digest(digest: B256) -> Self { + Self(Node::Digest(digest)) + } + + /// Creates a new trie from the given RLP encoded nodes. + /// + /// The first node provided must always be the root node. The remaining nodes can be in any + /// order and are resolved if they are referenced (directly or indirectly) by the root node. + /// + /// Nodes that are referenced by the root node (either directly or indirectly) but are not + /// provided in the input are represented by their hash digests within the trie. This allows for + /// the computation of the root hash and ensures that it matches the root hash of the fully + /// resolved trie, even if some nodes are missing. + /// + /// # Errors + /// + /// This function returns an error if it encounters any issues during the decoding of RLP + /// encoded nodes or if the provided nodes result in an invalid trie structure. + #[inline] + pub fn from_rlp>(nodes: impl IntoIterator) -> alloy_rlp::Result { + Ok(Self(Node::from_rlp(nodes)?)) + } + + /// Creates a new trie from a root digest and a map of pre-hashed, RLP-encoded nodes. + /// + /// This method offers an efficient way to construct a trie when the node digests are already + /// known, as it avoids re-computing the hashes. + /// + /// It is crucial that the provided `rlp_by_digest` map contains keys that are the correct + /// `keccak256` hashes of their corresponding RLP-encoded values. If the hashes are incorrect, + /// the resulting trie will be invalid, potentially leading to a different root hash than + /// the one provided and subsequent logical errors. + #[inline] + pub fn from_prehashed_nodes( + root: B256, + rlp_by_digest: &B256Map>, + ) -> alloy_rlp::Result { + let mut trie = Self::from_digest(root); + trie.0.resolve_digests(rlp_by_digest)?; + Ok(trie) + } +} + +impl> FromIterator<(K, Bytes)> for Trie { + fn from_iter>(iter: T) -> Self { + let mut trie = Self::default(); + iter.into_iter().for_each(|(k, v)| trie.insert(k, v)); + + trie + } +} + +/// A caching version of a sparse Merkle Patricia trie that stores byte values. +/// +/// `CachedTrie` enhances the basic `Trie` structure by caching the hash of each node. This +/// optimization significantly reduces the computational cost associated with operations that +/// require multiple hash calculations after small trie modifications. +/// +/// It maintains the same interface as `Trie`, allowing for seamless integration into existing +/// systems that rely on the non-caching version. The internal caching mechanism is transparent to +/// the user, automatically updating cached hashes as the trie is modified. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] +#[cfg_attr( + feature = "rkyv", + derive(::rkyv::Archive, ::rkyv::Serialize, ::rkyv::Deserialize) +)] +pub struct CachedTrie { + #[cfg_attr( + all(feature = "serde", feature = "rlp_serialize"), + serde(with = "serde::rlp_nodes") + )] + #[cfg_attr(all(feature = "rkyv", feature = "rlp_serialize"), rkyv(with = rkyv::RlpNodes))] + inner: Node, + #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "rkyv", rkyv(with = ::rkyv::with::Skip))] + hash: Option, +} + +impl Default for CachedTrie { + #[inline] + fn default() -> Self { + Self { + inner: Node::Null, + hash: Some(EMPTY_ROOT_HASH), + } + } +} + +impl CachedTrie { + /// Retrieves the value associated with a given key. + /// + /// See [`Trie::get`] for detailed documentation. + #[inline] + pub fn get(&self, key: impl AsRef<[u8]>) -> Option<&[u8]> { + self.inner + .get(NibbleSlice::from(&Nibbles::unpack(key))) + .map(|b| b.as_ref()) + } + + /// Inserts a key-value pair into the trie. + /// + /// See [`Trie::insert`] for detailed documentation. + #[inline] + pub fn insert(&mut self, key: impl AsRef<[u8]>, value: impl Into) { + self.inner + .insert(NibbleSlice::from(&Nibbles::unpack(key)), value.into()); + self.hash = None; + } + + /// Removes a key-value pair from the trie. + /// + /// See [`Trie::remove`] for detailed documentation. + #[inline] + pub fn remove(&mut self, key: impl AsRef<[u8]>) -> bool { + if !self.inner.remove(NibbleSlice::from(&Nibbles::unpack(key))) { + return false; + } + self.hash = None; + true + } + + /// Returns the number of full nodes in the trie. + /// + /// See [`Trie::size`] for detailed documentation. + #[inline] + pub fn size(&self) -> usize { + self.inner.size() + } + + /// Computes and returns the hash of the trie's root node. + /// + /// This method uses cached hashes when available (both root hash and internal node caches) + /// but does not update them. For optimal performance, prefer [`Self::hash`] which manages + /// and updates all caches. + #[inline] + pub fn hash_slow(&self) -> B256 { + match self.hash { + None => self.inner.hash(), + Some(hash) => hash, + } + } + + /// Computes and returns the hash of the trie's root node. + /// + /// If the root hash is already cached, it is returned directly. Otherwise, the hash is + /// computed, cached, and then returned. This method also triggers an internal `memoize` + /// operation on the underlying `Node` structure, populating its cache with the hashes of its + /// sub-nodes, further optimizing future hash computations. + /// + /// This is the preferred method for obtaining the root hash of a `CachedTrie` as it leverages + /// and updates the cache for optimal performance. + #[inline] + pub fn hash(&mut self) -> B256 { + *self.hash.get_or_insert_with(|| { + self.inner.memoize(); + self.inner.hash() + }) + } + + /// Clears the trie, removing all key-value pairs. + #[inline] + pub fn clear(&mut self) { + *self = Self { + inner: Node::Null, + hash: Some(EMPTY_ROOT_HASH), + } + } + + /// Returns whether the hash is currently cached or needs to be recomputed. + #[inline] + pub const fn is_cached(&self) -> bool { + self.hash.is_some() + } + + /// Resolves currently unresolved nodes within the trie using the provided RLP-encoded nodes. + /// + /// See [`Trie::hydrate_from_rlp`] for detailed documentation. + #[inline] + pub fn hydrate_from_rlp>( + &mut self, + nodes: impl IntoIterator, + ) -> alloy_rlp::Result<()> { + let rlp_by_digest = nodes + .into_iter() + .map(|rlp| (keccak256(&rlp), rlp)) + .collect(); + self.inner.resolve_digests(&rlp_by_digest) + } + + /// Returns the RLP-encoded nodes of the trie in preorder. + /// + /// See [`Trie::rlp_nodes`] for detailed documentation. + #[inline] + pub fn rlp_nodes(&self) -> Vec { + self.inner.rlp_nodes() + } + + /// Creates a new trie that only contains a digest of the root. + #[inline] + pub fn from_digest(digest: B256) -> Self { + if digest == EMPTY_ROOT_HASH { + Self::default() + } else { + Self { + inner: Node::Digest(digest), + hash: Some(digest), + } + } + } + + /// Creates a new trie from the given RLP encoded nodes. + /// + /// See [`Trie::from_rlp`] for detailed documentation. + #[inline] + pub fn from_rlp>(nodes: impl IntoIterator) -> alloy_rlp::Result { + let root = Node::from_rlp(nodes)?; + + Ok(Self { + inner: root, + hash: None, + }) + } + + /// Creates a new trie from a root digest and a map of pre-hashed, RLP-encoded nodes. + /// + /// See [`Trie::from_prehashed_nodes`] for detailed documentation. + #[inline] + pub fn from_prehashed_nodes( + root: B256, + rlp_by_digest: &B256Map>, + ) -> alloy_rlp::Result { + let mut trie = Self::from_digest(root); + trie.inner.resolve_digests(rlp_by_digest)?; + Ok(trie) + } +} + +impl PartialEq for CachedTrie { + /// Equality between cached tries ignores the cache. + #[inline] + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + } +} + +impl Eq for CachedTrie {} + +impl> FromIterator<(K, Bytes)> for CachedTrie { + fn from_iter>(iter: T) -> Self { + let mut trie = Self::default(); + iter.into_iter().for_each(|(k, v)| trie.insert(k, v)); + + trie + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::{Bytes, U256, b256, keccak256}; + use alloy_trie::HashBuilder; + use children::Children; + use std::{borrow::Borrow, collections::BTreeMap}; + + const N: usize = 512; + + fn trie_root(iter: impl IntoIterator>) -> B256 + where + K: AsRef<[u8]>, + V: AsRef<[u8]>, + { + let mut hb = HashBuilder::default(); + + let mut sorted_data: Vec<_> = iter.into_iter().collect(); + sorted_data.sort_by(|a, b| a.borrow().0.as_ref().cmp(b.borrow().0.as_ref())); + for (key, val) in sorted_data.iter().map(Borrow::borrow) { + hb.add_leaf(Nibbles::unpack(key), val.as_ref()); + } + + hb.root() + } + + #[test] + fn empty_root_hash() { + assert_eq!( + EMPTY_ROOT_HASH, + keccak256(vec![alloy_rlp::EMPTY_STRING_CODE]) + ); + } + + #[test] + fn mpt_null() { + let trie = Trie(Node::Null); + assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); + + assert_eq!(trie.hash_slow(), EMPTY_ROOT_HASH); + assert_eq!(trie.size(), 0); + + // the empty trie provides a non-inclusion proof for any key + assert_eq!(trie.get([]), None); + assert_eq!(trie.get([0]), None); + assert_eq!(trie.get([1, 2, 3]), None); + } + + #[test] + fn mpt_digest() { + let trie = Trie::from_digest(B256::ZERO); + assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); + + assert_eq!(trie.hash_slow(), B256::ZERO); + assert_eq!(trie.size(), 0); + } + + #[test] + fn mpt_leaf() { + let trie = Trie(Node::Leaf( + Nibbles::unpack(B256::ZERO), + vec![0].into(), + NoCache, + )); + assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); + + // a leave counts as a full node + assert_eq!(trie.size(), 1); + + // a single leave proves the inclusion of the key and non-inclusion of any other key + assert_eq!(trie.get(B256::ZERO), Some(&[0][..])); + assert_eq!(trie.get([]), None); + assert_eq!(trie.get([0]), None); + assert_eq!(trie.get([1, 2, 3]), None); + } + + #[test] + fn mpt_extension() { + let child = Node::Branch( + Children::from([ + ( + 0, + Node::Leaf(Nibbles::from_nibbles([0; 62]), vec![0].into(), NoCache), + ), + ( + 1, + Node::Leaf(Nibbles::from_nibbles([1; 62]), vec![1].into(), NoCache), + ), + ]), + NoCache, + ); + let trie = Trie(Node::Extension( + Nibbles::from_nibbles([0; 1]), + child.into(), + NoCache, + )); + assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); + + // there are one branch, two leaves plus one extension + assert_eq!(trie.size(), 4); + + assert_eq!(trie.get(B256::ZERO), Some(&[0][..])); + assert_eq!( + trie.get(b256!( + "0111111111111111111111111111111111111111111111111111111111111111" + )), + Some(&[1][..]) + ); + assert_eq!(trie.get([]), None); + assert_eq!(trie.get([0]), None); + assert_eq!(trie.get([1, 2, 3]), None); + assert_eq!(trie.get(B256::repeat_byte(0x11)), None); + } + + #[test] + fn mpt_branch() { + let trie = Trie(Node::Branch( + Children::from([ + ( + 0, + Node::Leaf(Nibbles::from_nibbles([0; 63]), vec![0].into(), NoCache), + ), + ( + 1, + Node::Leaf(Nibbles::from_nibbles([1; 63]), vec![1].into(), NoCache), + ), + ]), + NoCache, + )); + assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); + + // there are one branch plus two leaves + assert_eq!(trie.size(), 3); + + assert_eq!(trie.get(B256::repeat_byte(0x00)), Some(&[0][..])); + assert_eq!(trie.get(B256::repeat_byte(0x11)), Some(&[1][..])); + assert_eq!(trie.get([]), None); + assert_eq!(trie.get([0]), None); + assert_eq!(trie.get([1, 2, 3]), None); + } + + #[test] + fn short_encoding() { + // 4 leaves with 1-byte long keys, the resulting root node should be shorter than 32 bytes + let trie = Trie(Node::Branch( + Children::from([ + ( + 0, + Node::Leaf(Nibbles::from_nibbles([0]), vec![0].into(), NoCache), + ), + ( + 1, + Node::Leaf(Nibbles::from_nibbles([1]), vec![0].into(), NoCache), + ), + ( + 2, + Node::Leaf(Nibbles::from_nibbles([2]), vec![0].into(), NoCache), + ), + ( + 3, + Node::Leaf(Nibbles::from_nibbles([3]), vec![0].into(), NoCache), + ), + ]), + NoCache, + )); + assert!(trie.0.rlp_encoded().len() < 32); + let rlp = trie.0.rlp_nodes(); + + assert_eq!(trie, Trie::from_rlp(&rlp).unwrap()); + assert_eq!( + trie.hash_slow(), + trie_root([ + ([0x00], vec![0]), + ([0x11], vec![0]), + ([0x22], vec![0]), + ([0x33], vec![0]) + ]) + ); + assert_eq!(trie.hash_slow(), CachedTrie::from_rlp(&rlp).unwrap().hash(),); + } + + #[test] + fn b256_encoding() { + // 2 leaves with 5-byte long keys, the resulting root node should be exactly 32 bytes + let trie = Trie(Node::Branch( + Children::from([ + ( + 0, + Node::Leaf( + Nibbles::from_nibbles([0]), + vec![0, 1, 2, 3, 4].into(), + NoCache, + ), + ), + ( + 1, + Node::Leaf( + Nibbles::from_nibbles([1]), + vec![0, 1, 2, 3, 4].into(), + NoCache, + ), + ), + ]), + NoCache, + )); + assert_eq!(trie.0.rlp_encoded().len(), 32); + let rlp = trie.0.rlp_nodes(); + + assert_eq!(trie, Trie::from_rlp(&rlp).unwrap()); + assert_eq!( + trie.hash_slow(), + trie_root([([0x00], vec![0, 1, 2, 3, 4]), ([0x11], vec![0, 1, 2, 3, 4]),]) + ); + assert_eq!(trie.hash_slow(), CachedTrie::from_rlp(&rlp).unwrap().hash(),); + } + + #[test] + #[should_panic] + fn get_digest() { + let trie = Trie(Node::Digest(B256::ZERO)); + trie.get([]); + } + + #[test] + fn insert_empty_key() { + let mut trie = Trie::default(); + + trie.insert([], b"empty".to_vec()); + assert_eq!(trie.get([]), Some(b"empty".as_ref())); + assert!(trie.remove([])); + } + + #[test] + fn insert() { + let leaves = vec![ + ("painting", "place"), + ("guest", "ship"), + ("mud", "leave"), + ("paper", "call"), + ("gate", "boast"), + ("tongue", "gain"), + ("baseball", "wait"), + ("tale", "lie"), + ("mood", "cope"), + ("menu", "fear"), + ]; + + let mut trie = Trie::default(); + for (key, value) in &leaves { + trie.insert(key, value.as_bytes()); + } + + for (key, value) in &leaves { + assert_eq!(trie.get(key), Some(value.as_bytes())); + } + assert_eq!(trie.hash_slow(), trie_root(&leaves)); + } + + #[test] + fn index_trie() { + let leaves: Vec<(Vec, Bytes)> = (0..N) + .map(|i| { + let rlp = alloy_rlp::encode(i); + (rlp.clone(), rlp.into()) + }) + .collect(); + + // insert + let mut trie = Trie::default(); + for (i, (key, value)) in leaves.iter().enumerate() { + trie.insert(key, value.clone()); + + // check hash against trie build in reverse + let mut reference = Trie::default(); + for (k, v) in leaves.iter().take(i + 1).rev() { + reference.insert(k, v.clone()); + } + assert_eq!(trie, reference); + } + + assert_eq!(trie.hash_slow(), trie_root(&leaves)); + + // delete + for (i, (key, _)) in leaves.iter().enumerate() { + assert!(trie.remove(key)); + + let mut reference = Trie::default(); + for (k, v) in leaves.iter().rev().take(N - 1 - i) { + reference.insert(k, v.clone()); + } + assert_eq!(trie, reference); + } + + assert_eq!(trie.hash_slow(), EMPTY_ROOT_HASH); + } + + #[test] + fn keccak_trie() { + let leaves: Vec<(B256, Bytes)> = (0..N) + .map(|i| (keccak256(i.to_be_bytes()), alloy_rlp::encode(i).into())) + .collect(); + + // insert + let mut trie = Trie::default(); + for (i, (key, value)) in leaves.iter().enumerate() { + trie.insert(key, value.clone()); + + // check hash against trie build in reverse + let mut reference = Trie::default(); + for (k, v) in leaves.iter().take(i + 1).rev() { + reference.insert(k, v.clone()); + } + assert_eq!(trie, reference); + } + + assert_eq!(trie.hash_slow(), trie_root(&leaves)); + + // delete + for (i, (key, _)) in leaves.iter().enumerate() { + assert!(trie.remove(key)); + + let mut reference = Trie::default(); + for (k, v) in leaves.iter().rev().take(N - 1 - i) { + reference.insert(k, v.clone()); + } + assert_eq!(trie, reference); + } + + assert_eq!(trie.hash_slow(), EMPTY_ROOT_HASH); + } + + #[test] + fn hash_sparse_mpt() { + let leaves: BTreeMap<_, _> = (0..N) + .map(|i| { + let key = U256::from(i); + ( + Nibbles::unpack(keccak256(B256::from(key))), + alloy_rlp::encode(key), + ) + }) + .collect(); + + // generate proofs only for every other leaf + let proof_keys = leaves.keys().step_by(2).cloned().collect(); + let mut hb = HashBuilder::default().with_proof_retainer(proof_keys); + leaves.into_iter().for_each(|(k, v)| hb.add_leaf(k, &v)); + let exp_hash = hb.root(); + + // reconstruct the trie from the RLP encoded proofs and verify the root hash + let mpt = Trie::from_rlp( + hb.take_proof_nodes() + .into_nodes_sorted() + .into_iter() + .map(|node| node.1), + ) + .unwrap(); + assert!(mpt.size() < N); + assert_eq!(mpt.hash_slow(), exp_hash); + } + + #[test] + fn parse_empty_proof() { + let account_proof: Vec = Vec::new(); + + let mpt = Trie::from_rlp(account_proof).unwrap(); + assert_eq!(mpt.hash_slow(), EMPTY_ROOT_HASH); + } + + #[cfg(feature = "serde")] + #[test] + fn parse_eth_get_proof_existing() { + // { "id": 1, "jsonrpc": "2.0", + // "method": "eth_getProof", + // "params": ["0x0000000000000000000000000000000000000004", [], "0x12962D1"] } + let value = serde_json::json!([ + "0xf90211a064fba17f021dbb0322d3e7d30aff9db628377c960f1ebed87701f08ce0b040eca09d91529d0a9cfb8e091b206bbcc359f7734dff6815c73e65ecbec4063508f9e9a0558f96de53974dabf223c2501c08c97dfc1c3d47a9b2c4ea0655df221c8154bea057fbe18660f4919b33d1dfbccd340a3d9ddae1a0e7d7df6f8df4b3cbe7c9d875a084f9dc2615d641d4136337942a7c76b94164b4ebd29422b860fa2251f82d2b73a05b6b9d6d421156c0282dfe73491c8754906849e989210d766fe4e4e266b32605a024eb3df5b1a9d8c6e40fb604542bc70e38e33f32c0f2feebdbd9b7e7e31ba7e4a015935675b64554bdc16b1c1cfc25c89f5d284ff11dcfbf7993aec54a92f0bba4a0099d5fc449ccc8c39482564ac0dd831f1e05387dae9dfd9dea51cb0d4e19aa8aa031d64c42ebfbcecb9f0220b752ab56f06b2682778d17119b7324c0ad96dfc149a0095fe3791c69f53ed524f8edbea71ac57efd64b9198810cc763efa0f4a5c2897a0515238447863a22615f154bc9c72e3aa4f69c4726ff41063a467ae84416731aaa022f3633a252b9b64f1bfcf48fc267570bd4203e4f36feb85dded2c1bd1cff3e0a042d3afbd98a8965f366b72e2213895467a77159c1c3d28c84a29013f8cb12873a07fd2b3663f9fc8d7836096d9369a233eb17532e85e69a953011f7d698b2cc00aa0726b3dbf33d6ad6a58d3c6007a706bbcba5442ad17eda4dd1934fe40279ad71080", + "0xf90211a0f5271d0b41d27321301a4a99ee222e2f6993733b8bb4297e5f4a193309cea441a0308c36c27bc35ce53fa864873bbdda24f8dda698a8829976c654d71aed28d65fa077780501dffccc355bf0353e3641740ba33c12291c4a8f2a240c7c5e8c0f0ddaa0d571e89fdf190b87f84db4bf25b50648758b6d86940e172622b93c6e818ca4dba076419b70cc41744498d74746de84ef31ae62a324a60cfcb9f38b438e31c9325ca0d41cdf14b7a848eb7b90d53aecee8b656bdc4f21f1285b40075fc2cfb09970dca0d268e7c26b2bf55597f7f2e6b1783ff59468590ef813e2d0c941c545ac947093a0aaaa06235ff457fc16692855eb8f6417895e85ee99030273e67ed434ec9edc78a093176f5004283b61b43c5bc0ac81a64d1f8fa13f03151040c25f0687fd661a20a01875442e8e36fb90a38cfe7fbc47071e6a8d73afe31310167facf68f13428509a0e964058555501ab03129574589ec66fbd34af7af4f9ede88dd20e6d509d3ed78a070094346b748e0d7fe73f52655307fed3967a9b8b5d12abcb86baa338bfce384a07b944e9ffc124854852a026deac8105902cb9bd96bd45ee6548566fcd9d0280ba0e9ec860d689a8471762d8bbacdc453de018634b0d80aed35eb0f72e5d0b4f841a0fca2e3962d69a6927845d1537f58b3871ea19e775ac88b973ffa7717c9f9b1dba0c3ef3351fb2e76a5130b103ee85d83a7fc658fc306d43d29a016f8e696b412db80", + "0xf90211a07a0bc6ce42efd1947af01f6573b633c431a5b0d14fd22e0704cb8556b7098fd3a0105680327ae064d660fe790b6bbb4f1453d6188eaafd707b2d0be6010275b3a6a0b41d2058d4c85808c887fd70c07ed2629c9f5f138d8dd512c060de9b07d2cd18a0639cbfec697a3c8461f4dd0f0eda8a58cb186db9dd6831d0d0a3ce9c6f99a7fea0a9f7964dec293389bc37f594cb03be415ec76208081bd61aa56bb83b8e749d1da0541091360f807b91263b692989e1a2df1aa894568661ea88359fd0ad76837131a02bea3a3d833e46c77b3214e753f59157d232d5f1c4d9f1b936e82f343ed62f48a07d6282c3a3353eaba6503faaa91c2efe85d5c72a80d209ad2c2648ea24449b7ba0c0576e98237780fea7677ef30e5e5b966f8874d2defa0f4e2bc95ac6e3180ffda0514d5942624e2309086cfde5c70cce77a13d3d8c7e04a299d9c98d4bd76fc80da0267e7598bb09c5965509b91763d4ddf7eb8baaa19276ef1630ff904ba22c5836a0a18ede2979de3c02978dbf1542c517a3eb42fe537fde09a3fb0ab46e139d0712a066b2679d23b911ea309551b9453115ae26d92fd05f8ac3f2e2e6e31cf6ac9dc7a0d541bc04f0feaa8bd4239d25cb04b1ddb5976d65a20bf91eae810f8a8fc33bdaa0d75b751ed0a1ef82c9cae91b2e97ea78c218d9a8923be953753962ef81b1aa9ba0cc3d9261f5ba93857bdac0d26a341984b45d3a6aa38811e4ced7a12594722a9380", + "0xf90211a028e51fc851a6315210c3e973bc0c37db45b9cbc38384235414e7f83bd06097f9a04fddedaebfa0a6e8f6bc1c035ff20c0365a92911e8a9b6f267621f729461fa68a0a2a92894c4f4f64cd8563f2c5945b3fc2857ec60bce8549d5871966510234310a00f8ec60cdce60eca2287e2c08b6a074cec1218b355e08504f8e0209095cf2caaa0a7f6689140ac7d1230f773d0e7f395c884d4c4be8e19c752650e94d59e63d492a061dfe74f4e14f2a06dfeb9f268acd81559c4ef17de098630432b2ff342441c36a00c450940c088ad97119ac6b9ecef673ccc41c4244bffac10744bdd2868811f15a09d405cc6b538d9a9033a96818608fb801d4f1a4319448e459a802aa966f0637ea0a604db8246efa1a62859269ff28709d950d74b55b4730002c5639e383a2867bca0f11de25a06de0a1162bffb3d400edf07a64659aa59c3554898700082866997fda02454c86901086b11a1b11a0f7ed300aeb451ca9d50509f7f8d1818cdaa42177ba00b06fa9d11f507136397be1aa73ec37c8bf8a7b10d1ccd07d0bcd9634ce469d0a001e5be1f99d16e7b0f12d73d01c7aa54e109186b18c7c1eb04a6784d619ca452a0676f68104f74c5f03d7b4638bbbb9a0ec647f34ae489de642eb9fa6c03388e20a048b07679ba600363323c2304443d2815ebe87e64bcee9f5ea31d97a0c4720c95a035d02f8a26fb9926254b3309ac3cacb94852a9a7469ab094e12b8df2d820dac680", + "0xf90211a0af5538b1a07c6b743b04ed3a04d1b20db89c831e2f2acfd54d92f710004c9495a0c3abf984d9d723ec0aaa2d2c6afb75b693ddbd5538a0709bbc17f8b17325b78fa051d2081439320734f889a4de79d72ec9d009bdd7b33c1d2970cb88c98d13d4c6a0b55856ee040bc79be42aa48f807651502a07ea73d46a63d2997a5ee1493b3372a0df7a231010a67f2286fbcc6e9347e0f0d7706bc23a95a08342d61c9f83eb93a8a07c0dd78b4a5a44ad1fb26fb11c710f8478f039b89df1f6c888d1b984bf51338ba075367e67992101f00c0d4ac7b90110c901ba1dc0bff377084ec3c933643019a3a0ecbb4272ff5b494973deb3ea559bd5296c0de719b6cbc71d4469dd1b0697aa87a0441af491d98cf36d5c259ad8a183348aba1f642a6c5d408c846d09f86b52882ea083641f2add799b0244eeab16095698b801dad630a60a769fb3f378346514f44ca05829539f9d1d5835d74a994278ff03ede1fde23997a2d4bacaf7a74c7081308da038b4f88c187767463cac005228d458a26554fa28174a82b2d6ea47a86991f026a08f9bf87dc8b2cfae0f21ee5e300b71310b5092268921ea387ed4d1d68ebb47c2a0b1a29582a77306d0a48675f4ee4603f01b3744993d1b057592c0b4af91ed5c73a065cc8133f26ec26a0053f978068a41075b138f7cd077452832f7fa1c79ec2250a08b3561166e1256df806bc6ba3c7f6312493b38133aa3524f51884b9115c7cc9780", + "0xf90211a0000aba28e5abf987658d245aabf1157eedee3f099ebf95affabe5a1e9b53b521a0c37da1b511fc6e5925e9b3e6870866da39bd3a880b45b3d830dacddd5ca5d1c1a054eb2e6cd765137c3ebde36d30decd3a9461e9245ac510405740a1307f700f8fa009b3401df44a885d6ab901ba7b789b290f7c3fbbdb2739ab487e33ff48bb6f13a0b124c2c227b22040df405b92eeeae70b28f9f59cb355220a0184c2d26aebf765a06f9217b6b53f3258db8c9b91cd05a07d2e90608c490e76dff6a847a7ead45859a00007fd17fdc3326a80364d9e820ca33580fa9e4641c3d9864a653c90515e3255a0110ad882ed1c35d31bca099524ca8da2aec305bdcc02cbee38f986f3bbfd6946a0d1a7c39603704486613fe6a83d8fff219e1b4d71cecd01b460703f4d0c4fee26a084a158747da12a4c0e1df62f95b206779f6da199a9832d22f79cc6017b14eeb5a070dbfff894a8269d76bb53722185466c879eb601fd9b6c413ef69f8b282959a8a0ac026666c540c02a02838e725f62a41356e6617ccf16a930db35ad4b253253c2a001c4c0478fdbaadc5ad58defe18fb9df49bdd12c9b8efbe7acfb11bd8deb52eaa0637e3ebb17f8bf5e8e9d2a987e00a10070cd8a8623d327fdd0fac545e453000ea0052155fc9e62a4a89b260a55f0d470b91b1e009dc8923292284f260a9ecf8785a04fb3083fdd53a3023fc4aec62f307f7e87cf0e4a771fba42cbe62a10ba98f40a80", + "0xf901b1a0d3c18050bdcb55f8e919d224eb69062be67a76708fb45d5f4263e2bf26473339a08c8749c75e158292e70ecf6defbd039c5b739733db1105430b065c3d40dbafbba02a33fef2d0dc98049fb6e1ab176ceef4cf4a376a62d9076e4557618200b3c00ba0534f68319d219b17e6c94295329c3a85478d182591e721dcb82ade11212e8ab2a0a4b88347eb9d7466e1cd2b7025a14bc53b93e39532fb60e276f24ce64f43080ea0c3b3a7be7982dcbb5680948ec6e80103109bb7adb312d6f738870894c0cd7cef80a007e513f4512674cfc773e861e6a34250eae5508f5a24b1af07e62583eecfc675a0f501c13e330dd417836ad1a304a578575b4618880a479b542953248c4aaef3bca0a5d05faed975c0134a4333809d471a6afb7b19f7db1a2e928ec0e27b5e5cf651a0f90433f3b2fa2fae1df8ce6b1c2cd794fe4fd8f899767d9aa59607285efbe17f80a0f2d6a5c820099a8212b3af56264bda3b519af5379f1a09f2a6e6dc412a1e6561a0c82e9f321649f50e95a89db8fbdec55babc1a552850ee7fff4d22d9aecb5710f80a0c189cfed2417dd103f87679e16d3c8e178d61d5da36bbdb2aeb4aa170a1560ba80", + "0xf85180a0c3b71af926a3b464d43b79c4f3b91835b055202902801ec32940cd45d78c3ed3a06d11221db3e0db5015e8b8c4f2e738c733a0b212a1399021e7824e5f908ecf578080808080808080808080808080", + "0xf85180a0cce18d0d1d7b4befb137e8b893e0d62e61cc7e43474d885853697bc6729e6544808080808080a0b17e5bdc4a7d0f184dde26b3a718143439522942254dd9bd109255cc49d3b0ab8080808080808080", + "0xf86d9c3a393dbd067dc72abfa08d475ed6447fca96d92ec3f9e7eba503ca61b84ef84c80881a5fd46f92e55070a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + ]); + let account_proof = serde_json::from_value::>(value).unwrap(); + + let mpt = Trie::from_rlp(account_proof).unwrap(); + + let address = alloy_primitives::address!("0x0000000000000000000000000000000000000004"); + let account = mpt + .get(keccak256(address)) + .map(|rlp| alloy_rlp::decode_exact(rlp).unwrap()); + assert_eq!( + account, + Some(alloy_trie::TrieAccount { + balance: alloy_primitives::uint!(0x1a5fd46f92e55070_U256), + ..Default::default() + }) + ); + } + + #[cfg(feature = "serde")] + #[test] + fn parse_eth_get_proof_nonexisting() { + // { "id": 1, "jsonrpc": "2.0", + // "method": "eth_getProof", + // "params": ["0x0010000000000000000000000000000000000000", [], "0x12962D1"] } + let value = serde_json::json!([ + "0xf90211a064fba17f021dbb0322d3e7d30aff9db628377c960f1ebed87701f08ce0b040eca09d91529d0a9cfb8e091b206bbcc359f7734dff6815c73e65ecbec4063508f9e9a0558f96de53974dabf223c2501c08c97dfc1c3d47a9b2c4ea0655df221c8154bea057fbe18660f4919b33d1dfbccd340a3d9ddae1a0e7d7df6f8df4b3cbe7c9d875a084f9dc2615d641d4136337942a7c76b94164b4ebd29422b860fa2251f82d2b73a05b6b9d6d421156c0282dfe73491c8754906849e989210d766fe4e4e266b32605a024eb3df5b1a9d8c6e40fb604542bc70e38e33f32c0f2feebdbd9b7e7e31ba7e4a015935675b64554bdc16b1c1cfc25c89f5d284ff11dcfbf7993aec54a92f0bba4a0099d5fc449ccc8c39482564ac0dd831f1e05387dae9dfd9dea51cb0d4e19aa8aa031d64c42ebfbcecb9f0220b752ab56f06b2682778d17119b7324c0ad96dfc149a0095fe3791c69f53ed524f8edbea71ac57efd64b9198810cc763efa0f4a5c2897a0515238447863a22615f154bc9c72e3aa4f69c4726ff41063a467ae84416731aaa022f3633a252b9b64f1bfcf48fc267570bd4203e4f36feb85dded2c1bd1cff3e0a042d3afbd98a8965f366b72e2213895467a77159c1c3d28c84a29013f8cb12873a07fd2b3663f9fc8d7836096d9369a233eb17532e85e69a953011f7d698b2cc00aa0726b3dbf33d6ad6a58d3c6007a706bbcba5442ad17eda4dd1934fe40279ad71080", + "0xf90211a07c0b2ddf03d5254f0a71793b61268dcccbcba1bbf91f84e1f01dfc7e748a22b3a0d066cbf287fff296cdf1c8d672f64cd1c7b582237a0e56f5523cadc9fd02db99a0ef75b0e082af37853216e2f1e189e8ed4a8fd8597d4cafb6a009d593d149463ba06b26667374d83ee094dab3adf971df2e3ec3f8255ce8e34b73d89afad4e5cc2ba0cc64a85fd14a5b27ec9aecd563395ea1c34629c7dca53222e7d19d1213af4d6ca07e3b3fd39452db1f8da9316152693d688505eff731e8b9c0e4512ba4a7882bcaa03579517fa320d080a74555da75ea17e676486aca21cac482f5f90993acec7112a0d674f6623ec3aaccde4856376e52b439ef4ebec600903c1e554b908b97780f64a04ebcd669406c6e48c0d1eca18c6c4040c8af886eac25e7218ef48d4cac8acf2ca0a4136773e1fdbde71ac578c4f5d25ee1c23067c20b43ea539b264fd566920630a0e94cab7b03de5bc128c5a15f3058c3c5ebebdd6f16e17548c2669886c1221b7aa0b1716052ef9a44fee9c985c4a957961c6d389bf290c82338e82cde8de5b174d5a096a699c048dc1d20509738881a99f1a09bc83a9ec0730b763c81c7ffb300b744a0733197a2479190e993f9da804810515c0e07b5752a1d0e537856cca86212a0f0a0d89157cef32fad06a43dd3ee54094a9790632d68cf07468ded845212ad484338a06055bbdb3664389c6e66a1519e99e802cb450d78fef9b8f8397c400d915ffe4780", + "0xf90211a001caaac143549f9bf7006ea276d133e2c6830bdb68d16a294a8aa836eeff19a2a0a68cdb682f254b8d8dfaf054bd571f4a84848cd58182274278c6dc09269093aaa063b4ef8b826676cea42d875d5a917193003ca99863a28dd4e4532307964c7e86a084473c41238e3dab60c7074c0fe4d6b14fec21124bdb999ef9fe92675d9e47bea01093a60823539cb5598a972ae1626dc68e62b83306cd0a7d0ca35bb0ae095432a0ea97146fe913ab3ffa242230eb2b0034f883de2a946f615cf4b152d8e4f9c2f1a0600c57157158dda437fdb93a2902d5a6aaadd2c4c4ef781b0f3bb9db52589ff1a005cd22b0467087c13203f302bd75ee3a49a4f50f72f044c510dfb80c5fd73d08a01a610490b54f297f9ed7f86993b19a4f1fe481d0bae5f8cc36428b066a19f675a002591f7ca3e129662132c3c43abec639309c7276bcb93f056ae0e064b08e544ba04cff311608aad7f75fe8660422dea95de1299b59ea1a92bc090a88c0a85033a1a0a23bc8dbe3fa661f80a211fbe0d46b938d681ed5c218391d1fc078242c52e07aa05152a90bb3bf83bc20c79d41e21eba4128916e93e3b2aa44e91d66419fed631ca04b9939df74f3585051cc7a256316931e8bbdba7ffadd42fc6a526acea2a65d5da0ad62bdb2eafbf12a569ab87cb4afd20853fd749a14817501bc051e16ace4b31da032a623bd0d0e0866790c76333c7279c455723c6c878d0a45767f9dd590f6f82b80", + "0xf90211a070740fa5e0ff39e4ecaa3807014386782670ead0ca3930db6e201e0633883524a0fae359c9f3636a34addbd37e75822169ddb824795f59a422a663466feabde3fca0ae96a399523295fb7628aa987c92c324aa579f7a6a0ef3215924f5ab0e2c7785a08b997d1e84063ff2b49c6fc7dda806333bec8a5616475b35021dc7330a6e63f7a076379dbbac470d9f0f8752f363dbb2dff2a0c0e1028d0a5d9aacdf5b735e9d4fa0da495111c40fed1ec3f6ae187ef71a8536a4aa6c09e84720f3645f1967267474a081250ce896356ce835178ed98f1b848a5b4c832f32c113e235020910437adcdba03d5338d4eb62c4d1bad3120bfff7c202a54c365abf2324ad0d97a04077b76900a03fea24d162e9725dc5e204fa2b8db528d0fc21ac54aa9c94e15105053e7bfd24a0c0f751477ad4b3a51a0af066821259e1a6ad3ac4a515c761765dd69552d07abfa079824c28b22d7b33105663cb8520d62101e303e9a0fabe00dfe2598654559b02a04be5cf039ac5c1bb6f8a4bf5dc3ceaa55e8e3fa8a9f6ae1953f744ef8c4c312ca0924250c41261da55a231889b7e88ff81428734661112d4faaa2961623ddd607ba0952fe6d321af6a7c322180c15f6aa06a8e3a461068f0e8c08183fd7536f9fd08a00b47228191943da98cc93b06f2475cb33de07d12d1445be308ffd94d786df047a0befcc93acb07cdf6240f884f7b4064f238c55f997a517f4bfcf6b970ea100d4e80", + "0xf90211a035ab3b8892330b5d3a92328b1c739c931c357dd4a5dc03e97ce130eb4d6ecf88a02ac2040a3839d2addee3deea351e02549e1a6662a5ff0ba42b8da6fd8964d58da0d5bef1786b6c185e65857742a860b724cba879fa0e8ae58abfab97e9ba213cc3a0649a68c768383bd53cd4b633b5297046bd8bf5c8b5e3f7be38b9b7eb037028e2a0247f186e30f069ed59215d7ed366c311a5bc5bde30ba52a8decc1d9145dcf286a0a725755aa59c849d7896625bbe2f31e0df98158be40adc6a394ffb1b4c05edcaa028a1af512637cfa63d06d9a416c46c6c8823be383a1ba1c1f880ade56b857ae6a070c12456255d06936ff8279cd8ed2de4596ff666161b8519fe8467310e88318fa033dfb37033f44cdce425c078ebe9f8ceb083f2bdb2058409c51c724140c4e99da0e38a0e9efc642da0375974ce69672ade21c5d43703ea5a38ad69644ccd01dc05a0f0773bd08b76b985fb3add2bf308fd1c548e22acb7eae8375f01f4c163f76be8a0e9cde81fdd404fb391b8ba5b3446e8c2e013b7792bc80f77703f2753552f470ea00975fa52a240800fd50ef22dad2aba6d1b4aeb19ee580ca13640d8a6de0936b9a07dd0437de64d7b5053478116ba0447ee5181818aadfb4a00ea1df67cc5d0bd1ca005f923facc0fb4445a5a488f628b353f3eb89936fb9e6b29bb1882e5c0881907a01d4fb8aac5a8d71ac5c0ed0c4491aed1532551451f630d717809797b4c3423b480", + "0xf90211a011d5405f5bf3648db2730954e75f7562daf4f93ae301482f3de752db8c6f6633a0f5dfe0e59a8b701cc7255480aba875bf4b2f8ec2b2a75b40320989d061f239ffa0641476041254ae3679696731e89da6e8ac4edc30762b30f0237014db2097ca98a0bca8b92c364aa974060a83482b3fddcbda788ace19d249e24225eb91cea050e3a08d5bc061d99b9803d93ad307aefb95950a9e5092cd3de0d642ec6b78d47ff883a093950c5e2655b226fccfd19359302b4e5a19e0d4812dc4859b0eadb3ee984118a02cc1641e3a8f95cea933cd6486d30e8d78d4a33fc81660b580ab05a67d13e438a0e9a7107962410d730bbc8f2350edbb592e7fb741dddee692c4bd9d4b3f1c16b4a05de66765b606c7bce1889f7c55028d19187f9ab9096e4d1927de1376c5905f2da03ca1622b70663d6880d0470191a28805547888ee1ece7ac65fd5c77dc67f6489a0cb515b40517b5c150115cdc0de89ed0e2a962a1ccdea09863b84050406fbd3eda0ff490436b20b1c8113eb98909c82c268e5454c8092ba0bc48a2b2903a0b4d372a07798003e5b7c0a905f0920e98bb17cf0a7f66fde92b0dd356463976cdda8c2e4a00c0fa4a0181bb622b9a4073844d5a72853b21e78db968ad4cea027828d402169a06b227ce534153d2d3952d3085da4f747e1c647f43ee616774df6f50c3f5646e5a0964a937d6cb948eaee92f05bd1a9d03af8ea3ee4e68b02ca9644d96ad86a0cd880", + "0xf901118080a02c5fbef8c93de59996332553693c43cf28dda1d13ac91dbee861a720883c7301808080a00cafef025cf50981161339913df13fac3635bb4d4612a6779b992b0896c1779480a0ad841e530360d785f7f258c646148f4b51093724f3b769efbb621fee609d2c3aa00abab5bb26960da6d85071fb6f12cf052c70b61c53acd72558ee06048a532128a043ae5b927740bbb05d9e6643a5c2e8c473cef67e529d431faf6edc79d19ba78a80a04a8ad4e57fe8d09e8596dc5131380ea3068decd740c1641ff712b35e37d6586980a045bd253469234b741abe3c8b110c04b0b9f3f983f752c394ef77814351a8d1bda08f74385b8385a4ebff237231c67a623e7bbad8151654e9edf32fa8464802cc6a80" + ]); + let account_proof = serde_json::from_value::>(value).unwrap(); + + let mpt = Trie::from_rlp(account_proof).unwrap(); + + let address = alloy_primitives::address!("0x0010000000000000000000000000000000000000"); + let account = mpt.get(keccak256(address)); + assert_eq!(account, None); + } + + mod cached { + use super::*; + use crate::CachedTrie; + + #[test] + fn index_trie() { + let leaves: Vec<(Vec, Bytes)> = (0..N) + .map(|i| { + let rlp = alloy_rlp::encode(i); + (rlp.clone(), rlp.into()) + }) + .collect(); + + // insert + let mut trie = CachedTrie::default(); + for (i, (key, value)) in leaves.iter().enumerate() { + trie.insert(key, value.clone()); + assert_eq!(trie.hash(), trie_root(leaves.iter().take(i + 1))); + } + + assert_eq!( + trie.hash(), + CachedTrie::from_rlp(trie.inner.rlp_nodes()).unwrap().hash() + ); + + // delete + for (i, (key, _)) in leaves.iter().enumerate() { + assert!(trie.remove(key)); + assert_eq!(trie.hash(), trie_root(leaves.iter().rev().take(N - 1 - i))); + } + } + + #[test] + fn keccak_trie() { + let leaves: Vec<(B256, Bytes)> = (0..N) + .map(|i| (keccak256(i.to_be_bytes()), alloy_rlp::encode(i).into())) + .collect(); + + // insert + let mut trie = CachedTrie::default(); + for (i, (key, value)) in leaves.iter().enumerate() { + trie.insert(key, value.clone()); + assert_eq!(trie.hash(), trie_root(leaves.iter().take(i + 1))); + } + + assert_eq!( + trie.hash(), + CachedTrie::from_rlp(trie.inner.rlp_nodes()).unwrap().hash() + ); + + // delete + for (i, (key, _)) in leaves.iter().enumerate() { + assert!(trie.remove(key)); + assert_eq!(trie.hash(), trie_root(leaves.iter().rev().take(N - 1 - i))); + } + } + } +} diff --git a/patches/risc0-ethereum-trie/src/mpt/nibbles.rs b/patches/risc0-ethereum-trie/src/mpt/nibbles.rs new file mode 100644 index 00000000..52dea87e --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/nibbles.rs @@ -0,0 +1,115 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A zero-cost abstraction for handling nibbles (4-bit values) as byte slices. +//! +//! This module provides `NibbleSlice`, a wrapper around `&[u8]` that guarantees +//! each byte represents a valid nibble (0-15). It offers efficient operations +//! for working with nibble data without runtime overhead. + +use alloy_primitives::hex; +use alloy_trie::Nibbles; +use std::{fmt, ops::Deref}; + +/// A slice of bytes representing nibbles. +#[derive(Clone, Copy)] +pub(super) struct NibbleSlice<'a>(&'a [u8]); + +impl Deref for NibbleSlice<'_> { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl fmt::Debug for NibbleSlice<'_> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Nibbles(0x{})", hex::encode(self.as_slice())) + } +} + +impl<'a> From<&'a Nibbles> for NibbleSlice<'a> { + /// Creates a `NibbleSlice` from a `Nibbles` reference. + #[inline] + fn from(nibbles: &'a Nibbles) -> Self { + Self(nibbles.as_slice()) + } +} + +impl From> for Nibbles { + /// Converts a `NibbleSlice` back into a `Nibbles`. + #[inline] + fn from(slice: NibbleSlice<'_>) -> Self { + Nibbles::from_nibbles_unchecked(slice.0) + } +} + +#[allow(dead_code)] +impl<'a> NibbleSlice<'a> { + #[inline] + pub(super) const fn as_slice(&self) -> &'a [u8] { + self.0 + } + + #[inline] + pub(super) const fn len(&self) -> usize { + self.0.len() + } + + #[inline] + pub(super) const fn is_empty(&self) -> bool { + self.0.is_empty() + } + + #[inline] + pub(super) fn join(&self, other: impl Into) -> Nibbles { + let other = other.into(); + let mut nibbles = Nibbles::with_capacity(self.len() + other.len()); + nibbles.extend_from_slice_unchecked(self.as_slice()); + nibbles.extend_from_slice_unchecked(other.as_slice()); + nibbles + } + + #[inline] + pub(super) fn split_first(&self) -> Option<(u8, Self)> { + self.0.split_first().map(|(nib, tail)| (*nib, Self(tail))) + } + + #[inline] + pub(super) fn strip_prefix(&self, prefix: &[u8]) -> Option { + self.0.strip_prefix(prefix).map(Self) + } + + #[inline] + pub(super) fn strip_suffix(&self, suffix: &[u8]) -> Option { + self.0.strip_suffix(suffix).map(Self) + } + + /// Splits `self` and `other` at the first nibble that differs. + #[inline] + pub(super) fn split_common_prefix(&self, other: impl Into) -> (Self, Self, Self) { + let (a, b) = (self.0, other.into().0); + let mid = a.iter().zip(b).take_while(|&(x, y)| x == y).count(); + // SAFETY: mid is the length of the common prefix: mid <= a.len() ∧ mid <= b.len() + let (common, a_tail) = unsafe { a.split_at_unchecked(mid) }; + ( + Self(common), + Self(a_tail), + Self(unsafe { b.split_at_unchecked(mid).1 }), + ) + } +} diff --git a/patches/risc0-ethereum-trie/src/mpt/node.rs b/patches/risc0-ethereum-trie/src/mpt/node.rs new file mode 100644 index 00000000..b2d09d6f --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/node.rs @@ -0,0 +1,291 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{ + children::{Children, Entry}, + memoize::Memoization, + nibbles::NibbleSlice, +}; +use alloy_primitives::{B256, Bytes}; +use alloy_trie::Nibbles; +use std::mem; + +pub(super) type Child = Box>; + +#[derive(Debug, Clone, Default)] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(bound(serialize = "", deserialize = "M: Default")) +)] +#[cfg_attr( + feature = "rkyv", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + rkyv(bytecheck(bounds(__C: rkyv::validation::ArchiveContext))), + rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, __S::Error: rkyv::rancor::Source)), + rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source)) +)] +pub(super) enum Node { + #[default] + Null, + Leaf( + #[cfg_attr(feature = "rkyv", rkyv(with = super::rkyv::NibblesDef))] Nibbles, + #[cfg_attr(feature = "rkyv", rkyv(with = super::rkyv::BytesDef))] Bytes, + #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "rkyv", rkyv(with = rkyv::with::Skip))] + M, + ), + Extension( + #[cfg_attr(feature = "rkyv", rkyv(with = super::rkyv::NibblesDef))] Nibbles, + #[cfg_attr(feature = "rkyv", rkyv(omit_bounds))] Child, + #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "rkyv", rkyv(with = rkyv::with::Skip))] + M, + ), + Branch( + Children, + #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "rkyv", rkyv(with = rkyv::with::Skip))] + M, + ), + Digest(#[cfg_attr(feature = "rkyv", rkyv(with = super::rkyv::B256Def))] B256), +} + +impl PartialEq for Node { + /// Equality between nodes ignores the cache. + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Node::Null, Node::Null) => true, + (Node::Leaf(n1, b1, _), Node::Leaf(n2, b2, _)) => n1 == n2 && b1 == b2, + (Node::Extension(n1, c1, _), Node::Extension(n2, c2, _)) => n1 == n2 && c1 == c2, + (Node::Branch(c1, _), Node::Branch(c2, _)) => c1 == c2, + (Node::Digest(d1), Node::Digest(d2)) => d1 == d2, + _ => false, // different variants are not equal + } + } +} + +impl Eq for Node {} + +impl Node { + /// Retrieves the value associated with a given key. + pub(super) fn get(&self, key: NibbleSlice<'_>) -> Option<&Bytes> { + match self { + Node::Null => None, + Node::Leaf(prefix, value, _) if prefix == key.as_slice() => Some(value), + Node::Leaf(..) => None, + Node::Extension(prefix, child, _) => { + key.strip_prefix(prefix).and_then(|tail| child.get(tail)) + } + Node::Branch(children, _) => match key.split_first() { + Some((nib, tail)) => { + // SAFETY: `key` is a `NibbleSlice` and thus only contains values < 0xf + let child = unsafe { children.get_unchecked(nib) }; + child.and_then(|node| node.get(tail)) + } + None => None, // branch nodes don't have values in our MPT version + }, + Node::Digest(_) => panic!("MPT: Unresolved node access"), + } + } + + /// Inserts a key-value pair into the trie. + pub(super) fn insert(&mut self, key: NibbleSlice<'_>, value: Bytes) { + assert!(!value.is_empty()); + match self { + Node::Null => { + *self = Node::Leaf(key.into(), value, M::default()); + } + Node::Leaf(prefix, leaf_val, cache) => { + let (common, key_rem, prefix_rem) = key.split_common_prefix(&*prefix); + if common.len() == prefix.len() && common.len() == key.len() { + *leaf_val = value; + cache.clear(); + return; + } else if common.len() == prefix.len() || common.len() == key.len() { + panic!("MPT: Value in branch"); + } + + let mut children = Children::default(); + match prefix_rem.split_first() { + Some((nib, tail)) => { + children.insert( + nib, + Node::Leaf(tail.into(), mem::take(leaf_val), M::default()).into(), + ); + } + None => unreachable!(), // mid < prefix.len() + } + match key_rem.split_first() { + Some((nib, tail)) => { + children.insert(nib, Node::Leaf(tail.into(), value, M::default()).into()) + } + None => unreachable!(), // mid < key.len() + }; + let branch = Node::Branch(children, M::default()); + + *self = if common.is_empty() { + branch + } else { + Node::Extension(common.into(), branch.into(), M::default()) + }; + } + Node::Extension(prefix, child, cache) => { + let (common, key_rem, prefix_rem) = key.split_common_prefix(&*prefix); + if common.len() == prefix.len() { + child.insert(key_rem, value); + cache.clear(); + return; + } else if common.len() == key.len() { + panic!("MPT: Value in branch"); + } + + let mut children = Children::default(); + match prefix_rem.as_slice() { + [nib] => children.insert(*nib, mem::take(child)), + [nib, tail @ ..] => { + // SAFETY: `tail` is a slice of `prefix` and thus only contains nibbles + let prefix = Nibbles::from_nibbles_unchecked(tail); + children.insert( + *nib, + Node::Extension(prefix, mem::take(child), M::default()).into(), + ); + } + _ => unreachable!(), // mid < prefix.len() + } + match key_rem.split_first() { + Some((nib, tail)) => { + children.insert(nib, Node::Leaf(tail.into(), value, M::default()).into()) + } + None => unreachable!(), // mid < key.len() + }; + let branch = Node::Branch(children, M::default()); + + *self = if common.is_empty() { + branch + } else { + Node::Extension(common.into(), branch.into(), M::default()) + }; + } + Node::Branch(children, cache) => match key.split_first() { + Some((nib, tail)) => match children.entry(nib) { + Entry::Occupied(mut entry) => { + entry.get_mut().insert(tail, value); + cache.clear(); + } + Entry::Vacant(entry) => { + entry.insert(Node::Leaf(tail.into(), value, M::default()).into()); + cache.clear(); + } + }, + None => panic!("MPT: Value in branch"), + }, + Node::Digest(_) => panic!("MPT: Unresolved node access"), + } + } + + /// Removes a key-value pair from the trie. + pub(super) fn remove(&mut self, key: NibbleSlice<'_>) -> bool { + match self { + Node::Null => false, + Node::Leaf(prefix, ..) if prefix == key.as_slice() => { + *self = Node::Null; + true + } + Node::Leaf(..) => false, + Node::Extension(prefix, child, cache) => { + if !key + .strip_prefix(&*prefix) + .is_some_and(|tail| child.remove(tail)) + { + return false; + } + cache.clear(); + + // an extension always points to a branch, if this has changed because of the remove + match **child { + Node::Null => *self = Node::Null, + Node::Leaf(ref extension, ref mut value, _) => { + prefix.extend_from_slice(extension); + *self = Node::Leaf(mem::take(prefix), mem::take(value), M::default()) + } + Node::Extension(ref extension, ref mut child, _) => { + prefix.extend_from_slice(extension); + *self = Node::Extension(mem::take(prefix), mem::take(child), M::default()) + } + Node::Branch(..) => {} + Node::Digest(_) => unreachable!(), // child.remove() would have panicked + } + true + } + Node::Branch(children, cache) => { + match key.split_first() { + Some((nib, tail)) => match children.entry(nib) { + Entry::Occupied(mut entry) => { + if !entry.get_mut().remove(tail) { + return false; + } + } + Entry::Vacant(_) => return false, + }, + None => return false, // branch nodes don't have values in our MPT version + }; + cache.clear(); + + if let Some((nib, only_child)) = children.take_single_child() { + match *only_child { + // if the only child is a leaf, prepend the corresponding nib to it + Node::Leaf(mut extension, value, _) => { + // SAFETY: `take_single_child` always returns a nibble + extension.as_mut_vec_unchecked().insert(0, nib); + *self = Node::Leaf(extension, value, M::default()); + } + // if the only child is an extension, prepend the corresponding nib to it + Node::Extension(mut extension, child, ..) => { + // SAFETY: `take_single_child` always returns a nibble + extension.as_mut_vec_unchecked().insert(0, nib); + *self = Node::Extension(extension, child, M::default()); + } + // if the only child is a branch, convert to an extension + Node::Branch(..) => { + // SAFETY: `take_single_child` always returns a nibble + let prefix = Nibbles::from_nibbles_unchecked([nib]); + *self = Node::Extension(prefix, only_child, M::default()); + } + Node::Digest(_) => panic!("MPT: Unresolved node access"), + Node::Null => unreachable!(), // children does not contain any Node::Null + } + } + true + } + Node::Digest(_) => panic!("MPT: Unresolved node access"), + } + } + + /// Returns the number of full nodes in the trie. + pub(super) fn size(&self) -> usize { + match self { + Node::Null | Node::Digest(_) => 0, + Node::Leaf(..) => 1, + Node::Extension(_, child, ..) => 1 + child.size(), + Node::Branch(children, ..) => { + 1 + children + .iter() + .filter_map(Option::as_deref) + .map(Node::size) + .sum::() + } + } + } +} diff --git a/patches/risc0-ethereum-trie/src/mpt/orphan.rs b/patches/risc0-ethereum-trie/src/mpt/orphan.rs new file mode 100644 index 00000000..af6c5b15 --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/orphan.rs @@ -0,0 +1,330 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Functionality to resolve "orphan" nodes occurring during removes. +//! +//! Calling `remove` in sparse Merkle Patricia tries are only safe, if it does not lead to a Branch +//! node with just a single unresolved Digest child. Even though such a sparse trie is perfectly +//! valid to proof inclusion if the trie is not modified. + +use crate::{ + CachedTrie, Trie, + mpt::{memoize::Memoization, nibbles::NibbleSlice, node::Node}, +}; +use alloy_primitives::{keccak256, map::B256Map}; +use alloy_trie::Nibbles; +use std::fmt::Debug; + +/// Error returned by the `resolve_orphan` method. +#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)] +pub enum Error { + /// Indicates that the proof does not have a valid RLP encoding. + #[error("proof RLP encoding error")] + RlpError(#[from] alloy_rlp::Error), + + /// Indicates that the given proof is an invalid post-removal proof and does not prove the + /// non-inclusion of the key. + #[error("invalid proof")] + InvalidProof, + + /// Indicates that the orphan cannot be resolved using only the provided post-removal proof. + /// This typically occurs when the removal of a key transforms an `Extension` node into a + /// `Branch` node, and the proof does not contain sufficient information to reconstruct the + /// original `Extension` node. + /// It contains the key prefix that needs to be resolved, to make the removal valid. + #[error("key prefix `{0:?}` not resolved")] + Unresolvable(Nibbles), +} + +impl Trie { + /// Attempts to resolve orphaned branch children caused by the removal of a key-value pair. + /// + /// When a key-value pair is removed from the trie, it may leave behind "orphaned" nodes that + /// must be transformed into a different type of node for the trie to remain valid. + /// This method uses an [EIP-1186](https://eips.ethereum.org/EIPS/eip-1186) proof to resolve + /// these orphans. The proof should represent the state of the trie *after* the removal of the + /// key-value pair. + /// + /// # Errors + /// + /// Returns `Ok(())` if the orphan was successfully resolved. Returns `Error` if the proof is + /// invalid or the orphan cannot be resolved with the given proof. + /// + /// # Panics + /// + /// It panics if the key is not contained in the trie. + #[inline] + pub fn resolve_orphan(&mut self, key: K, proof: I) -> Result<(), Error> + where + K: AsRef<[u8]>, + I: IntoIterator, + T: AsRef<[u8]>, + { + self.0 + .resolve_orphan(NibbleSlice::from(&Nibbles::unpack(key)), proof) + } +} + +impl CachedTrie { + /// Attempts to resolve orphaned branch children caused by removing a key-value pair. + /// + /// See [`Trie::resolve_orphan`] for detailed documentation. + #[inline] + pub fn resolve_orphan(&mut self, key: K, proof: I) -> Result<(), Error> + where + K: AsRef<[u8]>, + I: IntoIterator, + T: AsRef<[u8]>, + { + self.inner + .resolve_orphan(NibbleSlice::from(&Nibbles::unpack(key)), proof) + } +} + +impl Node { + /// Attempts to resolve orphaned branch children caused by removing a key-value pair. + pub(super) fn resolve_orphan>( + &mut self, + key: NibbleSlice<'_>, + proof: impl IntoIterator, + ) -> Result<(), Error> { + assert!(self.get(key).is_some(), "key not contained"); + let other = Node::from_rlp(proof)?; + let Some((diverging, unmatched)) = other.diverging(key) else { + return Ok(()); + }; + let matched = key.strip_suffix(&unmatched).unwrap(); + + match diverging { + Node::Null => { + // the entire tree has been removed so trivially there can be no orphans + } + Node::Leaf(prefix, value, _) => { + // get the unmatched part of the Leaf-prefix + let (common, unmatched, _) = + NibbleSlice::from(prefix).split_common_prefix(unmatched); + // split the first nibble which used to belong to the Branch + let (idx, suffix) = unmatched.split_first().expect("empty unmatched key"); + // this can only be an orphan, if it is currently a Digest child of a Branch + if !self.is_branch_with_digest(&matched.join(common), idx) { + return Ok(()); + } + + // any orphan must be a Leaf with the suffix as a prefix + let sibling = Node::Leaf(suffix.into(), value.clone(), M::default()); + let rlp = sibling.rlp_encoded(); + self.resolve_digests(&B256Map::from_iter([(keccak256(&rlp), rlp)])) + .unwrap(); + } + Node::Extension(prefix, child, _) => { + // get the unmatched part of the Extension-prefix + let (common, unmatched, _) = + NibbleSlice::from(prefix).split_common_prefix(unmatched); + // split the first nibble which used to belong to the Branch + let (idx, suffix) = unmatched.split_first().expect("empty unmatched key"); + // this can only be an orphan, if it is currently a Digest child of a Branch + if !self.is_branch_with_digest(&matched.join(common), idx) { + return Ok(()); + } + + // Extensions cannot have an empty prefix. This means that if the suffix is empty, + // the orphan is a Branch, and because of the removal, its parent Branch has been + // converted to an Extension. So to resolve this orphan, we need to know the + // original Branch. + if suffix.is_empty() { + // if we are lucky, the post-removal proof does not stop at the Extension and + // the child still corresponds to the node we are looking for. + if !matches!(**child, Node::Digest(_)) { + let rlp = child.rlp_encoded(); + self.resolve_digests(&B256Map::from_iter([(keccak256(&rlp), rlp)])) + .unwrap(); + } + // the path to the orphan corresponds exactly to the path of the Extension-child + let orphan_prefix = matched.join(prefix); + // maybe the trie already contains a node with this prefix + if self.contains_prefix(&orphan_prefix) { + // in this case, the removal will not fail and nothing needs to be resolved + return Ok(()); + } + // otherwise return error that the given prefix needs to be resolved externally + return Err(Error::Unresolvable(orphan_prefix)); + } + + // any potential orphan must be an Extension with the (non-empty) suffix as a prefix + let sibling = Node::Extension(suffix.into(), (*child).clone(), M::default()); + let rlp = sibling.rlp_encoded(); + self.resolve_digests(&B256Map::from_iter([(keccak256(&rlp), rlp)])) + .unwrap(); + } + Node::Digest(_) => { + // the proof is invalid, as it does not proof the non-inclusion of `key` + return Err(Error::InvalidProof); + } + Node::Branch(..) => unreachable!("Branch node with value"), + } + + Ok(()) + } + + /// Returns the diverging trie node for a key. + /// + /// If the key is present in the trie, this method returns `None`. Otherwise, it returns the + /// node where the search for the key would fail, along with the unmatched portion of the key. + fn diverging<'a>(&'a self, key: NibbleSlice<'a>) -> Option<(&'a Node, NibbleSlice<'a>)> { + match self { + Node::Null => Some((&Node::Null, key)), + + Node::Leaf(prefix, ..) if prefix == key.as_slice() => None, + Node::Leaf(..) => Some((self, key)), + + Node::Extension(prefix, child, _) => key + .strip_prefix(prefix) + .map_or(Some((self, key)), |tail| child.diverging(tail)), + + Node::Branch(children, _) => match key.split_first() { + Some((idx, tail)) => { + let child = children.get(idx); + child.map_or(Some((&Node::Null, tail)), |node| node.diverging(tail)) + } + None => Some((self, key)), // branch nodes don't have values + }, + + Node::Digest(_) => Some((self, key)), + } + } + + fn contains_prefix<'a>(&'a self, key: impl Into>) -> bool { + match self.diverging(key.into()) { + None => true, // contains the prefix as a key + Some((Node::Digest(_), _)) => false, // prefix not resolved + Some((_, unmatched)) => unmatched.is_empty(), // prefix contained or not + } + } + + /// Returns whether the node at key is a Branch which has a Digest child at idx. + fn is_branch_with_digest<'a>(&'a self, key: impl Into>, idx: u8) -> bool { + match self.diverging(key.into()) { + // match only if, the node found is a `Node::Branch` and the *entire* key was consumed + Some((Node::Branch(children, ..), unmatched)) if unmatched.is_empty() => { + // if all the above conditions are met, check the specific child + matches!(children.get(idx), Some(Node::Digest(_))) + } + _ => false, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::Trie; + use alloy_primitives::{B256, Bytes}; + use alloy_trie::{HashBuilder, Nibbles, proof::ProofRetainer}; + use std::{borrow::Borrow, panic}; + + fn create_eip1186_proof( + key: K, + trie: impl IntoIterator>, + ) -> Vec + where + K: AsRef<[u8]>, + V: AsRef<[u8]>, + { + let hb = HashBuilder::default(); + let mut hb = + hb.with_proof_retainer(ProofRetainer::new(vec![Nibbles::unpack(key.as_ref())])); + + let mut sorted_data: Vec<_> = trie.into_iter().collect(); + sorted_data.sort_by(|a, b| a.borrow().0.as_ref().cmp(b.borrow().0.as_ref())); + for (key, val) in sorted_data.iter().map(Borrow::borrow) { + hb.add_leaf(Nibbles::unpack(key), val.as_ref()); + } + let _ = hb.root(); + + hb.take_proof_nodes() + .into_nodes_sorted() + .into_iter() + .map(|(_, rlp)| rlp) + .collect() + } + + #[test] + fn leaf_orphan() { + let keys = [vec![0x00], vec![0x11]]; + let key = &keys[0]; + let leaves = keys + .iter() + .map(|k| (k, Bytes::from(B256::ZERO))) + .collect::>(); + + let proof = create_eip1186_proof(key, &leaves); + let post_proof = create_eip1186_proof(key, &leaves[1..]); + + let mut trie = Trie::from_rlp(proof).unwrap(); + assert!(trie.get(key).is_some()); + assert!( + panic::catch_unwind(|| trie.clone().remove(key)).is_err(), + "Removal should panic" + ); + + trie.resolve_orphan(key, post_proof).unwrap(); + trie.remove(key); + } + + #[test] + fn extension_orphan() { + let keys = [vec![0x00], vec![0x10, 0x00], vec![0x10, 0x01]]; + let key = &keys[0]; + let leaves = keys + .iter() + .map(|k| (k, Bytes::from(B256::ZERO))) + .collect::>(); + + let proof = create_eip1186_proof(key, &leaves); + let post_proof = create_eip1186_proof(key, &leaves[1..]); + + let mut trie = Trie::from_rlp(proof).unwrap(); + assert!(trie.get(key).is_some()); + assert!( + panic::catch_unwind(|| trie.clone().remove(key)).is_err(), + "Removal should panic" + ); + + trie.resolve_orphan(key, post_proof).unwrap(); + trie.remove(key); + } + + #[test] + fn unresolvable_orphan() { + let keys = [vec![0x00], vec![0x10], vec![0x11]]; + let key = &keys[0]; + let leaves = keys + .iter() + .map(|k| (k, Bytes::from(B256::ZERO))) + .collect::>(); + + let proof = create_eip1186_proof(key, &leaves); + let post_proof = create_eip1186_proof(key, &leaves[1..]); + + let mut trie = Trie::from_rlp(proof).unwrap(); + assert!(trie.get(key).is_some()); + assert!( + panic::catch_unwind(|| trie.clone().remove(key)).is_err(), + "Removal should panic" + ); + + let err = trie.resolve_orphan(key, post_proof).unwrap_err(); + assert!(matches!(err, Error::Unresolvable(_))); + } +} diff --git a/patches/risc0-ethereum-trie/src/mpt/rkyv.rs b/patches/risc0-ethereum-trie/src/mpt/rkyv.rs new file mode 100644 index 00000000..e8797314 --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/rkyv.rs @@ -0,0 +1,189 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{ + memoize::{Cache, Memoization}, + node::Node, +}; +use alloy_primitives::{B256, Bytes}; +use alloy_trie::nybbles::Nibbles; +use itertools::Itertools; +use rkyv::{ + Archive, Archived, Deserialize, Place, Serialize, + rancor::{Fallible, Source}, + ser::{Allocator, Writer}, + vec::{ArchivedVec, VecResolver}, + with::{ArchiveWith, DeserializeWith, SerializeWith}, +}; + +/// Wrapper to encode a [B256] as an `[u8; 32]`. +#[derive(Archive, Serialize, Deserialize)] +#[rkyv(remote = B256)] +pub(super) struct B256Def([u8; B256::len_bytes()]); + +impl From for B256 { + #[inline] + fn from(B256Def(arr): B256Def) -> Self { + Self(arr) + } +} + +/// Wrapper to encode [Bytes] as an [`ArchivedVec`]. +pub(super) struct BytesDef; + +impl ArchiveWith for BytesDef { + type Archived = ArchivedVec; + type Resolver = VecResolver; + + fn resolve_with(bytes: &Bytes, resolver: Self::Resolver, out: Place) { + ArchivedVec::resolve_from_slice(bytes, resolver, out); + } +} + +impl SerializeWith for BytesDef { + fn serialize_with(bytes: &Bytes, serializer: &mut S) -> Result { + ArchivedVec::serialize_from_slice(bytes, serializer) + } +} + +impl DeserializeWith>, Bytes, D> for BytesDef +where + D: Fallible + ?Sized, + ::Error: Source, +{ + fn deserialize_with(field: &ArchivedVec, deserializer: &mut D) -> Result { + let vec = as Deserialize, D>>::deserialize(field, deserializer)?; + Ok(Bytes::from(vec)) + } +} + +/// Wrapper to encode [Nibbles] as an [`ArchivedVec`]. +pub(super) struct NibblesDef; + +impl ArchiveWith for NibblesDef { + type Archived = ArchivedVec; + type Resolver = VecResolver; + + fn resolve_with(nibbles: &Nibbles, resolver: Self::Resolver, out: Place) { + ArchivedVec::resolve_from_slice(nibbles, resolver, out); + } +} + +impl SerializeWith for NibblesDef { + fn serialize_with(nibbles: &Nibbles, serializer: &mut S) -> Result { + ArchivedVec::serialize_from_slice(nibbles, serializer) + } +} + +impl DeserializeWith>, Nibbles, D> for NibblesDef +where + D: Fallible + ?Sized, + ::Error: Source, +{ + fn deserialize_with(f: &ArchivedVec, deserializer: &mut D) -> Result { + let vec = as Deserialize, D>>::deserialize(f, deserializer)?; + Ok(Nibbles::from_vec_unchecked(vec)) + } +} + +/// RLP-encodes a cached trie during serialization. +/// +/// This has several advantages: +/// - The serialized bytes are fully verified at deserialization. +/// - The trie nodes already have an RLP-encoding when the hash is computed. +#[derive(Archive, Serialize, Deserialize)] +#[rkyv(remote = Node)] +pub(super) struct RlpNodes(#[rkyv(getter = rlp_nodes)] Vec>); + +fn rlp_nodes(node: &Node) -> Vec> { + node.rlp_nodes() + .into_iter() + .unique() + .map(Vec::from) + .collect() +} + +impl From for Node { + #[inline] + fn from(RlpNodes(nodes): RlpNodes) -> Self { + Node::from_rlp(nodes).unwrap() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mpt::{ArchivedTrie, Trie}; + use alloy_primitives::keccak256; + use rkyv::rancor::Error; + + const N: usize = 512; + + #[test] + fn round_trip() { + let trie: Trie = (0..N) + .map(|i| { + ( + keccak256(i.to_be_bytes()), + Bytes::from(alloy_rlp::encode(i)), + ) + }) + .collect(); + + let bytes = rkyv::to_bytes::(&trie).unwrap(); + let archived = rkyv::access::(&bytes).unwrap(); + let other = rkyv::deserialize::(archived).unwrap(); + + assert_eq!(trie, other); + } + + mod cached { + use super::*; + use crate::mpt::{ArchivedCachedTrie, CachedTrie}; + + #[test] + fn round_trip() { + let mut trie: CachedTrie = (0..N) + .map(|i| { + ( + keccak256(i.to_be_bytes()), + Bytes::from(alloy_rlp::encode(i)), + ) + }) + .collect(); + trie.hash(); + assert!(trie.hash.is_some()); + + let bytes = rkyv::to_bytes::(&trie).unwrap(); + let archived = rkyv::access::(&bytes).unwrap(); + let other = rkyv::deserialize::(archived).unwrap(); + assert!(other.hash.is_none()); + + assert_eq!(trie, other); + } + + #[test] + fn round_trip_dup() { + let trie: CachedTrie = (0..255) + .map(|i| (B256::with_last_byte(i), Bytes::from(B256::ZERO))) + .collect(); + + let bytes = rkyv::to_bytes::(&trie).unwrap(); + let archived = rkyv::access::(&bytes).unwrap(); + let other = rkyv::deserialize::(archived).unwrap(); + + assert_eq!(trie, other); + } + } +} diff --git a/patches/risc0-ethereum-trie/src/mpt/rlp.rs b/patches/risc0-ethereum-trie/src/mpt/rlp.rs new file mode 100644 index 00000000..21e4281f --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/rlp.rs @@ -0,0 +1,654 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::{ + children::{Children, Entry}, + memoize::Memoization, + node::Node, +}; +use alloy_primitives::{ + B256, Bytes, hex, keccak256, + map::{B256HashMap, B256Map}, +}; +use alloy_rlp::{BufMut, Decodable, EMPTY_STRING_CODE, Encodable, Header}; +use alloy_trie::{EMPTY_ROOT_HASH, Nibbles, nodes::encode_path_leaf}; +use arrayvec::ArrayVec; +use std::fmt; + +/// The length in bytes of an RLP-encoded digest, i.e. hash length + 1 byte for the RLP header. +const DIGEST_RLP_LENGTH: usize = 1 + B256::len_bytes(); + +impl Node { + /// Returns the hash of the node. + #[inline] + pub(super) fn hash(&self) -> B256 { + NodeRef::from_node(self).hash() + } + + /// Returns the RLP encoding of the node. + pub(super) fn rlp_encoded(&self) -> Vec { + match self { + Node::Null => vec![EMPTY_STRING_CODE], + Node::Leaf(prefix, value, _) => { + let path = encode_path_leaf(prefix, true); + let mut out = encode_list_header(path.length() + value.length()); + path.encode(&mut out); + value.encode(&mut out); + + out + } + Node::Extension(prefix, child, _) => { + let path = encode_path_leaf(prefix, false); + let node_ref = NodeRef::from_node(child); + let mut out = encode_list_header(path.length() + node_ref.length()); + path.encode(&mut out); + node_ref.encode(&mut out); + + out + } + Node::Branch(children, _) => { + let mut child_refs: [NodeRef<'_>; 16] = Default::default(); + let mut payload_length = 1; // start with 1 for the EMPTY_STRING_CODE at the end + + for (i, child) in children.iter().enumerate() { + match child { + Some(node) => { + let node_ref = NodeRef::from_node(node); + payload_length += node_ref.length(); + child_refs[i] = node_ref; + } + None => payload_length += 1, + } + } + + let mut out = encode_list_header(payload_length); + child_refs.iter().for_each(|child| child.encode(&mut out)); + // add an EMPTY_STRING_CODE for the missing value + out.push(EMPTY_STRING_CODE); + + out + } + Node::Digest(digest) => alloy_rlp::encode(digest), + } + } + + /// Memoize the hash of every sub-trie. + pub(super) fn memoize(&mut self) { + // early termination for already memoized nodes or Null/Digest + match self { + Node::Leaf(.., cache) | Node::Extension(.., cache) | Node::Branch(.., cache) + if cache.get().is_some() => + { + return; + } + Node::Null | Node::Digest(_) => return, + _ => {} // proceed to memoization for other variants + } + match self { + Node::Extension(_, child, _) => child.memoize(), + Node::Branch(children, _) => children.memoize(), + _ => {} // no children to memoize for Leaf, Null, or Digest + } + let rlp = self.rlp_encoded(); + match self { + Node::Leaf(.., cache) | Node::Extension(.., cache) | Node::Branch(.., cache) => { + cache.set(RlpNode::from_rlp(rlp)); + } + _ => unreachable!(), + } + } + + /// Returns the RLP-encoded nodes of the trie in preorder. + pub(super) fn rlp_nodes(&self) -> Vec { + fn rec<'a, M: Memoization>(node: &'a Node, nodes: &mut Vec) -> NodeRef<'a> { + let node_ref = match node { + Node::Extension(prefix, child, _) => { + let (path, child) = (encode_path_leaf(prefix, false), rec(child, nodes)); + let mut out = encode_list_header(path.length() + child.length()); + path.encode(&mut out); + child.encode(&mut out); + NodeRef::Rlp(out) + } + Node::Branch(children, _) => { + let mut list = Vec::with_capacity(17); + for child in children.iter() { + let node_ref = child.as_ref().map_or(NodeRef::Empty, |c| rec(c, nodes)); + list.push(node_ref); + } + list.push(NodeRef::Empty); + NodeRef::Rlp(encode_list(&list)) + } + Node::Leaf(..) => NodeRef::Rlp(node.rlp_encoded()), // do not use the cached value + Node::Digest(digest) => NodeRef::Digest(digest), + Node::Null => NodeRef::Empty, + }; + match &node_ref { + NodeRef::Rlp(rlp) if rlp.len() >= 32 => nodes.push(rlp.clone().into()), + NodeRef::Cached(..) => unreachable!(), + _ => {} + } + node_ref + } + + if matches!(self, Node::Null) { + return vec![]; + } + + let mut vec = Vec::new(); + match rec(self, &mut vec) { + NodeRef::Rlp(rlp) if rlp.len() >= 32 => {} + NodeRef::Cached(..) => unreachable!(), + node_ref => vec.push(alloy_rlp::encode(node_ref).into()), + } + vec.reverse(); + + vec + } + + /// Creates a new trie from the given RLP encoded nodes. + pub(super) fn from_rlp>( + nodes: impl IntoIterator, + ) -> alloy_rlp::Result { + let mut iterator = nodes.into_iter(); + + // the first node must be the root + let mut root = match iterator.next() { + None => return Ok(Self::default()), + Some(rlp) => { + let mut node: Node = alloy_rlp::decode_exact(rlp.as_ref())?; + node.cache_set(RlpNode::from_rlp(rlp)); + node + } + }; + + // compute the references of all the remaining nodes + let (lower, _) = iterator.size_hint(); + let mut rlp_by_digest = B256HashMap::with_capacity_and_hasher(lower, Default::default()); + for rlp in iterator { + rlp_by_digest.insert(keccak256(&rlp), rlp); + } + + // return the resolved trie + root.resolve_digests(&rlp_by_digest)?; + Ok(root) + } + + /// Resolves all applicable digest nodes with the node corresponding to the RLP encoding. + pub(super) fn resolve_digests( + &mut self, + rlp_by_digest: &B256Map>, + ) -> alloy_rlp::Result<()> { + match self { + Node::Null | Node::Leaf(..) => {} + Node::Extension(_, child, _) => { + child.resolve_digests(rlp_by_digest)?; + if !matches!(**child, Node::Branch(..) | Node::Digest(..)) { + return Err(alloy_rlp::Error::Custom( + "extension node with invalid child", + )); + } + } + Node::Branch(children, _) => { + for entry in children.entries() { + if let Entry::Occupied(mut entry) = entry { + entry.get_mut().resolve_digests(rlp_by_digest)?; + } + } + } + Node::Digest(digest) => { + if let Some(bytes) = rlp_by_digest.get(digest) { + let mut node: Node = alloy_rlp::decode_exact(bytes.as_ref())?; + // do not try to replace a node by a digest + if !matches!(node, Node::Digest(_)) { + node.cache_set(RlpNode::from_digest(digest)); + *self = node; + self.resolve_digests(rlp_by_digest)?; + } + } + } + } + + Ok(()) + } + + #[inline] + fn cache_set(&mut self, rlp_node: RlpNode) { + match self { + Node::Leaf(.., cache) | Node::Extension(.., cache) | Node::Branch(.., cache) => { + cache.set(rlp_node) + } + _ => {} + } + } +} + +/// Compile-time toggle: `false` restores the upstream alloy-rlp based node +/// decoder (for A/B cycle measurement). +const FAST_DECODE: bool = true; + +impl Decodable for Node { + fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { + if FAST_DECODE { + decode_node(buf) + } else { + decode_node_orig(buf) + } + } +} + +/// Upstream reference implementation (alloy-rlp `PayloadView` based), kept for +/// A/B measurement of the hand-written decoder. +#[allow(dead_code)] +fn decode_node_orig(buf: &mut &[u8]) -> alloy_rlp::Result> { + match Header::decode_raw(buf)? { + // if the node is not a list, it must be empty or a digest + alloy_rlp::PayloadView::String(payload) => match payload.len() { + 0 => Ok(Node::Null), + 32 => Ok(Node::Digest(B256::from_slice(payload))), + _ => Err(alloy_rlp::Error::UnexpectedLength), + }, + alloy_rlp::PayloadView::List(items) => match items.len() { + // branch node: 17-item node [ v0 ... v15, value ] + 17 => { + let mut children = Children::default(); + for (i, child_rlp) in items.iter().enumerate() { + if child_rlp != &[EMPTY_STRING_CODE] { + if i == 16 { + return Err(alloy_rlp::Error::Custom("branch node with value")); + } else { + children.insert( + i as u8, + decode_node_orig::(&mut &child_rlp[..])?.into(), + ); + } + } + } + if children.len() < 2 { + return Err(alloy_rlp::Error::Custom("branch node without two children")); + } + + Ok(Node::Branch(children, M::default())) + } + // leaf or extension node: 2-item node [ encodedPath, v ] + 2 => { + let [mut encode_path, mut v] = items.as_slice() else { + unreachable!() + }; + let (path, is_leaf) = decode_path_orig(&mut encode_path)?; + if is_leaf { + Ok(Node::Leaf(path, Bytes::decode(&mut v)?, M::default())) + } else { + let node = decode_node_orig::(&mut v)?; + if !matches!(node, Node::Branch(..) | Node::Digest(..)) { + return Err(alloy_rlp::Error::Custom( + "extension node with invalid child", + )); + } + Ok(Node::Extension(path, node.into(), M::default())) + } + } + _ => Err(alloy_rlp::Error::Custom("unexpected list length")), + }, + } +} + +/// Upstream reference implementation of the compact path decoder. +#[allow(dead_code)] +fn decode_path_orig(buf: &mut &[u8]) -> alloy_rlp::Result<(Nibbles, bool)> { + let path = Nibbles::unpack(Header::decode_bytes(buf, false)?); + if path.len() < 2 { + return Err(alloy_rlp::Error::InputTooShort); + } + let (is_leaf, odd_nibbles) = match path[0] { + 0b0000 => (false, false), + 0b0001 => (false, true), + 0b0010 => (true, false), + 0b0011 => (true, true), + _ => return Err(alloy_rlp::Error::Custom("node is not an extension or leaf")), + }; + let prefix = if odd_nibbles { &path[1..] } else { &path[2..] }; + Ok((Nibbles::from_nibbles_unchecked(prefix), is_leaf)) +} + +/// Reads the RLP header at the start of `bytes` without consuming it. +/// +/// Returns `(is_list, header_len, payload_len)`. +/// +/// Unlike `alloy_rlp::Header::decode_raw` this does not check canonical-form +/// rules (short-form vs long-form, leading zeros): the MPT root check at the +/// end of state verification rejects any incorrectly encoded witness anyway, +/// and the trie is re-encoded canonically when hashing. +#[inline] +fn peek_header(bytes: &[u8]) -> alloy_rlp::Result<(bool, usize, usize)> { + let Some(&b0) = bytes.first() else { + return Err(alloy_rlp::Error::InputTooShort); + }; + match b0 { + // single byte < 0x80 encodes itself + 0x00..=0x7f => Ok((false, 0, 1)), + 0x80..=0xb7 => Ok((false, 1, (b0 - 0x80) as usize)), + 0xb8..=0xbf => { + let ll = (b0 - 0xb7) as usize; + if bytes.len() < 1 + ll { + return Err(alloy_rlp::Error::InputTooShort); + } + let mut len = 0usize; + for &b in &bytes[1..1 + ll] { + len = (len << 8) | b as usize; + } + Ok((false, 1 + ll, len)) + } + 0xc0..=0xf7 => Ok((true, 1, (b0 - 0xc0) as usize)), + 0xf8..=0xff => { + let ll = (b0 - 0xf7) as usize; + if bytes.len() < 1 + ll { + return Err(alloy_rlp::Error::InputTooShort); + } + let mut len = 0usize; + for &b in &bytes[1..1 + ll] { + len = (len << 8) | b as usize; + } + Ok((true, 1 + ll, len)) + } + } +} + +/// Fast, allocation-light replacement for the alloy-rlp based `Node::decode`. +/// +/// Walks list items directly over the input slice (no intermediate `Vec` of +/// payload views), and decodes the compact path into a single small buffer. +fn decode_node(buf: &mut &[u8]) -> alloy_rlp::Result> { + let (is_list, hlen, plen) = peek_header(buf)?; + let bytes = *buf; + if bytes.len() < hlen + plen { + return Err(alloy_rlp::Error::InputTooShort); + } + let payload = &bytes[hlen..hlen + plen]; + *buf = &bytes[hlen + plen..]; + + if !is_list { + // if the node is not a list, it must be empty or a digest + return match plen { + 0 => Ok(Node::Null), + 32 => Ok(Node::Digest(B256::from_slice(payload))), + _ => Err(alloy_rlp::Error::UnexpectedLength), + }; + } + + // collect the items of the list as full RLP slices + let mut items: ArrayVec<&[u8], 17> = ArrayVec::new(); + let mut rest = payload; + while !rest.is_empty() { + let (_, ih, ip) = peek_header(rest)?; + if rest.len() < ih + ip { + return Err(alloy_rlp::Error::InputTooShort); + } + if items.try_push(&rest[..ih + ip]).is_err() { + return Err(alloy_rlp::Error::Custom("unexpected list length")); + } + rest = &rest[ih + ip..]; + } + + match items.len() { + // branch node: 17-item node [ v0 ... v15, value ] + 17 => { + let mut children = Children::default(); + for (i, child_rlp) in items.iter().enumerate() { + if *child_rlp != [EMPTY_STRING_CODE].as_slice() { + if i == 16 { + return Err(alloy_rlp::Error::Custom("branch node with value")); + } else if child_rlp.len() == DIGEST_RLP_LENGTH && child_rlp[0] == 0xa0 { + // fast path: a 33-byte item is a 32-byte digest string; + // skip the generic decoder recursion (111k of these per + // chunk, most of them never resolved further) + children.insert( + i as u8, + Node::Digest(B256::from_slice(&child_rlp[1..])).into(), + ); + } else { + children.insert(i as u8, decode_node(&mut &child_rlp[..])?.into()); + } + } + } + if children.len() < 2 { + return Err(alloy_rlp::Error::Custom("branch node without two children")); + } + + Ok(Node::Branch(children, M::default())) + } + // leaf or extension node: 2-item node [ encodedPath, v ] + // they are distinguished by a flag in the first nibble of the encodedPath + 2 => { + let (path, is_leaf) = decode_path(&mut &items[0][..])?; + if is_leaf { + let (v_list, vh, vp) = peek_header(items[1])?; + if v_list || items[1].len() < vh + vp { + return Err(alloy_rlp::Error::UnexpectedLength); + } + Ok(Node::Leaf( + path, + Bytes::copy_from_slice(&items[1][vh..vh + vp]), + M::default(), + )) + } else { + let v = &items[1][..]; + let node = if v.len() == DIGEST_RLP_LENGTH && v[0] == 0xa0 { + Node::Digest(B256::from_slice(&v[1..])) + } else { + decode_node(&mut &items[1][..])? + }; + if !matches!(node, Node::Branch(..) | Node::Digest(..)) { + return Err(alloy_rlp::Error::Custom( + "extension node with invalid child", + )); + } + Ok(Node::Extension(path, node.into(), M::default())) + } + } + _ => Err(alloy_rlp::Error::Custom("unexpected list length")), + } +} + +/// An RLP-encoded node. +#[derive(Clone)] +pub(super) struct RlpNode(ArrayVec); + +impl RlpNode { + #[inline] + fn from_rlp(rlp: impl AsRef<[u8]>) -> Self { + let rlp = rlp.as_ref(); + if rlp.len() >= B256::len_bytes() { + Self(alloy_rlp::encode_fixed_size(&keccak256(rlp))) + } else { + let mut arr = ArrayVec::new(); + // SAFETY: rlp.len() < 32 < DIGEST_RLP_LENGTH + unsafe { arr.try_extend_from_slice(rlp).unwrap_unchecked() }; + Self(arr) + } + } + + #[inline] + fn from_digest(digest: &B256) -> Self { + Self(alloy_rlp::encode_fixed_size(digest)) + } + + #[inline] + fn hash(&self) -> B256 { + if self.0.len() == DIGEST_RLP_LENGTH { + B256::from_slice(&self.0[1..]) + } else { + keccak256(&self.0) + } + } +} + +impl fmt::Debug for RlpNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x{}", hex::encode(&self.0)) + } +} + +impl Encodable for RlpNode { + #[inline] + fn encode(&self, out: &mut dyn BufMut) { + out.put_slice(&self.0) + } + + #[inline] + fn length(&self) -> usize { + self.0.len() + } +} + +/// Represents the way in which a node is referenced from within another node. +#[derive(Default)] +enum NodeRef<'a> { + #[default] + Empty, + Digest(&'a B256), + Cached(&'a RlpNode), + Rlp(Vec), +} + +impl NodeRef<'_> { + #[inline] + fn from_node(node: &Node) -> NodeRef<'_> { + match node { + Node::Null => NodeRef::Empty, + Node::Digest(digest) => NodeRef::Digest(digest), + Node::Leaf(.., cache) | Node::Extension(.., cache) | Node::Branch(.., cache) => cache + .get() + .map_or_else(|| NodeRef::Rlp(node.rlp_encoded()), NodeRef::Cached), + } + } + + #[inline] + fn hash(&self) -> B256 { + match self { + NodeRef::Empty => EMPTY_ROOT_HASH, + NodeRef::Digest(&digest) => digest, + NodeRef::Cached(rlp_node) => rlp_node.hash(), + NodeRef::Rlp(rlp) => keccak256(rlp), + } + } +} + +impl Encodable for NodeRef<'_> { + #[inline] + fn encode(&self, out: &mut dyn BufMut) { + match self { + NodeRef::Empty => out.put_u8(EMPTY_STRING_CODE), + NodeRef::Digest(digest) => digest.encode(out), + NodeRef::Cached(rlp_node) => rlp_node.encode(out), + NodeRef::Rlp(rlp) => { + if rlp.len() >= B256::len_bytes() { + keccak256(rlp).encode(out); + } else { + out.put_slice(rlp); + } + } + } + } + + #[inline] + fn length(&self) -> usize { + match self { + NodeRef::Empty => 1, + NodeRef::Digest(_) => DIGEST_RLP_LENGTH, + NodeRef::Cached(rlp_node) => rlp_node.length(), + NodeRef::Rlp(rlp) => { + if rlp.len() >= B256::len_bytes() { + DIGEST_RLP_LENGTH + } else { + rlp.len() + } + } + } + } +} + +#[inline] +fn encode_list_header(payload_length: usize) -> Vec { + debug_assert!(payload_length > 1); + let header = Header { + list: true, + payload_length, + }; + let mut out = Vec::with_capacity(header.length() + payload_length); + header.encode(&mut out); + out +} + +#[inline] +fn decode_path(buf: &mut &[u8]) -> alloy_rlp::Result<(Nibbles, bool)> { + let (is_list, hlen, plen) = peek_header(buf)?; + if is_list { + return Err(alloy_rlp::Error::Custom("path is not a string")); + } + let bytes = *buf; + if bytes.len() < hlen + plen { + return Err(alloy_rlp::Error::InputTooShort); + } + let packed = &bytes[hlen..hlen + plen]; + *buf = &bytes[hlen + plen..]; + + let Some(&first) = packed.first() else { + return Err(alloy_rlp::Error::InputTooShort); + }; + let (is_leaf, odd_nibbles) = match first >> 4 { + 0b0000 => (false, false), + 0b0001 => (false, true), + 0b0010 => (true, false), + 0b0011 => (true, true), + _ => return Err(alloy_rlp::Error::Custom("node is not an extension or leaf")), + }; + + // Expand the path nibbles directly into the final buffer: one SmallVec + // copy instead of unpack + re-slice + re-pack. + let skip = if odd_nibbles { 1 } else { 2 }; + let nib_len = 2 * plen - skip; + if nib_len <= 66 { + let mut tmp = [0u8; 66]; + let mut n = 0usize; + if odd_nibbles { + tmp[0] = first & 0x0f; + n = 1; + } + for &b in &packed[1..] { + tmp[n] = b >> 4; + tmp[n + 1] = b & 0x0f; + n += 2; + } + Ok((Nibbles::from_nibbles_unchecked(&tmp[..nib_len]), is_leaf)) + } else { + let path = Nibbles::unpack(packed); + Ok((Nibbles::from_nibbles_unchecked(&path[skip..]), is_leaf)) + } +} + +fn encode_list(values: &[B]) -> Vec +where + B: std::borrow::Borrow, + T: ?Sized + Encodable, +{ + let mut payload_length = 0; + for value in values { + payload_length += value.borrow().length(); + } + let mut out = encode_list_header(payload_length); + for value in values { + value.borrow().encode(&mut out); + } + out +} diff --git a/patches/risc0-ethereum-trie/src/mpt/serde.rs b/patches/risc0-ethereum-trie/src/mpt/serde.rs new file mode 100644 index 00000000..e9ad04db --- /dev/null +++ b/patches/risc0-ethereum-trie/src/mpt/serde.rs @@ -0,0 +1,116 @@ +// Copyright 2025 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// RLP-encodes a cached trie during serialization. +/// +/// This has several advantages: +/// - The serialized bytes are fully verified at deserialization. +/// - The trie nodes already have an RLP-encoding when the hash is computed. +#[cfg(feature = "rlp_serialize")] +pub(crate) mod rlp_nodes { + use crate::mpt::{memoize::Memoization, node::Node}; + use alloy_primitives::Bytes; + use itertools::Itertools; + use serde::{Deserialize, Deserializer, Serializer, de, ser::SerializeSeq}; + + #[inline] + pub(crate) fn serialize(trie: &Node, serializer: S) -> Result + where + S: Serializer, + M: Memoization, + { + // deduplicate the RLP nodes + let nodes: Vec = trie.rlp_nodes().into_iter().unique().collect(); + + let mut seq = serializer.serialize_seq(Some(nodes.len()))?; + for node in &nodes { + seq.serialize_element(&node[..])?; + } + seq.end() + } + + #[inline] + pub(crate) fn deserialize<'de, D, M>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + M: Memoization, + { + let nodes: Vec<&[u8]> = Vec::deserialize(deserializer)?; + + Node::from_rlp(nodes).map_err(de::Error::custom) + } +} + +#[cfg(test)] +mod tests { + use crate::Trie; + use alloy_primitives::{Bytes, keccak256}; + + const N: usize = 512; + + #[test] + fn round_trip() { + let trie: Trie = (0..N) + .map(|i| { + ( + keccak256(i.to_be_bytes()), + Bytes::from(alloy_rlp::encode(i)), + ) + }) + .collect(); + + let bytes = bincode::serialize(&trie).unwrap(); + let other: Trie = bincode::deserialize(&bytes).unwrap(); + + assert_eq!(trie, other); + } + + mod cached { + use super::*; + use crate::CachedTrie; + use alloy_primitives::B256; + + #[test] + fn round_trip() { + let mut trie: CachedTrie = (0..N) + .map(|i| { + ( + keccak256(i.to_be_bytes()), + Bytes::from(alloy_rlp::encode(i)), + ) + }) + .collect(); + trie.hash(); + assert!(trie.hash.is_some()); + + let bytes = bincode::serialize(&trie).unwrap(); + let other: CachedTrie = bincode::deserialize(&bytes).unwrap(); + assert!(other.hash.is_none()); + + assert_eq!(trie, other); + } + + #[test] + fn round_trip_dup() { + let trie: CachedTrie = (0..255) + .map(|i| (B256::with_last_byte(i), Bytes::from(B256::ZERO))) + .collect(); + + let bytes = bincode::serialize(&trie).unwrap(); + let other: CachedTrie = bincode::deserialize(&bytes).unwrap(); + + assert_eq!(trie, other); + } + } +} From 05af02e7bdcbc7161a7acd9d191cb345c534506e Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sat, 26 Sep 2026 07:00:10 +0000 Subject: [PATCH 14/15] revert: drop chunk cycle patches; keep experiment notes in AGENTS.md Reverts the two fork patches from 430b7acc (risc0-ethereum-trie MPT decoder, openvm-keccak256-guest xorin staging). The measured win (chunk cycles -12.1%, e2e prove -6.2%) was judged not worth carrying forked dependencies. Kept, documented in AGENTS.md ('Cycle-optimization experiments'): - the measured per-patch numbers and the full-execution bottleneck profile (revm interpreter ~50%+, keccak cells ~32%, memory-merkle ~23%) - rejected directions: SWAR jumpdest scan (83% of words contain a PUSH byte), witness-code dedup (already done host-side), keccak-count reduction (proof-model-inherent), revm-bytecode patching (path deps inside git repo) - methodology: GPU prove profiles truncate after ~26% of execution (use a CPU prove for full profiles); Cargo.lock discipline for [patch] edits The execute-path PROFILE_METRICS_DIR hook in tester_execute stays. Guests rebuilt clean: commitments match 3e1f42ef, chunk cycles back to 202,969,694, e2e chunk proves and verifies (43.89s on RTX 4090). --- AGENTS.md | 101 +- Cargo.lock | 2 + Cargo.toml | 16 +- .../batch-circuit/batch_exe_commit.rs | 2 +- .../bundle-circuit/bundle_exe_commit.rs | 2 +- .../chunk-circuit/chunk_exe_commit.rs | 2 +- patches/openvm-keccak256-guest/Cargo.toml | 16 - patches/openvm-keccak256-guest/src/lib.rs | 145 --- patches/risc0-ethereum-trie/Cargo.toml | 34 - patches/risc0-ethereum-trie/README.md | 3 - patches/risc0-ethereum-trie/src/lib.rs | 24 - .../risc0-ethereum-trie/src/mpt/children.rs | 197 ---- .../risc0-ethereum-trie/src/mpt/memoize.rs | 53 - patches/risc0-ethereum-trie/src/mpt/mod.rs | 919 ------------------ .../risc0-ethereum-trie/src/mpt/nibbles.rs | 115 --- patches/risc0-ethereum-trie/src/mpt/node.rs | 291 ------ patches/risc0-ethereum-trie/src/mpt/orphan.rs | 330 ------- patches/risc0-ethereum-trie/src/mpt/rkyv.rs | 189 ---- patches/risc0-ethereum-trie/src/mpt/rlp.rs | 654 ------------- patches/risc0-ethereum-trie/src/mpt/serde.rs | 116 --- 20 files changed, 83 insertions(+), 3128 deletions(-) delete mode 100644 patches/openvm-keccak256-guest/Cargo.toml delete mode 100644 patches/openvm-keccak256-guest/src/lib.rs delete mode 100644 patches/risc0-ethereum-trie/Cargo.toml delete mode 100644 patches/risc0-ethereum-trie/README.md delete mode 100644 patches/risc0-ethereum-trie/src/lib.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/children.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/memoize.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/mod.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/nibbles.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/node.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/orphan.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/rkyv.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/rlp.rs delete mode 100644 patches/risc0-ethereum-trie/src/mpt/serde.rs diff --git a/AGENTS.md b/AGENTS.md index a74231cb..c5d1bcb6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -166,33 +166,82 @@ Caveats: ## Local patch crates (`patches/`) -Dependencies patched to local sources via `[patch]` in the root `Cargo.toml`: - -- `patches/openvm-mem` — memmove recursion fix (see failure patterns). -- `patches/openvm-keccak256-guest` — `native_xorin` gains an aligned-stack staging fast path - for unaligned inputs/lengths (the common case for trie-node and digest hashing), avoiding - 2 heap allocations + 3 copies per call. ~27% of the chunk circuit's 87k keccak absorbs take - this path. Revert by deleting the `[patch]` entry and directory. -- `patches/risc0-ethereum-trie` — hand-written MPT node decoder replacing the - alloy-rlp `PayloadView` based one (no per-list `Vec` allocation, single-copy path - decoding), plus an inline fast path for the 33-byte digest children that dominate - branch nodes (~111k per chunk vs ~11.5k real nodes — skipping the generic decoder - recursion for them was the single biggest chunk win, −8%). The original - implementation is kept as `decode_node_orig`/`decode_path_orig` behind - `const FAST_DECODE` for A/B measurement; the crate's own unit tests - (`cargo test` inside the directory) cover the parser. - -Rules of engagement when editing `[patch]` tables here: - -- **Never** run a bare `cargo update` or a plain `cargo metadata` after changing patches — - unpinned git deps (`risc0-ethereum` by branch HEAD, `da-codec`, ...) float to the newest +- `patches/openvm-mem` — memmove recursion fix (see failure patterns). This is the only live + patch right now. + +## Cycle-optimization experiments (2026-09, reverted) + +We tried two further guest-cycle patches for the **chunk** circuit, measured them carefully, +and then **reverted** them — the cycles saved did not justify carrying forked dependencies. +The experiment code is preserved in commit `430b7acc` if it is ever wanted again. + +### What was tried, and the measured numbers + +Preset: GalileoV2 chunk, 6 blocks / 630 txs / 35.2M gas. Baseline 202,969,694 guest +instructions; e2e STARK prove 44.15s (RTX 4090). + +| change | cycles saved | note | +|---|---|---| +| `risc0-ethereum-trie`: hand-written MPT node parser (no per-list `Vec`, single-copy compact path) | −6.9M | decode side only | +| + inline fast path for 33-byte digest children | −15.6M | the single biggest win | +| `openvm-keccak256-guest`: `native_xorin` aligned-stack staging for unaligned input | −2.3M | 27% of absorbs took slow path | +| **total** | **−12.1%** (→178.4M) | e2e time only **−6.2%** (→41.4s) | + +Key structural insight: a chunk witness MPT holds ~11.5k real nodes but **~111k 33-byte +digest children** (upper branches are nearly full) — each digest child used to cost a full +decoder recursion + a heap box; inlining them was 2/3 of the total win. Also from the +ground-truth instrumentation: the chunk guest executes **87,192 keccak absorbs over 10.08 +MB** of input (~60% of it witness state nodes and bytecode hashing, which is inherent to +the stateless proof model). + +pi hashes were bit-identical across all changes; e2e chunk/batch/bundle all passed. + +### Where the chunk bottleneck actually is (full-execution CPU-prove profile, 194M instr) + +- **~50%+: the revm interpreter itself** (dispatch loop, instruction handlers, mstore/mload, + journal). No fork-level fix — needs an interpreter redesign (superinstructions, register + dispatch), which is a revm-scale project with high fork drift. +- **~32% of trace cells: KeccakfPermAir** — driven by hashing the witness MPT nodes + + bytecode (proof-model-inherent; only a smaller witness or a cheaper keccak circuit helps). +- **~23% of trace cells: Poseidon2 memory-merkle periphery** — scales with guest memory + traffic. +- MPT witness decode (after the reverted patches ~13%, before ~21%), `calculate_state_root` + dirty-path re-encode 7.7%, jumpdest `into_analyzed` 6.5%, ecrecover msm 4.1%, witness + bincode deserialize 2.4%, keccak call wrappers 4.8%. + +Realistic ceiling for more fork-level work: ~3-6%. The step change would be the interpreter +or the proof model, not more micro-patches. + +### Directions tried and rejected (do not retry blindly) + +- **SWAR / word-at-a-time jumpdest scan**: real contract code has a PUSH-opcode byte in + **~83% of 8-byte words**, so the word fast path almost never engages and the mask setup is + pure overhead (a first version was 3x *slower*). The upstream byte loop is at its floor. + (When bit-parallel tricks are needed elsewhere: the classic `(x−LO)&~x&HI` zero-byte mask + has false positives from cross-byte borrows; use `!(((x&0x7f..)+0x7f..)|x)&HI` instead.) +- **Deduplicating witness codes before analysis**: already done host-side in + `ChunkWitness::new` (a `HashSet<&Bytes>` filter) — nothing left on the table. +- **Reducing keccak absorb count**: witness state/code hashing is proof verification, not + overhead — it cannot be skipped without changing the security model. +- **Patching `revm-bytecode` directly**: a `[patch]` cannot intercept *path* deps inside a + git dependency (scroll-revm's crates inter-depend via workspace `path`), so it would + require vendoring the whole revm repo. Not worth it. + +### Methodology lessons + +- **GPU-prove function profiles truncate after ~26%** of a chunk-sized execution (the GPU + postflight program log only covers the first segments). Any hotspot ranking from + `PROFILE_METRICS_DIR` + GPU is a *biased, early-phase* sample — use a CPU prove for a + full-execution profile (~45 min for chunk, covers 100%). +- Cycle counts: `test_execute`'s metered `instret` equals the true retired-instruction count + (verified against in-guest counters); it is the right iteration metric and needs no GPU. +- `[patch]` table edits: afterwards run **no** bare `cargo update`/`cargo metadata` — + unpinned git deps (branch-HEAD `risc0-ethereum`, `da-codec`, ...) float to the newest fetched commit and `alloy-evm`'s `revm` req re-resolves to registry `30.2.0`, breaking the - build with duplicate-revm type mismatches. Instead hand-edit `Cargo.lock` to the minimal - diff (for a path patch: delete the package's `source =` line, adjust its dep list), then - verify with `cargo metadata --locked` (must print nothing / exit 0 without touching the lock). -- A `[patch]` cannot intercept *path* deps inside a git dependency (e.g. `revm-interpreter`'s - dep on `revm-bytecode` inside the scroll-revm repo) — patching individual crates out of such - a repo requires vendoring the whole repo, which we avoid. + build with duplicate-revm type mismatches. Hand-edit `Cargo.lock` to the minimal diff (for + a path patch: delete the package's `source =` line, adjust its dep list) and verify with + `cargo metadata --locked` (must exit 0 without touching the lock). + ## Common Failure Patterns diff --git a/Cargo.lock b/Cargo.lock index 9f3062a2..13bb9219 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4827,6 +4827,7 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?branch=develop-v2.1.0#29fc511e6892a3e45455404f25293468bc880228" dependencies = [ "openvm-platform", ] @@ -7581,6 +7582,7 @@ dependencies = [ [[package]] name = "risc0-ethereum-trie" version = "0.1.0" +source = "git+https://github.com/risc0/risc0-ethereum#c1ddb41a44dc0730da883bbfa9fbe75ad335df1b" dependencies = [ "alloy-primitives", "alloy-rlp", diff --git a/Cargo.toml b/Cargo.toml index 7c3d7d6e..7b78cbd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -165,21 +165,11 @@ revm-state = { git = "https://github.com/scroll-tech/revm", tag = "scroll-v91" } # openvm-mem's copy_forward/copy_backward use 64-byte aggregate copies that LLVM lowers # into `memmove` calls, making `memmove` recurse until the guest stack overflows. # Override with a local copy that uses u64 chunks instead. See patches/openvm-mem. -# openvm-keccak256-guest: local fork adds an unaligned-input fast path for native_xorin -# (avoids 2 heap allocs + 3 memcpys per keccak256 call). See patches/openvm-keccak256-guest. +# (Two further guest-cycle patches — openvm-keccak256-guest and risc0-ethereum-trie — +# were tried, measured at −12.1% chunk cycles, and reverted as not worth the fork. +# See AGENTS.md "Cycle-optimization experiments" and commit 430b7acc.) [patch."https://github.com/openvm-org/openvm.git"] openvm-mem = { path = "patches/openvm-mem" } -openvm-keccak256-guest = { path = "patches/openvm-keccak256-guest" } - -# (An sbv-trie fork for bytecode-analysis dedup was tried and rejected: witness -# codes are already deduplicated host-side in ChunkWitness::new, and a SWAR -# jumpdest scan loses to the byte-wise loop since ~83% of 8-byte words in real -# bytecode contain a PUSH opcode byte.) - -# Experimental local fork for guest cycle optimization (hand-written MPT node parser). -# Same code as c1ddb41 otherwise; delete this section to disable. -[patch."https://github.com/risc0/risc0-ethereum"] -risc0-ethereum-trie = { path = "patches/risc0-ethereum-trie" } [profile.maxperf] inherits = "release" diff --git a/crates/circuits/batch-circuit/batch_exe_commit.rs b/crates/circuits/batch-circuit/batch_exe_commit.rs index 4542ae03..e5495f4b 100644 --- a/crates/circuits/batch-circuit/batch_exe_commit.rs +++ b/crates/circuits/batch-circuit/batch_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [269629868, 11304576, 863701181, 1150881528, 59510026, 134705669, 876257829, 347575516]; +pub const COMMIT: [u32; 8] = [236400959, 1921678370, 1681141574, 435295083, 1495503815, 21325623, 212114691, 392953574]; diff --git a/crates/circuits/bundle-circuit/bundle_exe_commit.rs b/crates/circuits/bundle-circuit/bundle_exe_commit.rs index a0478042..80971976 100644 --- a/crates/circuits/bundle-circuit/bundle_exe_commit.rs +++ b/crates/circuits/bundle-circuit/bundle_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [377119168, 119635917, 112852172, 128935761, 622071650, 982588409, 1749410501, 766274532]; +pub const COMMIT: [u32; 8] = [159067914, 70283829, 1094250858, 1695200420, 1766304820, 1211651143, 955692376, 2323832]; diff --git a/crates/circuits/chunk-circuit/chunk_exe_commit.rs b/crates/circuits/chunk-circuit/chunk_exe_commit.rs index de609822..37f12f0d 100644 --- a/crates/circuits/chunk-circuit/chunk_exe_commit.rs +++ b/crates/circuits/chunk-circuit/chunk_exe_commit.rs @@ -1,4 +1,4 @@ #![cfg_attr(rustfmt, rustfmt_skip)] //! Generated by crates/build-guest. DO NOT EDIT! -pub const COMMIT: [u32; 8] = [1811353780, 763823461, 692493179, 1468603078, 466259603, 1427628903, 1282295217, 627556282]; +pub const COMMIT: [u32; 8] = [1192406321, 1007067640, 1433639583, 1891545475, 903990723, 621677400, 1106027141, 1005293682]; diff --git a/patches/openvm-keccak256-guest/Cargo.toml b/patches/openvm-keccak256-guest/Cargo.toml deleted file mode 100644 index 8de69183..00000000 --- a/patches/openvm-keccak256-guest/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "openvm-keccak256-guest" -description = "OpenVM guest library for keccak256" -version = "2.0.0" -edition = "2021" -license = "MIT OR Apache-2.0" - -# Local experimental fork of openvm `develop-v2.1.0` (29fc511e) keccak256 guest -# crate for zkVM cycle optimization. See patches/ notes in AGENTS.md. - -[dependencies] -openvm-platform = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } - -[features] -default = [] - diff --git a/patches/openvm-keccak256-guest/src/lib.rs b/patches/openvm-keccak256-guest/src/lib.rs deleted file mode 100644 index 75d490e0..00000000 --- a/patches/openvm-keccak256-guest/src/lib.rs +++ /dev/null @@ -1,145 +0,0 @@ -#![no_std] - -#[cfg(any(openvm_intrinsics, target_os = "openvm"))] -use openvm_platform::alloc::AlignedBuf; - -pub const OPCODE: u8 = 0x0b; -pub const KECCAKF_FUNCT3: u8 = 0b100; -pub const KECCAKF_FUNCT7: u8 = 0; -pub const XORIN_FUNCT3: u8 = 0b100; -pub const XORIN_FUNCT7: u8 = 1; - -pub const KECCAK_WIDTH_BYTES: usize = 200; -pub const KECCAK_RATE: usize = 136; -pub const KECCAK_OUTPUT_SIZE: usize = 32; -pub const MIN_ALIGN: usize = 8; - -/// Compile-time toggle: `false` disables the aligned-stack staging fast path in -/// `native_xorin` (for A/B cycle measurement). -#[cfg(any(openvm_intrinsics, target_os = "openvm"))] -const FAST_XORIN: bool = true; - -/// XOR `len` bytes from `input` into `buffer` using the native XORIN instruction. -/// -/// # Panics -/// -/// Panics if `len > KECCAK_RATE` (136): the XORIN circuit absorbs at most `KECCAK_RATE` bytes -/// per instruction, so a larger length would execute but fail to prove. -/// -/// # Safety -/// -/// - `buffer` must point to a buffer of at least `len` bytes. -/// - `input` must point to a buffer of at least `len` bytes. -#[cfg(any(openvm_intrinsics, target_os = "openvm"))] -#[no_mangle] -pub unsafe extern "C" fn native_xorin(buffer: *mut u8, input: *const u8, len: usize) { - assert!( - len <= KECCAK_RATE, - "native_xorin: len exceeds the XORIN circuit's maximum rate of {} bytes", - KECCAK_RATE - ); - if len == 0 { - return; - } - unsafe { - let buffer_aligned = buffer as usize % MIN_ALIGN == 0; - let input_aligned = input as usize % MIN_ALIGN == 0; - let len_aligned = len % MIN_ALIGN == 0; - let all_aligned = buffer_aligned && input_aligned && len_aligned; - - if all_aligned { - __native_xorin(buffer, input, len); - } else if buffer_aligned && FAST_XORIN { - // Fast path: stage the (possibly unaligned) input in an aligned stack - // buffer. The XORIN instruction consumes a whole number of 8-byte - // words, so zero the tail padding to leave those state words - // unchanged (x ^ 0 = x). This avoids two heap allocations and the - // buffer copy round-trip of the generic path below. - #[repr(align(8))] - struct Stage([u8; KECCAK_RATE]); - - let adjusted_len = len.next_multiple_of(MIN_ALIGN); - let mut stage = core::mem::MaybeUninit::::uninit(); - let stage_ptr = stage.as_mut_ptr() as *mut u8; - core::ptr::copy_nonoverlapping(input, stage_ptr, len); - core::ptr::write_bytes(stage_ptr.add(len), 0, adjusted_len - len); - __native_xorin(buffer, stage_ptr, adjusted_len); - } else { - let adjusted_len = len.next_multiple_of(MIN_ALIGN); - let aligned_buffer; - let aligned_input; - - let actual_buffer = if buffer_aligned && len_aligned { - buffer - } else { - aligned_buffer = AlignedBuf::uninit(adjusted_len, MIN_ALIGN); - core::ptr::copy_nonoverlapping(buffer, aligned_buffer.ptr, len); - aligned_buffer.ptr - }; - - let actual_input = if input_aligned && len_aligned { - input - } else { - aligned_input = AlignedBuf::uninit(adjusted_len, MIN_ALIGN); - core::ptr::copy_nonoverlapping(input, aligned_input.ptr, len); - aligned_input.ptr - }; - - __native_xorin(actual_buffer, actual_input, adjusted_len); - - if !buffer_aligned || !len_aligned { - core::ptr::copy_nonoverlapping(actual_buffer as *const u8, buffer, len); - } - } - } -} - -/// Apply the Keccak-f\[1600\] permutation to the 200-byte state buffer. -/// -/// # Safety -/// -/// - `buffer` must point to a buffer of at least `KECCAK_WIDTH_BYTES` (200) bytes. -#[cfg(any(openvm_intrinsics, target_os = "openvm"))] -#[no_mangle] -pub unsafe extern "C" fn native_keccakf(buffer: *mut u8) { - unsafe { - if buffer as usize % MIN_ALIGN == 0 { - __native_keccakf(buffer); - } else { - let aligned_buffer = AlignedBuf::new(buffer, KECCAK_WIDTH_BYTES, MIN_ALIGN); - __native_keccakf(aligned_buffer.ptr); - core::ptr::copy_nonoverlapping( - aligned_buffer.ptr as *const u8, - buffer, - KECCAK_WIDTH_BYTES, - ); - } - } -} - -#[cfg(any(openvm_intrinsics, target_os = "openvm"))] -#[inline(always)] -fn __native_xorin(mut buffer: *mut u8, input: *const u8, len: usize) { - openvm_platform::custom_insn_r!( - opcode = OPCODE, - funct3 = XORIN_FUNCT3, - funct7 = XORIN_FUNCT7, - rd = InOut buffer, - rs1 = In input, - rs2 = In len - ); -} - -#[cfg(any(openvm_intrinsics, target_os = "openvm"))] -#[inline(always)] -fn __native_keccakf(mut buffer: *mut u8) { - openvm_platform::custom_insn_r!( - opcode = OPCODE, - funct3 = KECCAKF_FUNCT3, - funct7 = KECCAKF_FUNCT7, - rd = InOut buffer, - rs1 = Const "x0", - rs2 = Const "x0", - ); -} - diff --git a/patches/risc0-ethereum-trie/Cargo.toml b/patches/risc0-ethereum-trie/Cargo.toml deleted file mode 100644 index 0dd69554..00000000 --- a/patches/risc0-ethereum-trie/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "risc0-ethereum-trie" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -repository = "https://github.com/risc0/risc0-ethereum" - -# Local experimental fork of risc0-ethereum-trie @ c1ddb41 for zkVM cycle -# optimization. See patches/ notes in AGENTS.md. - -[dependencies] -alloy-primitives = { version = "1.3", features = ["map"] } -alloy-rlp = { version = "0.3.8", features = ["arrayvec"] } -alloy-trie = { version = "0.8" } -arrayvec = "0.7" -bincode = { version = "1.3", optional = true } -itertools = "0.14" -rkyv = { version = "0.8", optional = true } -serde = { version = "1.0", optional = true } -thiserror = "2.0" - -[features] -default = [] -rkyv = ["dep:rkyv"] -serde = ["dep:serde", "dep:bincode", "alloy-primitives/serde", "alloy-trie/serde"] -rlp_serialize = [] -orphan = [] - -[dev-dependencies] -alloy-trie = { version = "0.8", features = ["ethereum"] } -serde_json = "1.0" - - -[workspace] diff --git a/patches/risc0-ethereum-trie/README.md b/patches/risc0-ethereum-trie/README.md deleted file mode 100644 index 688ff1f7..00000000 --- a/patches/risc0-ethereum-trie/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# risc0-ethereum-trie - -Fast Merkle-Patricia Trie (MPT) implementation. diff --git a/patches/risc0-ethereum-trie/src/lib.rs b/patches/risc0-ethereum-trie/src/lib.rs deleted file mode 100644 index 4942184f..00000000 --- a/patches/risc0-ethereum-trie/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![doc = include_str!("../README.md")] -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] - -mod mpt; - -#[cfg(feature = "orphan")] -pub use mpt::orphan; -pub use mpt::{CachedTrie, EMPTY_ROOT_HASH, Trie}; - -pub use alloy_trie::Nibbles; diff --git a/patches/risc0-ethereum-trie/src/mpt/children.rs b/patches/risc0-ethereum-trie/src/mpt/children.rs deleted file mode 100644 index 563c1016..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/children.rs +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::{ - memoize::Memoization, - node::{Child, Node}, -}; -use std::slice::Iter; - -/// Implements a helper wrapper for the children of a Branch node. -/// -/// This wrapper offers various convenience features and assures that there is never a Null child. -#[derive(Debug, Clone)] -#[cfg_attr( - feature = "serde", - derive(serde::Serialize, serde::Deserialize), - serde(transparent), - serde(bound(serialize = "Node: serde::Serialize")), - serde(bound(deserialize = "Node: serde::Deserialize<'de>")) -)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), - rkyv(bytecheck(bounds(__C: rkyv::validation::ArchiveContext, __C::Error: rkyv::rancor::Source))), - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, __S::Error: rkyv::rancor::Source)), - rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source, M: Default)) -)] -pub(super) struct Children( - #[cfg_attr(feature = "rkyv", rkyv(omit_bounds))] [Option>>; 16], -); - -impl Default for Children { - fn default() -> Self { - Self(Default::default()) - } -} - -impl PartialEq for Children { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl Eq for Children where Node: Eq {} - -/// A view into a single entry in a children map, which may either be vacant or occupied. -/// -/// This `enum` is constructed from the [`Children::entry`] method. -pub(super) enum Entry<'a, M> { - Vacant(VacantEntry<'a, M>), - Occupied(OccupiedEntry<'a, M>), -} - -/// A view into a vacant entry in a children map. -/// It is part of the [`Entry`] enum. -pub(super) struct VacantEntry<'a, M> { - child: &'a mut Option>, -} - -/// A view into an occupied entry in a children map. -/// It is part of the [`Entry`] enum. -pub(super) struct OccupiedEntry<'a, M> { - child: &'a mut Option>, -} - -impl Drop for OccupiedEntry<'_, M> { - fn drop(&mut self) { - if matches!(self.get(), Node::Null) { - *self.child = None; - } - } -} - -impl<'a, M> Entry<'a, M> { - #[inline] - const fn new(child: &'a mut Option>) -> Self { - match child { - None => Entry::Vacant(VacantEntry { child }), - Some(_) => Entry::Occupied(OccupiedEntry { child }), - } - } -} - -impl VacantEntry<'_, M> { - /// Sets the child of the entry with the `VacantEntry`'s index, and returns a mutable reference - /// to it. - #[inline] - pub(super) fn insert(self, child: Child) { - assert!(!matches!(child.as_ref(), Node::Null)); - *self.child = Some(child) - } -} - -impl OccupiedEntry<'_, M> { - /// Gets a reference to the child node in the entry. - #[inline] - pub(super) fn get(&self) -> &Node { - // SAFETY: an OccupiedEntry is only created for a child that is not `None` - unsafe { self.child.as_deref().unwrap_unchecked() } - } - - /// Gets a mutable reference to the child node in the entry. - #[inline] - pub(super) fn get_mut(&mut self) -> &mut Node { - // SAFETY: an OccupiedEntry is only created for a child that is not `None` - unsafe { self.child.as_deref_mut().unwrap_unchecked() } - } -} - -#[allow(dead_code)] -impl Children { - #[inline] - pub(super) fn get(&self, idx: u8) -> Option<&Node> { - self.0[idx as usize].as_deref() - } - - #[inline] - pub(super) unsafe fn get_unchecked(&self, idx: u8) -> Option<&Node> { - self.0.get_unchecked(idx as usize).as_deref() - } - - #[inline] - pub(super) const fn entry(&mut self, idx: u8) -> Entry<'_, M> { - Entry::new(&mut self.0[idx as usize]) - } - - #[inline] - pub(super) fn insert(&mut self, idx: u8, child: Child) { - assert!(!matches!(child.as_ref(), Node::Null)); - self.0[idx as usize] = Some(child); - } - - #[inline] - pub(super) fn len(&self) -> usize { - self.0.iter().flatten().count() - } - - pub(super) fn take_single_child(&mut self) -> Option<(u8, Child)> { - let mut child_idx = None; - for (i, child) in self.0.iter().enumerate() { - if child.is_some() { - if child_idx.is_some() { - return None; // more than one child found - } - child_idx = Some(i); - } - } - // SAFETY: if `child_idx` is only set when the corresponding child is `Some` - child_idx.map(|i| (i as u8, unsafe { self.0[i].take().unwrap_unchecked() })) - } - - #[inline] - pub(super) fn iter(&self) -> Iter<'_, Option>> { - self.0.iter() - } - - #[inline] - pub(super) fn into_iter(self) -> impl Iterator>> { - self.0.into_iter() - } - - #[inline] - pub(super) fn entries(&mut self) -> impl Iterator> { - self.0.iter_mut().map(Entry::new) - } -} - -impl Children { - #[inline] - pub(super) fn memoize(&mut self) { - self.0 - .iter_mut() - .flatten() - .for_each(|child| child.memoize()) - } -} - -impl>, const N: usize> From<[(u8, C); N]> for Children { - fn from(arr: [(u8, C); N]) -> Self { - let mut children = Children::default(); - for (idx, child) in arr { - children.insert(idx, child.into()); - } - children - } -} diff --git a/patches/risc0-ethereum-trie/src/mpt/memoize.rs b/patches/risc0-ethereum-trie/src/mpt/memoize.rs deleted file mode 100644 index dd450898..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/memoize.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::rlp::RlpNode; - -pub(super) trait Memoization: Default { - fn clear(&mut self); - fn get(&self) -> Option<&RlpNode>; - fn set(&mut self, rlp_node: RlpNode); -} - -#[derive(Debug, Clone, Copy, Default)] -pub(super) struct NoCache; - -impl Memoization for NoCache { - #[inline] - fn clear(&mut self) {} - #[inline] - fn get(&self) -> Option<&RlpNode> { - None - } - #[inline] - fn set(&mut self, _: RlpNode) {} -} - -#[derive(Debug, Clone, Default)] -pub(super) struct Cache(Option); - -impl Memoization for Cache { - #[inline] - fn clear(&mut self) { - self.0 = None - } - #[inline] - fn get(&self) -> Option<&RlpNode> { - self.0.as_ref() - } - #[inline] - fn set(&mut self, rlp_node: RlpNode) { - self.0 = Some(rlp_node) - } -} diff --git a/patches/risc0-ethereum-trie/src/mpt/mod.rs b/patches/risc0-ethereum-trie/src/mpt/mod.rs deleted file mode 100644 index 9de415ee..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/mod.rs +++ /dev/null @@ -1,919 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A sparse Merkle Patricia trie implementation. - -use alloy_primitives::{B256, Bytes, keccak256, map::B256Map}; -use alloy_trie::Nibbles; -use children::Children; -use memoize::{Cache, NoCache}; -use nibbles::NibbleSlice; -use node::Node; -use std::{cmp::PartialEq, fmt::Debug}; - -mod children; - -mod memoize; -mod nibbles; -mod node; -#[cfg(feature = "orphan")] -pub mod orphan; -#[cfg(feature = "rkyv")] -mod rkyv; -mod rlp; -#[cfg(feature = "serde")] -mod serde; - -pub use alloy_trie::EMPTY_ROOT_HASH; - -/// A sparse Merkle Patricia trie storing byte values. -#[derive(Debug, Clone, Default, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(::rkyv::Archive, ::rkyv::Serialize, ::rkyv::Deserialize) -)] -pub struct Trie(Node); - -impl Trie { - /// Retrieves the value associated with a given key. - /// - /// # Panics - /// - /// It panics when neither inclusion nor exclusion of the key can be guaranteed. - #[inline] - pub fn get(&self, key: impl AsRef<[u8]>) -> Option<&[u8]> { - self.0 - .get(NibbleSlice::from(&Nibbles::unpack(key))) - .map(|b| b.as_ref()) - } - - /// Inserts a key-value pair into the trie. - /// - /// # Panics - /// - /// This method may panic under the following conditions: - /// - /// * If the insertion would result in a value being stored directly in a branch node, which is - /// not allowed in this trie implementation. - /// * If the key to be inserted corresponds to a part of the trie that has not been resolved - /// (i.e., the node is represented by a digest and the full node is not available). - #[inline] - pub fn insert(&mut self, key: impl AsRef<[u8]>, value: impl Into) { - self.0 - .insert(NibbleSlice::from(&Nibbles::unpack(key)), value.into()); - } - - /// Removes a key-value pair from the trie. - /// - /// If the key exists in the trie, it is removed along with its associated value, and the method - /// returns `true`. If the key does not exist, the trie remains unchanged, and the method - /// returns `false`. - /// - /// # Panics - /// - /// This method may panic under the following conditions: - /// - /// * When neither the inclusion nor exclusion of the key can be guaranteed. - /// * If the removal of the key leads to a branch node having only a single, non-resolved child. - /// In such cases, the correct pruning of the trie cannot be guaranteed, indicating a - /// potential issue with the trie's construction. - #[inline] - pub fn remove(&mut self, key: impl AsRef<[u8]>) -> bool { - self.0.remove(NibbleSlice::from(&Nibbles::unpack(key))) - } - - /// Returns the number of full nodes in the trie. - /// - /// A full node is a node that needs to be fully encoded to compute the root hash. - #[inline] - pub fn size(&self) -> usize { - self.0.size() - } - - /// Computes and returns the hash of the trie's root node. - #[inline] - pub fn hash_slow(&self) -> B256 { - self.0.hash() - } - - /// Clears the trie, removing all key-value pairs. - #[inline] - pub fn clear(&mut self) { - self.0 = Node::Null - } - - /// Resolves currently unresolved nodes within the trie using the provided RLP-encoded nodes. - /// - /// This method iterates through the provided RLP-encoded nodes, computes the Keccak-256 hash of - /// each node, and attempts to replace any internal `Node::Digest` entries matching that hash - /// with the decoded node. - /// - /// # Errors - /// - /// This function returns an error if it encounters any issues during the decoding of RLP - /// encoded nodes or if the provided nodes result in an invalid trie structure. - pub fn hydrate_from_rlp>( - &mut self, - nodes: impl IntoIterator, - ) -> alloy_rlp::Result<()> { - let rlp_by_digest = nodes - .into_iter() - .map(|rlp| (keccak256(&rlp), rlp)) - .collect(); - self.0.resolve_digests(&rlp_by_digest) - } - - /// Converts the trie into a [CachedTrie]. - pub fn into_cached(self) -> CachedTrie { - fn rec(root: Node) -> Node { - match root { - Node::Null => Node::Null, - Node::Leaf(prefix, value, _) => Node::Leaf(prefix, value, Cache::default()), - Node::Extension(prefix, child, _) => { - Node::Extension(prefix, rec(*child).into(), Cache::default()) - } - Node::Branch(children, _) => { - let mut cached_children = Children::default(); - for (i, child) in children.into_iter().enumerate() { - if let Some(child) = child { - cached_children.insert(i as u8, rec(*child).into()); - } - } - Node::Branch(cached_children, Cache::default()) - } - Node::Digest(digest) => Node::Digest(digest), - } - } - - CachedTrie { - inner: rec(self.0), - hash: None, - } - } - - /// Returns the RLP-encoded nodes of the trie in preorder. It may return duplicate nodes. - /// - /// Each value but the first, represents a node with RLP-length >= 32, while shorter nodes are - /// included inline. - #[inline] - pub fn rlp_nodes(&self) -> Vec { - self.0.rlp_nodes() - } - - /// Creates a new trie that only contains a digest of the root. - #[inline] - pub const fn from_digest(digest: B256) -> Self { - Self(Node::Digest(digest)) - } - - /// Creates a new trie from the given RLP encoded nodes. - /// - /// The first node provided must always be the root node. The remaining nodes can be in any - /// order and are resolved if they are referenced (directly or indirectly) by the root node. - /// - /// Nodes that are referenced by the root node (either directly or indirectly) but are not - /// provided in the input are represented by their hash digests within the trie. This allows for - /// the computation of the root hash and ensures that it matches the root hash of the fully - /// resolved trie, even if some nodes are missing. - /// - /// # Errors - /// - /// This function returns an error if it encounters any issues during the decoding of RLP - /// encoded nodes or if the provided nodes result in an invalid trie structure. - #[inline] - pub fn from_rlp>(nodes: impl IntoIterator) -> alloy_rlp::Result { - Ok(Self(Node::from_rlp(nodes)?)) - } - - /// Creates a new trie from a root digest and a map of pre-hashed, RLP-encoded nodes. - /// - /// This method offers an efficient way to construct a trie when the node digests are already - /// known, as it avoids re-computing the hashes. - /// - /// It is crucial that the provided `rlp_by_digest` map contains keys that are the correct - /// `keccak256` hashes of their corresponding RLP-encoded values. If the hashes are incorrect, - /// the resulting trie will be invalid, potentially leading to a different root hash than - /// the one provided and subsequent logical errors. - #[inline] - pub fn from_prehashed_nodes( - root: B256, - rlp_by_digest: &B256Map>, - ) -> alloy_rlp::Result { - let mut trie = Self::from_digest(root); - trie.0.resolve_digests(rlp_by_digest)?; - Ok(trie) - } -} - -impl> FromIterator<(K, Bytes)> for Trie { - fn from_iter>(iter: T) -> Self { - let mut trie = Self::default(); - iter.into_iter().for_each(|(k, v)| trie.insert(k, v)); - - trie - } -} - -/// A caching version of a sparse Merkle Patricia trie that stores byte values. -/// -/// `CachedTrie` enhances the basic `Trie` structure by caching the hash of each node. This -/// optimization significantly reduces the computational cost associated with operations that -/// require multiple hash calculations after small trie modifications. -/// -/// It maintains the same interface as `Trie`, allowing for seamless integration into existing -/// systems that rely on the non-caching version. The internal caching mechanism is transparent to -/// the user, automatically updating cached hashes as the trie is modified. -#[derive(Debug, Clone)] -#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(::rkyv::Archive, ::rkyv::Serialize, ::rkyv::Deserialize) -)] -pub struct CachedTrie { - #[cfg_attr( - all(feature = "serde", feature = "rlp_serialize"), - serde(with = "serde::rlp_nodes") - )] - #[cfg_attr(all(feature = "rkyv", feature = "rlp_serialize"), rkyv(with = rkyv::RlpNodes))] - inner: Node, - #[cfg_attr(feature = "serde", serde(skip))] - #[cfg_attr(feature = "rkyv", rkyv(with = ::rkyv::with::Skip))] - hash: Option, -} - -impl Default for CachedTrie { - #[inline] - fn default() -> Self { - Self { - inner: Node::Null, - hash: Some(EMPTY_ROOT_HASH), - } - } -} - -impl CachedTrie { - /// Retrieves the value associated with a given key. - /// - /// See [`Trie::get`] for detailed documentation. - #[inline] - pub fn get(&self, key: impl AsRef<[u8]>) -> Option<&[u8]> { - self.inner - .get(NibbleSlice::from(&Nibbles::unpack(key))) - .map(|b| b.as_ref()) - } - - /// Inserts a key-value pair into the trie. - /// - /// See [`Trie::insert`] for detailed documentation. - #[inline] - pub fn insert(&mut self, key: impl AsRef<[u8]>, value: impl Into) { - self.inner - .insert(NibbleSlice::from(&Nibbles::unpack(key)), value.into()); - self.hash = None; - } - - /// Removes a key-value pair from the trie. - /// - /// See [`Trie::remove`] for detailed documentation. - #[inline] - pub fn remove(&mut self, key: impl AsRef<[u8]>) -> bool { - if !self.inner.remove(NibbleSlice::from(&Nibbles::unpack(key))) { - return false; - } - self.hash = None; - true - } - - /// Returns the number of full nodes in the trie. - /// - /// See [`Trie::size`] for detailed documentation. - #[inline] - pub fn size(&self) -> usize { - self.inner.size() - } - - /// Computes and returns the hash of the trie's root node. - /// - /// This method uses cached hashes when available (both root hash and internal node caches) - /// but does not update them. For optimal performance, prefer [`Self::hash`] which manages - /// and updates all caches. - #[inline] - pub fn hash_slow(&self) -> B256 { - match self.hash { - None => self.inner.hash(), - Some(hash) => hash, - } - } - - /// Computes and returns the hash of the trie's root node. - /// - /// If the root hash is already cached, it is returned directly. Otherwise, the hash is - /// computed, cached, and then returned. This method also triggers an internal `memoize` - /// operation on the underlying `Node` structure, populating its cache with the hashes of its - /// sub-nodes, further optimizing future hash computations. - /// - /// This is the preferred method for obtaining the root hash of a `CachedTrie` as it leverages - /// and updates the cache for optimal performance. - #[inline] - pub fn hash(&mut self) -> B256 { - *self.hash.get_or_insert_with(|| { - self.inner.memoize(); - self.inner.hash() - }) - } - - /// Clears the trie, removing all key-value pairs. - #[inline] - pub fn clear(&mut self) { - *self = Self { - inner: Node::Null, - hash: Some(EMPTY_ROOT_HASH), - } - } - - /// Returns whether the hash is currently cached or needs to be recomputed. - #[inline] - pub const fn is_cached(&self) -> bool { - self.hash.is_some() - } - - /// Resolves currently unresolved nodes within the trie using the provided RLP-encoded nodes. - /// - /// See [`Trie::hydrate_from_rlp`] for detailed documentation. - #[inline] - pub fn hydrate_from_rlp>( - &mut self, - nodes: impl IntoIterator, - ) -> alloy_rlp::Result<()> { - let rlp_by_digest = nodes - .into_iter() - .map(|rlp| (keccak256(&rlp), rlp)) - .collect(); - self.inner.resolve_digests(&rlp_by_digest) - } - - /// Returns the RLP-encoded nodes of the trie in preorder. - /// - /// See [`Trie::rlp_nodes`] for detailed documentation. - #[inline] - pub fn rlp_nodes(&self) -> Vec { - self.inner.rlp_nodes() - } - - /// Creates a new trie that only contains a digest of the root. - #[inline] - pub fn from_digest(digest: B256) -> Self { - if digest == EMPTY_ROOT_HASH { - Self::default() - } else { - Self { - inner: Node::Digest(digest), - hash: Some(digest), - } - } - } - - /// Creates a new trie from the given RLP encoded nodes. - /// - /// See [`Trie::from_rlp`] for detailed documentation. - #[inline] - pub fn from_rlp>(nodes: impl IntoIterator) -> alloy_rlp::Result { - let root = Node::from_rlp(nodes)?; - - Ok(Self { - inner: root, - hash: None, - }) - } - - /// Creates a new trie from a root digest and a map of pre-hashed, RLP-encoded nodes. - /// - /// See [`Trie::from_prehashed_nodes`] for detailed documentation. - #[inline] - pub fn from_prehashed_nodes( - root: B256, - rlp_by_digest: &B256Map>, - ) -> alloy_rlp::Result { - let mut trie = Self::from_digest(root); - trie.inner.resolve_digests(rlp_by_digest)?; - Ok(trie) - } -} - -impl PartialEq for CachedTrie { - /// Equality between cached tries ignores the cache. - #[inline] - fn eq(&self, other: &Self) -> bool { - self.inner == other.inner - } -} - -impl Eq for CachedTrie {} - -impl> FromIterator<(K, Bytes)> for CachedTrie { - fn from_iter>(iter: T) -> Self { - let mut trie = Self::default(); - iter.into_iter().for_each(|(k, v)| trie.insert(k, v)); - - trie - } -} - -#[cfg(test)] -mod tests { - use super::*; - use alloy_primitives::{Bytes, U256, b256, keccak256}; - use alloy_trie::HashBuilder; - use children::Children; - use std::{borrow::Borrow, collections::BTreeMap}; - - const N: usize = 512; - - fn trie_root(iter: impl IntoIterator>) -> B256 - where - K: AsRef<[u8]>, - V: AsRef<[u8]>, - { - let mut hb = HashBuilder::default(); - - let mut sorted_data: Vec<_> = iter.into_iter().collect(); - sorted_data.sort_by(|a, b| a.borrow().0.as_ref().cmp(b.borrow().0.as_ref())); - for (key, val) in sorted_data.iter().map(Borrow::borrow) { - hb.add_leaf(Nibbles::unpack(key), val.as_ref()); - } - - hb.root() - } - - #[test] - fn empty_root_hash() { - assert_eq!( - EMPTY_ROOT_HASH, - keccak256(vec![alloy_rlp::EMPTY_STRING_CODE]) - ); - } - - #[test] - fn mpt_null() { - let trie = Trie(Node::Null); - assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); - - assert_eq!(trie.hash_slow(), EMPTY_ROOT_HASH); - assert_eq!(trie.size(), 0); - - // the empty trie provides a non-inclusion proof for any key - assert_eq!(trie.get([]), None); - assert_eq!(trie.get([0]), None); - assert_eq!(trie.get([1, 2, 3]), None); - } - - #[test] - fn mpt_digest() { - let trie = Trie::from_digest(B256::ZERO); - assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); - - assert_eq!(trie.hash_slow(), B256::ZERO); - assert_eq!(trie.size(), 0); - } - - #[test] - fn mpt_leaf() { - let trie = Trie(Node::Leaf( - Nibbles::unpack(B256::ZERO), - vec![0].into(), - NoCache, - )); - assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); - - // a leave counts as a full node - assert_eq!(trie.size(), 1); - - // a single leave proves the inclusion of the key and non-inclusion of any other key - assert_eq!(trie.get(B256::ZERO), Some(&[0][..])); - assert_eq!(trie.get([]), None); - assert_eq!(trie.get([0]), None); - assert_eq!(trie.get([1, 2, 3]), None); - } - - #[test] - fn mpt_extension() { - let child = Node::Branch( - Children::from([ - ( - 0, - Node::Leaf(Nibbles::from_nibbles([0; 62]), vec![0].into(), NoCache), - ), - ( - 1, - Node::Leaf(Nibbles::from_nibbles([1; 62]), vec![1].into(), NoCache), - ), - ]), - NoCache, - ); - let trie = Trie(Node::Extension( - Nibbles::from_nibbles([0; 1]), - child.into(), - NoCache, - )); - assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); - - // there are one branch, two leaves plus one extension - assert_eq!(trie.size(), 4); - - assert_eq!(trie.get(B256::ZERO), Some(&[0][..])); - assert_eq!( - trie.get(b256!( - "0111111111111111111111111111111111111111111111111111111111111111" - )), - Some(&[1][..]) - ); - assert_eq!(trie.get([]), None); - assert_eq!(trie.get([0]), None); - assert_eq!(trie.get([1, 2, 3]), None); - assert_eq!(trie.get(B256::repeat_byte(0x11)), None); - } - - #[test] - fn mpt_branch() { - let trie = Trie(Node::Branch( - Children::from([ - ( - 0, - Node::Leaf(Nibbles::from_nibbles([0; 63]), vec![0].into(), NoCache), - ), - ( - 1, - Node::Leaf(Nibbles::from_nibbles([1; 63]), vec![1].into(), NoCache), - ), - ]), - NoCache, - )); - assert_eq!(trie, Trie::from_rlp(trie.0.rlp_nodes()).unwrap()); - - // there are one branch plus two leaves - assert_eq!(trie.size(), 3); - - assert_eq!(trie.get(B256::repeat_byte(0x00)), Some(&[0][..])); - assert_eq!(trie.get(B256::repeat_byte(0x11)), Some(&[1][..])); - assert_eq!(trie.get([]), None); - assert_eq!(trie.get([0]), None); - assert_eq!(trie.get([1, 2, 3]), None); - } - - #[test] - fn short_encoding() { - // 4 leaves with 1-byte long keys, the resulting root node should be shorter than 32 bytes - let trie = Trie(Node::Branch( - Children::from([ - ( - 0, - Node::Leaf(Nibbles::from_nibbles([0]), vec![0].into(), NoCache), - ), - ( - 1, - Node::Leaf(Nibbles::from_nibbles([1]), vec![0].into(), NoCache), - ), - ( - 2, - Node::Leaf(Nibbles::from_nibbles([2]), vec![0].into(), NoCache), - ), - ( - 3, - Node::Leaf(Nibbles::from_nibbles([3]), vec![0].into(), NoCache), - ), - ]), - NoCache, - )); - assert!(trie.0.rlp_encoded().len() < 32); - let rlp = trie.0.rlp_nodes(); - - assert_eq!(trie, Trie::from_rlp(&rlp).unwrap()); - assert_eq!( - trie.hash_slow(), - trie_root([ - ([0x00], vec![0]), - ([0x11], vec![0]), - ([0x22], vec![0]), - ([0x33], vec![0]) - ]) - ); - assert_eq!(trie.hash_slow(), CachedTrie::from_rlp(&rlp).unwrap().hash(),); - } - - #[test] - fn b256_encoding() { - // 2 leaves with 5-byte long keys, the resulting root node should be exactly 32 bytes - let trie = Trie(Node::Branch( - Children::from([ - ( - 0, - Node::Leaf( - Nibbles::from_nibbles([0]), - vec![0, 1, 2, 3, 4].into(), - NoCache, - ), - ), - ( - 1, - Node::Leaf( - Nibbles::from_nibbles([1]), - vec![0, 1, 2, 3, 4].into(), - NoCache, - ), - ), - ]), - NoCache, - )); - assert_eq!(trie.0.rlp_encoded().len(), 32); - let rlp = trie.0.rlp_nodes(); - - assert_eq!(trie, Trie::from_rlp(&rlp).unwrap()); - assert_eq!( - trie.hash_slow(), - trie_root([([0x00], vec![0, 1, 2, 3, 4]), ([0x11], vec![0, 1, 2, 3, 4]),]) - ); - assert_eq!(trie.hash_slow(), CachedTrie::from_rlp(&rlp).unwrap().hash(),); - } - - #[test] - #[should_panic] - fn get_digest() { - let trie = Trie(Node::Digest(B256::ZERO)); - trie.get([]); - } - - #[test] - fn insert_empty_key() { - let mut trie = Trie::default(); - - trie.insert([], b"empty".to_vec()); - assert_eq!(trie.get([]), Some(b"empty".as_ref())); - assert!(trie.remove([])); - } - - #[test] - fn insert() { - let leaves = vec![ - ("painting", "place"), - ("guest", "ship"), - ("mud", "leave"), - ("paper", "call"), - ("gate", "boast"), - ("tongue", "gain"), - ("baseball", "wait"), - ("tale", "lie"), - ("mood", "cope"), - ("menu", "fear"), - ]; - - let mut trie = Trie::default(); - for (key, value) in &leaves { - trie.insert(key, value.as_bytes()); - } - - for (key, value) in &leaves { - assert_eq!(trie.get(key), Some(value.as_bytes())); - } - assert_eq!(trie.hash_slow(), trie_root(&leaves)); - } - - #[test] - fn index_trie() { - let leaves: Vec<(Vec, Bytes)> = (0..N) - .map(|i| { - let rlp = alloy_rlp::encode(i); - (rlp.clone(), rlp.into()) - }) - .collect(); - - // insert - let mut trie = Trie::default(); - for (i, (key, value)) in leaves.iter().enumerate() { - trie.insert(key, value.clone()); - - // check hash against trie build in reverse - let mut reference = Trie::default(); - for (k, v) in leaves.iter().take(i + 1).rev() { - reference.insert(k, v.clone()); - } - assert_eq!(trie, reference); - } - - assert_eq!(trie.hash_slow(), trie_root(&leaves)); - - // delete - for (i, (key, _)) in leaves.iter().enumerate() { - assert!(trie.remove(key)); - - let mut reference = Trie::default(); - for (k, v) in leaves.iter().rev().take(N - 1 - i) { - reference.insert(k, v.clone()); - } - assert_eq!(trie, reference); - } - - assert_eq!(trie.hash_slow(), EMPTY_ROOT_HASH); - } - - #[test] - fn keccak_trie() { - let leaves: Vec<(B256, Bytes)> = (0..N) - .map(|i| (keccak256(i.to_be_bytes()), alloy_rlp::encode(i).into())) - .collect(); - - // insert - let mut trie = Trie::default(); - for (i, (key, value)) in leaves.iter().enumerate() { - trie.insert(key, value.clone()); - - // check hash against trie build in reverse - let mut reference = Trie::default(); - for (k, v) in leaves.iter().take(i + 1).rev() { - reference.insert(k, v.clone()); - } - assert_eq!(trie, reference); - } - - assert_eq!(trie.hash_slow(), trie_root(&leaves)); - - // delete - for (i, (key, _)) in leaves.iter().enumerate() { - assert!(trie.remove(key)); - - let mut reference = Trie::default(); - for (k, v) in leaves.iter().rev().take(N - 1 - i) { - reference.insert(k, v.clone()); - } - assert_eq!(trie, reference); - } - - assert_eq!(trie.hash_slow(), EMPTY_ROOT_HASH); - } - - #[test] - fn hash_sparse_mpt() { - let leaves: BTreeMap<_, _> = (0..N) - .map(|i| { - let key = U256::from(i); - ( - Nibbles::unpack(keccak256(B256::from(key))), - alloy_rlp::encode(key), - ) - }) - .collect(); - - // generate proofs only for every other leaf - let proof_keys = leaves.keys().step_by(2).cloned().collect(); - let mut hb = HashBuilder::default().with_proof_retainer(proof_keys); - leaves.into_iter().for_each(|(k, v)| hb.add_leaf(k, &v)); - let exp_hash = hb.root(); - - // reconstruct the trie from the RLP encoded proofs and verify the root hash - let mpt = Trie::from_rlp( - hb.take_proof_nodes() - .into_nodes_sorted() - .into_iter() - .map(|node| node.1), - ) - .unwrap(); - assert!(mpt.size() < N); - assert_eq!(mpt.hash_slow(), exp_hash); - } - - #[test] - fn parse_empty_proof() { - let account_proof: Vec = Vec::new(); - - let mpt = Trie::from_rlp(account_proof).unwrap(); - assert_eq!(mpt.hash_slow(), EMPTY_ROOT_HASH); - } - - #[cfg(feature = "serde")] - #[test] - fn parse_eth_get_proof_existing() { - // { "id": 1, "jsonrpc": "2.0", - // "method": "eth_getProof", - // "params": ["0x0000000000000000000000000000000000000004", [], "0x12962D1"] } - let value = serde_json::json!([ - "0xf90211a064fba17f021dbb0322d3e7d30aff9db628377c960f1ebed87701f08ce0b040eca09d91529d0a9cfb8e091b206bbcc359f7734dff6815c73e65ecbec4063508f9e9a0558f96de53974dabf223c2501c08c97dfc1c3d47a9b2c4ea0655df221c8154bea057fbe18660f4919b33d1dfbccd340a3d9ddae1a0e7d7df6f8df4b3cbe7c9d875a084f9dc2615d641d4136337942a7c76b94164b4ebd29422b860fa2251f82d2b73a05b6b9d6d421156c0282dfe73491c8754906849e989210d766fe4e4e266b32605a024eb3df5b1a9d8c6e40fb604542bc70e38e33f32c0f2feebdbd9b7e7e31ba7e4a015935675b64554bdc16b1c1cfc25c89f5d284ff11dcfbf7993aec54a92f0bba4a0099d5fc449ccc8c39482564ac0dd831f1e05387dae9dfd9dea51cb0d4e19aa8aa031d64c42ebfbcecb9f0220b752ab56f06b2682778d17119b7324c0ad96dfc149a0095fe3791c69f53ed524f8edbea71ac57efd64b9198810cc763efa0f4a5c2897a0515238447863a22615f154bc9c72e3aa4f69c4726ff41063a467ae84416731aaa022f3633a252b9b64f1bfcf48fc267570bd4203e4f36feb85dded2c1bd1cff3e0a042d3afbd98a8965f366b72e2213895467a77159c1c3d28c84a29013f8cb12873a07fd2b3663f9fc8d7836096d9369a233eb17532e85e69a953011f7d698b2cc00aa0726b3dbf33d6ad6a58d3c6007a706bbcba5442ad17eda4dd1934fe40279ad71080", - "0xf90211a0f5271d0b41d27321301a4a99ee222e2f6993733b8bb4297e5f4a193309cea441a0308c36c27bc35ce53fa864873bbdda24f8dda698a8829976c654d71aed28d65fa077780501dffccc355bf0353e3641740ba33c12291c4a8f2a240c7c5e8c0f0ddaa0d571e89fdf190b87f84db4bf25b50648758b6d86940e172622b93c6e818ca4dba076419b70cc41744498d74746de84ef31ae62a324a60cfcb9f38b438e31c9325ca0d41cdf14b7a848eb7b90d53aecee8b656bdc4f21f1285b40075fc2cfb09970dca0d268e7c26b2bf55597f7f2e6b1783ff59468590ef813e2d0c941c545ac947093a0aaaa06235ff457fc16692855eb8f6417895e85ee99030273e67ed434ec9edc78a093176f5004283b61b43c5bc0ac81a64d1f8fa13f03151040c25f0687fd661a20a01875442e8e36fb90a38cfe7fbc47071e6a8d73afe31310167facf68f13428509a0e964058555501ab03129574589ec66fbd34af7af4f9ede88dd20e6d509d3ed78a070094346b748e0d7fe73f52655307fed3967a9b8b5d12abcb86baa338bfce384a07b944e9ffc124854852a026deac8105902cb9bd96bd45ee6548566fcd9d0280ba0e9ec860d689a8471762d8bbacdc453de018634b0d80aed35eb0f72e5d0b4f841a0fca2e3962d69a6927845d1537f58b3871ea19e775ac88b973ffa7717c9f9b1dba0c3ef3351fb2e76a5130b103ee85d83a7fc658fc306d43d29a016f8e696b412db80", - "0xf90211a07a0bc6ce42efd1947af01f6573b633c431a5b0d14fd22e0704cb8556b7098fd3a0105680327ae064d660fe790b6bbb4f1453d6188eaafd707b2d0be6010275b3a6a0b41d2058d4c85808c887fd70c07ed2629c9f5f138d8dd512c060de9b07d2cd18a0639cbfec697a3c8461f4dd0f0eda8a58cb186db9dd6831d0d0a3ce9c6f99a7fea0a9f7964dec293389bc37f594cb03be415ec76208081bd61aa56bb83b8e749d1da0541091360f807b91263b692989e1a2df1aa894568661ea88359fd0ad76837131a02bea3a3d833e46c77b3214e753f59157d232d5f1c4d9f1b936e82f343ed62f48a07d6282c3a3353eaba6503faaa91c2efe85d5c72a80d209ad2c2648ea24449b7ba0c0576e98237780fea7677ef30e5e5b966f8874d2defa0f4e2bc95ac6e3180ffda0514d5942624e2309086cfde5c70cce77a13d3d8c7e04a299d9c98d4bd76fc80da0267e7598bb09c5965509b91763d4ddf7eb8baaa19276ef1630ff904ba22c5836a0a18ede2979de3c02978dbf1542c517a3eb42fe537fde09a3fb0ab46e139d0712a066b2679d23b911ea309551b9453115ae26d92fd05f8ac3f2e2e6e31cf6ac9dc7a0d541bc04f0feaa8bd4239d25cb04b1ddb5976d65a20bf91eae810f8a8fc33bdaa0d75b751ed0a1ef82c9cae91b2e97ea78c218d9a8923be953753962ef81b1aa9ba0cc3d9261f5ba93857bdac0d26a341984b45d3a6aa38811e4ced7a12594722a9380", - "0xf90211a028e51fc851a6315210c3e973bc0c37db45b9cbc38384235414e7f83bd06097f9a04fddedaebfa0a6e8f6bc1c035ff20c0365a92911e8a9b6f267621f729461fa68a0a2a92894c4f4f64cd8563f2c5945b3fc2857ec60bce8549d5871966510234310a00f8ec60cdce60eca2287e2c08b6a074cec1218b355e08504f8e0209095cf2caaa0a7f6689140ac7d1230f773d0e7f395c884d4c4be8e19c752650e94d59e63d492a061dfe74f4e14f2a06dfeb9f268acd81559c4ef17de098630432b2ff342441c36a00c450940c088ad97119ac6b9ecef673ccc41c4244bffac10744bdd2868811f15a09d405cc6b538d9a9033a96818608fb801d4f1a4319448e459a802aa966f0637ea0a604db8246efa1a62859269ff28709d950d74b55b4730002c5639e383a2867bca0f11de25a06de0a1162bffb3d400edf07a64659aa59c3554898700082866997fda02454c86901086b11a1b11a0f7ed300aeb451ca9d50509f7f8d1818cdaa42177ba00b06fa9d11f507136397be1aa73ec37c8bf8a7b10d1ccd07d0bcd9634ce469d0a001e5be1f99d16e7b0f12d73d01c7aa54e109186b18c7c1eb04a6784d619ca452a0676f68104f74c5f03d7b4638bbbb9a0ec647f34ae489de642eb9fa6c03388e20a048b07679ba600363323c2304443d2815ebe87e64bcee9f5ea31d97a0c4720c95a035d02f8a26fb9926254b3309ac3cacb94852a9a7469ab094e12b8df2d820dac680", - "0xf90211a0af5538b1a07c6b743b04ed3a04d1b20db89c831e2f2acfd54d92f710004c9495a0c3abf984d9d723ec0aaa2d2c6afb75b693ddbd5538a0709bbc17f8b17325b78fa051d2081439320734f889a4de79d72ec9d009bdd7b33c1d2970cb88c98d13d4c6a0b55856ee040bc79be42aa48f807651502a07ea73d46a63d2997a5ee1493b3372a0df7a231010a67f2286fbcc6e9347e0f0d7706bc23a95a08342d61c9f83eb93a8a07c0dd78b4a5a44ad1fb26fb11c710f8478f039b89df1f6c888d1b984bf51338ba075367e67992101f00c0d4ac7b90110c901ba1dc0bff377084ec3c933643019a3a0ecbb4272ff5b494973deb3ea559bd5296c0de719b6cbc71d4469dd1b0697aa87a0441af491d98cf36d5c259ad8a183348aba1f642a6c5d408c846d09f86b52882ea083641f2add799b0244eeab16095698b801dad630a60a769fb3f378346514f44ca05829539f9d1d5835d74a994278ff03ede1fde23997a2d4bacaf7a74c7081308da038b4f88c187767463cac005228d458a26554fa28174a82b2d6ea47a86991f026a08f9bf87dc8b2cfae0f21ee5e300b71310b5092268921ea387ed4d1d68ebb47c2a0b1a29582a77306d0a48675f4ee4603f01b3744993d1b057592c0b4af91ed5c73a065cc8133f26ec26a0053f978068a41075b138f7cd077452832f7fa1c79ec2250a08b3561166e1256df806bc6ba3c7f6312493b38133aa3524f51884b9115c7cc9780", - "0xf90211a0000aba28e5abf987658d245aabf1157eedee3f099ebf95affabe5a1e9b53b521a0c37da1b511fc6e5925e9b3e6870866da39bd3a880b45b3d830dacddd5ca5d1c1a054eb2e6cd765137c3ebde36d30decd3a9461e9245ac510405740a1307f700f8fa009b3401df44a885d6ab901ba7b789b290f7c3fbbdb2739ab487e33ff48bb6f13a0b124c2c227b22040df405b92eeeae70b28f9f59cb355220a0184c2d26aebf765a06f9217b6b53f3258db8c9b91cd05a07d2e90608c490e76dff6a847a7ead45859a00007fd17fdc3326a80364d9e820ca33580fa9e4641c3d9864a653c90515e3255a0110ad882ed1c35d31bca099524ca8da2aec305bdcc02cbee38f986f3bbfd6946a0d1a7c39603704486613fe6a83d8fff219e1b4d71cecd01b460703f4d0c4fee26a084a158747da12a4c0e1df62f95b206779f6da199a9832d22f79cc6017b14eeb5a070dbfff894a8269d76bb53722185466c879eb601fd9b6c413ef69f8b282959a8a0ac026666c540c02a02838e725f62a41356e6617ccf16a930db35ad4b253253c2a001c4c0478fdbaadc5ad58defe18fb9df49bdd12c9b8efbe7acfb11bd8deb52eaa0637e3ebb17f8bf5e8e9d2a987e00a10070cd8a8623d327fdd0fac545e453000ea0052155fc9e62a4a89b260a55f0d470b91b1e009dc8923292284f260a9ecf8785a04fb3083fdd53a3023fc4aec62f307f7e87cf0e4a771fba42cbe62a10ba98f40a80", - "0xf901b1a0d3c18050bdcb55f8e919d224eb69062be67a76708fb45d5f4263e2bf26473339a08c8749c75e158292e70ecf6defbd039c5b739733db1105430b065c3d40dbafbba02a33fef2d0dc98049fb6e1ab176ceef4cf4a376a62d9076e4557618200b3c00ba0534f68319d219b17e6c94295329c3a85478d182591e721dcb82ade11212e8ab2a0a4b88347eb9d7466e1cd2b7025a14bc53b93e39532fb60e276f24ce64f43080ea0c3b3a7be7982dcbb5680948ec6e80103109bb7adb312d6f738870894c0cd7cef80a007e513f4512674cfc773e861e6a34250eae5508f5a24b1af07e62583eecfc675a0f501c13e330dd417836ad1a304a578575b4618880a479b542953248c4aaef3bca0a5d05faed975c0134a4333809d471a6afb7b19f7db1a2e928ec0e27b5e5cf651a0f90433f3b2fa2fae1df8ce6b1c2cd794fe4fd8f899767d9aa59607285efbe17f80a0f2d6a5c820099a8212b3af56264bda3b519af5379f1a09f2a6e6dc412a1e6561a0c82e9f321649f50e95a89db8fbdec55babc1a552850ee7fff4d22d9aecb5710f80a0c189cfed2417dd103f87679e16d3c8e178d61d5da36bbdb2aeb4aa170a1560ba80", - "0xf85180a0c3b71af926a3b464d43b79c4f3b91835b055202902801ec32940cd45d78c3ed3a06d11221db3e0db5015e8b8c4f2e738c733a0b212a1399021e7824e5f908ecf578080808080808080808080808080", - "0xf85180a0cce18d0d1d7b4befb137e8b893e0d62e61cc7e43474d885853697bc6729e6544808080808080a0b17e5bdc4a7d0f184dde26b3a718143439522942254dd9bd109255cc49d3b0ab8080808080808080", - "0xf86d9c3a393dbd067dc72abfa08d475ed6447fca96d92ec3f9e7eba503ca61b84ef84c80881a5fd46f92e55070a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" - ]); - let account_proof = serde_json::from_value::>(value).unwrap(); - - let mpt = Trie::from_rlp(account_proof).unwrap(); - - let address = alloy_primitives::address!("0x0000000000000000000000000000000000000004"); - let account = mpt - .get(keccak256(address)) - .map(|rlp| alloy_rlp::decode_exact(rlp).unwrap()); - assert_eq!( - account, - Some(alloy_trie::TrieAccount { - balance: alloy_primitives::uint!(0x1a5fd46f92e55070_U256), - ..Default::default() - }) - ); - } - - #[cfg(feature = "serde")] - #[test] - fn parse_eth_get_proof_nonexisting() { - // { "id": 1, "jsonrpc": "2.0", - // "method": "eth_getProof", - // "params": ["0x0010000000000000000000000000000000000000", [], "0x12962D1"] } - let value = serde_json::json!([ - "0xf90211a064fba17f021dbb0322d3e7d30aff9db628377c960f1ebed87701f08ce0b040eca09d91529d0a9cfb8e091b206bbcc359f7734dff6815c73e65ecbec4063508f9e9a0558f96de53974dabf223c2501c08c97dfc1c3d47a9b2c4ea0655df221c8154bea057fbe18660f4919b33d1dfbccd340a3d9ddae1a0e7d7df6f8df4b3cbe7c9d875a084f9dc2615d641d4136337942a7c76b94164b4ebd29422b860fa2251f82d2b73a05b6b9d6d421156c0282dfe73491c8754906849e989210d766fe4e4e266b32605a024eb3df5b1a9d8c6e40fb604542bc70e38e33f32c0f2feebdbd9b7e7e31ba7e4a015935675b64554bdc16b1c1cfc25c89f5d284ff11dcfbf7993aec54a92f0bba4a0099d5fc449ccc8c39482564ac0dd831f1e05387dae9dfd9dea51cb0d4e19aa8aa031d64c42ebfbcecb9f0220b752ab56f06b2682778d17119b7324c0ad96dfc149a0095fe3791c69f53ed524f8edbea71ac57efd64b9198810cc763efa0f4a5c2897a0515238447863a22615f154bc9c72e3aa4f69c4726ff41063a467ae84416731aaa022f3633a252b9b64f1bfcf48fc267570bd4203e4f36feb85dded2c1bd1cff3e0a042d3afbd98a8965f366b72e2213895467a77159c1c3d28c84a29013f8cb12873a07fd2b3663f9fc8d7836096d9369a233eb17532e85e69a953011f7d698b2cc00aa0726b3dbf33d6ad6a58d3c6007a706bbcba5442ad17eda4dd1934fe40279ad71080", - "0xf90211a07c0b2ddf03d5254f0a71793b61268dcccbcba1bbf91f84e1f01dfc7e748a22b3a0d066cbf287fff296cdf1c8d672f64cd1c7b582237a0e56f5523cadc9fd02db99a0ef75b0e082af37853216e2f1e189e8ed4a8fd8597d4cafb6a009d593d149463ba06b26667374d83ee094dab3adf971df2e3ec3f8255ce8e34b73d89afad4e5cc2ba0cc64a85fd14a5b27ec9aecd563395ea1c34629c7dca53222e7d19d1213af4d6ca07e3b3fd39452db1f8da9316152693d688505eff731e8b9c0e4512ba4a7882bcaa03579517fa320d080a74555da75ea17e676486aca21cac482f5f90993acec7112a0d674f6623ec3aaccde4856376e52b439ef4ebec600903c1e554b908b97780f64a04ebcd669406c6e48c0d1eca18c6c4040c8af886eac25e7218ef48d4cac8acf2ca0a4136773e1fdbde71ac578c4f5d25ee1c23067c20b43ea539b264fd566920630a0e94cab7b03de5bc128c5a15f3058c3c5ebebdd6f16e17548c2669886c1221b7aa0b1716052ef9a44fee9c985c4a957961c6d389bf290c82338e82cde8de5b174d5a096a699c048dc1d20509738881a99f1a09bc83a9ec0730b763c81c7ffb300b744a0733197a2479190e993f9da804810515c0e07b5752a1d0e537856cca86212a0f0a0d89157cef32fad06a43dd3ee54094a9790632d68cf07468ded845212ad484338a06055bbdb3664389c6e66a1519e99e802cb450d78fef9b8f8397c400d915ffe4780", - "0xf90211a001caaac143549f9bf7006ea276d133e2c6830bdb68d16a294a8aa836eeff19a2a0a68cdb682f254b8d8dfaf054bd571f4a84848cd58182274278c6dc09269093aaa063b4ef8b826676cea42d875d5a917193003ca99863a28dd4e4532307964c7e86a084473c41238e3dab60c7074c0fe4d6b14fec21124bdb999ef9fe92675d9e47bea01093a60823539cb5598a972ae1626dc68e62b83306cd0a7d0ca35bb0ae095432a0ea97146fe913ab3ffa242230eb2b0034f883de2a946f615cf4b152d8e4f9c2f1a0600c57157158dda437fdb93a2902d5a6aaadd2c4c4ef781b0f3bb9db52589ff1a005cd22b0467087c13203f302bd75ee3a49a4f50f72f044c510dfb80c5fd73d08a01a610490b54f297f9ed7f86993b19a4f1fe481d0bae5f8cc36428b066a19f675a002591f7ca3e129662132c3c43abec639309c7276bcb93f056ae0e064b08e544ba04cff311608aad7f75fe8660422dea95de1299b59ea1a92bc090a88c0a85033a1a0a23bc8dbe3fa661f80a211fbe0d46b938d681ed5c218391d1fc078242c52e07aa05152a90bb3bf83bc20c79d41e21eba4128916e93e3b2aa44e91d66419fed631ca04b9939df74f3585051cc7a256316931e8bbdba7ffadd42fc6a526acea2a65d5da0ad62bdb2eafbf12a569ab87cb4afd20853fd749a14817501bc051e16ace4b31da032a623bd0d0e0866790c76333c7279c455723c6c878d0a45767f9dd590f6f82b80", - "0xf90211a070740fa5e0ff39e4ecaa3807014386782670ead0ca3930db6e201e0633883524a0fae359c9f3636a34addbd37e75822169ddb824795f59a422a663466feabde3fca0ae96a399523295fb7628aa987c92c324aa579f7a6a0ef3215924f5ab0e2c7785a08b997d1e84063ff2b49c6fc7dda806333bec8a5616475b35021dc7330a6e63f7a076379dbbac470d9f0f8752f363dbb2dff2a0c0e1028d0a5d9aacdf5b735e9d4fa0da495111c40fed1ec3f6ae187ef71a8536a4aa6c09e84720f3645f1967267474a081250ce896356ce835178ed98f1b848a5b4c832f32c113e235020910437adcdba03d5338d4eb62c4d1bad3120bfff7c202a54c365abf2324ad0d97a04077b76900a03fea24d162e9725dc5e204fa2b8db528d0fc21ac54aa9c94e15105053e7bfd24a0c0f751477ad4b3a51a0af066821259e1a6ad3ac4a515c761765dd69552d07abfa079824c28b22d7b33105663cb8520d62101e303e9a0fabe00dfe2598654559b02a04be5cf039ac5c1bb6f8a4bf5dc3ceaa55e8e3fa8a9f6ae1953f744ef8c4c312ca0924250c41261da55a231889b7e88ff81428734661112d4faaa2961623ddd607ba0952fe6d321af6a7c322180c15f6aa06a8e3a461068f0e8c08183fd7536f9fd08a00b47228191943da98cc93b06f2475cb33de07d12d1445be308ffd94d786df047a0befcc93acb07cdf6240f884f7b4064f238c55f997a517f4bfcf6b970ea100d4e80", - "0xf90211a035ab3b8892330b5d3a92328b1c739c931c357dd4a5dc03e97ce130eb4d6ecf88a02ac2040a3839d2addee3deea351e02549e1a6662a5ff0ba42b8da6fd8964d58da0d5bef1786b6c185e65857742a860b724cba879fa0e8ae58abfab97e9ba213cc3a0649a68c768383bd53cd4b633b5297046bd8bf5c8b5e3f7be38b9b7eb037028e2a0247f186e30f069ed59215d7ed366c311a5bc5bde30ba52a8decc1d9145dcf286a0a725755aa59c849d7896625bbe2f31e0df98158be40adc6a394ffb1b4c05edcaa028a1af512637cfa63d06d9a416c46c6c8823be383a1ba1c1f880ade56b857ae6a070c12456255d06936ff8279cd8ed2de4596ff666161b8519fe8467310e88318fa033dfb37033f44cdce425c078ebe9f8ceb083f2bdb2058409c51c724140c4e99da0e38a0e9efc642da0375974ce69672ade21c5d43703ea5a38ad69644ccd01dc05a0f0773bd08b76b985fb3add2bf308fd1c548e22acb7eae8375f01f4c163f76be8a0e9cde81fdd404fb391b8ba5b3446e8c2e013b7792bc80f77703f2753552f470ea00975fa52a240800fd50ef22dad2aba6d1b4aeb19ee580ca13640d8a6de0936b9a07dd0437de64d7b5053478116ba0447ee5181818aadfb4a00ea1df67cc5d0bd1ca005f923facc0fb4445a5a488f628b353f3eb89936fb9e6b29bb1882e5c0881907a01d4fb8aac5a8d71ac5c0ed0c4491aed1532551451f630d717809797b4c3423b480", - "0xf90211a011d5405f5bf3648db2730954e75f7562daf4f93ae301482f3de752db8c6f6633a0f5dfe0e59a8b701cc7255480aba875bf4b2f8ec2b2a75b40320989d061f239ffa0641476041254ae3679696731e89da6e8ac4edc30762b30f0237014db2097ca98a0bca8b92c364aa974060a83482b3fddcbda788ace19d249e24225eb91cea050e3a08d5bc061d99b9803d93ad307aefb95950a9e5092cd3de0d642ec6b78d47ff883a093950c5e2655b226fccfd19359302b4e5a19e0d4812dc4859b0eadb3ee984118a02cc1641e3a8f95cea933cd6486d30e8d78d4a33fc81660b580ab05a67d13e438a0e9a7107962410d730bbc8f2350edbb592e7fb741dddee692c4bd9d4b3f1c16b4a05de66765b606c7bce1889f7c55028d19187f9ab9096e4d1927de1376c5905f2da03ca1622b70663d6880d0470191a28805547888ee1ece7ac65fd5c77dc67f6489a0cb515b40517b5c150115cdc0de89ed0e2a962a1ccdea09863b84050406fbd3eda0ff490436b20b1c8113eb98909c82c268e5454c8092ba0bc48a2b2903a0b4d372a07798003e5b7c0a905f0920e98bb17cf0a7f66fde92b0dd356463976cdda8c2e4a00c0fa4a0181bb622b9a4073844d5a72853b21e78db968ad4cea027828d402169a06b227ce534153d2d3952d3085da4f747e1c647f43ee616774df6f50c3f5646e5a0964a937d6cb948eaee92f05bd1a9d03af8ea3ee4e68b02ca9644d96ad86a0cd880", - "0xf901118080a02c5fbef8c93de59996332553693c43cf28dda1d13ac91dbee861a720883c7301808080a00cafef025cf50981161339913df13fac3635bb4d4612a6779b992b0896c1779480a0ad841e530360d785f7f258c646148f4b51093724f3b769efbb621fee609d2c3aa00abab5bb26960da6d85071fb6f12cf052c70b61c53acd72558ee06048a532128a043ae5b927740bbb05d9e6643a5c2e8c473cef67e529d431faf6edc79d19ba78a80a04a8ad4e57fe8d09e8596dc5131380ea3068decd740c1641ff712b35e37d6586980a045bd253469234b741abe3c8b110c04b0b9f3f983f752c394ef77814351a8d1bda08f74385b8385a4ebff237231c67a623e7bbad8151654e9edf32fa8464802cc6a80" - ]); - let account_proof = serde_json::from_value::>(value).unwrap(); - - let mpt = Trie::from_rlp(account_proof).unwrap(); - - let address = alloy_primitives::address!("0x0010000000000000000000000000000000000000"); - let account = mpt.get(keccak256(address)); - assert_eq!(account, None); - } - - mod cached { - use super::*; - use crate::CachedTrie; - - #[test] - fn index_trie() { - let leaves: Vec<(Vec, Bytes)> = (0..N) - .map(|i| { - let rlp = alloy_rlp::encode(i); - (rlp.clone(), rlp.into()) - }) - .collect(); - - // insert - let mut trie = CachedTrie::default(); - for (i, (key, value)) in leaves.iter().enumerate() { - trie.insert(key, value.clone()); - assert_eq!(trie.hash(), trie_root(leaves.iter().take(i + 1))); - } - - assert_eq!( - trie.hash(), - CachedTrie::from_rlp(trie.inner.rlp_nodes()).unwrap().hash() - ); - - // delete - for (i, (key, _)) in leaves.iter().enumerate() { - assert!(trie.remove(key)); - assert_eq!(trie.hash(), trie_root(leaves.iter().rev().take(N - 1 - i))); - } - } - - #[test] - fn keccak_trie() { - let leaves: Vec<(B256, Bytes)> = (0..N) - .map(|i| (keccak256(i.to_be_bytes()), alloy_rlp::encode(i).into())) - .collect(); - - // insert - let mut trie = CachedTrie::default(); - for (i, (key, value)) in leaves.iter().enumerate() { - trie.insert(key, value.clone()); - assert_eq!(trie.hash(), trie_root(leaves.iter().take(i + 1))); - } - - assert_eq!( - trie.hash(), - CachedTrie::from_rlp(trie.inner.rlp_nodes()).unwrap().hash() - ); - - // delete - for (i, (key, _)) in leaves.iter().enumerate() { - assert!(trie.remove(key)); - assert_eq!(trie.hash(), trie_root(leaves.iter().rev().take(N - 1 - i))); - } - } - } -} diff --git a/patches/risc0-ethereum-trie/src/mpt/nibbles.rs b/patches/risc0-ethereum-trie/src/mpt/nibbles.rs deleted file mode 100644 index 52dea87e..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/nibbles.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A zero-cost abstraction for handling nibbles (4-bit values) as byte slices. -//! -//! This module provides `NibbleSlice`, a wrapper around `&[u8]` that guarantees -//! each byte represents a valid nibble (0-15). It offers efficient operations -//! for working with nibble data without runtime overhead. - -use alloy_primitives::hex; -use alloy_trie::Nibbles; -use std::{fmt, ops::Deref}; - -/// A slice of bytes representing nibbles. -#[derive(Clone, Copy)] -pub(super) struct NibbleSlice<'a>(&'a [u8]); - -impl Deref for NibbleSlice<'_> { - type Target = [u8]; - - #[inline] - fn deref(&self) -> &Self::Target { - self.as_slice() - } -} - -impl fmt::Debug for NibbleSlice<'_> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Nibbles(0x{})", hex::encode(self.as_slice())) - } -} - -impl<'a> From<&'a Nibbles> for NibbleSlice<'a> { - /// Creates a `NibbleSlice` from a `Nibbles` reference. - #[inline] - fn from(nibbles: &'a Nibbles) -> Self { - Self(nibbles.as_slice()) - } -} - -impl From> for Nibbles { - /// Converts a `NibbleSlice` back into a `Nibbles`. - #[inline] - fn from(slice: NibbleSlice<'_>) -> Self { - Nibbles::from_nibbles_unchecked(slice.0) - } -} - -#[allow(dead_code)] -impl<'a> NibbleSlice<'a> { - #[inline] - pub(super) const fn as_slice(&self) -> &'a [u8] { - self.0 - } - - #[inline] - pub(super) const fn len(&self) -> usize { - self.0.len() - } - - #[inline] - pub(super) const fn is_empty(&self) -> bool { - self.0.is_empty() - } - - #[inline] - pub(super) fn join(&self, other: impl Into) -> Nibbles { - let other = other.into(); - let mut nibbles = Nibbles::with_capacity(self.len() + other.len()); - nibbles.extend_from_slice_unchecked(self.as_slice()); - nibbles.extend_from_slice_unchecked(other.as_slice()); - nibbles - } - - #[inline] - pub(super) fn split_first(&self) -> Option<(u8, Self)> { - self.0.split_first().map(|(nib, tail)| (*nib, Self(tail))) - } - - #[inline] - pub(super) fn strip_prefix(&self, prefix: &[u8]) -> Option { - self.0.strip_prefix(prefix).map(Self) - } - - #[inline] - pub(super) fn strip_suffix(&self, suffix: &[u8]) -> Option { - self.0.strip_suffix(suffix).map(Self) - } - - /// Splits `self` and `other` at the first nibble that differs. - #[inline] - pub(super) fn split_common_prefix(&self, other: impl Into) -> (Self, Self, Self) { - let (a, b) = (self.0, other.into().0); - let mid = a.iter().zip(b).take_while(|&(x, y)| x == y).count(); - // SAFETY: mid is the length of the common prefix: mid <= a.len() ∧ mid <= b.len() - let (common, a_tail) = unsafe { a.split_at_unchecked(mid) }; - ( - Self(common), - Self(a_tail), - Self(unsafe { b.split_at_unchecked(mid).1 }), - ) - } -} diff --git a/patches/risc0-ethereum-trie/src/mpt/node.rs b/patches/risc0-ethereum-trie/src/mpt/node.rs deleted file mode 100644 index b2d09d6f..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/node.rs +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::{ - children::{Children, Entry}, - memoize::Memoization, - nibbles::NibbleSlice, -}; -use alloy_primitives::{B256, Bytes}; -use alloy_trie::Nibbles; -use std::mem; - -pub(super) type Child = Box>; - -#[derive(Debug, Clone, Default)] -#[cfg_attr( - feature = "serde", - derive(serde::Serialize, serde::Deserialize), - serde(bound(serialize = "", deserialize = "M: Default")) -)] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), - rkyv(bytecheck(bounds(__C: rkyv::validation::ArchiveContext))), - rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator, __S::Error: rkyv::rancor::Source)), - rkyv(deserialize_bounds(__D::Error: rkyv::rancor::Source)) -)] -pub(super) enum Node { - #[default] - Null, - Leaf( - #[cfg_attr(feature = "rkyv", rkyv(with = super::rkyv::NibblesDef))] Nibbles, - #[cfg_attr(feature = "rkyv", rkyv(with = super::rkyv::BytesDef))] Bytes, - #[cfg_attr(feature = "serde", serde(skip))] - #[cfg_attr(feature = "rkyv", rkyv(with = rkyv::with::Skip))] - M, - ), - Extension( - #[cfg_attr(feature = "rkyv", rkyv(with = super::rkyv::NibblesDef))] Nibbles, - #[cfg_attr(feature = "rkyv", rkyv(omit_bounds))] Child, - #[cfg_attr(feature = "serde", serde(skip))] - #[cfg_attr(feature = "rkyv", rkyv(with = rkyv::with::Skip))] - M, - ), - Branch( - Children, - #[cfg_attr(feature = "serde", serde(skip))] - #[cfg_attr(feature = "rkyv", rkyv(with = rkyv::with::Skip))] - M, - ), - Digest(#[cfg_attr(feature = "rkyv", rkyv(with = super::rkyv::B256Def))] B256), -} - -impl PartialEq for Node { - /// Equality between nodes ignores the cache. - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Node::Null, Node::Null) => true, - (Node::Leaf(n1, b1, _), Node::Leaf(n2, b2, _)) => n1 == n2 && b1 == b2, - (Node::Extension(n1, c1, _), Node::Extension(n2, c2, _)) => n1 == n2 && c1 == c2, - (Node::Branch(c1, _), Node::Branch(c2, _)) => c1 == c2, - (Node::Digest(d1), Node::Digest(d2)) => d1 == d2, - _ => false, // different variants are not equal - } - } -} - -impl Eq for Node {} - -impl Node { - /// Retrieves the value associated with a given key. - pub(super) fn get(&self, key: NibbleSlice<'_>) -> Option<&Bytes> { - match self { - Node::Null => None, - Node::Leaf(prefix, value, _) if prefix == key.as_slice() => Some(value), - Node::Leaf(..) => None, - Node::Extension(prefix, child, _) => { - key.strip_prefix(prefix).and_then(|tail| child.get(tail)) - } - Node::Branch(children, _) => match key.split_first() { - Some((nib, tail)) => { - // SAFETY: `key` is a `NibbleSlice` and thus only contains values < 0xf - let child = unsafe { children.get_unchecked(nib) }; - child.and_then(|node| node.get(tail)) - } - None => None, // branch nodes don't have values in our MPT version - }, - Node::Digest(_) => panic!("MPT: Unresolved node access"), - } - } - - /// Inserts a key-value pair into the trie. - pub(super) fn insert(&mut self, key: NibbleSlice<'_>, value: Bytes) { - assert!(!value.is_empty()); - match self { - Node::Null => { - *self = Node::Leaf(key.into(), value, M::default()); - } - Node::Leaf(prefix, leaf_val, cache) => { - let (common, key_rem, prefix_rem) = key.split_common_prefix(&*prefix); - if common.len() == prefix.len() && common.len() == key.len() { - *leaf_val = value; - cache.clear(); - return; - } else if common.len() == prefix.len() || common.len() == key.len() { - panic!("MPT: Value in branch"); - } - - let mut children = Children::default(); - match prefix_rem.split_first() { - Some((nib, tail)) => { - children.insert( - nib, - Node::Leaf(tail.into(), mem::take(leaf_val), M::default()).into(), - ); - } - None => unreachable!(), // mid < prefix.len() - } - match key_rem.split_first() { - Some((nib, tail)) => { - children.insert(nib, Node::Leaf(tail.into(), value, M::default()).into()) - } - None => unreachable!(), // mid < key.len() - }; - let branch = Node::Branch(children, M::default()); - - *self = if common.is_empty() { - branch - } else { - Node::Extension(common.into(), branch.into(), M::default()) - }; - } - Node::Extension(prefix, child, cache) => { - let (common, key_rem, prefix_rem) = key.split_common_prefix(&*prefix); - if common.len() == prefix.len() { - child.insert(key_rem, value); - cache.clear(); - return; - } else if common.len() == key.len() { - panic!("MPT: Value in branch"); - } - - let mut children = Children::default(); - match prefix_rem.as_slice() { - [nib] => children.insert(*nib, mem::take(child)), - [nib, tail @ ..] => { - // SAFETY: `tail` is a slice of `prefix` and thus only contains nibbles - let prefix = Nibbles::from_nibbles_unchecked(tail); - children.insert( - *nib, - Node::Extension(prefix, mem::take(child), M::default()).into(), - ); - } - _ => unreachable!(), // mid < prefix.len() - } - match key_rem.split_first() { - Some((nib, tail)) => { - children.insert(nib, Node::Leaf(tail.into(), value, M::default()).into()) - } - None => unreachable!(), // mid < key.len() - }; - let branch = Node::Branch(children, M::default()); - - *self = if common.is_empty() { - branch - } else { - Node::Extension(common.into(), branch.into(), M::default()) - }; - } - Node::Branch(children, cache) => match key.split_first() { - Some((nib, tail)) => match children.entry(nib) { - Entry::Occupied(mut entry) => { - entry.get_mut().insert(tail, value); - cache.clear(); - } - Entry::Vacant(entry) => { - entry.insert(Node::Leaf(tail.into(), value, M::default()).into()); - cache.clear(); - } - }, - None => panic!("MPT: Value in branch"), - }, - Node::Digest(_) => panic!("MPT: Unresolved node access"), - } - } - - /// Removes a key-value pair from the trie. - pub(super) fn remove(&mut self, key: NibbleSlice<'_>) -> bool { - match self { - Node::Null => false, - Node::Leaf(prefix, ..) if prefix == key.as_slice() => { - *self = Node::Null; - true - } - Node::Leaf(..) => false, - Node::Extension(prefix, child, cache) => { - if !key - .strip_prefix(&*prefix) - .is_some_and(|tail| child.remove(tail)) - { - return false; - } - cache.clear(); - - // an extension always points to a branch, if this has changed because of the remove - match **child { - Node::Null => *self = Node::Null, - Node::Leaf(ref extension, ref mut value, _) => { - prefix.extend_from_slice(extension); - *self = Node::Leaf(mem::take(prefix), mem::take(value), M::default()) - } - Node::Extension(ref extension, ref mut child, _) => { - prefix.extend_from_slice(extension); - *self = Node::Extension(mem::take(prefix), mem::take(child), M::default()) - } - Node::Branch(..) => {} - Node::Digest(_) => unreachable!(), // child.remove() would have panicked - } - true - } - Node::Branch(children, cache) => { - match key.split_first() { - Some((nib, tail)) => match children.entry(nib) { - Entry::Occupied(mut entry) => { - if !entry.get_mut().remove(tail) { - return false; - } - } - Entry::Vacant(_) => return false, - }, - None => return false, // branch nodes don't have values in our MPT version - }; - cache.clear(); - - if let Some((nib, only_child)) = children.take_single_child() { - match *only_child { - // if the only child is a leaf, prepend the corresponding nib to it - Node::Leaf(mut extension, value, _) => { - // SAFETY: `take_single_child` always returns a nibble - extension.as_mut_vec_unchecked().insert(0, nib); - *self = Node::Leaf(extension, value, M::default()); - } - // if the only child is an extension, prepend the corresponding nib to it - Node::Extension(mut extension, child, ..) => { - // SAFETY: `take_single_child` always returns a nibble - extension.as_mut_vec_unchecked().insert(0, nib); - *self = Node::Extension(extension, child, M::default()); - } - // if the only child is a branch, convert to an extension - Node::Branch(..) => { - // SAFETY: `take_single_child` always returns a nibble - let prefix = Nibbles::from_nibbles_unchecked([nib]); - *self = Node::Extension(prefix, only_child, M::default()); - } - Node::Digest(_) => panic!("MPT: Unresolved node access"), - Node::Null => unreachable!(), // children does not contain any Node::Null - } - } - true - } - Node::Digest(_) => panic!("MPT: Unresolved node access"), - } - } - - /// Returns the number of full nodes in the trie. - pub(super) fn size(&self) -> usize { - match self { - Node::Null | Node::Digest(_) => 0, - Node::Leaf(..) => 1, - Node::Extension(_, child, ..) => 1 + child.size(), - Node::Branch(children, ..) => { - 1 + children - .iter() - .filter_map(Option::as_deref) - .map(Node::size) - .sum::() - } - } - } -} diff --git a/patches/risc0-ethereum-trie/src/mpt/orphan.rs b/patches/risc0-ethereum-trie/src/mpt/orphan.rs deleted file mode 100644 index af6c5b15..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/orphan.rs +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Functionality to resolve "orphan" nodes occurring during removes. -//! -//! Calling `remove` in sparse Merkle Patricia tries are only safe, if it does not lead to a Branch -//! node with just a single unresolved Digest child. Even though such a sparse trie is perfectly -//! valid to proof inclusion if the trie is not modified. - -use crate::{ - CachedTrie, Trie, - mpt::{memoize::Memoization, nibbles::NibbleSlice, node::Node}, -}; -use alloy_primitives::{keccak256, map::B256Map}; -use alloy_trie::Nibbles; -use std::fmt::Debug; - -/// Error returned by the `resolve_orphan` method. -#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)] -pub enum Error { - /// Indicates that the proof does not have a valid RLP encoding. - #[error("proof RLP encoding error")] - RlpError(#[from] alloy_rlp::Error), - - /// Indicates that the given proof is an invalid post-removal proof and does not prove the - /// non-inclusion of the key. - #[error("invalid proof")] - InvalidProof, - - /// Indicates that the orphan cannot be resolved using only the provided post-removal proof. - /// This typically occurs when the removal of a key transforms an `Extension` node into a - /// `Branch` node, and the proof does not contain sufficient information to reconstruct the - /// original `Extension` node. - /// It contains the key prefix that needs to be resolved, to make the removal valid. - #[error("key prefix `{0:?}` not resolved")] - Unresolvable(Nibbles), -} - -impl Trie { - /// Attempts to resolve orphaned branch children caused by the removal of a key-value pair. - /// - /// When a key-value pair is removed from the trie, it may leave behind "orphaned" nodes that - /// must be transformed into a different type of node for the trie to remain valid. - /// This method uses an [EIP-1186](https://eips.ethereum.org/EIPS/eip-1186) proof to resolve - /// these orphans. The proof should represent the state of the trie *after* the removal of the - /// key-value pair. - /// - /// # Errors - /// - /// Returns `Ok(())` if the orphan was successfully resolved. Returns `Error` if the proof is - /// invalid or the orphan cannot be resolved with the given proof. - /// - /// # Panics - /// - /// It panics if the key is not contained in the trie. - #[inline] - pub fn resolve_orphan(&mut self, key: K, proof: I) -> Result<(), Error> - where - K: AsRef<[u8]>, - I: IntoIterator, - T: AsRef<[u8]>, - { - self.0 - .resolve_orphan(NibbleSlice::from(&Nibbles::unpack(key)), proof) - } -} - -impl CachedTrie { - /// Attempts to resolve orphaned branch children caused by removing a key-value pair. - /// - /// See [`Trie::resolve_orphan`] for detailed documentation. - #[inline] - pub fn resolve_orphan(&mut self, key: K, proof: I) -> Result<(), Error> - where - K: AsRef<[u8]>, - I: IntoIterator, - T: AsRef<[u8]>, - { - self.inner - .resolve_orphan(NibbleSlice::from(&Nibbles::unpack(key)), proof) - } -} - -impl Node { - /// Attempts to resolve orphaned branch children caused by removing a key-value pair. - pub(super) fn resolve_orphan>( - &mut self, - key: NibbleSlice<'_>, - proof: impl IntoIterator, - ) -> Result<(), Error> { - assert!(self.get(key).is_some(), "key not contained"); - let other = Node::from_rlp(proof)?; - let Some((diverging, unmatched)) = other.diverging(key) else { - return Ok(()); - }; - let matched = key.strip_suffix(&unmatched).unwrap(); - - match diverging { - Node::Null => { - // the entire tree has been removed so trivially there can be no orphans - } - Node::Leaf(prefix, value, _) => { - // get the unmatched part of the Leaf-prefix - let (common, unmatched, _) = - NibbleSlice::from(prefix).split_common_prefix(unmatched); - // split the first nibble which used to belong to the Branch - let (idx, suffix) = unmatched.split_first().expect("empty unmatched key"); - // this can only be an orphan, if it is currently a Digest child of a Branch - if !self.is_branch_with_digest(&matched.join(common), idx) { - return Ok(()); - } - - // any orphan must be a Leaf with the suffix as a prefix - let sibling = Node::Leaf(suffix.into(), value.clone(), M::default()); - let rlp = sibling.rlp_encoded(); - self.resolve_digests(&B256Map::from_iter([(keccak256(&rlp), rlp)])) - .unwrap(); - } - Node::Extension(prefix, child, _) => { - // get the unmatched part of the Extension-prefix - let (common, unmatched, _) = - NibbleSlice::from(prefix).split_common_prefix(unmatched); - // split the first nibble which used to belong to the Branch - let (idx, suffix) = unmatched.split_first().expect("empty unmatched key"); - // this can only be an orphan, if it is currently a Digest child of a Branch - if !self.is_branch_with_digest(&matched.join(common), idx) { - return Ok(()); - } - - // Extensions cannot have an empty prefix. This means that if the suffix is empty, - // the orphan is a Branch, and because of the removal, its parent Branch has been - // converted to an Extension. So to resolve this orphan, we need to know the - // original Branch. - if suffix.is_empty() { - // if we are lucky, the post-removal proof does not stop at the Extension and - // the child still corresponds to the node we are looking for. - if !matches!(**child, Node::Digest(_)) { - let rlp = child.rlp_encoded(); - self.resolve_digests(&B256Map::from_iter([(keccak256(&rlp), rlp)])) - .unwrap(); - } - // the path to the orphan corresponds exactly to the path of the Extension-child - let orphan_prefix = matched.join(prefix); - // maybe the trie already contains a node with this prefix - if self.contains_prefix(&orphan_prefix) { - // in this case, the removal will not fail and nothing needs to be resolved - return Ok(()); - } - // otherwise return error that the given prefix needs to be resolved externally - return Err(Error::Unresolvable(orphan_prefix)); - } - - // any potential orphan must be an Extension with the (non-empty) suffix as a prefix - let sibling = Node::Extension(suffix.into(), (*child).clone(), M::default()); - let rlp = sibling.rlp_encoded(); - self.resolve_digests(&B256Map::from_iter([(keccak256(&rlp), rlp)])) - .unwrap(); - } - Node::Digest(_) => { - // the proof is invalid, as it does not proof the non-inclusion of `key` - return Err(Error::InvalidProof); - } - Node::Branch(..) => unreachable!("Branch node with value"), - } - - Ok(()) - } - - /// Returns the diverging trie node for a key. - /// - /// If the key is present in the trie, this method returns `None`. Otherwise, it returns the - /// node where the search for the key would fail, along with the unmatched portion of the key. - fn diverging<'a>(&'a self, key: NibbleSlice<'a>) -> Option<(&'a Node, NibbleSlice<'a>)> { - match self { - Node::Null => Some((&Node::Null, key)), - - Node::Leaf(prefix, ..) if prefix == key.as_slice() => None, - Node::Leaf(..) => Some((self, key)), - - Node::Extension(prefix, child, _) => key - .strip_prefix(prefix) - .map_or(Some((self, key)), |tail| child.diverging(tail)), - - Node::Branch(children, _) => match key.split_first() { - Some((idx, tail)) => { - let child = children.get(idx); - child.map_or(Some((&Node::Null, tail)), |node| node.diverging(tail)) - } - None => Some((self, key)), // branch nodes don't have values - }, - - Node::Digest(_) => Some((self, key)), - } - } - - fn contains_prefix<'a>(&'a self, key: impl Into>) -> bool { - match self.diverging(key.into()) { - None => true, // contains the prefix as a key - Some((Node::Digest(_), _)) => false, // prefix not resolved - Some((_, unmatched)) => unmatched.is_empty(), // prefix contained or not - } - } - - /// Returns whether the node at key is a Branch which has a Digest child at idx. - fn is_branch_with_digest<'a>(&'a self, key: impl Into>, idx: u8) -> bool { - match self.diverging(key.into()) { - // match only if, the node found is a `Node::Branch` and the *entire* key was consumed - Some((Node::Branch(children, ..), unmatched)) if unmatched.is_empty() => { - // if all the above conditions are met, check the specific child - matches!(children.get(idx), Some(Node::Digest(_))) - } - _ => false, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::Trie; - use alloy_primitives::{B256, Bytes}; - use alloy_trie::{HashBuilder, Nibbles, proof::ProofRetainer}; - use std::{borrow::Borrow, panic}; - - fn create_eip1186_proof( - key: K, - trie: impl IntoIterator>, - ) -> Vec - where - K: AsRef<[u8]>, - V: AsRef<[u8]>, - { - let hb = HashBuilder::default(); - let mut hb = - hb.with_proof_retainer(ProofRetainer::new(vec![Nibbles::unpack(key.as_ref())])); - - let mut sorted_data: Vec<_> = trie.into_iter().collect(); - sorted_data.sort_by(|a, b| a.borrow().0.as_ref().cmp(b.borrow().0.as_ref())); - for (key, val) in sorted_data.iter().map(Borrow::borrow) { - hb.add_leaf(Nibbles::unpack(key), val.as_ref()); - } - let _ = hb.root(); - - hb.take_proof_nodes() - .into_nodes_sorted() - .into_iter() - .map(|(_, rlp)| rlp) - .collect() - } - - #[test] - fn leaf_orphan() { - let keys = [vec![0x00], vec![0x11]]; - let key = &keys[0]; - let leaves = keys - .iter() - .map(|k| (k, Bytes::from(B256::ZERO))) - .collect::>(); - - let proof = create_eip1186_proof(key, &leaves); - let post_proof = create_eip1186_proof(key, &leaves[1..]); - - let mut trie = Trie::from_rlp(proof).unwrap(); - assert!(trie.get(key).is_some()); - assert!( - panic::catch_unwind(|| trie.clone().remove(key)).is_err(), - "Removal should panic" - ); - - trie.resolve_orphan(key, post_proof).unwrap(); - trie.remove(key); - } - - #[test] - fn extension_orphan() { - let keys = [vec![0x00], vec![0x10, 0x00], vec![0x10, 0x01]]; - let key = &keys[0]; - let leaves = keys - .iter() - .map(|k| (k, Bytes::from(B256::ZERO))) - .collect::>(); - - let proof = create_eip1186_proof(key, &leaves); - let post_proof = create_eip1186_proof(key, &leaves[1..]); - - let mut trie = Trie::from_rlp(proof).unwrap(); - assert!(trie.get(key).is_some()); - assert!( - panic::catch_unwind(|| trie.clone().remove(key)).is_err(), - "Removal should panic" - ); - - trie.resolve_orphan(key, post_proof).unwrap(); - trie.remove(key); - } - - #[test] - fn unresolvable_orphan() { - let keys = [vec![0x00], vec![0x10], vec![0x11]]; - let key = &keys[0]; - let leaves = keys - .iter() - .map(|k| (k, Bytes::from(B256::ZERO))) - .collect::>(); - - let proof = create_eip1186_proof(key, &leaves); - let post_proof = create_eip1186_proof(key, &leaves[1..]); - - let mut trie = Trie::from_rlp(proof).unwrap(); - assert!(trie.get(key).is_some()); - assert!( - panic::catch_unwind(|| trie.clone().remove(key)).is_err(), - "Removal should panic" - ); - - let err = trie.resolve_orphan(key, post_proof).unwrap_err(); - assert!(matches!(err, Error::Unresolvable(_))); - } -} diff --git a/patches/risc0-ethereum-trie/src/mpt/rkyv.rs b/patches/risc0-ethereum-trie/src/mpt/rkyv.rs deleted file mode 100644 index e8797314..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/rkyv.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::{ - memoize::{Cache, Memoization}, - node::Node, -}; -use alloy_primitives::{B256, Bytes}; -use alloy_trie::nybbles::Nibbles; -use itertools::Itertools; -use rkyv::{ - Archive, Archived, Deserialize, Place, Serialize, - rancor::{Fallible, Source}, - ser::{Allocator, Writer}, - vec::{ArchivedVec, VecResolver}, - with::{ArchiveWith, DeserializeWith, SerializeWith}, -}; - -/// Wrapper to encode a [B256] as an `[u8; 32]`. -#[derive(Archive, Serialize, Deserialize)] -#[rkyv(remote = B256)] -pub(super) struct B256Def([u8; B256::len_bytes()]); - -impl From for B256 { - #[inline] - fn from(B256Def(arr): B256Def) -> Self { - Self(arr) - } -} - -/// Wrapper to encode [Bytes] as an [`ArchivedVec`]. -pub(super) struct BytesDef; - -impl ArchiveWith for BytesDef { - type Archived = ArchivedVec; - type Resolver = VecResolver; - - fn resolve_with(bytes: &Bytes, resolver: Self::Resolver, out: Place) { - ArchivedVec::resolve_from_slice(bytes, resolver, out); - } -} - -impl SerializeWith for BytesDef { - fn serialize_with(bytes: &Bytes, serializer: &mut S) -> Result { - ArchivedVec::serialize_from_slice(bytes, serializer) - } -} - -impl DeserializeWith>, Bytes, D> for BytesDef -where - D: Fallible + ?Sized, - ::Error: Source, -{ - fn deserialize_with(field: &ArchivedVec, deserializer: &mut D) -> Result { - let vec = as Deserialize, D>>::deserialize(field, deserializer)?; - Ok(Bytes::from(vec)) - } -} - -/// Wrapper to encode [Nibbles] as an [`ArchivedVec`]. -pub(super) struct NibblesDef; - -impl ArchiveWith for NibblesDef { - type Archived = ArchivedVec; - type Resolver = VecResolver; - - fn resolve_with(nibbles: &Nibbles, resolver: Self::Resolver, out: Place) { - ArchivedVec::resolve_from_slice(nibbles, resolver, out); - } -} - -impl SerializeWith for NibblesDef { - fn serialize_with(nibbles: &Nibbles, serializer: &mut S) -> Result { - ArchivedVec::serialize_from_slice(nibbles, serializer) - } -} - -impl DeserializeWith>, Nibbles, D> for NibblesDef -where - D: Fallible + ?Sized, - ::Error: Source, -{ - fn deserialize_with(f: &ArchivedVec, deserializer: &mut D) -> Result { - let vec = as Deserialize, D>>::deserialize(f, deserializer)?; - Ok(Nibbles::from_vec_unchecked(vec)) - } -} - -/// RLP-encodes a cached trie during serialization. -/// -/// This has several advantages: -/// - The serialized bytes are fully verified at deserialization. -/// - The trie nodes already have an RLP-encoding when the hash is computed. -#[derive(Archive, Serialize, Deserialize)] -#[rkyv(remote = Node)] -pub(super) struct RlpNodes(#[rkyv(getter = rlp_nodes)] Vec>); - -fn rlp_nodes(node: &Node) -> Vec> { - node.rlp_nodes() - .into_iter() - .unique() - .map(Vec::from) - .collect() -} - -impl From for Node { - #[inline] - fn from(RlpNodes(nodes): RlpNodes) -> Self { - Node::from_rlp(nodes).unwrap() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mpt::{ArchivedTrie, Trie}; - use alloy_primitives::keccak256; - use rkyv::rancor::Error; - - const N: usize = 512; - - #[test] - fn round_trip() { - let trie: Trie = (0..N) - .map(|i| { - ( - keccak256(i.to_be_bytes()), - Bytes::from(alloy_rlp::encode(i)), - ) - }) - .collect(); - - let bytes = rkyv::to_bytes::(&trie).unwrap(); - let archived = rkyv::access::(&bytes).unwrap(); - let other = rkyv::deserialize::(archived).unwrap(); - - assert_eq!(trie, other); - } - - mod cached { - use super::*; - use crate::mpt::{ArchivedCachedTrie, CachedTrie}; - - #[test] - fn round_trip() { - let mut trie: CachedTrie = (0..N) - .map(|i| { - ( - keccak256(i.to_be_bytes()), - Bytes::from(alloy_rlp::encode(i)), - ) - }) - .collect(); - trie.hash(); - assert!(trie.hash.is_some()); - - let bytes = rkyv::to_bytes::(&trie).unwrap(); - let archived = rkyv::access::(&bytes).unwrap(); - let other = rkyv::deserialize::(archived).unwrap(); - assert!(other.hash.is_none()); - - assert_eq!(trie, other); - } - - #[test] - fn round_trip_dup() { - let trie: CachedTrie = (0..255) - .map(|i| (B256::with_last_byte(i), Bytes::from(B256::ZERO))) - .collect(); - - let bytes = rkyv::to_bytes::(&trie).unwrap(); - let archived = rkyv::access::(&bytes).unwrap(); - let other = rkyv::deserialize::(archived).unwrap(); - - assert_eq!(trie, other); - } - } -} diff --git a/patches/risc0-ethereum-trie/src/mpt/rlp.rs b/patches/risc0-ethereum-trie/src/mpt/rlp.rs deleted file mode 100644 index 21e4281f..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/rlp.rs +++ /dev/null @@ -1,654 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::{ - children::{Children, Entry}, - memoize::Memoization, - node::Node, -}; -use alloy_primitives::{ - B256, Bytes, hex, keccak256, - map::{B256HashMap, B256Map}, -}; -use alloy_rlp::{BufMut, Decodable, EMPTY_STRING_CODE, Encodable, Header}; -use alloy_trie::{EMPTY_ROOT_HASH, Nibbles, nodes::encode_path_leaf}; -use arrayvec::ArrayVec; -use std::fmt; - -/// The length in bytes of an RLP-encoded digest, i.e. hash length + 1 byte for the RLP header. -const DIGEST_RLP_LENGTH: usize = 1 + B256::len_bytes(); - -impl Node { - /// Returns the hash of the node. - #[inline] - pub(super) fn hash(&self) -> B256 { - NodeRef::from_node(self).hash() - } - - /// Returns the RLP encoding of the node. - pub(super) fn rlp_encoded(&self) -> Vec { - match self { - Node::Null => vec![EMPTY_STRING_CODE], - Node::Leaf(prefix, value, _) => { - let path = encode_path_leaf(prefix, true); - let mut out = encode_list_header(path.length() + value.length()); - path.encode(&mut out); - value.encode(&mut out); - - out - } - Node::Extension(prefix, child, _) => { - let path = encode_path_leaf(prefix, false); - let node_ref = NodeRef::from_node(child); - let mut out = encode_list_header(path.length() + node_ref.length()); - path.encode(&mut out); - node_ref.encode(&mut out); - - out - } - Node::Branch(children, _) => { - let mut child_refs: [NodeRef<'_>; 16] = Default::default(); - let mut payload_length = 1; // start with 1 for the EMPTY_STRING_CODE at the end - - for (i, child) in children.iter().enumerate() { - match child { - Some(node) => { - let node_ref = NodeRef::from_node(node); - payload_length += node_ref.length(); - child_refs[i] = node_ref; - } - None => payload_length += 1, - } - } - - let mut out = encode_list_header(payload_length); - child_refs.iter().for_each(|child| child.encode(&mut out)); - // add an EMPTY_STRING_CODE for the missing value - out.push(EMPTY_STRING_CODE); - - out - } - Node::Digest(digest) => alloy_rlp::encode(digest), - } - } - - /// Memoize the hash of every sub-trie. - pub(super) fn memoize(&mut self) { - // early termination for already memoized nodes or Null/Digest - match self { - Node::Leaf(.., cache) | Node::Extension(.., cache) | Node::Branch(.., cache) - if cache.get().is_some() => - { - return; - } - Node::Null | Node::Digest(_) => return, - _ => {} // proceed to memoization for other variants - } - match self { - Node::Extension(_, child, _) => child.memoize(), - Node::Branch(children, _) => children.memoize(), - _ => {} // no children to memoize for Leaf, Null, or Digest - } - let rlp = self.rlp_encoded(); - match self { - Node::Leaf(.., cache) | Node::Extension(.., cache) | Node::Branch(.., cache) => { - cache.set(RlpNode::from_rlp(rlp)); - } - _ => unreachable!(), - } - } - - /// Returns the RLP-encoded nodes of the trie in preorder. - pub(super) fn rlp_nodes(&self) -> Vec { - fn rec<'a, M: Memoization>(node: &'a Node, nodes: &mut Vec) -> NodeRef<'a> { - let node_ref = match node { - Node::Extension(prefix, child, _) => { - let (path, child) = (encode_path_leaf(prefix, false), rec(child, nodes)); - let mut out = encode_list_header(path.length() + child.length()); - path.encode(&mut out); - child.encode(&mut out); - NodeRef::Rlp(out) - } - Node::Branch(children, _) => { - let mut list = Vec::with_capacity(17); - for child in children.iter() { - let node_ref = child.as_ref().map_or(NodeRef::Empty, |c| rec(c, nodes)); - list.push(node_ref); - } - list.push(NodeRef::Empty); - NodeRef::Rlp(encode_list(&list)) - } - Node::Leaf(..) => NodeRef::Rlp(node.rlp_encoded()), // do not use the cached value - Node::Digest(digest) => NodeRef::Digest(digest), - Node::Null => NodeRef::Empty, - }; - match &node_ref { - NodeRef::Rlp(rlp) if rlp.len() >= 32 => nodes.push(rlp.clone().into()), - NodeRef::Cached(..) => unreachable!(), - _ => {} - } - node_ref - } - - if matches!(self, Node::Null) { - return vec![]; - } - - let mut vec = Vec::new(); - match rec(self, &mut vec) { - NodeRef::Rlp(rlp) if rlp.len() >= 32 => {} - NodeRef::Cached(..) => unreachable!(), - node_ref => vec.push(alloy_rlp::encode(node_ref).into()), - } - vec.reverse(); - - vec - } - - /// Creates a new trie from the given RLP encoded nodes. - pub(super) fn from_rlp>( - nodes: impl IntoIterator, - ) -> alloy_rlp::Result { - let mut iterator = nodes.into_iter(); - - // the first node must be the root - let mut root = match iterator.next() { - None => return Ok(Self::default()), - Some(rlp) => { - let mut node: Node = alloy_rlp::decode_exact(rlp.as_ref())?; - node.cache_set(RlpNode::from_rlp(rlp)); - node - } - }; - - // compute the references of all the remaining nodes - let (lower, _) = iterator.size_hint(); - let mut rlp_by_digest = B256HashMap::with_capacity_and_hasher(lower, Default::default()); - for rlp in iterator { - rlp_by_digest.insert(keccak256(&rlp), rlp); - } - - // return the resolved trie - root.resolve_digests(&rlp_by_digest)?; - Ok(root) - } - - /// Resolves all applicable digest nodes with the node corresponding to the RLP encoding. - pub(super) fn resolve_digests( - &mut self, - rlp_by_digest: &B256Map>, - ) -> alloy_rlp::Result<()> { - match self { - Node::Null | Node::Leaf(..) => {} - Node::Extension(_, child, _) => { - child.resolve_digests(rlp_by_digest)?; - if !matches!(**child, Node::Branch(..) | Node::Digest(..)) { - return Err(alloy_rlp::Error::Custom( - "extension node with invalid child", - )); - } - } - Node::Branch(children, _) => { - for entry in children.entries() { - if let Entry::Occupied(mut entry) = entry { - entry.get_mut().resolve_digests(rlp_by_digest)?; - } - } - } - Node::Digest(digest) => { - if let Some(bytes) = rlp_by_digest.get(digest) { - let mut node: Node = alloy_rlp::decode_exact(bytes.as_ref())?; - // do not try to replace a node by a digest - if !matches!(node, Node::Digest(_)) { - node.cache_set(RlpNode::from_digest(digest)); - *self = node; - self.resolve_digests(rlp_by_digest)?; - } - } - } - } - - Ok(()) - } - - #[inline] - fn cache_set(&mut self, rlp_node: RlpNode) { - match self { - Node::Leaf(.., cache) | Node::Extension(.., cache) | Node::Branch(.., cache) => { - cache.set(rlp_node) - } - _ => {} - } - } -} - -/// Compile-time toggle: `false` restores the upstream alloy-rlp based node -/// decoder (for A/B cycle measurement). -const FAST_DECODE: bool = true; - -impl Decodable for Node { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - if FAST_DECODE { - decode_node(buf) - } else { - decode_node_orig(buf) - } - } -} - -/// Upstream reference implementation (alloy-rlp `PayloadView` based), kept for -/// A/B measurement of the hand-written decoder. -#[allow(dead_code)] -fn decode_node_orig(buf: &mut &[u8]) -> alloy_rlp::Result> { - match Header::decode_raw(buf)? { - // if the node is not a list, it must be empty or a digest - alloy_rlp::PayloadView::String(payload) => match payload.len() { - 0 => Ok(Node::Null), - 32 => Ok(Node::Digest(B256::from_slice(payload))), - _ => Err(alloy_rlp::Error::UnexpectedLength), - }, - alloy_rlp::PayloadView::List(items) => match items.len() { - // branch node: 17-item node [ v0 ... v15, value ] - 17 => { - let mut children = Children::default(); - for (i, child_rlp) in items.iter().enumerate() { - if child_rlp != &[EMPTY_STRING_CODE] { - if i == 16 { - return Err(alloy_rlp::Error::Custom("branch node with value")); - } else { - children.insert( - i as u8, - decode_node_orig::(&mut &child_rlp[..])?.into(), - ); - } - } - } - if children.len() < 2 { - return Err(alloy_rlp::Error::Custom("branch node without two children")); - } - - Ok(Node::Branch(children, M::default())) - } - // leaf or extension node: 2-item node [ encodedPath, v ] - 2 => { - let [mut encode_path, mut v] = items.as_slice() else { - unreachable!() - }; - let (path, is_leaf) = decode_path_orig(&mut encode_path)?; - if is_leaf { - Ok(Node::Leaf(path, Bytes::decode(&mut v)?, M::default())) - } else { - let node = decode_node_orig::(&mut v)?; - if !matches!(node, Node::Branch(..) | Node::Digest(..)) { - return Err(alloy_rlp::Error::Custom( - "extension node with invalid child", - )); - } - Ok(Node::Extension(path, node.into(), M::default())) - } - } - _ => Err(alloy_rlp::Error::Custom("unexpected list length")), - }, - } -} - -/// Upstream reference implementation of the compact path decoder. -#[allow(dead_code)] -fn decode_path_orig(buf: &mut &[u8]) -> alloy_rlp::Result<(Nibbles, bool)> { - let path = Nibbles::unpack(Header::decode_bytes(buf, false)?); - if path.len() < 2 { - return Err(alloy_rlp::Error::InputTooShort); - } - let (is_leaf, odd_nibbles) = match path[0] { - 0b0000 => (false, false), - 0b0001 => (false, true), - 0b0010 => (true, false), - 0b0011 => (true, true), - _ => return Err(alloy_rlp::Error::Custom("node is not an extension or leaf")), - }; - let prefix = if odd_nibbles { &path[1..] } else { &path[2..] }; - Ok((Nibbles::from_nibbles_unchecked(prefix), is_leaf)) -} - -/// Reads the RLP header at the start of `bytes` without consuming it. -/// -/// Returns `(is_list, header_len, payload_len)`. -/// -/// Unlike `alloy_rlp::Header::decode_raw` this does not check canonical-form -/// rules (short-form vs long-form, leading zeros): the MPT root check at the -/// end of state verification rejects any incorrectly encoded witness anyway, -/// and the trie is re-encoded canonically when hashing. -#[inline] -fn peek_header(bytes: &[u8]) -> alloy_rlp::Result<(bool, usize, usize)> { - let Some(&b0) = bytes.first() else { - return Err(alloy_rlp::Error::InputTooShort); - }; - match b0 { - // single byte < 0x80 encodes itself - 0x00..=0x7f => Ok((false, 0, 1)), - 0x80..=0xb7 => Ok((false, 1, (b0 - 0x80) as usize)), - 0xb8..=0xbf => { - let ll = (b0 - 0xb7) as usize; - if bytes.len() < 1 + ll { - return Err(alloy_rlp::Error::InputTooShort); - } - let mut len = 0usize; - for &b in &bytes[1..1 + ll] { - len = (len << 8) | b as usize; - } - Ok((false, 1 + ll, len)) - } - 0xc0..=0xf7 => Ok((true, 1, (b0 - 0xc0) as usize)), - 0xf8..=0xff => { - let ll = (b0 - 0xf7) as usize; - if bytes.len() < 1 + ll { - return Err(alloy_rlp::Error::InputTooShort); - } - let mut len = 0usize; - for &b in &bytes[1..1 + ll] { - len = (len << 8) | b as usize; - } - Ok((true, 1 + ll, len)) - } - } -} - -/// Fast, allocation-light replacement for the alloy-rlp based `Node::decode`. -/// -/// Walks list items directly over the input slice (no intermediate `Vec` of -/// payload views), and decodes the compact path into a single small buffer. -fn decode_node(buf: &mut &[u8]) -> alloy_rlp::Result> { - let (is_list, hlen, plen) = peek_header(buf)?; - let bytes = *buf; - if bytes.len() < hlen + plen { - return Err(alloy_rlp::Error::InputTooShort); - } - let payload = &bytes[hlen..hlen + plen]; - *buf = &bytes[hlen + plen..]; - - if !is_list { - // if the node is not a list, it must be empty or a digest - return match plen { - 0 => Ok(Node::Null), - 32 => Ok(Node::Digest(B256::from_slice(payload))), - _ => Err(alloy_rlp::Error::UnexpectedLength), - }; - } - - // collect the items of the list as full RLP slices - let mut items: ArrayVec<&[u8], 17> = ArrayVec::new(); - let mut rest = payload; - while !rest.is_empty() { - let (_, ih, ip) = peek_header(rest)?; - if rest.len() < ih + ip { - return Err(alloy_rlp::Error::InputTooShort); - } - if items.try_push(&rest[..ih + ip]).is_err() { - return Err(alloy_rlp::Error::Custom("unexpected list length")); - } - rest = &rest[ih + ip..]; - } - - match items.len() { - // branch node: 17-item node [ v0 ... v15, value ] - 17 => { - let mut children = Children::default(); - for (i, child_rlp) in items.iter().enumerate() { - if *child_rlp != [EMPTY_STRING_CODE].as_slice() { - if i == 16 { - return Err(alloy_rlp::Error::Custom("branch node with value")); - } else if child_rlp.len() == DIGEST_RLP_LENGTH && child_rlp[0] == 0xa0 { - // fast path: a 33-byte item is a 32-byte digest string; - // skip the generic decoder recursion (111k of these per - // chunk, most of them never resolved further) - children.insert( - i as u8, - Node::Digest(B256::from_slice(&child_rlp[1..])).into(), - ); - } else { - children.insert(i as u8, decode_node(&mut &child_rlp[..])?.into()); - } - } - } - if children.len() < 2 { - return Err(alloy_rlp::Error::Custom("branch node without two children")); - } - - Ok(Node::Branch(children, M::default())) - } - // leaf or extension node: 2-item node [ encodedPath, v ] - // they are distinguished by a flag in the first nibble of the encodedPath - 2 => { - let (path, is_leaf) = decode_path(&mut &items[0][..])?; - if is_leaf { - let (v_list, vh, vp) = peek_header(items[1])?; - if v_list || items[1].len() < vh + vp { - return Err(alloy_rlp::Error::UnexpectedLength); - } - Ok(Node::Leaf( - path, - Bytes::copy_from_slice(&items[1][vh..vh + vp]), - M::default(), - )) - } else { - let v = &items[1][..]; - let node = if v.len() == DIGEST_RLP_LENGTH && v[0] == 0xa0 { - Node::Digest(B256::from_slice(&v[1..])) - } else { - decode_node(&mut &items[1][..])? - }; - if !matches!(node, Node::Branch(..) | Node::Digest(..)) { - return Err(alloy_rlp::Error::Custom( - "extension node with invalid child", - )); - } - Ok(Node::Extension(path, node.into(), M::default())) - } - } - _ => Err(alloy_rlp::Error::Custom("unexpected list length")), - } -} - -/// An RLP-encoded node. -#[derive(Clone)] -pub(super) struct RlpNode(ArrayVec); - -impl RlpNode { - #[inline] - fn from_rlp(rlp: impl AsRef<[u8]>) -> Self { - let rlp = rlp.as_ref(); - if rlp.len() >= B256::len_bytes() { - Self(alloy_rlp::encode_fixed_size(&keccak256(rlp))) - } else { - let mut arr = ArrayVec::new(); - // SAFETY: rlp.len() < 32 < DIGEST_RLP_LENGTH - unsafe { arr.try_extend_from_slice(rlp).unwrap_unchecked() }; - Self(arr) - } - } - - #[inline] - fn from_digest(digest: &B256) -> Self { - Self(alloy_rlp::encode_fixed_size(digest)) - } - - #[inline] - fn hash(&self) -> B256 { - if self.0.len() == DIGEST_RLP_LENGTH { - B256::from_slice(&self.0[1..]) - } else { - keccak256(&self.0) - } - } -} - -impl fmt::Debug for RlpNode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "0x{}", hex::encode(&self.0)) - } -} - -impl Encodable for RlpNode { - #[inline] - fn encode(&self, out: &mut dyn BufMut) { - out.put_slice(&self.0) - } - - #[inline] - fn length(&self) -> usize { - self.0.len() - } -} - -/// Represents the way in which a node is referenced from within another node. -#[derive(Default)] -enum NodeRef<'a> { - #[default] - Empty, - Digest(&'a B256), - Cached(&'a RlpNode), - Rlp(Vec), -} - -impl NodeRef<'_> { - #[inline] - fn from_node(node: &Node) -> NodeRef<'_> { - match node { - Node::Null => NodeRef::Empty, - Node::Digest(digest) => NodeRef::Digest(digest), - Node::Leaf(.., cache) | Node::Extension(.., cache) | Node::Branch(.., cache) => cache - .get() - .map_or_else(|| NodeRef::Rlp(node.rlp_encoded()), NodeRef::Cached), - } - } - - #[inline] - fn hash(&self) -> B256 { - match self { - NodeRef::Empty => EMPTY_ROOT_HASH, - NodeRef::Digest(&digest) => digest, - NodeRef::Cached(rlp_node) => rlp_node.hash(), - NodeRef::Rlp(rlp) => keccak256(rlp), - } - } -} - -impl Encodable for NodeRef<'_> { - #[inline] - fn encode(&self, out: &mut dyn BufMut) { - match self { - NodeRef::Empty => out.put_u8(EMPTY_STRING_CODE), - NodeRef::Digest(digest) => digest.encode(out), - NodeRef::Cached(rlp_node) => rlp_node.encode(out), - NodeRef::Rlp(rlp) => { - if rlp.len() >= B256::len_bytes() { - keccak256(rlp).encode(out); - } else { - out.put_slice(rlp); - } - } - } - } - - #[inline] - fn length(&self) -> usize { - match self { - NodeRef::Empty => 1, - NodeRef::Digest(_) => DIGEST_RLP_LENGTH, - NodeRef::Cached(rlp_node) => rlp_node.length(), - NodeRef::Rlp(rlp) => { - if rlp.len() >= B256::len_bytes() { - DIGEST_RLP_LENGTH - } else { - rlp.len() - } - } - } - } -} - -#[inline] -fn encode_list_header(payload_length: usize) -> Vec { - debug_assert!(payload_length > 1); - let header = Header { - list: true, - payload_length, - }; - let mut out = Vec::with_capacity(header.length() + payload_length); - header.encode(&mut out); - out -} - -#[inline] -fn decode_path(buf: &mut &[u8]) -> alloy_rlp::Result<(Nibbles, bool)> { - let (is_list, hlen, plen) = peek_header(buf)?; - if is_list { - return Err(alloy_rlp::Error::Custom("path is not a string")); - } - let bytes = *buf; - if bytes.len() < hlen + plen { - return Err(alloy_rlp::Error::InputTooShort); - } - let packed = &bytes[hlen..hlen + plen]; - *buf = &bytes[hlen + plen..]; - - let Some(&first) = packed.first() else { - return Err(alloy_rlp::Error::InputTooShort); - }; - let (is_leaf, odd_nibbles) = match first >> 4 { - 0b0000 => (false, false), - 0b0001 => (false, true), - 0b0010 => (true, false), - 0b0011 => (true, true), - _ => return Err(alloy_rlp::Error::Custom("node is not an extension or leaf")), - }; - - // Expand the path nibbles directly into the final buffer: one SmallVec - // copy instead of unpack + re-slice + re-pack. - let skip = if odd_nibbles { 1 } else { 2 }; - let nib_len = 2 * plen - skip; - if nib_len <= 66 { - let mut tmp = [0u8; 66]; - let mut n = 0usize; - if odd_nibbles { - tmp[0] = first & 0x0f; - n = 1; - } - for &b in &packed[1..] { - tmp[n] = b >> 4; - tmp[n + 1] = b & 0x0f; - n += 2; - } - Ok((Nibbles::from_nibbles_unchecked(&tmp[..nib_len]), is_leaf)) - } else { - let path = Nibbles::unpack(packed); - Ok((Nibbles::from_nibbles_unchecked(&path[skip..]), is_leaf)) - } -} - -fn encode_list(values: &[B]) -> Vec -where - B: std::borrow::Borrow, - T: ?Sized + Encodable, -{ - let mut payload_length = 0; - for value in values { - payload_length += value.borrow().length(); - } - let mut out = encode_list_header(payload_length); - for value in values { - value.borrow().encode(&mut out); - } - out -} diff --git a/patches/risc0-ethereum-trie/src/mpt/serde.rs b/patches/risc0-ethereum-trie/src/mpt/serde.rs deleted file mode 100644 index e9ad04db..00000000 --- a/patches/risc0-ethereum-trie/src/mpt/serde.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2025 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/// RLP-encodes a cached trie during serialization. -/// -/// This has several advantages: -/// - The serialized bytes are fully verified at deserialization. -/// - The trie nodes already have an RLP-encoding when the hash is computed. -#[cfg(feature = "rlp_serialize")] -pub(crate) mod rlp_nodes { - use crate::mpt::{memoize::Memoization, node::Node}; - use alloy_primitives::Bytes; - use itertools::Itertools; - use serde::{Deserialize, Deserializer, Serializer, de, ser::SerializeSeq}; - - #[inline] - pub(crate) fn serialize(trie: &Node, serializer: S) -> Result - where - S: Serializer, - M: Memoization, - { - // deduplicate the RLP nodes - let nodes: Vec = trie.rlp_nodes().into_iter().unique().collect(); - - let mut seq = serializer.serialize_seq(Some(nodes.len()))?; - for node in &nodes { - seq.serialize_element(&node[..])?; - } - seq.end() - } - - #[inline] - pub(crate) fn deserialize<'de, D, M>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - M: Memoization, - { - let nodes: Vec<&[u8]> = Vec::deserialize(deserializer)?; - - Node::from_rlp(nodes).map_err(de::Error::custom) - } -} - -#[cfg(test)] -mod tests { - use crate::Trie; - use alloy_primitives::{Bytes, keccak256}; - - const N: usize = 512; - - #[test] - fn round_trip() { - let trie: Trie = (0..N) - .map(|i| { - ( - keccak256(i.to_be_bytes()), - Bytes::from(alloy_rlp::encode(i)), - ) - }) - .collect(); - - let bytes = bincode::serialize(&trie).unwrap(); - let other: Trie = bincode::deserialize(&bytes).unwrap(); - - assert_eq!(trie, other); - } - - mod cached { - use super::*; - use crate::CachedTrie; - use alloy_primitives::B256; - - #[test] - fn round_trip() { - let mut trie: CachedTrie = (0..N) - .map(|i| { - ( - keccak256(i.to_be_bytes()), - Bytes::from(alloy_rlp::encode(i)), - ) - }) - .collect(); - trie.hash(); - assert!(trie.hash.is_some()); - - let bytes = bincode::serialize(&trie).unwrap(); - let other: CachedTrie = bincode::deserialize(&bytes).unwrap(); - assert!(other.hash.is_none()); - - assert_eq!(trie, other); - } - - #[test] - fn round_trip_dup() { - let trie: CachedTrie = (0..255) - .map(|i| (B256::with_last_byte(i), Bytes::from(B256::ZERO))) - .collect(); - - let bytes = bincode::serialize(&trie).unwrap(); - let other: CachedTrie = bincode::deserialize(&bytes).unwrap(); - - assert_eq!(trie, other); - } - } -} From e811487127705306bec3898aff3691d82981aba1 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Mon, 28 Sep 2026 02:21:48 +0000 Subject: [PATCH 15/15] perf: host-side proving speedups (mimalloc, thin LTO, cached StarkProver) Measured end-to-end (GPU, RTX 4090): chunk prove 43.9s -> 39.8s (-9%), batch e2e 54.9s -> 47.3s (-14%), bundle e2e 163.8s -> ~126-130s (-22%). - openvm-sdk: enable mimalloc (upstream default is jemalloc, which we had dropped via default-features=false; jemalloc measures 13% SLOWER here, mimalloc accounts for essentially the whole bundle/SNARK win) - [profile.release] lto=thin, codegen-units=1 (runtime effect ~= 0, kept for consistency; does not affect guest maxperf builds) - prover: cache StarkProver per Prover instead of letting Sdk::prove() rebuild it on every call (re-commits the program on device each time; ~1.1s per small chunk proof, ~3s for the 203M-cycle chunk); cleared on reset() Rejected after measurement (details in AGENTS.md): jemalloc, rvr (per-proof clang recompiles + rvr-ext-deferral broken upstream), VPMM_PAGES, halo2curves asm, CUDA arch/opt-level (already optimal). --- AGENTS.md | 81 +++++++++++++++++++++++++++++++++ Cargo.lock | 19 ++++++++ Cargo.toml | 7 ++- crates/prover/src/prover/mod.rs | 37 +++++++++++++-- 4 files changed, 140 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c5d1bcb6..dd07aabf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -243,6 +243,87 @@ or the proof model, not more micro-patches. `cargo metadata --locked` (must exit 0 without touching the lock). +## Host-side proving speed experiments (2026-09) + +Compile-option / feature-flag sweep for **end-to-end proving time** (GPU 1, RTX 4090, +EPYC 9554). Baseline: chunk `test-single-chunk` prove 43.89s (202,969,694 cycles, exec +2.35s), `test-e2e-batch` 54.9s, `test-e2e-bundle` 163.8s (of which the bundle +STARK→SNARK→EVM span ≈ 101s). + +### Adopted (in tree) + +- `openvm-sdk` feature **`mimalloc`** (workspace `Cargo.toml`). Upstream defaults to + `jemalloc`; we build with `default-features = false` and had **no** custom allocator. + **This is essentially the whole bundle win**: attribution runs show + native+LTO *without* mimalloc = 162.6s (≈ baseline 163.8s), adding mimalloc → 125.9s. + (halo2 SNARK host code is allocation-dominated; mimalloc also gives chunk exec −11%.) +- **Cached `StarkProver` per `Prover`** (`crates/prover/src/prover/mod.rs`): + `Sdk::prove()` rebuilds a `StarkProver` (re-committing the program on device) on + *every* call — ~1.1s per small chunk proof, ~3s for the big 203M-cycle chunk. + Caching it (cleared by `reset()`) gives batch e2e 51.3s → 47.3s (−8%) with 3 chunks, + and chunk `test-single-chunk` 43.0s → 39.8s. +- `[profile.release] lto = "thin", codegen-units = 1` — kept, but attribution says its + runtime effect here is ≈ 0 (it mainly raises build time; drop it if build time hurts). + Does not affect guest builds (`maxperf` already sets fat/1 explicitly). +- Recommended env (NOT committed; makes binaries machine-specific): + `RUSTFLAGS="-C target-cpu=native"` — measured ≈ 0 on both chunk and bundle in + isolation; harmless to use on fixed proving hardware. + +Final config (mimalloc + LTO + native + prover cache): **chunk 39.8s (−9.3%), batch e2e +47.3s (−13.8%), bundle e2e ~126-130s (−21%..−23%)**. Per-phase in bundle e2e: chunks −3% +(−15% with cache), batch −8~15%, exec −15~20%, the 101s bundle STARK+SNARK span → ~69-73s +(−30%). + +### Tried and rejected (measured, do not retry blindly) + +- **`jemalloc`**: chunk prove 49.6s — **13% SLOWER** than no custom allocator under the + GPU proving flow. (mimalloc and jemalloc behave very differently here.) +- **`rvr`** (runtime native-compiled execution), even *with* the StarkProver cache: + - First proof pays ~85s of clang compiles (metered + preflight-tracer artifacts in + `PreparedContinuation::new`); with the cache, *subsequent* chunk proofs do get + faster: 7.91s → 6.02s (**−24%**), i.e. preflight ~10s → ~2-3s on a 203M chunk. + - But `execute_guest`'s `sdk.compile_metered_cost()` (the cycle-count/precheck call in + `gen_proof_stark`) recompiles a native artifact **on every proof** (~22.5s each) — + the returned `CompiledExeMeteredCost<'_>` borrows the SDK so it can't be cached in + `Prover` without unsafe or an SDK API change. Net: still a loss. + - And RVR + deferral is **broken at this rev**: `rvr_ext_deferral.c` fails with + `use of undeclared identifier 'OPENVM_MEM_SIZE'` — batch/bundle can't run at all. + - Toolchain note if ever retried: prebuilt LLVM 22.1.8 at `/home/scroll/tools/llvm-22` + works with `RVR_CC=clang-22 RVR_LD=lld LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/11` + (`RVR_LD=ld.lld` is rejected by clang-22; `-lstdc++` needs the GCC dir on + `LIBRARY_PATH`). +- **`VPMM_PAGES` preallocation** (openvm VPMM pool): no measurable effect. +- **`halo2curves-axiom` `asm` feature** (x86_64 bn254 field asm): bundle e2e 125.81s + with vs 125.87s without — no effect; the halo2-gpu SNARK path is not CPU-field-bound. + NB: enabling it must be done in a **host-only** crate's dep (e.g. crates/prover), + never in workspace deps — the asm module is x86_64-only and would break riscv64 guest + builds through feature unification. +- CUDA side was already optimal: kernels compile for `sm_89` (auto-detected) with + `-O3` (`CUDA_OPT_LEVEL` default). `CUDA_ARCH` env override only affects build time. + +### Where the remaining chunk time goes (GPU prove, 24 segments) + +Per 203M-cycle chunk: ~25s GPU kernels (logup-zerocheck 16.4s, stacked_commit 6.1s, +whir 4.7s, merkle 5.9s), ~10s CPU preflight (per-segment re-execution), ~3s trace gen, +~3.3s metered executions. Per segment: CPU ≈ 0.62s (preflight+tracegen+postflight), +GPU ≈ 0.73s, run **strictly serially** (`sdk-config/src/preflight_driver.rs`) — the GPU +is idle ~40-45% of app-prove time. A software pipeline (preflight of segment i+1 +overlapping GPU prove of segment i) is the biggest known host-side lever left +(~20-25% off chunk) but is a medium-large fork of openvm-sdk-config: execution state +chains sequentially through one `VirtualMachine`, while postflight/tracegen/prove need +`&mut vm` and the engine — splitting that ownership safely is ~300+ lines with a +~1-segment-trace VRAM increase. Not done. + +A smaller same-direction win inside our own tree: `gen_proof_stark` runs +`execute_and_check` purely for cycle count + PI≠0 precheck, then `prove()` executes +again — removing the double execution (take instret from the prove path) saves +~2s/chunk. Not done (behavioral change: loses the fail-fast precheck). + +Span breakdown recipe: run the test with `--no-default-features --features +scroll-zkvm-integration/scroll,scroll-zkvm-integration/cuda` (the default `limit-logs` +feature hard-filters to scroll_zkvm_* targets and hides all openvm spans), with +`RUST_LOG="off,scroll_zkvm_integration=debug,scroll_zkvm_prover=debug,openvm_circuit=info,openvm_cuda_backend=info,openvm_stark_backend=info,openvm_sdk=info,openvm_continuations=info"`. + ## Common Failure Patterns ### `NativeHintSliceSubEx` assertion failure diff --git a/Cargo.lock b/Cargo.lock index 13bb9219..651d84ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3544,6 +3544,15 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "libmimalloc-sys" +version = "0.1.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9" +dependencies = [ + "cc", +] + [[package]] name = "libsecp256k1" version = "0.7.2" @@ -3748,6 +3757,15 @@ dependencies = [ "sketches-ddsketch", ] +[[package]] +name = "mimalloc" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862" +dependencies = [ + "libmimalloc-sys", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -5262,6 +5280,7 @@ dependencies = [ "hex-literal 1.1.0", "itertools 0.14.0", "metrics", + "mimalloc", "num-bigint", "openvm-codec-derive", "p3-air", diff --git a/Cargo.toml b/Cargo.toml index 7b78cbd4..a2d3bfd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,8 @@ openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", branch = "devel "parallel", "evm-prove", "tco", - "unprotected" + "unprotected", + "mimalloc" ] } openvm-transpiler = { git = "https://github.com/openvm-org/openvm.git", branch = "develop-v2.1.0", default-features = false } @@ -176,6 +177,10 @@ inherits = "release" lto = "fat" codegen-units = 1 +[profile.release] +lto = "thin" +codegen-units = 1 + [profile.profiling] inherits = "release" debug = 2 diff --git a/crates/prover/src/prover/mod.rs b/crates/prover/src/prover/mod.rs index 976bf066..44249332 100644 --- a/crates/prover/src/prover/mod.rs +++ b/crates/prover/src/prover/mod.rs @@ -174,8 +174,24 @@ pub struct Prover { app_config: SdkAppConfig, /// Lazily initialized SDK sdk: OnceLock, + /// Lazily built, cached `StarkProver`. `Sdk::prove()` rebuilds one on every + /// call, which re-commits the program on device (and with the `rvr` feature + /// would recompile the native execution artifacts from scratch — tens of + /// seconds per proof). Cache it once per SDK instance; `reset()` clears it. + stark_prover: OnceLock>, } +#[cfg(feature = "cuda")] +type SdkStarkProver = openvm_sdk::prover::StarkProver< + openvm_cuda_backend::BabyBearPoseidon2GpuEngine, + openvm_sdk_config::SdkVmGpuBuilder, +>; +#[cfg(not(feature = "cuda"))] +type SdkStarkProver = openvm_sdk::prover::StarkProver< + openvm_stark_sdk::config::baby_bear_poseidon2::BabyBearPoseidon2CpuEngine, + openvm_sdk_config::SdkVmCpuBuilder, +>; + /// Configure the [`Prover`]. #[derive(Debug, Clone, Default)] pub struct ProverConfig { @@ -197,11 +213,13 @@ impl Prover { prover_name: name.unwrap_or("universal").to_string(), app_config, sdk: OnceLock::new(), + stark_prover: OnceLock::new(), }) } /// Release OpenVM SDK resources pub fn reset(&mut self) { + self.stark_prover = OnceLock::new(); self.sdk = OnceLock::new(); } @@ -452,9 +470,22 @@ impl Prover { #[cfg(feature = "perf-metrics")] profile_dump::install(); let sdk = self.get_sdk()?; - let (vm_stark_proof, baseline) = sdk - .prove(self.app_exe.clone(), stdin, def_inputs) - .map_err(|e| Error::GenProof(e.to_string()))?; + // Reuse a cached `StarkProver` instead of `Sdk::prove()`, which rebuilds + // one (re-committing the program on device) on every call. + let stark_prover = self.stark_prover.get_or_try_init(|| { + sdk.prover(self.app_exe.clone()) + .map(std::sync::Mutex::new) + .map_err(|e| Error::GenProof(e.to_string())) + })?; + let (vm_stark_proof, baseline) = { + let mut prover = stark_prover + .lock() + .map_err(|e| Error::GenProof(format!("stark prover lock poisoned: {e}")))?; + let (proof, _metadata) = prover + .prove(stdin, def_inputs) + .map_err(|e| Error::GenProof(e.to_string()))?; + (proof, prover.generate_baseline()) + }; #[cfg(feature = "perf-metrics")] profile_dump::dump(&self.prover_name); let proving_time_mills = t.elapsed().as_millis() as u64;