-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Currently, witness generation fills the entire is_last_segment column with self.is_last_segment:
Line 447 in c36d317
| cols.is_last_segment = SC::Val::from_canonical_u32(self.is_last_segment); |
However, the AIR constraint only enforces correctness on the first row:
Line 543 in c36d317
| .when_first_row() |
This means a malicious prover can arbitrarily flip non–first-row values of is_last_segment. Doing so reintroduces the early termination vulnerability (see #16). Importantly, the fix in #17 assumes that is_last_segment is trustworthy, and manipulating later rows bypasses that protection.
A working PoC is available: https://github.com/Koukyosyumei/valida-vm/tree/fix-poc-mal-DidStop-flag
This PoC reproduces the attack from #16 with a minor mutation in the CPU chip’s op_to_row:
if self.registers[clk as usize].pc != 0 {
cols.is_last_segment = SC::Val::zero();
}Proposed Fix:
Remove the .when_first_row() restriction in:
Line 543 in c36d317
| .when_first_row() |
and instead enforce:
assert_eq(local.is_last_segment, public.is_last_segment);on all rows, ensuring that every value of is_last_segment is consistent and not forgeable.