Skip to main content
Version: 0.20

Building zkVM Hello World

This tutorial will walk you through building your first zkVM application. By following the steps in this guide, you will learn how:

  • to use the cargo-risczero tool to create a new project
  • to send private data to the guest program
  • the zkVM executes and generates a proof of a guest program
  • the guest writes public output

Step 1: Create a new project

Firstly, visit the installation page for how to install all the necessary software. Next, using the cargo-risczero tool create a hello-world project from the command line. The cargo-risczero tool provides a --guest-name parameter which allows control over the name of the guest program:

cargo risczero new hello-world --guest-name hello_guest
cd hello-world

In the project folder, hello-world, build and run the project using cargo run --release. Use this command any time you'd like to check your progress.

Step 2 (Host): Share private data as input with the guest

zkVM or a prover runs on the host. The host code is in hello-world/host/src/ The host creates an executor environment ExecutorEnv before constructing a prover. The host makes the value input available to the guest before execution. It does it by adding input to the executor environment, which is responsible for managing guest-readable memory. When the prover executes the program, it can access input:

use risc0_zkvm::{default_prover, ExecutorEnv};

fn main() {
let input: u32 = 7;
let env = ExecutorEnv::builder().write(&input).unwrap().build().unwrap();

Step 3 (Guest): Read input and commit output

Now, let's look at the guest code located in methods/guest/src/ This is the portion of the code that will be proven. In the code snippet below, the guest reads the input value from the host and then commits it to the journal portion of the receipt.

use risc0_zkvm::guest::env;

fn main() {
// read the input
let input: u32 = env::read();

// do something with the input
// writing to the journal makes it public

The env::commit function commits public results to the journal. Once committed to the journal, anyone with the receipt can read this value.

Notice, by committing any private information to the journal, we make this private data public. We want to avoid committing sensitive data to public journal.

Step 4 (Host): Generate a receipt and read its journal contents

Let's look at how the host generates a receipt and extracts the journal's contents. We get a receipt, extract a journal from the receipt, and verify it. In a real-world scenario, we'd want to hand the receipt to someone else for verification, and the prove function does internal verification of the receipt. After we extract the journal from the receipt, let's print Hello world with the public output by adding this line to the host:

println!("Hello, world! I generated a proof of guest execution! {} is a public output from journal", output);
use risc0_zkvm::{default_prover, ExecutorEnv};

fn main() {
let input: u32 = 15 * u32::pow(2, 27) + 1;
let env = ExecutorEnv::builder().write(&input).unwrap().build().unwrap();

// Obtain the default prover.
let prover = default_prover();

// Produce a receipt by proving the specified ELF binary.
let receipt = prover.prove(env, HELLO_GUEST_ELF).unwrap();

// Extract journal of receipt
let output: u32 = receipt.journal.decode().unwrap();

// Print, notice, after committing to a journal, the private input became public
println!("Hello, world! I generated a proof of guest execution! {} is a public output from journal ", output);

You should now be able to see your proof with cargo run --release. If your program printed the "Hello, world!" assertion and receipt verification was a success, congratulations! If not, we hope that troubleshooting will get you familiar with the system, and we'd love to chat with you on Discord. Or, if you believe you've found a bug or other problem in our code, please open an issue describing the problem.

If you're ready to start building more complex projects, we recommend taking a look at the other examples for more project ideas that use zero-knowledge proofs.