Registers
Jolt proves the correctness of register updates using the Twist memory checking algorithm, specifically utilizing the "local" prover algorithm.
In this Twist instance, because we have 32 RISC-V registers and 32 virtual registers. This is small enough that we can use .
Deviations from the Twist algorithm as described in the paper
Our implementation of the Twist prover algorithm differs from the description given in the Twist and Shout paper in a couple of ways. One such deviation is wv virtualization. Other, register-specific deviations are described below.
Two reads, one write per cycle
The Twist algorithm as described in the paper assumes one read and one write per cycle, with corresponding polynomials (read address) and (write address).
However, in the context of the RV32IM instruction set, a single instruction (specifically, an R-type instruction) can read from two source registers (rs1
and rs2
) and write to a destination register (rd
).
Thus, we have two polynomials corresponding to rs1
and rs2
, plus a ) polynomial corresponding to rd
.
Similarly, there are two polynomials and one polynomial.
As a result, we have two read-checking sumcheck instances and one write-checking sumcheck instance. In practice, all three are batched into a single sumcheck instance.
Why we don't need one-hot checks
Normally in Twist and Shout, polynomials like and need to be checked for one-hotness using the Booleanity and Hamming weight sumchecks.
In the context of registers, we do not need to perform these one-hot checks for , , and .
Observe that the registers are hardcoded in the program bytecode. Thus we can virtualize , , and using the bytecode read-checking sumcheck. Since the bytecode is known by the verifier and assumed to be "well-formed", the soundness of the read-checking sumcheck effectively ensures the one-hotness of , , and .
A (simplified) sumcheck expression to illustrate how this virtualization works:
where if the instruction at index in the bytecode has .