Skip to content

Instantly share code, notes, and snippets.

@pirapira
Created August 31, 2026 22:48
Show Gist options
  • Select an option

  • Save pirapira/a5cc0088ade5ac31fcbed3b562e3e9b1 to your computer and use it in GitHub Desktop.

Select an option

Save pirapira/a5cc0088ade5ac31fcbed3b562e3e9b1 to your computer and use it in GitHub Desktop.
bench-20260831.md

ZisK Stateless Validator Benchmark: EvmAsm vs reth

Date: 2026-08-31
Block: 115260 (glamsterdam-devnet-7, chainId 7082904758)
Emulator: ZisK ziskemu v1.1.0-alpha (9a5a1ac, 2026-08-18)


Results

Metric EvmAsm reth v0.1.0-rc.1
ZisK steps 4,345,958,375 124,579,543
ZisK cost 938,559,514,686 14,873,440,147
Wall time (emulation) 142.3 s 5.04 s
Throughput 30.5 Msteps/s 24.7 Msteps/s

EvmAsm / reth ratio: 34.9× steps, 63× cost

Cost distribution

Category EvmAsm EvmAsm % reth rc.1 reth rc.1 %
Base 287,309,824 0.0% 287,309,824 1.9%
Main 295,525,169,500 31.5% 8,471,408,924 57.0%
Opcodes 37,587,461,702 4.0% 4,070,136,570 27.4%
Precompiles 537,880,722,692 57.3% 1,244,717,427 8.4%
Memory 67,278,850,968 7.2% 799,867,402 5.4%
Total 938,559,514,686 14,873,440,147

EvmAsm's dominant cost is the Precompile category (keccak256, 57.3%), reflecting the heavy keccak hashing over the witness trie nodes. reth rc.1's cost is dominated by Main + Opcodes (84.4%), consistent with a more conventional interpreter loop.


Block details

Field Value
Network glamsterdam-devnet-7
Block number 115260
Gas used 65,318,413
statelessInputBytes size 568,669 bytes
Fixture archive 115260-115269.tar.zst

Prerequisites

  • ziskemu v1.1.0-alpha at ~/.zisk/bin/ziskemu
    • Install: ~/.zisk/bin/ziskup -v 1.1.0-alpha --nokey -y (no leading v)
  • Lean 4 + Lake (for EvmAsm guest only)
  • riscv64-elf-ld (for EvmAsm guest only)
  • zstd, Python 3

Step 1 – Prepare the input file

#!/usr/bin/env python3
import json, struct, tarfile, pathlib

with tarfile.open("115260-115269.tar.zst", "r:zst") as tf:
    names = [n for n in tf.getnames() if "115260" in n and n.endswith(".json")]
    data = json.loads(tf.extractfile(names[0]).read())

network = next(iter(data.values()))
block   = next(iter(network.values()))
blob    = bytes.fromhex(block["statelessInputBytes"].lstrip("0x"))

payload = struct.pack("<Q", len(blob)) + blob
padded  = payload + b"\x00" * ((8 - len(payload) % 8) % 8)
pathlib.Path("block115260.input").write_bytes(padded)
print(f"blob={len(blob)} bytes, packed={len(padded)} bytes")
# blob=568669 bytes, packed=568680 bytes

Step 2 – Run EvmAsm

Build the guest ELF

lake exe codegen --program stateless_guest --halt linux93 -o gen-out/stateless_guest

Relink with explicit PHDRS (required for ZisK)

# /tmp/zisk_clean.ld
PHDRS {
  text PT_LOAD FLAGS(5);
  data PT_LOAD FLAGS(6);
  bss  PT_LOAD FLAGS(6);
  rlp  PT_LOAD FLAGS(6);
  ssz  PT_LOAD FLAGS(6);
}
SECTIONS {
  . = 0x80000000;
  .text : { *(.text .text.*) *(.rodata .rodata.*) } :text
  . = 0xa0b00000;
  .data : { *(.data .data.*) *(.sdata .sdata.*) } :data
  . = 0xa0b70000;
  .bss (NOLOAD) : { *(.bss .bss.*) *(COMMON) } :bss
  . = 0xbf5e2000;
  .rlp_recursive_frame (NOLOAD) : { *(.rlp_recursive_frame) } :rlp
  . = 0xbf980000;
  .sszscratch (NOLOAD) : { *(.sszscratch) } :ssz
  /DISCARD/ : { *(.riscv.attributes) *(.note.*) *(.comment) }
}
riscv64-elf-ld -T /tmp/zisk_clean.ld -nostdlib --no-relax \
  -o gen-out/stateless_guest_clean.elf gen-out/stateless_guest.o

Run

~/.zisk/bin/ziskemu \
  -e gen-out/stateless_guest_clean.elf \
  -i block115260.input \
  -m -X --sdk

Output

STEPS    4,345,958,375
COST   938,559,514,686
RAM      0.00 MB / 0.00 MB

Base         ░░  287,309,824   0.0%
Main         ███ 295,525,169,500  31.5%
Opcodes      ░   37,587,461,702   4.0%
Precompiles  ████537,880,722,692  57.3%
Memory       █   67,278,850,968   7.2%

process_rom() steps=4345958375 duration=142.2886 tp=30.5433 Msteps/s

Step 3 – Run reth

Download

curl -L -o stateless-validator-reth-zisk-v100.elf \
  https://github.com/paradigmxyz/stateless/releases/download/reth-guest-v0.1.0-rc.1/stateless-validator-reth-zisk-v1.0.0-alpha.elf
# sha256: 4be1da7ef95b07c4158ca3a08078d6db0fcbaddca9ff37e5c74453a984e6dc40

Run

~/.zisk/bin/ziskemu \
  -e stateless-validator-reth-zisk-v100.elf \
  -i block115260.input \
  -m -X --sdk

Output

STEPS      124,579,543
COST    14,873,440,147
RAM    2571.78 MB / 0.00 MB

Base         █    287,309,824   1.9%
Main         ████ 8,471,408,924  57.0%
Opcodes      ██   4,070,136,570  27.4%
Precompiles  █    1,244,717,427   8.4%
Memory       █      799,867,402   5.4%

process_rom() steps=124579543 duration=5.0437 tp=24.6999 Msteps/s

Note: ziskemu warns DEPRECATED INSTRUCTION: dma_memcmp — the reth rc.1 ELF was compiled with the older ZisK v1.0.0-alpha toolchain. The emulator still executes it correctly; the cost numbers are directionally accurate.


Notes

  • ZisK cost is a proving-complexity metric (Base + Main + Opcodes + Precompiles + Memory). It determines how the ZisK prover parallelises segments; it is not wall time.
  • Base cost (287,309,824) is the fixed ZisK ROM startup overhead, identical for both guests.
  • The EvmAsm guest does not use ZisK's heap allocator (RAM 0.00 MB); reth uses ~2.6 GB of emulated RAM for its in-memory trie.
  • EvmAsm's high precompile cost reflects keccak256 hashing over witness trie nodes. reth's high Main+Opcodes cost reflects its general-purpose Rust interpreter loop.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment