> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/a16z/jolt/llms.txt
> Use this file to discover all available pages before exploring further.

# Runtime Advice

> 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.

## Why Advice?

Some computations are easy to verify but hard to compute:

* **Factoring**: Given `n = a * b`, computing `(a, b)` is hard, but verifying is trivial
* **Path finding**: Finding a path is hard, verifying a path is easy
* **Merkle proofs**: Computing the proof path is non-trivial, verification is simple
* **Preimages**: Finding `x` such that `hash(x) = y` is hard, checking is easy

Advice lets the prover provide the "hard part" (witness) while the guest verifies correctness inside the zkVM.

## Types of Advice

### TrustedAdvice

`TrustedAdvice<T>` is committed before the prover sees any challenges:

```rust theme={null}
pub struct TrustedAdvice<T> {
    value: T,
}
```

**Use trusted advice for:**

* Secret keys
* Private witness data
* Data that must be hidden from the verifier

**Example:**

```rust theme={null}
#[jolt::provable]
fn prove_knowledge(
    public_key: [u8; 32],
    secret: jolt::TrustedAdvice<[u8; 64]>,
) -> bool {
    let derived_pubkey = derive_public_key(&secret);
    derived_pubkey == public_key
}
```

The verifier only sees the commitment to `secret`, never the value itself.

### UntrustedAdvice

`UntrustedAdvice<T>` is provided by the prover but must be verified:

```rust theme={null}
pub struct UntrustedAdvice<T> {
    value: T,
}
```

**Use untrusted advice for:**

* Witness data
* Intermediate computation results
* Optimization hints

**Example:**

```rust theme={null}
#[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
}
```

<Warning>
  **Always verify untrusted advice!** Untrusted data comes from the prover and could be malicious. Use `check_advice!` macros.
</Warning>

## Runtime Advice Functions

The `#[jolt::advice]` macro creates dual-mode advice functions:

### Basic Advice Function

```rust theme={null}
#[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:**

1. **During advice computation phase** (feature `compute_advice`):
   * Function body executes
   * Result is written to advice tape via `AdviceTapeIO`

2. **During proof generation** (without `compute_advice`):
   * Function body is skipped
   * Result is read from advice tape

### Using Advice in Guests

```rust theme={null}
#[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
}
```

## Verification Macros

### check\_advice!

Verifies a boolean condition:

```rust theme={null}
jolt::check_advice!(condition);
jolt::check_advice!(condition, "error message");
```

**Implementation:**

* On RISC-V: Emits `VirtualAssertEQ` custom instruction
* On native: Regular `assert!`

**Example:**

```rust theme={null}
let advice = get_merkle_proof(leaf);
jolt::check_advice!(advice.len() == expected_depth);
jolt::check_advice!(verify_proof(&advice), "Invalid Merkle proof");
```

### check\_advice\_eq!

Verifies equality directly (more efficient):

```rust theme={null}
jolt::check_advice_eq!(left, right);
jolt::check_advice_eq!(left, right, "error message");
```

**Example:**

```rust theme={null}
let factors = factor_u64(n);
let (a, b) = *factors;
jolt::check_advice_eq!((a as u128) * (b as u128), n as u128);
```

<Note>
  `check_advice_eq!` requires values that fit in registers. For `u128`, use `check_advice!` instead.
</Note>

## AdviceTapeIO Trait

Custom types need to implement `AdviceTapeIO` to work with advice:

### Automatic Implementation (Pod Types)

```rust theme={null}
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 }
}
```

### Manual Implementation

```rust theme={null}
struct CustomData {
    a: u8,
    b: Vec<u16>,
    c: u64,
}

impl jolt::AdviceTapeIO for CustomData {
    fn write_to_advice_tape(&self) {
        self.a.write_to_advice_tape();
        self.b.write_to_advice_tape();
        self.c.write_to_advice_tape();
    }
    
