Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 112 additions & 28 deletions crates/miden-agglayer/asm/agglayer/bridge/bridge_in.masm
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ type MemoryAddress = u32
# ERRORS
# =================================================================================================

const ERR_BRIDGE_NOT_MAINNET = "bridge not mainnet"
const ERR_BRIDGE_NOT_MAINNET = "mainnet flag must be 1 for a mainnet deposit"
const ERR_BRIDGE_NOT_ROLLUP = "mainnet flag must be 0 for a rollup deposit"
const ERR_LEADING_BITS_NON_ZERO = "leading bits of global index must be zero"
const ERR_MAINNET_FLAG_INVALID = "mainnet flag must be 0 or 1"
const ERR_ROLLUP_INDEX_NON_ZERO = "rollup index must be zero for a mainnet deposit"
const ERR_SMT_ROOT_VERIFICATION_FAILED = "merkle proof verification failed: provided SMT root does not match the computed root"

Expand All @@ -49,7 +51,6 @@ const CLAIM_LEAF_DATA_WORD_LEN = 8
const MINT_NOTE_NUM_STORAGE_ITEMS = 18

# P2ID output note constants
const P2ID_NOTE_NUM_STORAGE_ITEMS = 2
const OUTPUT_NOTE_TYPE_PUBLIC = 1

# P2ID attachment constants (the P2ID note created by the faucet has no attachment)
Expand All @@ -59,13 +60,23 @@ const P2ID_ATTACHMENT_SCHEME_NONE = 0
# -------------------------------------------------------------------------------------------------

# Memory pointers for proof data layout (used by verify_leaf / get_leaf_value)
const PROOF_DATA_PTR = 0
const SMT_PROOF_LOCAL_EXIT_ROOT_PTR = 0 # local SMT proof is first
const GLOBAL_INDEX_PTR = PROOF_DATA_PTR + 2 * 256 # 512
const EXIT_ROOTS_PTR = GLOBAL_INDEX_PTR + 8 # 520
const MAINNET_EXIT_ROOT_PTR = EXIT_ROOTS_PTR # it's the first exit root
# Memory layout for proof data (loaded from advice map via pipe_preimage_to_memory).
# The proof data occupies addresses [PROOF_DATA_PTR .. PROOF_DATA_PTR + 535]:
# [0..255] smtProofLocalExitRoot (256 felts = 32 Keccak256 nodes)
# [256..511] smtProofRollupExitRoot (256 felts = 32 Keccak256 nodes)
# [512..519] globalIndex (8 felts)
# [520..527] mainnetExitRoot (8 felts)
# [528..535] rollupExitRoot (8 felts)

# the memory address where leaf data is stored for get_leaf_value
const PROOF_DATA_PTR = 0
const SMT_PROOF_LOCAL_EXIT_ROOT_PTR = PROOF_DATA_PTR
const SMT_PROOF_ROLLUP_EXIT_ROOT_PTR = SMT_PROOF_LOCAL_EXIT_ROOT_PTR + 256
const GLOBAL_INDEX_PTR = SMT_PROOF_ROLLUP_EXIT_ROOT_PTR + 256
const EXIT_ROOTS_PTR = GLOBAL_INDEX_PTR + 8
const MAINNET_EXIT_ROOT_PTR = EXIT_ROOTS_PTR
const ROLLUP_EXIT_ROOT_PTR = EXIT_ROOTS_PTR + 8

# Memory layout for leaf data (loaded separately via get_leaf_value)
const LEAF_DATA_START_PTR = 0

# Memory pointers for piped advice map data (used by claim procedure)
Expand Down Expand Up @@ -189,17 +200,16 @@ end
#!
#! Invocation: exec
pub proc process_global_index_mainnet
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should have a helper procedure which takes GLOBAL_INDEX[8] and returns leaf_index & sourceBridgeNetwork. Not for this PR, but for the nullifier tracking PR.

# for v0.1, let's only implement the mainnet branch
# the top 191 bits of the global index are zero
repeat.5 assertz.err=ERR_LEADING_BITS_NON_ZERO end

# the next element is the mainnet flag (LE-packed u32)
# byte-swap to get the BE value, then assert it is exactly 1
# => [mainnet_flag_le, rollup_index_le, leaf_index_le, ...]
# => [mainnet_flag_le, rollup_index_le, leaf_index_le]
exec.utils::swap_u32_bytes
assert.err=ERR_BRIDGE_NOT_MAINNET

# the next element is the rollup index, must be zero for a mainnet deposit
# the rollup index must be zero for a mainnet deposit
# (zero is byte-order-independent, so no swap needed)
assertz.err=ERR_ROLLUP_INDEX_NON_ZERO

Expand All @@ -208,6 +218,38 @@ pub proc process_global_index_mainnet
# => [leaf_index]
end

