Overview
Jolt’s instruction lookup system proves that each instruction in the execution trace produces the correct output. Instead of implementing instruction logic as R1CS constraints (which would be massive), Jolt uses a novel lookup argument that proves instruction correctness by looking up precomputed outputs in committed tables.Role in the Proving System
Instruction lookups are central to Jolt’s efficiency:- Stage: Stage 5 (Instruction Lookups)
- Input: Execution trace with instruction operands (RS1, RS2, immediate)
- Method: Lookup outputs in committed tables, prove via sumcheck
- Output: Opening claims for instruction flags and lookup results
- Benefit: Drastically smaller proof size than constraint-per-instruction approaches
Instruction Decomposition
Subtable Structure
Jolt decomposes each instruction into small subtables: Example: 64-bit XOR- Naive approach: 2^128 entry table (operands A, B)
- Jolt approach: Split operands into 8-byte chunks
- 8 subtables, each 2^16 entries (8-bit input, 8-bit output)
- Total size: 8 · 2^16 = 524,288 entries (vs. 2^128)
Virtual vs. Physical Instructions
Physical instructions:- Direct RISC-V opcodes (ADD, XOR, LOAD, etc.)
- One lookup per instruction
- Multi-cycle operations (e.g., 256-bit multiplication)
- Decomposed into multiple subtable lookups
- Used by jolt-inlines for optimized cryptographic operations
Lookup Argument Protocol
Jolt uses the Twist/Shout lookup argument (modified Lasso):High-Level Protocol
- Prover commits to subtables (one-time preprocessing)
- Trace generation: For each instruction, record:
- Instruction flags (one-hot encoding of opcode)
- Operands (RS1, RS2, immediate)
- Chunk indices (operands split into subtable indices)
- Sumcheck: Prove that looked-up values match instruction outputs
- Opening proofs: Verify subtable commitments at queried indices
RA (Read-After) Polynomial
The RA polynomial encodes which table entry is accessed:RAF (Read-After-Final) Checking
Similar to RAM checking, instruction lookups verify RAF=0 to ensure:- No lookups to invalid table entries
- All lookups reference valid subtable indices
Instruction Flags
Each cycle has instruction flags (one-hot encoding):- Activate correct subtable lookups for each instruction
- Used in R1CS constraints to conditionally enforce instruction semantics
- One flag set per cycle (except no-ops)
Subtable Implementations
Lookup Table Trait
Example: XOR Table
Subtable Categories
Arithmetic: ADD, SUB, MUL, DIV Logical: AND, OR, XOR, NOT Shifts: SLL, SRL, SRA, rotate Comparisons: LT, LTE, EQ Memory: Load/store address computation Specialized: Sign extension, byte reversal, bit countingInstruction Lookups Sumcheck (Stage 5)
RA Virtual Sumcheck
Purpose: Reduce RA polynomial claims to subtable evaluations. Sumcheck claim:RA_instruction(x) is the RA polynomial for instruction lookups at cycle x.
Polynomial structure:
- One RA polynomial per instruction type
- Shared across multiple subtables (prefix/suffix decomposition)
- Lazy materialization via
SharedRaPolynomials(memory optimization)
Read-RAF Checking
Purpose: Verify no invalid lookups (like RAM RAF checking). Sumcheck claim:Performance Characteristics
Prover Time
Subtable commitment (one-time preprocessing):- O(table_size · log(table_size)) field operations
- ~1-5 seconds for all subtables (amortized across all proofs)
- O(trace_length · num_subtables · log(table_size))
- ~15-20% of total proving time
Memory Usage
Subtable storage:- ~50-100MB for all RISC-V subtables
- Shared across all proofs (one-time cost)
- Uses
SharedRaPolynomialsto deduplicate equality tables - ~10-20MB for 10⁶ cycles
Proof Size
Without lookups (naive R1CS):- Would require ~1000 constraints per instruction type
- Proof size: O(num_instructions · trace_length)
- O(num_subtables · log(table_size))
- ~10x smaller proof size for typical workloads
Verifier Time
- O(num_subtables · log(trace_length))
- ~1-3ms for typical traces
- Verifies sumcheck round polynomials + subtable commitment openings
Comparison with Other zkVMs
| Approach | Jolt (Lookups) | Cairo (AIR) | RISC Zero (AIR) | Polygon Miden (Lookups) |
|---|---|---|---|---|
| Instruction cost | O(log table_size) | O(degree) | O(degree) | O(log table_size) |
| Proof size | Logarithmic | Linear | Logarithmic | Logarithmic |
| Setup | Subtable commitment | None | None | Subtable commitment |
| Flexibility | High (custom tables) | Medium | Medium | High |
Optimizations
Prefix/Suffix Decomposition
Problem: Some instructions need different lookup tables for different operand chunks. Solution: Split polynomials as:Shared RA Polynomials
Problem: Multiple instructions share subtable structures (e.g., all shifts use same bit-extraction tables). Solution:SharedRaPolynomials deduplicates equality tables:
Lazy RA Materialization
Problem: Materializing full RA polynomials for all instructions is expensive. Solution:RaPolynomial uses lazy state machine:
Key Files
jolt-core/src/zkvm/instruction_lookups/ra_virtual.rs: RA polynomial sumcheckjolt-core/src/zkvm/instruction_lookups/read_raf_checking.rs: RAF verificationjolt-core/src/zkvm/lookup_table/: All subtable implementationsjolt-core/src/poly/ra_polynomial.rs: Lazy RA polynomial materializationjolt-core/src/poly/shared_ra_polynomials.rs: Shared equality table optimization
Next Steps
- Bytecode: Instruction encoding and PC mapping
- Opening Proofs: Verifying subtable commitments
- Spartan: Integration with R1CS constraints