feat(fast-inbox): domain-separate the inbox rolling-hash chain - #25067
Open
spalladino wants to merge 1 commit into
Open
feat(fast-inbox): domain-separate the inbox rolling-hash chain#25067spalladino wants to merge 1 commit into
spalladino wants to merge 1 commit into
Conversation
Every Inbox message leaf advanced the consensus rolling hash as `h' = sha256ToField(h || leaf)` over the two 32-byte
big-endian values. That 64-byte preimage is byte-identical to the one the L2-to-L1 `out_hash` merkle node hash absorbs,
so nothing distinguished a chain link from a merkle node. Each link now absorbs a domain separator first:
h' = sha256ToField(DOM_SEP__INBOX_ROLLING_HASH || h || leaf)
The tag is a 4-byte big-endian u32 written as a prefix, not a padded field element, so the preimage grows from 64 to 68
bytes and stays inside two sha256 compression blocks in-circuit. On L1 the precompile moves up one word tier
(60 + 12*ceil(len/32), 84 -> 96 gas per link); the measured end-to-end `sendL2Message` delta is +36-38 gas including
the extra `abi.encodePacked` memory word (absorb into an open bucket: 8369 -> 8405). The genesis rolling hash is
unchanged at zero, so `Inbox.sol` needs no migration. `out_hash` is deliberately left untagged and is not touched here.
- `DOM_SEP__INBOX_ROLLING_HASH` joins the domain-separator registry in `constants.nr`, derived and collision-checked
like its siblings in `constants_tests.nr` (`hash_to_u32("az_dom_sep", "inbox_rolling_hash")` = 3737216265).
- `generateSolidityConstants` now emits domain separators alongside plain constants, mirroring the C++, PIL and Rust
generators, so the tag can reach `ConstantsGen.sol` through the `solidity.json` allowlist rather than by hand.
- `Hash.accumulateInboxRollingHash` prepends `uint32(Constants.DOM_SEP__INBOX_ROLLING_HASH)`.
- `types::hash` gains `accumulate_sha256_with_separator`, the tagged sibling of `accumulate_sha256` (this is the
variant the `accumulate_sha256` TODO asked for); `accumulate_inbox_rolling_hash` uses it.
- The TS mirror in `stdlib` prepends the same 4-byte tag from the generated `DomainSeparator` enum.
The pinned cross-language test vectors in the noir helper, the `stdlib` suite and `InboxBuckets.t.sol` were recomputed
from an independent node `crypto.createHash` reference over the exact 68-byte preimages, and the nine rollup
`Prover.toml` sample inputs that carry rolling-hash values were regenerated with
`AZTEC_GENERATE_TEST_DATA=1 yarn workspace @aztec/prover-client test regenerate_rollup_sample_inputs`.
Testing:
- `nargo test --package rollup_lib`: 385/385 pass; `--package types`: 413/413 pass.
- `nargo execute` passes for all 16 crates with committed sample inputs.
- `forge test` (full l1-contracts suite): 889 passed, 0 failed, 3 skipped.
- `@aztec/stdlib` inbox_rolling_hash (6) and `@aztec/archiver` message_store (38) pass; constants-codegen node tests
(20) pass.
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.
Part of the Fast Inbox (AZIP-22) stack, on top of #25038. Umbrella: #25041.
Context
The streaming-inbox consensus rolling hash advanced as
h' = sha256ToField(h || leaf)over two 32-byte big-endian values — a 64-byte preimage byte-identical to the L2-to-L1out_hashmerkle node hash, so nothing structurally distinguished a chain link from a merkle node. The domain-separation assessment (A-1431) concluded this identical-preimage ambiguity is not exploitable today but is ~free to close, and the free window ends when the streaming-inbox flip lands (post-flip the construction is consensus).Approach
Each link now prefixes a domain separator:
h' = sha256ToField(DOM_SEP__INBOX_ROLLING_HASH || h || leaf). The tag is a 4-byte big-endian u32, so the preimage grows 64 → 68 bytes and stays inside two sha256 compression blocks in-circuit; on L1 the precompile moves up one word tier (84 → 96 gas per link), with a measured end-to-endsendL2Messagedelta of +36–38 gas. Genesis stays zero, so theInboxneeds no migration.out_hashis deliberately left untagged.DOM_SEP__INBOX_ROLLING_HASHjoins the domain-separator registry inconstants.nr, derived and collision-checked like its siblings inconstants_tests.nr(hash_to_u32("az_dom_sep", "inbox_rolling_hash")= 3737216265).generateSolidityConstantsnow emits domain separators alongside plain constants (mirroring the C++, PIL and Rust generators), so the tag reachesConstantsGen.solthrough thesolidity.jsonallowlist.accumulate_inbox_rolling_hash(via a newtypes::hash::accumulate_sha256_with_separator), and the TS mirror all adopt the tagged construction.stdlib,InboxBuckets.t.sol) were recomputed from an independent sha256 reference over the exact 68-byte preimages, and the nine rollupProver.tomlsample inputs carrying rolling-hash values were regenerated through the canonical prover-client path.Fixes A-1431