feat: introduce inboxRollingHash end to end, dual with inHash (A-1373)#24600
Open
spalladino wants to merge 4 commits into
Open
feat: introduce inboxRollingHash end to end, dual with inHash (A-1373)#24600spalladino wants to merge 4 commits into
spalladino wants to merge 4 commits into
Conversation
Adds the Fast Inbox (AZIP-22) rolling-hash commitment as a dual of the
legacy inHash, flowing through parity circuits, block/checkpoint rollup
public inputs, the checkpoint header, L1, and the node/prover.
Circuits (noir):
- Parity base absorbs only real leaves into a truncated-to-field sha256
chain (accumulate_inbox_rolling_hash, guarded by num_msgs +
assert_trailing_zeros); merkle roots keep absorbing padding. Parity
public inputs gain start_rolling_hash / end_rolling_hash / num_msgs;
parity root threads the four base segments sequentially and sums counts.
- BlockRollupPublicInputs and CheckpointRollupPublicInputs carry a
{start,end} pair propagated exactly like in_hash (first block root sets
it, merges take left's, validate asserts right's is zero). Checkpoint
merge asserts right.start == left.end (decision 11). CheckpointHeader
gains inbox_rolling_hash (the end value) immediately after in_hash.
- Root rollup public inputs are unchanged: exposing the epoch pair is
inseparable from the L1 epoch-proof anchoring that is out of scope here
(FI-08/FI-14), so it is deferred with the rest of L1 anchoring.
TS: stdlib inbox_rolling_hash mirror (unit-tested against the FI-02
vectors), CheckpointHeader / parity / block / checkpoint PI classes,
noir-protocol-circuits-types conversions, orchestrator threading of
per-base start hashes + counts, and node header population at the
sequencer / prover / validator sites (sourced from the previous
checkpoint header via getPreviousCheckpointInboxRollingHash).
L1: ProposedHeader + ProposedHeaderLib.hash pack inboxRollingHash after
inHash (no new propose checks); test fixtures + headerHash regenerated.
Add the {previous, end} inbox rolling-hash pair to RootRollupPublicInputs so
the epoch's consumed chain segment is carried through to proof verification.
The root rollup sources the pair from the merged checkpoint public inputs;
continuity within the range is already enforced by the checkpoint merges.
On L1, PublicInputArgs gains previousInboxRollingHash/endInboxRollingHash and
EpochProofLib places them at public-input positions 3 and 4 (header hashes,
fees, constants and blob inputs shift by two). Both values are deliberately
unvalidated until the Fast Inbox flip, when they will be checked against the
per-checkpoint records written at propose; for now they are pass-through only.
Also fixes two ivc-integration benchmark generators whose hand-built parity
base inputs were missing start_rolling_hash/num_msgs.
spalladino
commented
Jul 8, 2026
Comment on lines
+146
to
+155
| const start = baseParityIndex * NUM_MSGS_PER_BASE_PARITY; | ||
| const realMessages = this.l1ToL2Messages.slice(start, start + NUM_MSGS_PER_BASE_PARITY); | ||
| const messages = padArrayEnd(realMessages, Fr.ZERO, NUM_MSGS_PER_BASE_PARITY); | ||
| // Thread the rolling hash: this base's start is the chain value after all real messages in earlier bases, so the | ||
| // four bases chain sequentially and the parity root ends at the checkpoint's rolling hash. Only real (non-padding) | ||
| // messages are absorbed, matching the proposer's `accumulateInboxRollingHash`. | ||
| const startRollingHash = accumulateInboxRollingHash( | ||
| this.startInboxRollingHash, | ||
| this.l1ToL2Messages.slice(0, start), | ||
| ); |
Contributor
Author
There was a problem hiding this comment.
I don't think this is correct. Aren't the this.l1ToL2Messages already padded? And shouldn't realMessages drop the pads? Or is that left for a future PR?
…1373) Exposing the inbox rolling hash on the parity-root and rollup public inputs changed the ABI of the block-root-first variants, block-merge, checkpoint-merge and root circuits, but their committed crates/rollup-*/Prover.toml sample inputs were not refreshed. CI runs `nargo execute` against these fixtures, so all six failed to deserialize (e.g. missing parity_root.public_inputs.start_rolling_hash and previous_rollups[].public_inputs.start_inbox_rolling_hash). Regenerate the six stale fixtures. The circuits push their serialized inputs via pushTestData when run through the prover, so a new prover-client test drives representative epochs through the simulated orchestrator and dumps the captured inputs, replacing the dead orchestrator_single_checkpoint.test.ts regeneration path. The suite is skipped unless AZTEC_GENERATE_TEST_DATA=1 is set.
spalladino
commented
Jul 8, 2026
Contributor
Author
There was a problem hiding this comment.
Why is this needed? How were those inputs generated before for the tests? Or are these new tests?
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.
Stacked on #24587 (A-1372). Part of the AZIP-22 Fast Inbox work.
What
Introduces the
inboxRollingHash— a truncated-to-field sha256 rolling chain over the L1→L2 message leaves — end to end, carried as a dual of the legacyinHash. The legacyinHashremains authoritative; the rolling hash is computed and threaded everywhere but not yet enforced on L1, so this change is behavior-preserving pre-flip.Each link is
h' = sha256ToField(h_be32 || leaf_be32)with the top byte of the digest zeroed, genesis value zero.Changes
Circuits (noir)
start_rolling_hash→end_rolling_hash,num_msgs), asserting trailing padding lanes are zero. Parity root asserts chunk continuity (children[i].start == children[i-1].end) and sums the counts.{start, end}rolling-hash pair, propagated exactly likein_hash. Checkpoint merges assertright.start == left.end(decision 11 anchoring).inbox_rolling_hashimmediately afterin_hash.{previous, end}pair sourced from the merged checkpoint public inputs, so the epoch's consumed chain segment is passed through to proof verification.L1 (Solidity)
ProposedHeaderLibserializes the new header field (header 348 → 380 bytes).PublicInputArgsgainspreviousInboxRollingHash/endInboxRollingHash;EpochProofLibplaces them at public-input positions 3 and 4 (header hashes, fees, constants and blob inputs shift by two). Both values are deliberately unvalidated until the Fast Inbox flip — for now they are pass-through only.TypeScript
updateInboxRollingHash/accumulateInboxRollingHashmirror the circuit chain;getPreviousCheckpointInboxRollingHashsources the previous checkpoint's end value (returns zero for checkpoint ≤ 1). The sequencer, validator, and prover populate the header field; the orchestrator threads per-base start hashes; the prover-node publisher fills the two newPublicInputArgs.RootRollupPublicInputsgains the pair with matching serialization, conversion, factories and viem types.Constants
CHECKPOINT_HEADER_LENGTH13 → 14,BLOCK_ROLLUP_PUBLIC_INPUTS_LENGTH56 → 58,CHECKPOINT_ROLLUP_PUBLIC_INPUTS_LENGTH149 → 151,ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH111 → 113.pinned-build.tar.gzis regenerated and committed.Testing
yarn buildgreen;forge testgreen (870 passed); noir rollup-lib root suites green (176 passed).l1_to_l2e2e confirms the header field round-trips through L1 and the archiver (decodedinboxRollingHash= 0 for the genesis checkpoint, as expected). This suite is registered flaky (.test_patterns.yml); the repeated-consumption cases exhibit a pre-existing nullifier-sync timing race unrelated to this change.