Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/risc0/risc0/llms.txt

Use this file to discover all available pages before exploring further.

Guest code is the program that executes inside the RISC Zero zkVM and gets proven. The guest code runs in a constrained RISC-V environment and produces cryptographic proofs of correct execution.

Basic Structure

A minimal guest program requires three components:
#![no_main]
#![no_std]

use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    // Your guest code here
}
The #![no_main] and #![no_std] attributes are required when not using the std feature. These keep the guest binary lightweight for better performance.

Boilerplate Explained

  • #![no_std] - Excludes the Rust standard library to keep the guest code lightweight and performant
  • #![no_main] - Indicates this is not a standalone executable with a standard entry point
  • risc0_zkvm::guest::entry!(main) - Macro that designates which function to call when the host starts executing the guest code

Reading Input Data

Guest programs receive private inputs from the host using the env::read() function:
use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    // Read a single value
    let a: u64 = env::read();
    let b: u64 = env::read();
    
    // Compute with the inputs
    let result = a.checked_mul(b).expect("Integer overflow");
}

Reading Slices (Performance Optimized)

For better performance, use env::read_slice() to read raw bytes without deserialization overhead:
use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    // Read the length first
    let len: usize = env::read();
    
    // Allocate and read the slice
    let mut data = vec![0u8; len];
    env::read_slice(&mut data);
}
Performance matters in zkVM guest code. Use _slice variants when working with large amounts of data to reduce cycle count and proof generation time.

Committing to the Journal

The journal contains public outputs that are included in the receipt and available to verifiers:
use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    let a: u64 = env::read();
    let b: u64 = env::read();
    
    if a == 1 || b == 1 {
        panic!("Trivial factors");
    }
    
    let product = a.checked_mul(b).expect("Integer overflow");
    
    // Commit the result to the journal (public output)
    env::commit(&product);
}

Committing Slices

For performance-critical applications, commit slices directly:
use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    let data = [1u8, 2, 3, 4];
    
    // Commit raw bytes to the journal
    env::commit_slice(&data);
}

Writing Private Output

Use env::write() to send private data back to the host (not included in the receipt):
use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    let intermediate_result = 42;
    
    // Send private data to the host
    env::write(&intermediate_result);
}

Working with Complex Data Types

Guest programs support serialization with serde:
use risc0_zkvm::guest::env;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct Input {
    value: u64,
    metadata: String,
}

#[derive(Serialize)]
struct Output {
    result: u64,
    hash: [u8; 32],
}

risc0_zkvm::guest::entry!(main);

fn main() {
    // Read structured input
    let input: Input = env::read();
    
    // Process
    let output = Output {
        result: input.value * 2,
        hash: [0; 32],
    };
    
    // Commit structured output
    env::commit(&output);
}

Real-World Example: JSON Processing

Here’s an example from the RISC Zero examples that processes JSON data:
use json::parse;
use risc0_zkvm::{
    guest::env,
    sha::{Impl, Sha256},
};

fn main() {
    // Read JSON string from host
    let data: String = env::read();
    
    // Hash the input data
    let sha = *Impl::hash_bytes(&data.as_bytes());
    
    // Parse and extract critical data
    let data = parse(&data).unwrap();
    let proven_val = data["critical_data"].as_u32().unwrap();
    
    // Commit both the hash and extracted value
    let out = Outputs {
        data: proven_val,
        hash: sha,
    };
    env::commit(&out);
}

Debugging and Optimization

Logging

Use env::log() to print debug messages:
use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    env::log("Starting computation");
    
    let result = 42;
    env::log(&format!("Result: {}", result));
}

Cycle Counting

Measure performance with env::cycle_count():
use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    let start = env::cycle_count();
    
    // Your computation
    let result = expensive_computation();
    
    let end = env::cycle_count();
    env::log(&format!("Cycles: {}", end - start));
}
Warning: The cycle count is provided by the host and is not checked by the zkVM circuit. Use it only for debugging and optimization.

Advanced Features

File Descriptors

Access standard input/output streams directly:
use risc0_zkvm::guest::env;
use risc0_zkvm::guest::env::{Read, Write};

risc0_zkvm::guest::entry!(main);

fn main() {
    let mut stdin = env::stdin();
    let mut stdout = env::stdout();
    let mut journal = env::journal();
    
    // Use Read and Write traits
    stdin.read(&my_struct);
    stdout.write(&result);
    journal.write(&public_output);
}

Pausing and Exiting

Control zkVM execution flow:
use risc0_zkvm::guest::env;

risc0_zkvm::guest::entry!(main);

fn main() {
    // Pause execution (can be resumed later)
    env::pause(0);
    
    // Exit with status code
    env::exit(0); // Success
    // env::exit(1); // Error
}

Best Practices

1
Minimize Cycle Count
2
Use _slice variants for large data transfers and avoid unnecessary allocations.
3
Validate Input Early
4
Check input validity at the start to fail fast if data is invalid.
5
Use Appropriate Data Types
6
Choose the smallest sufficient types (e.g., u32 vs u64) to reduce cycle count.
7
Leverage Precompiles
8
Use built-in cryptographic functions like SHA-256 and Keccak for better performance.

See Also