Skip to content

feat: message-bundle components in rollup-lib (A-1372)#24587

Open
spalladino wants to merge 2 commits into
merge-train/spartan-v6from
spl/a-1372-msg-bundle-components
Open

feat: message-bundle components in rollup-lib (A-1372)#24587
spalladino wants to merge 2 commits into
merge-train/spartan-v6from
spl/a-1372-msg-bundle-components

Conversation

@spalladino

Copy link
Copy Markdown
Contributor

First PR of the Fast Inbox circuits series (A-1372). Pure library components in rollup-lib/types plus new constants — no circuit interface changes, nothing consumes these yet. They exist so the follow-up PRs (inboxRollingHash end to end, per-block bundles) are reviewable as wiring rather than wiring + primitives.

Components

  • append_leaves_to_snapshot (types/src/merkle_tree/append_only_tree.nr): variable-length append of up to MaxLeaves leaves into a poseidon AppendOnlyTreeSnapshot at an arbitrary (non-aligned) index, replacing the alignment assumption of the fixed height-10 subtree insert. Takes a frontier hint validated against the snapshot root (same trust model as sibling-path hints; unpinned hint lanes are provably never read). Implemented as a level-by-level batched merge costing ~MaxLeaves + 3·TreeHeight poseidon hashes — 1,166 for a 1024-leaf bundle in the height-36 tree, 398 for 256 — matching the cost model from the design analysis. An exhaustive small-tree sweep tests every (start, num) combination against a reference tree, and an equivalence test proves a 1024-leaf append at an aligned index reproduces insert_subtree_root_to_snapshot bit for bit (root 0x27b87d4d3b78d1fc49a6cb4d83e0cc81de7f5972cda7fe29a6a82aa2c255cb3d) — this is what keeps the transitional wiring identical to production today.
  • L1ToL2MessageSponge (rollup-lib/src/abis/l1_to_l2_message_sponge.nr): absorb-only poseidon2 sponge over message leaves (the inHashSponge from AZIP-22 Option 3), modeled on SpongeBlob. Compared by state equality, never squeezed on the block path; iv = 0 (unlike SpongeBlob, whose iv encodes expected length because its squeeze feeds the blob challenge — this sponge's TS mirror must use iv 0). Length bound is enforced by the underlying poseidon2_absorb_in_chunks_existing_sponge.
  • accumulate_inbox_rolling_hash (rollup-lib/src/inbox_rolling_hash.nr): rolling truncated sha256 chain, each link h' = sha256ToField(h_32be || leaf_32be) via the existing accumulate_sha256 — byte-identical to Solidity Hash.sol::sha256ToField and TS truncateAndPad. Takes a start, returns an end, no chunk-position assumptions, so it threads sequentially across chunked circuits.
  • Constants: MAX_L1_TO_L2_MSGS_PER_BLOCK = 1024 (transitional; drops to 256 at the flip) and MAX_L1_TO_L2_MSGS_PER_CHECKPOINT = 1024 (semantically today's NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, which stays untouched until cleanup). TS constants regenerated; ConstantsGen.sol is intentionally unchanged (the Solidity emitter allow-list doesn't include them — L1 constants land with the Inbox L1 work).

Shared test vectors

Generated from an independent sha256 implementation and embedded in the noir tests; the TS mirror and the L1 Foundry tests must pin the same values. chain(start, leaves) folds h' = sha256ToField(h || leaf):

Case Value
chain(0, [11]) 0x00815fb1e9d2076ae5761439b6144ad11da69eb6c41ab2aca39e770407ad8d12
chain(0, [11, 22, 33]) 0x0014cae968461979aab6d33266a2310ed234d3f6cf4472737c57551db07bd0da
chain(0, [1..=256]) 0x00ea95b96f17b75be03525b35a2a1918b42f03ad8c00a437cf641751825f3992
chain(0x2a, [7, 8]) 0x0054d96b8a074a5030a5838972d0a3c04ba47cf5956348c853e02e9566233f65
chain(0x2a, [7]) (intermediate link) 0x0032a934005556d1b9d22708666ee8b05f91fafad624dd64a6ea878e048e5438

Testing

  • 25 new noir tests across both crates (append: empty/single/non-aligned/max/partial/equivalence/exhaustive sweep/failure cases; sponge: split-boundary threading, padding exclusion; rolling hash: reference vectors, segment continuity, padding exclusion). Full suites green: types 373, rollup-lib 381.
  • yarn build green. No compiled circuit artifacts change (library-only code, unused constants).

Pure library components for the Fast Inbox (AZIP-22), consumed by nothing
yet: new MAX_L1_TO_L2_MSGS_PER_BLOCK / MAX_L1_TO_L2_MSGS_PER_CHECKPOINT
constants, a variable-length frontier-based append to an
AppendOnlyTreeSnapshot at arbitrary (non-aligned) indices, an absorb-only
poseidon message-bundle sponge (L1ToL2MessageSponge), and the rolling
sha256 chain helper (accumulate_inbox_rolling_hash) matching the L1
truncated-to-field policy. No circuit interface changes.
Replaces the per-leaf frontier walk (MaxLeaves x TreeHeight poseidon
hashes) with a level-by-level batched merge: the batch is prepended with
the pending left sibling when it starts as a right child, dangling odd
nodes become the new frontier entries, and remaining nodes are paired
into the next level with lane bounds halving per level. Total cost drops
to ~MaxLeaves + 3 x TreeHeight hashes (1,166 for 1024 leaves in the
height-36 tree vs ~36,900 before). Same signature, semantics, and error
messages. Adds an exhaustive small-tree sweep over every (start, num)
combination and a fail-closed test for appending to a completely full
tree.
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