Skip to content

feat(AggLayer claim e2e #4): e2e bridge-in flow with real bridge data#2413

Merged
mmagician merged 18 commits intoagglayer-newfrom
mmagician-real-bridge-data
Feb 15, 2026
Merged

feat(AggLayer claim e2e #4): e2e bridge-in flow with real bridge data#2413
mmagician merged 18 commits intoagglayer-newfrom
mmagician-real-bridge-data

Conversation

@mmagician
Copy link
Collaborator

@mmagician mmagician commented Feb 8, 2026

Changes:

  • unify loading of all ProofData elements (exit roots, merkle paths) to use LE ordering
  • unify procedure locals to also use LE ordering (this is mostly for consistency with the above; it doesn't matter if we do loc_storew_be ... loc_loadw_be or loc_storew_le ... loc_loadw_le)
  • use "real" bridge-in data
    • I made a transfer from L1 -> Katana which triggered a claimAsset tx on Katana on Katana to a Miden-like address 0x00000000b0E79c68cafC54802726C6F102Cca300
    • this would be very similar to a claim on Miden; the only difference would be the chain ID
    • for compatibility testing, the address on L1 must be decodable into a Miden AccountId

This concludes the PR tower: we now fully verify the data inside the CLAIM note.
What's missing for a full integration is actually checking that the GER we compute is part of onchain storage, which is tackled separately in #2388

@mmagician mmagician force-pushed the mmagician-global-index-wrapper branch from 19cb775 to 778b6e7 Compare February 8, 2026 21:33
@mmagician mmagician changed the title feat(AggLayer): e2e bridge-in flow with real bridge data feat(AggLayer claim e2e #4): e2e bridge-in flow with real bridge data Feb 8, 2026
@mmagician mmagician force-pushed the mmagician-real-bridge-data branch from be37f12 to 43fbf27 Compare February 8, 2026 21:39
@mmagician mmagician added the agglayer PRs or issues related to AggLayer bridging integration label Feb 8, 2026
@mmagician mmagician linked an issue Feb 8, 2026 that may be closed by this pull request
@mmagician mmagician marked this pull request as ready for review February 8, 2026 21:43
@mmagician mmagician added the no changelog This PR does not require an entry in the `CHANGELOG.md` file label Feb 8, 2026
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

a lot of the test vectors have duplicated data, maybe we could eventually create one big test vector, but it's not a priority right now

@mmagician mmagician requested review from bobbinth and partylikeits1983 and removed request for partylikeits1983 February 8, 2026 22:02
@mmagician mmagician added the pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority label Feb 9, 2026
@mmagician mmagician requested a review from Fumuran February 10, 2026 11:33
Copy link
Contributor

@Fumuran Fumuran left a comment

Choose a reason for hiding this comment

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

Looks great! I left a few questions and proposals inline.

# Merkle path is guaranteed to contain 32 nodes
repeat.32
# load the Merkle path node onto the stack
mem_stream
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder do we have an incorrect documentation for the mem_stream instruction or it was just already updated to work with the latest VM which uses LE.

If we have [1, 2, 3, 4, 5, 6, 7, 8] memory layout, where 1 is placed at memory address 0 and 8 at memory address 7, then the mem_stream will load this double word onto the stack in the reversed order: [8, 7, 6, 5, 4, 3, 2, 1], where 8 is placed at the top. At the same time in the mem_stream docs it is written:

Stack transition: [C, B, A, a, ... ] -> [E, D, A, a', ... ], where
[E, D] ← [mem[a..(a+4)], mem[(a+4)..(a+8)]], a' ← a+8.

So it describes the transition in LE, not BE.

Also the necessity of whiting the LE mem_stream by your own made me think whether should we create the LE version of the mem_stream (the same way it was done with mem_storew_le and the others) and rename the current mem_stream into the mem_stream_be.

Copy link
Contributor

@partylikeits1983 partylikeits1983 left a comment

Choose a reason for hiding this comment

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

This is awesome! Looks great!

Great to see the actual claim in bridge data being finally used in the claim note test!!!!

Comment on lines +129 to +137
// Note: We intentionally do NOT verify the exact note ID or asset amount here because
// the scale_u256_to_native_amount function is currently a TODO stub that doesn't perform
// proper u256-to-native scaling. The test verifies that the bridge-in flow correctly
// validates the Merkle proof using real cryptographic proof data and creates an output note.
//
// TODO: Once scale_u256_to_native_amount is properly implemented, add:
// - Verification that the minted amount matches the expected scaled value
// - Full note ID comparison with the expected P2ID note
// - Asset content verification
Copy link
Contributor

Choose a reason for hiding this comment

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

Just FYI, the procedure that checks the u256 amount to Felt scaling amount needs the Felt amount to be provided via NoteStorage

@mmagician mmagician force-pushed the mmagician-global-index-wrapper branch from 12c5dda to df775f2 Compare February 14, 2026 17:44
Base automatically changed from mmagician-global-index-wrapper to agglayer-new February 14, 2026 18:12
mmagician and others added 8 commits February 14, 2026 18:17
chore: add claim test gen to makefile
… compatibility

The keccak256::merge MASM function applies word::reverse to its input words
before hashing. mem_stream (used to load SMT proof nodes) does NOT apply
per-word reversal, while loc_loadw_be (used to load the current hash) DOES.

To produce consistent per-word reversed format on the stack for both the
current hash (via loc_storew_be/loc_loadw_be) and the path nodes (via
mem_stream), SMT proof nodes must be stored in fully reversed element order
in memory.

Exit roots are per-word reversed because they are loaded via
mem_load_double_word (which uses mem_loadw_be), and the per-word reversal
by mem_loadw_be undoes the storage reversal to produce natural order on
the stack.

Also adds diagnostic and integration tests for Merkle proof verification
using claim_asset_vectors data.

Co-authored-by: marti <marti@hungrycats.studio>

fix: simplify bridge_in test assertions for stubbed scale function

The test now correctly verifies that the bridge-in flow validates the Merkle
proof and creates an output note, without asserting specific note content
that depends on the stubbed scale_u256_to_native_amount function.

Removes diagnostic test test_claim_asset_verify_leaf_via_advice_map which
has a stack management issue unrelated to the core fix.

Co-authored-by: marti <marti@hungrycats.studio>

chore: fix warnings and remove diagnostic test

- Remove unused imports (Asset, NoteRecipient, NoteStorage)
- Remove unused leaf_elements variable
- Remove test_claim_asset_verify_leaf_via_advice_map diagnostic test
  (covered by test_bridge_in_claim_to_p2id)

Co-authored-by: marti <marti@hungrycats.studio>

refactor: use data-level fix without MASM changes

The keccak256::merge function (from external miden-core-lib) applies
word::reverse internally and expects per-word reversed input. Since
loc_loadw_be naturally produces per-word reversal, changing to
loc_loadw_le would break merge's byte ordering.

Instead, fix at the data level:
- SMT proof nodes: fully reversed (to_memory_elements) so mem_stream's
  half-swap produces per-word reversed format matching loc_loadw_be output
- Exit roots: per-word reversed (to_word_reversed_elements) so
  mem_load_double_word's mem_loadw_be reversal produces natural order
- No MASM code changes needed

Co-authored-by: marti <marti@hungrycats.studio>

chore: remove diagnostic tests

Remove 7 diagnostic/exploratory tests that were added during debugging.
The pre-existing tests (pack_leaf_data, get_leaf_value,
test_solidity_verify_merkle_proof_compatibility) plus the fixed
test_bridge_in_claim_to_p2id provide sufficient coverage.

Co-authored-by: marti <marti@hungrycats.studio>
Replace mem_stream (which requires RPO hasher state padding) with two
explicit mem_loadw_be calls for loading Merkle path nodes. This uses the
same instruction as loc_loadw_be for the current hash, ensuring both
undergo identical element ordering.

The change eliminates 12 elements of RPO padding from the stack, simplifies
pointer management, and makes the memory access pattern more explicit.

Co-authored-by: marti <marti@hungrycats.studio>
mmagician and others added 9 commits February 14, 2026 18:17
- Replace loc_storew_be/loc_loadw_be with loc_storew_le/loc_loadw_le
- Replace mem_load_double_word with inline mem_loadw_le
- Replace mem_store_double_word with inline mem_storew_le
- Update canonical_zeros.masm and build.rs to use mem_storew_le

Co-authored-by: marti <marti@hungrycats.studio>

chore: update mem_load/store_double_word to LE and resolve TODO

- Update utils.masm: mem_storew_be -> mem_storew_le, mem_loadw_be -> mem_loadw_le
- Replace inline mem_loadw_le in crypto_utils.masm with exec.utils::mem_load_double_word
- Restore mem_load/store_double_word usage in mmr_frontier32_keccak.masm and canonical_zeros.masm
- Update stale comment in claim_note.rs

Co-authored-by: marti <marti@hungrycats.studio>
@mmagician mmagician force-pushed the mmagician-real-bridge-data branch from 4bf984c to e8c4306 Compare February 14, 2026 18:25
@mmagician mmagician merged commit c5cc3d2 into agglayer-new Feb 15, 2026
15 checks passed
@mmagician mmagician deleted the mmagician-real-bridge-data branch February 15, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agglayer PRs or issues related to AggLayer bridging integration no changelog This PR does not require an entry in the `CHANGELOG.md` file pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AggLayer: Use real bridge data for testing Bridging in: AggLayerFungibleFaucet contract (only bridging in functionality)

4 participants