-
Notifications
You must be signed in to change notification settings - Fork 87
Description
Context: folding-schemes/src/folding/nova/decider.rs
Description:
verify() takes z_0 and z_i as owned Vecs and then builds c1_public_input/c2_public_input via .concat(), which allocates and copies all elements into new vectors.
If verify() is reachable with attacker-controlled z_0/z_i sizes, this can cause large allocations and excessive copying (memory/CPU DoS) even when the proof is invalid.
Exploit path: a verifier service that accepts user-supplied z_0/z_i (or deserializes them from user input) can be forced to allocate/copy very large buffers by sending oversized arrays.
Impacted code
let c1_public_input = [
&[vp.pp_hash, i][..],
&z_0,
&z_i,
&U_final_commitments.inputize_nonnative(),
&cf_U.inputize_nonnative(),
&proof.cs1_challenges,
&proof.cs1_proofs.iter().map(|p| p.eval).collect::<Vec<_>>(),
&proof.cmT.inputize_nonnative(),
]
.concat();
let c2_public_input: Vec<C2::ScalarField> = [
&[pp_hash_Fq][..],
&cf_U.inputize(),
&proof.cs2_challenges,
&proof.cs2_proofs.iter().map(|p| p.eval).collect::<Vec<_>>(),
]
.concat();Recommendation
Avoid .concat() over attacker-sized vectors.
Instead, pre-check expected public input length from the SNARK verifying keys (e.g., Groth16 vk.gamma_abc_g1.len() - 1) and reject mismatched sizes early, then build the public input with Vec::with_capacity(expected) and extend_from_slice to avoid repeated allocations/copies.
Consider taking z_0/z_i as slices (&[C1::ScalarField]) rather than owned Vecs.