A fast, modular, optimized ZKEVM core written in C++
[ALPHA STAGE: This is in pre-release. Functional for block execution and proof generation, but not yet production-ready.]
Zilkworm is a prototype implementation of a ZKEVM (Zero-Knowledge Ethereum Virtual Machine) generating ZK proofs that an
Ethereum block was executed correctly, without requiring re-execution of the block itself.
Zilkworm is written in C++ (with a Rust orchestration layer) building on past works within Silkworm and EVMOne to run on zkVM provers with native support for RISC-V targets (e.g. rv32im). At the moment, the zkVM integrated is Succint's SP1 Hypercube.
High-Level Workflow
- Fetch — Retrieve a block + its execution witness from an Ethereum RPC node (Reth/Geth)
- Execute (dry-run) — Run the EVM inside the zkVM without proof generation (for testing)
- Prove — Generate a full ZK proof of correct block execution
- Verify — Verify a previously generated proof
- Service mode — Continuously poll a node and prove blocks as they arrive
Architecture
For a high-level overview of the system, see here.
How ZK Ethereum Provers Work Generally
The broader idea: a ZK prover takes an Ethereum block + pre-state witness, re-executes all transactions inside a zkVM and produces a cryptographic proof that the execution was done correctly. This proof can be verified cheaply by anyone on a lighter hardware without re-executing the block. This also enables other applications like light clients, bridges, and rollup verification.
Zilkworm sits alongside other ZKEVM provers in this ecosystem, differentiated by its approach of running a C++ EVM inside the zkVM rather than a Rust one.
At the moment the building from source requires elaborate setup with conan, linux packages and SP1 Turbo SDK pre-requisites. It's recommended to use the pre-built docker image.
To run with pre-built docker
$ docker run somnergy/z6m_prover --help
Usage: z6m_prover [OPTIONS] [COMMAND]
Commands:
setup Run setup to generate proving and verifying keys
fetch Fetch block and witness from RPC
execute Execute the guest program without proving
prove Generate a proof for a block
verify Verify a proof using a verification key
help Print this message or the help of the given subcommand(s)
Options:
--service
--rpc-url <RPC_URL>
--data-dir <DATA_DIR> [default: temp]
--save-all-responses
--prove-every <PROVE_EVERY>
--execute-every <EXECUTE_EVERY>
--post-every <POST_EVERY>
--start-block <START_BLOCK>
--end-block <END_BLOCK>
--pk-path <PK_PATH> [default: pk.bin]
--proof-type <PROOF_TYPE> [default: compressed]
--ethproofs-endpoint <ETHPROOFS_ENDPOINT>
--ethproofs-token <ETHPROOFS_TOKEN>
--ethproofs-cluster-id <ETHPROOFS_CLUSTER_ID>
-h, --help
Usage: z6m_prover fetch [OPTIONS]
Options:
--rpc-url <RPC_URL> RPC endpoint URL
--block-number <BLOCK_NUMBER> Block number to fetch
--data-dir <DATA_DIR> Output directory
--save-all-responses Whether to save all the json files to disk after download
--build-eth-test Whether to create an ethereum/tests format json file too
-h, --help Print help
Usage: z6m_prover execute [OPTIONS]
Options:
--block-number <BLOCK_NUMBER> Block number to execute [default: 0]
--file-name <FILE_NAME> Whether the input file is an Ethereum/tests file
--is-test
--data-dir <DATA_DIR> Data directory
-h, --help Print help
Usage: z6m_prover prove [OPTIONS]
Options:
--block-number <BLOCK_NUMBER> JSON file to load ethereum/tests format test from [default: 0]
--file-name <FILE_NAME> Whether the input file is an Ethereum/tests file
--is-test
--data-dir <DATA_DIR> Data directory
--pk-path <PK_PATH> Proving key path [default: pk.bin]
--proof-path <PROOF_PATH> Proof output path
--proof-type <PROOF_TYPE> Proof type: core, compressed, groth16, plonk [default: compressed]
-h, --help Print help
Execute a range of blocks from disk without RPC or prover key setup:
z6m_prover --test-service \
--data-dir /path/to/witness_blocks \
--start-block 24490786 --end-block 24490805 \
--execute-every 1Blocks are read from <data-dir>/blocks/<block_number>/unifiedBlockAndStateRlp<block_number>.bin. Missing blocks are skipped with a warning. Results are appended to <data-dir>/executionLogs.log.
z6m_prover execute --file-name /path/to/unifiedBlockAndStateRlp24490786.bin --data-dir /path/to/outputInstall the Python dependencies first:
pip install -r requirements.txtPlot execution metrics from the log file:
python3 prover/prover_hypercube/src/stats/cycle_stats.py \
-i /path/to/executionLogs.log \
-o /path/to/results_plot.png \
--no-displayFirst make sure to install NVIDIA drivers and the NVIDIA Container Toolkit https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
$ user@machine-with-gpu
docker run --gpus all --rm --network host -v "$PWD:/work:rw" -v /var/run/docker.sock:/var/run/docker.sock -w /work -it --entrypoint bash somnergy/z6m_prover
root@instance-20250919-091229:/work#
SP1_PROVER=cuda RUST_BACKTRACE=full RUST_LOG=info --prove --n 1 --file-name test.json
- Download and unpack the latest stable EEST release.
- Configure and build the CMake project with the path to the blockchain tests of the EEST:
cmake -B build/release -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DTESTS_DIR=/path/to/fixtures/blockchain_tests cmake --build build/release
- Run all tests with CTest:
ctest --test-dir build/release --parallel
- Run specific unified RLP-encoded block file:
build/release/zilk_core/dev/cli/state_transition temp/blocks/23519000/unifiedBlockAndStateRlp23519000.bin
We thank the hard work done by the teams and people behind
- Silkworm
- EVMOne (especially @chfast)
- Succicnt (for SP1 and rsp)
- RISCV
- C++ Conglomerate
- The Rust community