ePrint 2025/105 | Srinath Setty, Justin Thaler, 2025 Jolt docs | a16z blog post | zkSummit 13 talk
Replacements for Lasso and Spice (Offline Memory Checking) in Jolt, based purely on the Multivariate Sum-Check Protocol. No grand product arguments.
- Shout: Read-only memory (a.k.a. lookup arguments)
- Twist: Read/write memory
Shout
Lookups as a matrix-vector product
Let be the result of reads into a read-only memory . At each cycle , encode the read address as a one-hot vector . Stack these into a matrix , which is sparse. Then the read values are simply:
To verify this via sum-check, pick random and check:
The prover commits only to (the one-hot addresses). The read-value polynomial is virtual: it is fully determined by and , so it need not be committed. is either public, committed or evaluable by the verifier in time for MLE-structured tables.
Prover cost (): The sum-check is over terms, but only are non-zero (one per row), so the prover runs in time. Commitment: non-zero values committed (all 1s), plus field multiplications.
Committing to
They use an Elliptic Curve based commitment scheme, so the commitment cost for is only proportional to (just one group operation per bit). On top of this, the one-hot property has to be proven, by proving booleanity of all the entries and proving that the sum along the memory dimension is 1.
See Twist and Shout via logup* for alternative ways to commit to , applicable to hash-based commitments.
Parameter : splitting the one-hot encoding
Motivation: The commitment key has entries, which is a problem for large memories. Also, the evaluation proofs become more expensive, but I skipped the details of that.
Fix and let . Decompose each one-hot vector as a tensor product of smaller one-hot vectors:
The prover commits to polynomials (each over ) instead of one polynomial over . The sum-check becomes:
Tradeoff: The polynomials share one SRS, so the commitment key drops from to group elements. The number of commitments per cycle grows from 1 to ( non-zero values total, each a 1). The degree in each variable increases from 3 to , raising prover field work.
Twist
Read/write memory with cells and cycles (alternating reads and writes). The data:
| Description | Committed? | |
|---|---|---|
| One-hot read addresses (as in Shout) | yes | |
| One-hot write addresses | yes | |
| Increment per cycle (see below) | yes | |
| Read values | virtual | |
| Write values | virtual | |
| Value of each cell at each cycle | virtual |
Unlike Shout, changes over time, so is no longer a simple matrix-vector product with a static table.
Increments
Since only one cell is written per cycle , define:
Note: this is one-dimensional, unlike in the paper. See the Jolt book.
Given commitments to , , and , evaluations of the virtual polynomials can be obtained via three sum-checks.
Sum-checks
Val-evaluation sum-check: is the sum of all prior increments to cell :
where iff . At the end, the verifier needs evaluations of and (from commitments) and (computable in time).
Read-checking sum-check: Like Shout, but summing over both and since is time-varying:
This requires evaluating at a random point, which is handled by the Val-evaluation sum-check above.
Write-checking sum-check: The write value is the old cell value plus the increment:
Also requires a evaluation, obtained from the same Val-evaluation sum-check (run once, shared by both).
Parameter : Just like Shout, the sparse matrices can be committed as separate matrices.
Locality benefit: A read/write to a cell last accessed cycles ago costs only field multiplications, because the relevant vectors become sparser in early sum-check rounds.
Recovering dense addresses
The zkVM naturally represents addresses as field elements: where is the address read at cycle (and similarly ). These are virtual polynomials, recoverable from the one-hot commitments via:
where converts binary to a field element. The verifier runs a sum-check over ; at the end it needs at a random point (from commitment) and at a random point (computable in time).