Skip to content

fix(core): reject malformed multi-proofs instead of panicking - #959

Merged
rphmeier merged 1 commit into
thrumdev:masterfrom
citizen-stig:fix/multiproof-verify-malformed
Oct 23, 2026
Merged

rphmeier merged 1 commit into
thrumdev:masterfrom
citizen-stig:fix/multiproof-verify-malformed

Conversation

@citizen-stig

Copy link
Copy Markdown
Contributor

proof::verify_multi_proof panics on malformed input. verify_range trusts three things taken straight from the proof (MultiPathProof.depth, the terminal path lengths and the number of siblings) and slices with them unchecked. Proofs come from untrusted parties and MultiProof is deserializable (serde/borsh), so anyone who can submit a proof can crash the verifier.

Found from #958

Fix

verify now validates the structure before calling verify_range:

  • depth <= terminal.path().len(), else InvalidDepth.
  • Neighbouring paths must diverge above both of their depths, i.e. terminals sit in disjoint subtrees, else PathPrefixOfAnother. For sorted paths, checking neighbours is enough. This guarantees start_depth <= depth <= path.len() and common_len < 256 everywhere in verify_range, which removes the old TODO.

verify_range checks that enough siblings remain before slicing, at a terminal and at a bisection, else TooFewSiblings.

Honest proofs always satisfy these conditions, so their behaviour is unchanged.

API impact

This adds three variants to MultiProofVerificationError: TooFewSiblings, InvalidDepth and PathPrefixOfAnother. The enum is not #[non_exhaustive], so downstream code that matches it exhaustively will stop compiling. Nothing in this repo matches it. If this needs to ship as a patch release, the alternative is to map these cases onto existing variants and give up the precise error.

Testing

  • New unit tests in multi_proof.rs (verify_rejects_depth_beyond_terminal_path, verify_rejects_path_prefix_of_another, verify_rejects_too_few_siblings), covering each new check at both the terminal and the bisection level. All three panicked in verify_range before the fix.
  • cargo test -p nomt -p nomt-core on Linux (io_uring): 278 passed, 0 failed.
  • All 5674 crash inputs from the proof_verify corpus replay without a crash.
  • Fresh proof_verify run, 10 min, 8 workers: pending

🤖 Generated with Claude Code

@rphmeier
rphmeier merged commit b0ee15f into thrumdev:master Oct 23, 2026
7 checks passed
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.

2 participants