This sample shows how to drive the RISC Zero zkVM with a C guest that compiles
other C code. The guest embeds a lightly modified copy of
chibicc. When the host provides a source
file (main.c by default) the guest parses it, emits x86-64 style assembly, and
commits both the input and generated output to the zkVM journal. A separate
verifier binary demonstrates how to check the resulting receipt and recover the
assembly listing.
See Verifiable Provenance of Software Artifacts with Zero-Knowledge Compilation
guest/– C sources for the guest program.main.ccreates the execution environment, invokes the tokenizer, parser, and code generator (tokenize.c,parse.c,type.c,codegen.c), and streams the resulting log back to the host.platform/– Rust crate compiled to a static library that provides the shim used by the C guest (init_allocator,env_read,env_commit,env_exit, SHA-256 helpers, etc.).host/– Rust binary that builds the guest image, feeds the guest withmain.c, and writes the resulting receipt toout/receipt.bin.verifier/– Rust binary that loads the stored receipt, verifies it against the computed image ID, prints the journal contents, and saves the generated assembly toprogram.s.input/main.c– (workspace root) – program to be compiled.csmith-programs– Synthetic programs for tool validaiton.libsodium-/*– Programs and copmilation/verification results for a subset of libsodium source files, includig tampering experiments.openssl-/*– Programs and copmilation/verification results for a subset of OpenSSL source files, including tampering experiments.
- rustup with the RISC Zero toolchain installed (
rzup install rust). cargoavailable in your shell (set automatically byrzup).- Optional:
cbindgenif you intend to regenerate the guest header viamake headers.
Note: The build scripts use
rzupto locate the appropriate toolchain. Ensurerzupis on yourPATHbefore running the commands below.
The Makefile mirrors the logic in the Cargo build scripts and is convenient
for end-to-end runs.
# Build the guest image, execute inside the zkVM, and emit a receipt in dev mode
make execute
# Produce an attested receipt (same as execute, but without dev mode shortcuts)
make prove
# Verify an existing receipt and write the generated assembly to program.s
make verify
# Assemble output program
make assembleBehind the scenes these steps:
- Compile the
zkvm-platformcrate to a static library (platform/src/lib.rs) so that the guest can call into the zkVM syscalls. - Build the C guest sources into
guest/out/main. - Run the host binary (
c-guest-host) which reads./main.c, writes it to the guest viaExecutorEnv, and saves the resulting receipt. - (For
make verify) Run the verifier binary to recompute the image ID usingProgramBinary, validate the receipt, and export the journal payload toprogram.s.
You can also drive the components manually with Cargo:
# Build everything (host build.rs handles the guest compilation)
cargo run -p c-guest-host
# After a receipt exists in out/receipt.bin
cargo run -p verifierEdit the workspace-level main.c to change the program compiled by the guest.
When you rerun make execute or cargo run -p c-guest-host, the host reloads
the file, the guest recompiles it deterministically, and the verifier will emit
the new assembly listing. The guest input buffer is limited to 256 bytes, so
keep the example small or update guest/main.c if you need more room.
out/receipt.bin– Binary-encoded receipt saved by the host.program.s– Assembly recovered by the verifier from the journal payload.- Journal contents also include the original source (first 256 bytes) followed
by the log buffer produced by
codegen.c.
- Ensure
rzuphas installed the Rust toolchain and that thecargo +risc0targets are available; otherwise the host build script will panic. - If you regenerate headers with
make headers, runmake executeafterward to rebuild the guest with the updated platform bindings. - Receipts must be generated (
make executeormake prove) before runningmake verify. - The
Cargo.tomlfiles in this repo reference RISC Zero crates via relativepathdependencies (e.g.path = "../../../risc0/zkvm"). If you cloned this repository outside the RISC Zero monorepo tree, those paths won't resolve. Update them to point to your local checkout ofrisc0, or replace them with registry / git dependencies (e.g.risc0-zkvm = "1.x").