-
Notifications
You must be signed in to change notification settings - Fork 36
Unsigned underflow yields panicable constraint sizes #182
Description
Context: crates/whir/src/lib.rs
Description
The SparseStatement does not enforce the invariant total_num_variables >= point.len(). As a result, selector_num_variables() performs unchecked usize subtraction and can underflow (wrapping to a huge value in release builds).
Downstream code uses selector_num_variables() for indexing, slicing, and bit-shifts (e.g., 1 << selector_num_variables() and iterating 0..selector_num_variables()), which can panic due to out-of-bounds slicing or oversized shifts.
A real exploitation path is a verifier/prover service that accepts attacker-controlled SparseStatement: the attacker supplies a statement with total_num_variables smaller than point.len(), triggering a panic during verification/proving and causing a denial of service.
impl<EF> SparseStatement<EF> {
pub fn new(total_num_variables: usize, point: MultilinearPoint<EF>, values: Vec<SparseValue<EF>>) -> Self {
Self {
total_num_variables,
point,
values,
}
}
pub fn selector_num_variables(&self) -> usize {
self.total_num_variables - self.inner_num_variables()
}
pub fn inner_num_variables(&self) -> usize {
self.point.len()
}
}Recommendation
- Enforce
total_num_variables >= point.len()at construction time (e.g., make constructors returnResultand validate), and computeselector_num_variableswithchecked_sub(returning an error on invalid statements). - Also prefer returning structured errors instead of panicking in verification/proving paths.