Skip to main content

Overview

The prove_<function_name> function generates a zero-knowledge proof that a computation was executed correctly. It is automatically generated by the #[jolt::provable] macro for each provable function.

Function Signature

pub fn prove_<function_name>(
    mut program: jolt::host::Program,
    preprocessing: jolt::JoltProverPreprocessing<jolt::F, jolt::PCS>,
    // ... function arguments (public inputs, untrusted advice, trusted advice)
    // Optional: trusted_advice_commitment and trusted_advice_hint (if function has trusted advice)
) -> (ReturnType, jolt::RV64IMACProof, jolt::JoltDevice)

Parameters

  • program - The compiled guest program (obtained from compile_<function_name>)
  • preprocessing - Prover preprocessing data (obtained from preprocess_prover_<function_name>)
  • Function arguments in order:
    • Public inputs - Regular function parameters that become part of the proof statement
    • Untrusted advice - Parameters marked with jolt::UntrustedAdvice<T> wrapper
    • Trusted advice - Parameters marked with jolt::TrustedAdvice<T> wrapper
  • trusted_advice_commitment (optional) - Commitment to trusted advice, if function has trusted advice parameters
  • trusted_advice_hint (optional) - Opening proof hint for trusted advice commitment

Return Value

Returns a tuple containing:
  1. Return value - The function’s output (or () if no return value)
  2. Proof - The generated zero-knowledge proof (jolt::RV64IMACProof)
  3. Program I/O - I/O device state including inputs, outputs, and panic flag (jolt::JoltDevice)

Two-Pass Proving Strategy

The prove function uses a two-pass strategy for programs with advice:
  1. First pass (if compute_advice ELF exists): Runs the compute_advice version to populate the advice tape
  2. Second pass: Runs the normal version with the populated advice tape to generate the proof
This allows complex computations to be performed off-circuit while maintaining zero-knowledge properties.

Usage Example

Basic Usage

use std::time::Instant;

// Compile and preprocess
let target_dir = "/tmp/jolt-guest-targets";
let mut program = guest::compile_fib(target_dir);
let shared_preprocessing = guest::preprocess_shared_fib(&mut program);
let prover_preprocessing = guest::preprocess_prover_fib(shared_preprocessing);

// Generate proof
let now = Instant::now();
let (output, proof, io_device) = guest::prove_fib(program, prover_preprocessing, 50);
println!("Prover runtime: {} s", now.elapsed().as_secs_f64());

println!("Output: {}", output);
For repeated proving with the same preprocessing:
let prove_fib = guest::build_prover_fib(program, prover_preprocessing);

// Can now call prove_fib multiple times with different inputs
let (output1, proof1, io1) = prove_fib(10);
let (output2, proof2, io2) = prove_fib(20);
let (output3, proof3, io3) = prove_fib(30);

With Trusted Advice

For functions that use trusted advice, you must first commit to the advice:
let trusted_data = vec![1, 2, 3, 4, 5];

// Commit to trusted advice
let (commitment, hint) = guest::commit_trusted_advice_my_function(
    trusted_data.clone(),
    &prover_preprocessing,
);

// Generate proof with committed advice
let public_input = 42;
let (output, proof, io_device) = guest::prove_my_function(
    program,
    prover_preprocessing,
    public_input,
    trusted_data,
    commitment,
    hint,
);

Generated From

For a function annotated with #[jolt::provable]:
#[jolt::provable]
fn fib(n: u32) -> u32 {
    // function implementation
}
The macro generates prove_fib with the signature shown above.
  • verify - Verifies a generated proof
  • preprocess - Generates preprocessing data required for proving
  • analyze - Analyzes execution without generating a proof

Build docs developers (and LLMs) love