Skip to content

Perf/fri merkle folding#611

Draft
diegokingston wants to merge 3 commits into
mainfrom
perf/fri-merkle-folding
Draft

Perf/fri merkle folding#611
diegokingston wants to merge 3 commits into
mainfrom
perf/fri-merkle-folding

Conversation

@diegokingston
Copy link
Copy Markdown
Collaborator

No description provided.

A Merkle cap commits the top 2^cap_height tree nodes instead of a single
root, so every authentication path stops cap_height levels early — smaller
proofs and cap_height fewer hash compressions per opening.

The cap is just a slice of the existing heap-ordered node array (the nodes
at tree depth cap_height), so no new tree storage is needed. Adds
`cap`, `get_proof_by_pos_capped`, `get_batch_proof_capped`, and
`Proof`/`BatchProof::verify_capped`; the existing root-based methods become
cap_height=0 wrappers and are bit-for-bit unchanged in behavior. cap_height
clamps to the tree depth, so small trees degrade gracefully to a single root.

Stage 1 of the caps + arity-4 FRI plan; purely additive, no STARK-layer
changes yet.
`FieldElementQuadBackend` hashes a fixed group of four field elements into
one leaf. With arity-4 FRI folding a single fold orbit is four evaluations
that are always opened together, so they belong under one leaf hash — this
is the FRI-layer leaf for the arity-4 commit phase.

Mirrors the existing `FieldElementPairBackend`; exposed as
`QuadKeccak256Backend`. Building block for stage 2b (arity-4 FRI).
@github-actions
Copy link
Copy Markdown

Codex Code Review

Findings

  • Low Security / Bug: proof.rs lets cap_height exceed depth when cap.len() > num_leaves, then depth - cap_height underflows at line 179. A malformed external cap can make verify_capped panic in debug builds, or behave incorrectly in release. Add an explicit guard after computing both values:
    if cap_height > depth {
        return false;
    }

No other real issues found in the PR diff.

I attempted to run cargo test -p crypto merkle_cap_tests --quiet, but the environment could not create rustup temp files under /home/runner/.rustup because it is read-only.

let cap_height = cap.len().trailing_zeros() as usize;
// Process level by level, from the leaves up to the cap level, same as
// `get_batch_auth_path_positions`.
for _ in 0..depth - cap_height {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium — DoS via usize underflow

depth - cap_height is an unchecked usize subtraction. If a caller passes a cap with more nodes than the tree has leaves (e.g. cap.len() = 2 * num_leaves), then cap_height > depth, which:

  • debug builds: panics immediately.
  • release builds: wraps to usize::MAX, causing the for loop to iterate ~2⁶⁴ times (effectively an infinite hang).

The is_power_of_two guard a few lines up doesn't prevent this — it only ensures the cap is a power of two, not that it's ≤ num_leaves.

The verifier is meant to be called with untrusted inputs, so this needs a bounds check before the arithmetic:

Suggested change
for _ in 0..depth - cap_height {
let depth = num_leaves.trailing_zeros() as usize;
let cap_height = cap.len().trailing_zeros() as usize;
if cap_height > depth {
return false;
}
// Process level by level, from the leaves up to the cap level, same as
// `get_batch_auth_path_positions`.
for _ in 0..depth - cap_height {

Commit the top 2^c Merkle nodes as a cap instead of a single root, so
every opening path is c hashes shorter, and fold FRI by 4 per committed
layer (two binary folds) to halve the number of FRI trees and paths.

- StarkProof / prover / verifier carry MerkleCap commitments; preprocessed
  trees stay uncapped to preserve the AIR-hardcoded constants.
- FRI layers commit quad-leaf trees (one leaf per arity-4 fold orbit);
  commit_phase does one uncommitted initial fold then number_layers/2
  arity-4 layers, folding to a constant last value.
- Verifier replays two challenges per committed layer and folds each
  4-element orbit, with the (-1)^(index&1) twiddle parity handled.

The CUDA pair-leaf FRI tree builder is now stale w.r.t. arity-4; its
CPU-parity test is disabled with a TODO until the CUDA builder is updated.
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