Overview
RAM read-write checking ensures that memory accesses are consistent throughout program execution. Every memory read must return the value from the most recent write to that address, and initial memory must match the program’s bytecode and inputs.Role in the Proving System
RAM checking is one of the most complex and performance-critical components:- Stages: Spans multiple stages (2, 4, 7)
- Stage 2: RAF evaluation and read-write checking
- Stage 4: Val evaluation and output checking
- Stage 7: Claim reductions
- Input: Execution trace with memory reads/writes
- Output: Opening claims proving memory consistency
- Cost: ~30-40% of total proving time
Memory Model
Address Space
Jolt uses a word-addressed memory model:- Word size: 8 bytes (64 bits)
- Address space: 2^K words (K configured per trace)
- Addressing: Byte addresses divided by 8, remapped to [0, 2^K)
Memory Layout
Memory Checking Protocol
Like register checking, RAM uses offline memory checking via multiset equality.Multiset Representation
Reads multisetR:
W:
Incremental Fingerprints
Fingerprints computed incrementally (like registers):(timestamp, address, value) as a field element.
RAM Checking Stages
Stage 2: Read-Write Checking & RAF Evaluation
Purpose: Core memory consistency check via fingerprint sumcheck. Sumcheck claim:final_ratio should equal ratio of initial states if R ⊆ W.
RAF Evaluation:
Read-After-Final (RAF) polynomial detects invalid reads:
Stage 4: Val Evaluation & Output Check
Val Evaluation: Computes memory value evaluations at challenge points:Stage 7: Claim Reductions
Aggregates RAM opening claims:- RA (Read-After) polynomial evaluations
- Incremental polynomial evaluations
- Final state polynomial evaluations
Initial and Final Memory States
Initial State Construction
- Bytecode: Program image at
min_bytecode_address - Inputs: Public inputs at
memory_layout.input_start - Advice: Trusted/untrusted advice at respective start addresses
- Zero padding: Remaining memory initialized to 0
Final State Verification
- DRAM: Final heap/stack state from emulator
- Outputs: Public outputs at
memory_layout.output_start - Panic bit: 1 if program panicked, else 0
- Termination bit: 1 if program terminated normally, else 0
Sparse Memory Evaluation
Jolt uses sparse evaluation to avoid materializing full memory vectors:- Only evaluates non-zero regions (bytecode, inputs, outputs)
- Uses aligned power-of-two block decomposition
- Avoids O(2^K) memory materialization
- Critical for large address spaces
Example: Initial RAM Evaluation
r_address in O(bytecode_size + input_size) instead of O(2^K).
Advice Polynomials
Jolt supports advice inputs (prover-supplied data not part of program inputs):Trusted vs. Untrusted Advice
Trusted Advice:- Prover commits to advice via polynomial commitment
- Verifier checks commitment against public hash/digest
- Used for pre-verified data (e.g., Merkle proofs)
- Prover commits to advice
- Constraints verify correctness (e.g., witness for cryptographic operations)
- Used for optimization (e.g., bigint multiplication)
Advice Integration
Advice is embedded in initial memory state:- Prover: Opens advice commitment at challenge point
- Verifier: Uses opening to compute init_eval contribution
- BlindFold constraints: Decompose init_eval as
public + Σ(selector_i · advice_i)
Advice Selector Computation
advice_start in memory.
Hamming Weight Booleanity
RAM checking includes booleanity checks for one-hot encodings: Purpose: Verify that RA (Read-After) indices are valid one-hot encodings. Sumcheck:Stage Alignment Constraints
Critical invariant fromram/mod.rs documentation:
After Stage 2 address-round alignment, there is exactly one RAM address point: r_address.
Why this matters:
- Multiple RAM sumchecks (RW-checking, RAF-eval, Val-check) open RA polynomials
- All must use the same address challenge vector
r_address - Enforced by careful padding/alignment of sumcheck rounds
- Violation causes RA reduction sumcheck to fail
RamReadWriteCheckingbinds address variables in config-dependent scheduleRamRafEvaluationandOutputCheckpadded to align with same global roundsRamValCheckcaches openings at the samer_addresspoint
Performance Characteristics
Prover Time
Stage 2 (Read-Write Checking + RAF):- O(trace_length · K) field operations
- ~20-25% of total proving time
- Dominated by incremental fingerprint updates
- O(trace_length · K) field operations
- ~10-15% of total proving time
Memory Usage
With sparse evaluation:- ~50-100MB for 10⁶ cycles with K=20
- No materialized memory vectors
- Would require ~8GB for K=20 (2^20 · 8 bytes · 2 states)
Verifier Time
- O(K · log(trace_length)) field operations
- ~1-5ms for typical traces
- Sparse evaluation critical for verifier efficiency
Key Files
jolt-core/src/zkvm/ram/mod.rs: Core RAM checking protocol and utilitiesjolt-core/src/zkvm/ram/read_write_checking.rs: Fingerprint-based consistency checkingjolt-core/src/zkvm/ram/raf_evaluation.rs: Read-After-Final polynomial checkingjolt-core/src/zkvm/ram/val_check.rs: Memory value evaluationjolt-core/src/zkvm/ram/output_check.rs: Public output verificationjolt-core/src/zkvm/ram/hamming_booleanity.rs: One-hot encoding verification
Next Steps
- Register Checking: Simpler version of same protocol
- Bytecode: Program image preprocessing
- Opening Proofs: Batched commitment verification