    fn new_from_advice_tape() -> Self {
        CustomData {
            a: u8::new_from_advice_tape(),
            b: Vec::<u16>::new_from_advice_tape(),
            c: u64::new_from_advice_tape(),
        }
    }
}
```

### Built-in Implementations

* Primitives: `u8`, `u16`, `u32`, `u64`, `i8`, `i16`, `i32`, `i64`, `usize`
* Arrays: `[T; N]` where `T: Pod`
* Tuples: Up to 7 elements where each implements `AdviceTapeIO`
* Vectors: `Vec<T>` where `T: Pod` (requires `std` or `guest-std`)

## Advanced Example: Subset Verification

```rust theme={null}
/// 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);
}
```

## Low-Level Advice API

For advanced use cases, use the raw advice tape API:

### AdviceWriter (Compute Advice Phase)

```rust theme={null}
let mut writer = jolt::AdviceWriter::get();
writer.write_u8(42);
writer.write_u32(0xdeadbeef);
writer.write_u64(123456789);
```

### AdviceReader (Proof Generation Phase)

```rust theme={null}
let mut reader = jolt::AdviceReader::get();
let value = reader.read_u8();
let count = reader.read_u32();
let data = reader.read_u64();

// Check remaining bytes
let remaining = reader.bytes_remaining();
```

<Warning>
  Raw advice API is error-prone. Prefer `#[jolt::advice]` functions which handle serialization automatically.
</Warning>

## Two-Pass Execution

Jolt uses a two-pass strategy for advice:

### Pass 1: Compute Advice

Guest builds with `compute_advice` feature:

* Advice functions execute their bodies
* Results written to advice tape
* Tape is saved

### Pass 2: Generate Proof

Guest builds without `compute_advice`:

* Advice functions read from tape
* Bodies are not executed
* Proof is generated

**This is handled automatically by the `#[jolt::provable]` macro.**

## Best Practices

<CardGroup cols={2}>
  <Card title="Always Verify" icon="shield-check">
    Use `check_advice!` for all `UntrustedAdvice`. Never trust prover-provided data.
  </Card>

  <Card title="Use Trusted for Secrets" icon="lock">
    Secrets should be `TrustedAdvice`, never public inputs or `UntrustedAdvice`.
  </Card>

  <Card title="Optimize Advice Computation" icon="gauge-high">
    Advice functions run outside the proof. Use efficient native algorithms.
  </Card>

  <Card title="Minimize Advice Size" icon="minimize">
    Large advice increases memory usage. Provide minimal witness data.
  </Card>
</CardGroup>

## Common Patterns

### Pattern: Factorization Witness

```rust theme={null}
#[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
}
```

### Pattern: Merkle Proof Verification

```rust theme={null}
#[jolt::advice]
fn get_merkle_proof(
    tree: &MerkleTree,
    leaf: [u8; 32]
) -> jolt::UntrustedAdvice<Vec<[u8; 32]>> {
    tree.proof_for_leaf(leaf)
}

#[jolt::provable]
fn verify_membership(
    root: [u8; 32],
    leaf: [u8; 32],
    tree: jolt::UntrustedAdvice<MerkleTree>,
) -> bool {
    let proof = get_merkle_proof(&tree, leaf);
    verify_merkle_proof(root, leaf, &proof)
}
```

### Pattern: Search Result

```rust theme={null}
#[jolt::advice]
fn find_index(haystack: &[u8], needle: u8) -> jolt::UntrustedAdvice<usize> {
    haystack.iter().position(|&x| x == needle).unwrap_or(haystack.len())
}

fn search(haystack: &[u8], needle: u8) -> Option<usize> {
    let idx = *find_index(haystack, needle);
    jolt::check_advice!(idx <= haystack.len());
    if idx < haystack.len() {
        jolt::check_advice_eq!(haystack[idx], needle);
        Some(idx)
    } else {
        None
    }
}
```

## Related Concepts

* [Provable Macro](/concepts/provable-macro) - Configure advice memory sizes
* [Guest and Host Architecture](/concepts/guests-and-hosts) - Understanding guest/host separation
