Skip to main content

Overview

AdviceReader provides low-level access to read data from the advice tape during the proving phase of a zkVM program. The advice tape is a mechanism for the prover to provide non-deterministic inputs to the guest program that can be verified within the zkVM.
Reading beyond the end of the advice tape will result in a runtime error during proof generation.

Type Definition

pub struct AdviceReader;

Methods

get

Returns a reference to the global advice reader.
pub fn get() -> Self
Returns: An AdviceReader instance Example:
use jolt_sdk::AdviceReader;

let mut reader = AdviceReader::get();

read_u8

Reads a single byte (u8) from the advice tape.
pub fn read_u8(&mut self) -> u8
Returns: The next byte from the advice tape Example:
let mut reader = AdviceReader::get();
let byte_value = reader.read_u8();
This method is only available on RISC-V targets (riscv32 or riscv64). On other targets, it will panic.

read_u16

Reads a halfword (2 bytes, u16) from the advice tape in little-endian format.
pub fn read_u16(&mut self) -> u16
Returns: The next 2 bytes from the advice tape as a u16 Example:
let mut reader = AdviceReader::get();
let halfword_value = reader.read_u16();

read_u32

Reads a word (4 bytes, u32) from the advice tape in little-endian format.
pub fn read_u32(&mut self) -> u32
Returns: The next 4 bytes from the advice tape as a u32 Example:
let mut reader = AdviceReader::get();
let word_value = reader.read_u32();

read_u64

Reads a doubleword (8 bytes, u64) from the advice tape in little-endian format.
pub fn read_u64(&mut self) -> u64
Returns: The next 8 bytes from the advice tape as a u64 Example:
let mut reader = AdviceReader::get();
let doubleword_value = reader.read_u64();
On 32-bit RISC-V targets (riscv32), this is performed via two 4-byte reads. On 64-bit targets (riscv64), it’s a single 8-byte read.

bytes_remaining

Returns the number of bytes remaining in the advice tape.
pub fn bytes_remaining(&mut self) -> u64
Returns: The count of unread bytes in the advice tape Example:
let mut reader = AdviceReader::get();
let remaining = reader.bytes_remaining();
println!("Bytes left: {}", remaining);

Usage Example

Basic Reading

use jolt_sdk::AdviceReader;

#[jolt::provable]
fn read_advice_data() -> (u8, u16, u32, u64) {
    let mut reader = AdviceReader::get();
    
    let byte = reader.read_u8();
    let halfword = reader.read_u16();
    let word = reader.read_u32();
    let doubleword = reader.read_u64();
    
    (byte, halfword, word, doubleword)
}

Reading with Length Checking

use jolt_sdk::{AdviceReader, check_advice};

#[jolt::provable]
fn safe_read_advice() -> Vec<u64> {
    let mut reader = AdviceReader::get();
    let mut result = Vec::new();
    
    while reader.bytes_remaining() >= 8 {
        result.push(reader.read_u64());
    }
    
    result
}

Reading Complex Types

For reading complex types, use the AdviceTapeIO trait:
use jolt_sdk::AdviceTapeIO;

#[jolt::provable]
fn read_vec() -> Vec<u32> {
    // Automatically reads length, capacity, and data
    Vec::<u32>::new_from_advice_tape()
}

#[jolt::provable]
fn read_tuple() -> (u64, u32, u16) {
    <(u64, u32, u16)>::new_from_advice_tape()
}

Platform Support

The following table shows platform-specific behavior:
TargetSupportedNotes
riscv32Yesread_u64 uses two 4-byte reads
riscv64YesFull native support
OthersNoAll methods panic

Implementation Details

RISC-V Custom Instructions

AdviceReader uses custom RISC-V instructions to read from the advice tape:
  • FUNCT3_ADVICE_LB (0b011) - Load byte
  • FUNCT3_ADVICE_LH (0b100) - Load halfword
  • FUNCT3_ADVICE_LW (0b101) - Load word
  • FUNCT3_ADVICE_LD (0b110) - Load doubleword
  • FUNCT3_ADVICE_LEN (0b111) - Get remaining bytes
These are encoded using the custom opcode 0x5B.

Memory Alignment

When reading slices of data (via AdviceTapeIO trait implementations), AdviceReader optimizes for alignment:
  1. Performs largest aligned reads possible until 8-byte boundary
  2. Reads in aligned 8-byte chunks
  3. Handles remaining bytes greedily with aligned reads/writes
See jolt-sdk/src/lib.rs:344 for the internal read_slice implementation.

See Also

Build docs developers (and LLMs) love