#! Assert the global index is valid for a rollup deposit.
#!
#! Each element of the global index is a LE-packed u32 felt (as produced by
#! `bytes_to_packed_u32_felts` / `GlobalIndex::to_elements()`).
#!
#! Inputs: [GLOBAL_INDEX[8]]
#! Outputs: [leaf_index, rollup_index]
#!
#! Panics if:
#! - the leading bits of the global index are not zero.
#! - the mainnet flag is not 0.
#!
#! Invocation: exec
pub proc process_global_index_rollup
# the top 191 bits of the global index are zero
repeat.5 assertz.err=ERR_LEADING_BITS_NON_ZERO end

# the next element is the mainnet flag (LE-packed u32)
# for a rollup deposit it must be exactly 0; zero is byte-order-independent,
# so no swap is needed before asserting
# => [mainnet_flag_le, rollup_index_le, leaf_index_le]
assertz.err=ERR_BRIDGE_NOT_ROLLUP

# byte-swap rollup_index from LE to BE
exec.utils::swap_u32_bytes
# => [rollup_index, leaf_index_le]

# byte-swap leaf_index from LE to BE
swap exec.utils::swap_u32_bytes
# => [leaf_index, rollup_index]
end

#! Computes the Global Exit Tree (GET) root from the mainnet and rollup exit roots.
#!
#! The mainnet exit root is expected at `exit_roots_ptr` and
Expand Down Expand Up @@ -474,27 +516,69 @@ proc verify_leaf
padw push.GLOBAL_INDEX_PTR add.4 mem_loadw_le swapw
# => [GLOBAL_INDEX[8], LEAF_VALUE[8]]

# to see if we're dealing with a deposit from mainnet or from a rollup, process the global index
# TODO currently only implemented for mainnet deposits (mainnet flag must be 1)
exec.process_global_index_mainnet
# => [leaf_index, LEAF_VALUE[8]]
# Determine if we're dealing with a deposit from mainnet or from a rollup.
# The global index is laid out as:
# [gi0, gi1, gi2, gi3, gi4, mainnet_flag_le, rollup_index_le, leaf_index_le]
# gi0 is on top (position 0). The mainnet flag is at stack position 5.

# load the pointers to the merkle proof and root, to pass to `verify_merkle_proof`
push.MAINNET_EXIT_ROOT_PTR swap
push.SMT_PROOF_LOCAL_EXIT_ROOT_PTR
# => [smt_proof_ptr, leaf_index, mainnet_exit_root_ptr, LEAF_VALUE[8]]
# Duplicate the mainnet flag element, byte-swap from LE to BE,
# assert it is a valid boolean (0 or 1), then use it to branch.
dup.5 exec.utils::swap_u32_bytes dup
# => [mainnet_flag, mainnet_flag, GLOBAL_INDEX[8], LEAF_VALUE[8]]

# prepare the stack for the verify_merkle_proof procedure: move the pointers deep in the stack
movdn.10 movdn.10 movdn.10
# => [LEAF_VALUE[8], smt_proof_ptr, leaf_index, mainnet_exit_root_ptr]
u32lt.2 assert.err=ERR_MAINNET_FLAG_INVALID
# => [mainnet_flag, GLOBAL_INDEX[8], LEAF_VALUE[8]]

exec.verify_merkle_proof
# => [verification_flag]
if.true
# ==================== MAINNET DEPOSIT ====================
exec.process_global_index_mainnet
# => [leaf_index, LEAF_VALUE[8]]

# verify_merkle_proof procedure returns `true` if the verification was successful and `false`
# otherwise. Assert that `true` was returned.
assert.err=ERR_SMT_ROOT_VERIFICATION_FAILED
# => []
# verify single Merkle proof: leaf against mainnetExitRoot
push.MAINNET_EXIT_ROOT_PTR swap
push.SMT_PROOF_LOCAL_EXIT_ROOT_PTR
# => [smt_proof_ptr, leaf_index, mainnet_exit_root_ptr, LEAF_VALUE[8]]

movdn.10 movdn.10 movdn.10
# => [LEAF_VALUE[8], smt_proof_ptr, leaf_index, mainnet_exit_root_ptr]

exec.verify_merkle_proof
# => [verification_flag]

assert.err=ERR_SMT_ROOT_VERIFICATION_FAILED
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we have different error messages for if the proof verification failed for rollup vs mainnet deposit?

Say, ERR_SMT_ROOT_VERIFICATION_FAILED_ROLLUP & ERR_SMT_ROOT_VERIFICATION_FAILED_MAINNET?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We could, but we only ever verify one of them per CLAIM note, and I think it should be clear for the submitted of the CLAIM note which path they're taking (by definition, they must know where this data came from, mainnet or rollup). So I think not strictly necessary, lmk if you disagree though (I'll merge as-is, this can be done in a follow up if needed)

