Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions crypto/stark/src/tests/small_trace_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,34 @@ fn test_verify_rejects_truncated_composition_poly_parts_ood() {
);
}

/// A malformed proof whose `deep_poly_openings` Vec is shorter than the FRI
/// query count. `reconstruct_deep_composition_poly_evaluations_for_all_queries`
/// indexes `deep_poly_openings[i]` for every query index, and this Vec's length
/// is not otherwise bound (the `query_list.len()` guard checks a different
/// field), so a truncated `deep_poly_openings` must make the verifier return
/// `false` instead of panicking with an out-of-bounds index in release builds.
#[test_log::test]
fn test_verify_rejects_truncated_deep_poly_openings() {
let (air, mut proof) = make_valid_simple_proof();

assert!(
proof.deep_poly_openings.len() >= 2,
"test precondition: a valid proof has one deep-poly opening per FRI query",
);
// Drop the last opening so the Vec is shorter than `fri_number_of_queries`;
// the query loop would then index past the end.
proof.deep_poly_openings.pop();

assert!(
!Verifier::verify(
&proof,
&air,
&mut DefaultTranscript::<GoldilocksField>::new(&[])
),
"Verifier must reject when deep_poly_openings is shorter than the query count"
);
}

/// A malformed proof whose deep-poly opening `evaluations` slice has the
/// wrong number of columns. The runtime width-mismatch guard added in this
/// PR must cause the verifier to return `false` instead of indexing past
Expand Down
12 changes: 12 additions & 0 deletions crypto/stark/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,18 @@ pub trait IsStarkVerifier<
proof: &StarkProof<Field, FieldExtension, PI>,
) -> Option<DeepPolynomialEvaluations<FieldExtension>> {
let num_queries = challenges.iotas.len();

// `deep_poly_openings` comes straight from the untrusted proof and its
// length is not otherwise pinned (the `query_list.len()` guard checks a
// different field). The loop below indexes `deep_poly_openings[i]` for
// every `i` in `0..num_queries`, so a truncated Vec would panic the
// verifier with an out-of-bounds index on a malicious proof. Reject
// instead. (Extra entries are harmless — they are never indexed —
// matching the `<` convention of the `query_list` guard.)
if proof.deep_poly_openings.len() < num_queries {
return None;
}

let mut deep_poly_evaluations = Vec::with_capacity(num_queries);
let mut deep_poly_evaluations_sym = Vec::with_capacity(num_queries);

Expand Down
Loading