Bound proof-controlled codeword dimension in basefold verify#3
Open
aryaethn wants to merge 1 commit into
Open
Conversation
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hardens the BaseFold verifier against malformed proofs — the "verifier panic risks" item from the audit (#1).
basefold::verifyderivesk_code(the log2 codeword length) from the proof-suppliedround_messagescount —k_code = (round_messages.len() - log_batch_size) + log_inv_rate— and feeds it into1 << k_codemasks and FRI twiddle lookups at layers up tok_code - 1, without bounding it. The verifier's NTT only carrieslog_domain_size()layers of twiddles (it is built asAdditiveNttF128::standard(params.k_code())for the committed instance). A proof claiming a larger codeword makesAdditiveNttF128::twiddleevaluateself.evals[log_domain_size - layer - 1]withlayer >= log_domain_size— ausizeunderflow → 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 withVerifyError::InvalidProofShape. Honest proofs havek_code == log_domain_size, so they are unaffected (the existing PCS roundtrip and end-to-end tests still pass).What I checked
While auditing
verifyI confirmed the other proof-controlled index sites are already in-bounds by construction, so no extra checks are warranted there:compute_fri_aritiesreturns positive arities summing to exactlylog_dim, soarities[i + 1], thechallenges[start..start + arity]slices, andcum_arity == log_dim(hencefinal_codeword[q.position >> cum_arity]) are all bounded.k_codebits, and per-query leaf lengths are length-checked before indexing.queries.len() == default_fri_queries(..)) and this dimension bound together keep theVec::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
verify_rejects_oversized_codeword_dim_without_panic: a proof whoseround_messagescount impliesk_codebeyond the NTT domain is rejected withInvalidProofShapeinstead of panicking.