Skip to content

Bound proof-controlled codeword dimension in basefold verify#3

Open
aryaethn wants to merge 1 commit into
succinctlabs:mainfrom
aryaethn:harden/basefold-verify-bounds
Open

Bound proof-controlled codeword dimension in basefold verify#3
aryaethn wants to merge 1 commit into
succinctlabs:mainfrom
aryaethn:harden/basefold-verify-bounds

Conversation

@aryaethn

Copy link
Copy Markdown

Summary

Hardens the BaseFold verifier against malformed proofs — the "verifier panic risks" item from the audit (#1).

basefold::verify derives k_code (the log2 codeword length) from the proof-supplied round_messages count — k_code = (round_messages.len() - log_batch_size) + log_inv_rate — and feeds it into 1 << k_code masks and FRI twiddle lookups at layers up to k_code - 1, without bounding it. The verifier's NTT only carries log_domain_size() layers of twiddles (it is built as AdditiveNttF128::standard(params.k_code()) for the committed instance). A proof claiming a larger codeword makes AdditiveNttF128::twiddle evaluate self.evals[log_domain_size - layer - 1] with layer >= log_domain_size — a usize underflow → out-of-bounds index → panic — reached before any Merkle check could reject the proof.

The fix rejects k_code > ntt.log_domain_size() up front with VerifyError::InvalidProofShape. Honest proofs have k_code == log_domain_size, so they are unaffected (the existing PCS roundtrip and end-to-end tests still pass).

What I checked

While auditing verify I confirmed the other proof-controlled index sites are already in-bounds by construction, so no extra checks are warranted there:

  • compute_fri_arities returns positive arities summing to exactly log_dim, so arities[i + 1], the challenges[start..start + arity] slices, and cum_arity == log_dim (hence final_codeword[q.position >> cum_arity]) are all bounded.
  • Query positions are masked to k_code bits, and per-query leaf lengths are length-checked before indexing.
  • The query-count check (queries.len() == default_fri_queries(..)) and this dimension bound together keep the Vec::with_capacity(..) allocations bounded.

The Ligerito verifier already performs its own dimension/shape validation (e.g. the 1 << (cols + rate) query-count checks), so it is out of scope here.

Tests

  • New verify_rejects_oversized_codeword_dim_without_panic: a proof whose round_messages count implies k_code beyond the NTT domain is rejected with InvalidProofShape instead of panicking.
  • Full flock-core suite (257) + end-to-end roundtrip green.

The BaseFold verifier derived k_code (log2 codeword length) from the
proof's round_messages count and used it for `1 << k_code` masks and FRI
twiddle lookups without bounding it. A malformed proof claiming a
codeword larger than the verifier's NTT domain made
AdditiveNttF128::twiddle index past its twiddle tables and panic (usize
underflow on `log_domain_size - layer - 1`), reached before any Merkle
check could reject the proof.

Reject `k_code > ntt.log_domain_size()` up front with InvalidProofShape.
Honest proofs satisfy k_code == log_domain_size (the NTT is built as
standard(params.k_code())), so they are unaffected. The surrounding
index sites are already guarded by the arities-sum-to-log_dim invariant.

Adds a regression test that a proof with an oversized round_messages
count is rejected instead of panicking.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SipengXie2024 added a commit to SipengXie2024/flock that referenced this pull request Jul 2, 2026
Review findings (36 agents, 86 candidates, 15 confirmed):

Fixed:
- succinctlabs#7: SSE2 convert-table dispatch missing in s_hat_v partial path
  (copy-paste omission — x86 fell back to scalar in boundary window)
- succinctlabs#8/succinctlabs#12: multi_base.rs imported route.rs (FANOUT=4) instead of
  route_f32.rs (FANOUT=32). Any fanout>4 would panic. Fixed import
  + updated acceptance test to use RouteF32Witness.

Skipped (documented, not fixable without larger changes):
- succinctlabs#1/succinctlabs#3/succinctlabs#6: route_single.rs 3 soundness gaps (documented in header,
  needs wiring sumcheck)
- succinctlabs#2/succinctlabs#4/succinctlabs#9/succinctlabs#10: files >700 LOC (route 810, route_f32 936, route_single
  950 — needs structural refactor, separate PR)
- succinctlabs#5: multi_base missing padding skip (perf-only, not correctness)
- succinctlabs#11: PaddingSpec inconsistency in hash_only PCS open (no effect —
  padding skip only applies to zerocheck, not PCS)
- succinctlabs#13/succinctlabs#14/succinctlabs#15: Ligerito floor magic number, PCS PaddingSpec, target_feature
  annotation — all by-design or no-impact

338 tests pass (279 flock-core + 50 mhot unit + 8 acceptance + 1 profile).
SipengXie2024 added a commit to SipengXie2024/flock that referenced this pull request Jul 2, 2026
Review findings (36 agents, 86 candidates, 15 confirmed):

Fixed:
- succinctlabs#7: SSE2 convert-table dispatch missing in s_hat_v partial path
  (copy-paste omission — x86 fell back to scalar in boundary window)
- succinctlabs#8/succinctlabs#12: multi_base.rs imported route.rs (FANOUT=4) instead of
  route_f32.rs (FANOUT=32). Any fanout>4 would panic. Fixed import
  + updated acceptance test to use RouteF32Witness.

Skipped (documented, not fixable without larger changes):
- succinctlabs#1/succinctlabs#3/succinctlabs#6: route_single.rs 3 soundness gaps (documented in header,
  needs wiring sumcheck)
- succinctlabs#2/succinctlabs#4/succinctlabs#9/succinctlabs#10: files >700 LOC (route 810, route_f32 936, route_single
  950 — needs structural refactor, separate PR)
- succinctlabs#5: multi_base missing padding skip (perf-only, not correctness)
- succinctlabs#11: PaddingSpec inconsistency in hash_only PCS open (no effect —
  padding skip only applies to zerocheck, not PCS)
- succinctlabs#13/succinctlabs#14/succinctlabs#15: Ligerito floor magic number, PCS PaddingSpec, target_feature
  annotation — all by-design or no-impact

338 tests pass (279 flock-core + 50 mhot unit + 8 acceptance + 1 profile).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant