fix(agglayer): enforce NoteType::Public for B2AGG bridge-out notes (#2988)#3005
Merged
mmagician merged 4 commits intoMay 29, 2026
Merged
Conversation
mmagician
reviewed
May 28, 2026
Collaborator
mmagician
left a comment
There was a problem hiding this comment.
I'm not sure I fully understand: it says it intentionally skips agglayer-specific changes, but the original issue was meant to solve a concrete agglayer bug.
So is this only a first in the series of PRs? i.e. the first adds the protocol-level changes, the second applies it to AggLayer contracts?
Cherry-pick the reusable protocol-level building blocks from #2988, which was merged to the agglayer branch as an agglayer-specific B2AGG bridge-out hardening: - active_note::is_public - active_note::is_private Both procs read the active note's metadata and decode its note type via the existing note::metadata_into_note_type primitive (from #2738), then compare against NOTE_TYPE_PUBLIC / NOTE_TYPE_PRIVATE from miden::protocol::util::note. A parameterized kernel test covers the Public and Private cases. The agglayer-only files from #2988 (bridge_out.masm, B2AGG.masm, tests/agglayer/bridge_out.rs) and the constant-value flip the PR applied on agglayer's NoteType encoding are intentionally not brought along: next already encodes Private=0, Public=1, and the existing metadata_into_note_type is tailored to next's metadata bit layout. Co-Authored-By: Claude (Opus) <noreply@anthropic.com>
217efd5 to
7b8de8d
Compare
51bb95d to
c43fab9
Compare
…2988) Cherry-pick the bridge-side half of #2988 to next. The B2AGG note type lives in NoteMetadata, not in the recipient commitment, so an attacker could submit a note with an identical recipient, attachment, and asset but NoteType::Private. consensus would accept it, the leaf would be folded into the on-chain Local Exit Tree, but aggkit could never recover the pre-image off-chain — the LET mirror would permanently desync and the bridge-out path would brick. Add an active_note::is_public assert at the top of bridge_out, extend the bridge_out and b2agg.masm doc comments, and parameterize the existing destination-network-is-Miden test into test_bridge_out_rejects_invalid_b2agg_note covering the recipient-identical private-note case too. Co-Authored-By: Claude (Opus) <noreply@anthropic.com>
c43fab9 to
162cc26
Compare
PhilippGackstatter
approved these changes
May 29, 2026
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
mmagician
approved these changes
May 29, 2026
mmagician
added a commit
that referenced
this pull request
May 29, 2026
…2988) (#3005) * feat(protocol): add active_note::is_public / is_private (#2988) Cherry-pick the reusable protocol-level building blocks from #2988, which was merged to the agglayer branch as an agglayer-specific B2AGG bridge-out hardening: - active_note::is_public - active_note::is_private Both procs read the active note's metadata and decode its note type via the existing note::metadata_into_note_type primitive (from #2738), then compare against NOTE_TYPE_PUBLIC / NOTE_TYPE_PRIVATE from miden::protocol::util::note. A parameterized kernel test covers the Public and Private cases. The agglayer-only files from #2988 (bridge_out.masm, B2AGG.masm, tests/agglayer/bridge_out.rs) and the constant-value flip the PR applied on agglayer's NoteType encoding are intentionally not brought along: next already encodes Private=0, Public=1, and the existing metadata_into_note_type is tailored to next's metadata bit layout. Co-Authored-By: Claude (Opus) <noreply@anthropic.com> * fix(agglayer): enforce NoteType::Public for B2AGG bridge-out notes (#2988) Cherry-pick the bridge-side half of #2988 to next. The B2AGG note type lives in NoteMetadata, not in the recipient commitment, so an attacker could submit a note with an identical recipient, attachment, and asset but NoteType::Private. consensus would accept it, the leaf would be folded into the on-chain Local Exit Tree, but aggkit could never recover the pre-image off-chain — the LET mirror would permanently desync and the bridge-out path would brick. Add an active_note::is_public assert at the top of bridge_out, extend the bridge_out and b2agg.masm doc comments, and parameterize the existing destination-network-is-Miden test into test_bridge_out_rejects_invalid_b2agg_note covering the recipient-identical private-note case too. Co-Authored-By: Claude (Opus) <noreply@anthropic.com> * Apply suggestions from code review Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com> * chore: fmt files --------- Co-authored-by: Claude (Opus) <noreply@anthropic.com> Co-authored-by: Marti <marti@miden.team> Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
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.
Cherry-picks #2988 (merged to
agglayer) back tonext.The B2AGG note type lives in
NoteMetadata, not in the recipient commitment, so an attacker could submit a B2AGG note with an identical recipient/attachment/asset butNoteType::Private. The bridge would accept it, fold the leaf into the on-chain Local Exit Tree, but aggkit could never recover the pre-image off-chain — the LET mirror would permanently desync and the bridge-out path would brick for everyone.This PR:
active_note::is_publicandactive_note::is_privateto the protocol (built onnote::metadata_into_note_typefrom #2738).active_note::is_publicat the top ofbridge::bridge_out::bridge_outwithERR_B2AGG_NOTE_MUST_BE_PUBLIC.test_bridge_out_rejects_invalid_b2agg_notecovering both theDestinationIsMidenandPrivateNoteTypecases.note::metadata_into_note_type(from #2738) is reused instead of portingnote::extract_note_type_from_metadatafrom #2988 — the two procs decode different bit positions becausenextandagglayerlay out the metadata header differently, andmetadata_into_note_typeis the correct primitive fornext.