Skip to content

feat: Zilkworm benchmark (RV64IM C++ guest) + Zilkworm Benchmark workflow - #673

Open
yi-sun wants to merge 5 commits into
develop-v2.1.0from
feat/zilkworm-benchmark
Open

feat: Zilkworm benchmark (RV64IM C++ guest) + Zilkworm Benchmark workflow#673
yi-sun wants to merge 5 commits into
develop-v2.1.0from
feat/zilkworm-benchmark

Conversation

@yi-sun

@yi-sun yi-sun commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds Zilkworm support to the OpenVM benchmark stack, stacked on develop-v2.1.0 (openvm pinned to openvm-org/openvm branch develop-v2.1.0):

  • bin/zilkworm-benchmark — a standalone benchmark host (no reth/alloy deps) for the Zilkworm stateless validator, a bare-metal C++ RV64IM guest ELF. VM config (openvm.toml): rv64i + rv64m + io + keccak + sha2 plus the ECC extensions below, 256 bytes of user public values. Modes: execute, execute-metered, prove-app, prove-stark, keygen, generate-vm-vkey, with the same proving-parameter CLI as the Reth host. The guest ELF is loaded at runtime via --guest-elf; input is a raw eth-act SSZ StatelessInput byte vector (--input-path), with optional --expected-output conformance checking.
  • Zilkworm Benchmark workflow (.github/workflows/zilkworm-benchmark.yml) — parallel to the Reth Benchmark: builds the guest ELF from axiom-crypto/zilkworm-stateless (pinned xPack riscv-none-elf-gcc 15.2.0-1.1), prepares the input (mock conformance vector or an s3:///https:// URL), and reuses the same exec-mode selection (rvr default / tco / interpreter), metrics, openvm-prof markdown, S3 and gh-pages publication as reth-benchmark.yml.
    Green end-to-end runs (prove-stark, rvr, g7e.2xlarge):

Guest side (axiom-crypto/zilkworm-stateless, branch feat/openvm-rv64)

RV64IM port of zilkworm's OpenVM shim (was rv32im/ilp32 on openvm v2.0.0-rc.3):

  • dword-granular hint ABI (u64 length prefix, HINT_BUFFER in dwords ≤ 1023/instruction), reveal as u64 words at byte offset index*8, unchanged keccak-f/sha256 encodings with 8-byte-aligned pointers
  • elf64 linker script with the unchanged OpenVM layout (TEXT_START 0x200800, STACK_TOP 0x200400, 512 MiB); SP1's rv64 strict-alignment memcpy/memmove; -mstrict-align for conservative bring-up

ECC precompile acceleration via OpenVM custom-1 (0x2b) instructions, mirroring the repo's existing SP1/ZisK hook seams (hooks ship as a patch applied to the fetched zilkworm tree via FetchContent PATCH_COMMAND — no fork needed):

  • openvm_ecc.hpp: modular add/sub/mul/div intrinsics (secp256k1 Fp/Fr, bn254 Fp/Fr), bn254 Fp2 ops, secp256k1/bn254 short-Weierstrass add_ne/double, with lazy per-modulus/curve setup (mirrors the Rust guest libs' once_cell; Fp2 setup takes the modulus concatenated twice — one copy per coefficient)
  • evmmax ModArith<BN>: canonical-form OpenVM mul/add/sub + native DivMod inversion (replaces binary-Euclid software inversion); bn254 BN_ACCELERATED for OPENVM; pairing Fq2 hooks via the Fp2 extension
  • secp256k1 ecrecover (used for every tx sender recovery): canonical scalar math via OpenVM Fr ops + Shamir msm over OpenVM EC point instructions (mirrors the ZisK branch)
  • Z6M_ECC_SELFTEST cmake option: in-guest self-test of bn254 G+G, [7]G, and the pairing identity e(G1,G2)·e(−G1,G2)=1 through the accelerator ABI — halts the guest on mismatch

Validation

  • execute (interpreter and rvr): mock vector byte-exact vs mock_expected_failure.bin (the synthetic mock block intentionally fails validation)
  • EEST zkevm@v0.4.0 fixtures (converted via zilkworm's conformance eest): in-VM results match the native software build's verdicts on all sampled fixtures; the natively-passing tx-bearing fixture precompiles__t0_b0 returns success=true byte-exact in-VM — wrong accelerated ecrecover would corrupt the post-state root
  • prove-app + verify_segments pass for: the ecrecover fixture (secp256k1 modular + EC AIRs) and the bn254 self-test guest (bn254 modular/Fp2/DivMod AIRs; this proof is what caught the Fp2 setup-layout bug)
  • CI: green prove-stark run linked above (93,537 insns on mock; rvr backend)

Notes

  • The moduli/fp2/curve order in openvm.toml is ABI with the guest's funct7 indices (documented in both files).
  • input_source=mock is smoke-test-sized. Benchmark-grade inputs: EEST *.input.bin files (from fixtures_zkevm releases via conformance eest) uploaded to S3, or — as a follow-up — an eth-act witness pipeline for real mainnet blocks. Note the upstream zilkworm core currently fails a large fraction of the zkevm@v0.4.0 suite natively (block-level insert_block=0x1c), independent of this work.
  • bn254 EC point instructions and bn254 Fr are configured but not yet wired into evmone's bn254 G1 add/mul (those currently run Jacobian formulas over accelerated field ops); hooking them natively is a follow-up optimization.

@yi-sun
yi-sun force-pushed the feat/zilkworm-benchmark branch from c8d9881 to be60fd2 Compare July 24, 2026 22:32
Adds bin/zilkworm-benchmark, a benchmark host for the Zilkworm stateless
Ethereum validator (github.com/eth-act/zilkworm-stateless), a bare-metal
C++ RV64IM guest. The host loads the prebuilt guest ELF, feeds it an
eth-act SSZ StatelessInput byte vector, and reuses the same OpenVM
execute / prove pipeline as the Reth benchmark with a VM config of
rv64i + rv64m + io + keccak + sha2.

Adds the Zilkworm Benchmark workflow, parallel to the Reth Benchmark:
builds the guest ELF from axiom-crypto/shadow-zilkworm-stateless with
the pinned xPack riscv-none-elf-gcc toolchain, generates (or downloads)
the guest input, and runs the selected mode with the same metrics /
openvm-prof / gh-pages reporting.
yi-sun added 4 commits July 24, 2026 22:58
The nested checkout made cargo adopt the conformance crate into the
openvm-eth workspace ('current package believes it's in a workspace').
Clone into RUNNER_TEMP and reference it via ZILKWORM_DIR; the repo is
public now, so clone over https.
The previous fix's replacement anchor no longer matched after the
https-clone change, so the clone stayed inside the workspace while the
later steps read the never-set ZILKWORM_DIR.
Adds the modular (secp256k1 Fp/Fr, bn254 Fp/Fr), Fp2 (Bn254Fp2) and
short-Weierstrass (secp256k1, bn254) extensions to the Zilkworm guest
VM config, matching the ECC precompile acceleration hooks added to the
guest (zilkworm-stateless feat/openvm-rv64). The moduli/curve order in
openvm.toml is ABI with the guest's funct7 indices.
Adds a zilkworm-input generator binary to openvm-rpc-proxy: builds the
execution witness for a block through the same preflight pipeline the
Reth benchmark uses and emits payload/witness JSONs, which
zilkworm-stateless's new 'conformance reth' subcommand assembles into
an eth-act SSZ StatelessInput (mainnet ChainConfig derived from the
block timestamp; execution requests must be empty, true for blocks
whose requestsHash is the empty commitment).

The Zilkworm Benchmark workflow accepts input_source=block:<number>:
restores the generated input from the S3 fixtures cache when available,
else generates it via RPC_URL_1 and uploads it back. Validated locally
on mainnet block 24001988 (65 txs, ~60M gas): native conformance passes
and the in-VM run matches the expected success output byte-exactly at
854,301,241 instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant