Provide non-deterministic hints to guest programs using the advice system
Jolt’s advice system allows guest programs to receive non-deterministic hints (witnesses) from the prover. This enables efficient zero-knowledge proofs for computations that require witness data.
UntrustedAdvice<T> is provided by the prover but must be verified:
pub struct UntrustedAdvice<T> { value: T,}
Use untrusted advice for:
Witness data
Intermediate computation results
Optimization hints
Example:
#[jolt::provable]fn verify_factors( n: u64, factors: jolt::UntrustedAdvice<(u64, u64)>,) -> bool { let (a, b) = *factors; // CRITICAL: Must verify untrusted advice! a * b == n && a > 1 && b > 1}
Always verify untrusted advice! Untrusted data comes from the prover and could be malicious. Use check_advice! macros.
#[jolt::advice]fn factor_u32(n: u32) -> jolt::UntrustedAdvice<(u32, u32)> { // Expensive computation runs OUTSIDE the proof for i in 2..=n { if n % i == 0 { return (i, n / i); } } (1, n)}
How it works:
During advice computation phase (feature compute_advice):
#[jolt::provable]fn verify_composite(n: u32) -> bool { // Get factors from advice let factors_advice = factor_u32(n); let (a, b) = *factors_advice; // Deref UntrustedAdvice // MUST verify the advice! jolt::check_advice_eq!(a * b, n); jolt::check_advice!(a > 1 && b > 1 && a <= b); true}
use bytemuck_derive::{Pod, Zeroable};use jolt::JoltPod;#[derive(Copy, Clone, Pod, Zeroable)]#[repr(C)]struct Point { x: u32, y: u32,}impl JoltPod for Point {}// Point now works with advice automatically!#[jolt::advice]fn get_point() -> jolt::UntrustedAdvice<Point> { Point { x: 10, y: 20 }}
/// Provide indices showing that `a` is a subset of `b`#[jolt::advice]fn subset_index(a: &[usize], b: &[usize]) -> jolt::UntrustedAdvice<Vec<usize>> { let mut indices = Vec::new(); for &item in a { for (i, &b_item) in b.iter().enumerate() { if item == b_item { indices.push(i); break; } } } indices}/// Verify that all elements of `a` exist in `b`fn verify_subset(a: &[usize], b: &[usize]) { let advice = subset_index(a, b); let indices = &*advice; // Verify advice correctness jolt::check_advice_eq!(indices.len(), a.len()); for (i, &item) in a.iter().enumerate() { let idx = indices[i]; jolt::check_advice!(idx < b.len()); jolt::check_advice_eq!(b[idx], item); }}#[jolt::provable]fn prove_subset(a: Vec<usize>, b: Vec<usize>) { verify_subset(&a, &b);}
#[jolt::advice]fn factor(n: u64) -> jolt::UntrustedAdvice<(u64, u64)> { /* expensive factorization */}#[jolt::provable]fn prove_composite(n: u64) -> bool { let (a, b) = *factor(n); jolt::check_advice_eq!((a as u128) * (b as u128), n as u128); jolt::check_advice!(1 < a && a <= b && b < n); true}