# => []
else
# ==================== ROLLUP DEPOSIT ====================
# mainnet_flag = 0; extract rollup_index and leaf_index via helper,
# then do two-level verification
exec.process_global_index_rollup
# => [leaf_index, rollup_index, LEAF_VALUE[8]]

# Step 1: calculate_root(leafValue, smtProofLocalExitRoot, leafIndex) -> localExitRoot
# calculate_root expects: [LEAF_VALUE_LO, LEAF_VALUE_HI, merkle_path_ptr, leaf_index]
movdn.9 movdn.9
# => [LEAF_VALUE[8], leaf_index, rollup_index]

# Insert smt_proof_local_ptr before leaf_index
push.SMT_PROOF_LOCAL_EXIT_ROOT_PTR movdn.8
# => [LEAF_VALUE[8], smt_proof_local_ptr, leaf_index, rollup_index]

exec.calculate_root
# => [LOCAL_EXIT_ROOT_LO, LOCAL_EXIT_ROOT_HI, rollup_index]

# Step 2: verify_merkle_proof(localExitRoot, smtProofRollupExitRoot, rollupIndex, rollupExitRootPtr)
push.ROLLUP_EXIT_ROOT_PTR movdn.9
# => [LOCAL_EXIT_ROOT_LO, LOCAL_EXIT_ROOT_HI, rollup_index, rollup_exit_root_ptr]
push.SMT_PROOF_ROLLUP_EXIT_ROOT_PTR movdn.8

# => [LOCAL_EXIT_ROOT[8], smt_proof_rollup_ptr, rollup_index, rollup_exit_root_ptr]

exec.verify_merkle_proof
# => [verification_flag]

assert.err=ERR_SMT_ROOT_VERIFICATION_FAILED
# => []
end
end

# Inputs: [PROOF_DATA_KEY, LEAF_DATA_KEY]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"amount": "100000000000000000000",
"deposit_count": 3,
"description": "Rollup deposit test vectors with valid two-level Merkle proofs (non-zero indices)",
"destination_address": "0x00000000AA0000000000bb000000cc000000Dd00",
"destination_network": 20,
"global_exit_root": "0x677d4ecba0ff4871f33163e70ea39a13fe97f2fa9b4dbad110e398830a324159",
"global_index": "0x0000000000000000000000000000000000000000000000000000000500000002",
"leaf_type": 0,
"leaf_value": "0x4a6a047a2b89dd9c557395833c5e34c4f72e6f9aae70779e856f14a6a2827585",
"local_exit_root": "0x985cff7ee35794b30fba700b64546b4ec240d2d78aaf356d56e83d907009367f",
"mainnet_exit_root": "0x4d63440b08ffffe5a049aae4161d54821a09973965a1a1728534a0f117b6d6c9",
"metadata": "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a5465737420546f6b656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045445535400000000000000000000000000000000000000000000000000000000",
"metadata_hash": "0x4d0d9fb7f9ab2f012da088dc1c228173723db7e09147fe4fea2657849d580161",
"origin_network": 3,
"origin_token_address": "0x2DC70fb75b88d2eB4715bc06E1595E6D97c34DFF",
"rollup_exit_root": "0x91105681934ca0791f4e760fb1f702050d81e4b7c866d42f540710999c90ea97",
"smt_proof_local_exit_root": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0xa8367b4263332f7e5453faa770f07ef4ce3e74fc411e0a788a98b38b91fd3b3e",
"0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30",
"0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85",
"0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344",
"0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d",
"0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968",
"0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83",
"0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af",
"0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0",
"0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5",
"0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892",
"0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c",
"0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb",
"0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc",
"0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2",
"0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f",
"0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a",
"0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0",
"0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0",
"0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2",
"0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9",
"0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377",
"0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652",
"0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef",
"0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d",
"0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0",
"0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e",
"0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e",
"0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322",
"0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735",
"0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9"
],
"smt_proof_rollup_exit_root": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5",
"0xb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30",
"0x21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85",
"0xe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344",
"0x0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d",
"0x887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968",
"0xffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83",
"0x9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af",
"0xcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0",
"0xf9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5",
"0xf8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892",
"0x3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c",
"0xc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb",
"0x5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc",
"0xda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2",
"0x2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f",
"0xe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a",
"0x5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0",
"0xb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0",
"0xc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2",
"0xf4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9",
"0x5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377",
"0x4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652",
"0xcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef",
"0x0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d",
"0xb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0",
"0x838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e",
"0x662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e",
"0x388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322",
"0x93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735",
"0x8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9"
]
}
Loading
Loading