feat: Zilkworm benchmark (RV64IM C++ guest) + Zilkworm Benchmark workflow - #673
Open
yi-sun wants to merge 5 commits into
Open
feat: Zilkworm benchmark (RV64IM C++ guest) + Zilkworm Benchmark workflow#673yi-sun wants to merge 5 commits into
yi-sun wants to merge 5 commits into
Conversation
yi-sun
force-pushed
the
feat/zilkworm-benchmark
branch
from
July 24, 2026 22:32
c8d9881 to
be60fd2
Compare
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
force-pushed
the
feat/zilkworm-benchmark
branch
from
July 24, 2026 22:34
be60fd2 to
e1cc0a6
Compare
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Zilkworm support to the OpenVM benchmark stack, stacked on
develop-v2.1.0(openvm pinned to openvm-org/openvm branchdevelop-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 + sha2plus 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 SSZStatelessInputbyte vector (--input-path), with optional--expected-outputconformance checking.Zilkworm Benchmarkworkflow (.github/workflows/zilkworm-benchmark.yml) — parallel to the Reth Benchmark: builds the guest ELF from axiom-crypto/zilkworm-stateless (pinned xPackriscv-none-elf-gcc15.2.0-1.1), prepares the input (mockconformance vector or ans3:///https://URL), and reuses the same exec-mode selection (rvrdefault /tco/interpreter), metrics,openvm-profmarkdown, S3 and gh-pages publication asreth-benchmark.yml.Green end-to-end runs (prove-stark, rvr, g7e.2xlarge):
input_source=block:24001988pipeline ran in CI (RPC witness → SSZ assembly → 14.1 MB input → prove-stark), and the CI-generated input is byte-size identical to the locally-generated one.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):
HINT_BUFFERin dwords ≤ 1023/instruction),revealas u64 words at byte offsetindex*8, unchanged keccak-f/sha256 encodings with 8-byte-aligned pointersTEXT_START0x200800,STACK_TOP0x200400, 512 MiB); SP1's rv64 strict-alignment memcpy/memmove;-mstrict-alignfor conservative bring-upECC 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-Weierstrassadd_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)ModArith<BN>: canonical-form OpenVM mul/add/sub + native DivMod inversion (replaces binary-Euclid software inversion); bn254BN_ACCELERATEDfor OPENVM; pairing Fq2 hooks via the Fp2 extensionecrecover(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_SELFTESTcmake 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 mismatchValidation
execute(interpreter andrvr): mock vector byte-exact vsmock_expected_failure.bin(the synthetic mock block intentionally fails validation)zkevm@v0.4.0fixtures (converted via zilkworm'sconformance eest): in-VM results match the native software build's verdicts on all sampled fixtures; the natively-passing tx-bearing fixtureprecompiles__t0_b0returnssuccess=truebyte-exact in-VM — wrong accelerated ecrecover would corrupt the post-state rootprove-app+verify_segmentspass 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)Notes
openvm.tomlis ABI with the guest's funct7 indices (documented in both files).input_source=mockis smoke-test-sized. Benchmark-grade inputs: EEST*.input.binfiles (fromfixtures_zkevmreleases viaconformance 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 thezkevm@v0.4.0suite natively (block-levelinsert_block=0x1c), independent of this work.