Skip to content

feat(mmr): add authenticated rooted-frontier path - #3184

Draft
krushimir wants to merge 3 commits into
0xMiden:mainfrom
reilabs:krushimir/mmr-frontier-root
Draft

feat(mmr): add authenticated rooted-frontier path#3184
krushimir wants to merge 3 commits into
0xMiden:mainfrom
reilabs:krushimir/mmr-frontier-root

Conversation

@krushimir

Copy link
Copy Markdown
Contributor

Note

Draft/WIP, opening for visibility. VM-side companion to 0xMiden/crypto#984. Based on main for local interop testing; will rebase/retarget later.

Adds the authenticated Merkle-frontier path to the MMR:

  • mmr::root - raw rooted frontier root
  • mmr::root_with_len - authenticated (num_leaves, root) pair
  • mmr::unpack_frontier - authenticates (num_leaves, root) against advice-provided padded peaks, then loads them so get/add keep working

root alone doesn't bind length (raw roots collide across lengths under empty padding); root_with_len disambiguates, per the 0xMiden/crypto#984 regression. Also adds mmr/hash_primitives benches.

@krushimir krushimir changed the title feat(mmr): rooted-frontier commitment with len-bound authentication feat(mmr): add authenticated rooted-frontier path May 22, 2026
@krushimir

Copy link
Copy Markdown
Contributor Author

Follow-up to @huitseeker's benchmark question on 0xMiden/crypto#984. This is for the current PR implementation.

  • Root/hash component: rooted-frontier auth is ~2.0x hash_peaks at 10^3 blocks, rising to ~3.0x at 10^6 in hasher rows. hash_peaks is mostly flat (peaks pad to a 16-word floor); the rooted-frontier path grows with bit length.

  • get: the standalone win (verifying a leaf directly against the root skips re-hashing the peaks) - is real, but doesn't surface in the tx kernel: unpack_frontier authenticates (num_leaves, root) once, peaks land in the normal MMR memory layout, and every subsequent get opens within that authenticated peak memory, so tx get is unchanged.

  • Transaction benchmark: padded proving cost is unchanged in the tested Falcon and ECDSA scenarios. unpackunpack_frontier adds ~+560 chip rows per tx at bench MockChain scale and ~+1,740 at ~10^6 blocks, staying below the next power-of-two trace boundary in both cases.

  • Raw execution: ~+200 clk per tx (<1% Falcon, ~1–2% ECDSA); proving dominates and padded size is unchanged.

  • Methodology: standalone VM ExecutionTrace::trace_len_summary for per-procedure costs, applied as deltas to an actual bench-transaction baseline; bench MockChain delta also confirmed by literal in-tx injection. All measured tx scenarios use K=1 consumed note, so multi-note amortization follows from the shared-unpack structure rather than a separate K>1 measurement.

Caveat: assumes this PR's shared unpack/peak-memory representation; per-get root-path verification would be a different transaction shape.

@huitseeker
huitseeker self-requested a review June 9, 2026 18:12
# Load the first 16 padded peak words via 8 unrolled adv_pipes. `adv_pipe` is 1 cycle and writes
# 2 words to memory while leaving the sponge capacity unchanged, so this load is free of
# hash-chiplet rows.
adv_pipe adv_pipe adv_pipe adv_pipe adv_pipe adv_pipe adv_pipe adv_pipe

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could we either zero the padded peak words here, or assert that they are zero?

unpack_frontier writes all padded words from advice into MMR memory, but root_from_peak_end only authenticates the real peaks before peak_end. So the same (num_leaves, ROOT) can be accepted with different non-zero padding, and a later mmr::pack will hash those padding slots into a different legacy commitment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. unpack_frontier now zeroes the padded peak slots after loading them from advice. The root check still only uses the real peaks, but the memory layout is now canonical, so a later mmr::pack cannot hash non-zero padding.

Added a regression test for this.

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