-
CVSS Score
-The vulnerability exists because of a missing constraint in the rv32im circuit design, which is defined in the risc0/zirgen repository. Specifically, the circuit did not properly constrain the case where the source registers rs1 and rs2 for a 3-register instruction are the same. This allowed a malicious prover to generate a proof where the virtual machine would use the value of rs1 for the rs1 operation, but a different, unconstrained value for the rs2 operation, even though rs2 was the same register as rs1.
The fix was twofold:
risc0/zirgen): The ZIR (Zero-Knowledge Intermediate Representation) files that define the circuit logic were updated. A new component, ReadSourceRegs, was introduced in inst.zir. This component explicitly checks if rs1 and rs2 are the same. If they are, it performs only one register read. If not, it reads both. This new, constrained component was then used by the input-handling components for various instruction types (DivInput, MulInput, MiscInput, MemStoreInput), patching the logical flaw in the circuit's definition.risc0/risc0): The Rust and C++/CUDA emulators, which execute guest code and generate the execution trace for the prover, needed to be updated to match the new circuit logic. In the Rust code (risc0/circuit/rv32im/src/execute/rv32im.rs), the step_compute and step_store functions were identified as vulnerable. They previously fetched rs1 and rs2 in separate, unconstrained operations. The patch introduced a new load_rs2 helper function that implements the same logic as the ReadSourceRegs circuit component. By calling this function, step_compute and step_store now correctly handle the rs1 == rs2 case, preventing the vulnerability.The identified vulnerable functions are the key points in the software emulator where this flawed logic was executed. Any 3-register instruction passing through these functions was susceptible to the attack.
| Package Name | Ecosystem | Vulnerable Versions | First Patched Version |
|---|---|---|---|
| risc0-zkvm | rust | >= 2.0.0, <= 2.0.2 | 2.1.0 |
| risc0-circuit-rv32im | rust | >= 2.0.0, <= 2.0.3 | 2.0.4 |