Skip to content

feat(fast-inbox): single variable-size InboxParity proof per checkpoint (A-1427)#24759

Open
spalladino wants to merge 7 commits into
spl/a-1375-msgs-only-blockfrom
spl/a-1427-inbox-parity
Open

feat(fast-inbox): single variable-size InboxParity proof per checkpoint (A-1427)#24759
spalladino wants to merge 7 commits into
spl/a-1375-msgs-only-blockfrom
spl/a-1427-inbox-parity

Conversation

@spalladino

Copy link
Copy Markdown
Contributor

Replaces the parity base (×4) + parity root fan-in with one variable-size InboxParity<S> proof per checkpoint, S ∈ {64, 256, 1024} (one VK per size; the prover proves the smallest rung ≥ the checkpoint's message count). The parity-root circuit is deleted; the checkpoint root keeps a single parity verification, now accepting the 3-rung VK ladder. Net +1 VK.

Stacked on #24612 (spl/a-1375-msgs-only-block).

Two transitional decisions (dev-only; closed by the future Fast Inbox flip)

  • in_hash unconstrained pass-through. The circuit no longer builds the sha256 frontier tree. in_hash stays in the parity public inputs as an unconstrained hint — the orchestrator supplies the true frontier root via computeInHashFromL1ToL2Messages, the circuit echoes it out, and the checkpoint root copies it into the header. L1's require(header.inHash == inbox.consume()) still passes, so no L1 changes (ConstantsGen.sol regenerates byte-identical to the base).
  • Sponge real-count decoupling. Block roots absorb the message sponge at the real count while the L1-to-L2 tree insert stays a padded fixed subtree, via a new L1ToL2MessageBundle { messages, num_msgs, num_real_msgs } struct so the real count can be dropped later with minimal change. num_msgs is not otherwise pinned in-circuit — documented as a dev-mode gap backstopped by the L1 pending-chain header hash, parallel to in_hash.

Scope

Threads the single sized proof through the orchestrator, bb-prover, proving broker, and TS bindings — collapsing getBaseParityProof/getRootParityProof into getInboxParityProof and PARITY_BASE/PARITY_ROOT into one INBOX_PARITY request type. The UltraHonk parity benchmark and bb.js debug test move to InboxParity256.

Validation

  • rollup_lib nargo suite: 387/387 passing.
  • Reviewed by a second model (Fable) and codex sol; their build-break and consistency findings are folded in.
  • Full yarn build, VK/artifact regen, real proofs, and e2e run in CI (blocked locally by a bb write_vk memory-arena OOM on the unchanged rollup_root circuit).

Known follow-up (out of scope, pre-existing on base)

inbox_rolling_hash.nr's doc comment claims the sha256 chain "matches the L1 Inbox," but Inbox.sol accumulates bytes16(keccak256(...)). Harmless today (the rolling hash isn't validated on L1), but the comment should be corrected on the base branch.

@spalladino
spalladino requested a review from LeilaWang as a code owner July 17, 2026 01:49
@spalladino
spalladino force-pushed the spl/a-1427-inbox-parity branch from 071f3d1 to 4375d97 Compare July 17, 2026 02:04
@spalladino spalladino added the ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure label Jul 17, 2026
@spalladino
spalladino requested a review from Thunkar as a code owner July 17, 2026 03:29
@spalladino spalladino changed the title feat: single variable-size InboxParity proof per checkpoint (A-1427) feat(fast-inbox): single variable-size InboxParity proof per checkpoint (A-1427) Jul 17, 2026
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from 9d669cb to eb88eba Compare July 17, 2026 19:38
@spalladino
spalladino requested a review from just-mitch as a code owner July 17, 2026 19:38
@spalladino
spalladino force-pushed the spl/a-1427-inbox-parity branch from c18b69c to 1872323 Compare July 17, 2026 19:38
Replace the parity base (x4) + parity root fan-in with one variable-size
InboxParity<S> proof per checkpoint, S in {64, 256, 1024} (one VK per size;
the prover proves the smallest rung >= the checkpoint's message count). The
parity-root circuit is deleted; the checkpoint root keeps one parity
verification, now accepting the 3-rung VK ladder. Net +1 VK.

Two transitional decisions (dev-only, closed by the future Fast Inbox flip):
- in_hash is kept in the parity public inputs as an unconstrained pass-through
  hint (the orchestrator supplies the true sha256 frontier root via
  computeInHashFromL1ToL2Messages), so L1's inHash == inbox.consume() check
  still passes with no L1 changes. The frontier tree is no longer built in
  circuit.
- The block-root message sponge absorbs at the real message count while the
  L1-to-L2 tree insert stays a padded fixed subtree, decoupled via a new
  L1ToL2MessageBundle { messages, num_msgs, num_real_msgs } struct so the real
  count can be dropped later with minimal change. num_msgs is not otherwise
  pinned in-circuit; documented as a dev-mode gap backstopped by the L1
  pending-chain header hash.

Threads the single sized proof through the orchestrator, bb-prover, proving
broker, and TS bindings, collapsing getBaseParityProof/getRootParityProof into
getInboxParityProof and PARITY_BASE/PARITY_ROOT into one INBOX_PARITY request
type. The UltraHonk parity benchmark and bb.js debug test move to InboxParity256.
…e parity method merge

Deleting getRootParityProof removed the last uses of NESTED_RECURSIVE_PROOF_LENGTH
in mock_prover.ts and broker_prover_facade.ts; @typescript-eslint/no-unused-vars
is error-level so yarn lint would fail. Also corrects two 'base parity' JSDoc
lines to 'inbox parity'.
The generated L1ToL2MessageBundle.messages type is a fixed-length (1024) array,
but the bundle's messages field is a plain Fr[], so mapFieldArrayToNoir inferred
length `number` and tsc rejected it (TS2322) at the six block-root mapper call
sites. Pass MAX_L1_TO_L2_MSGS_PER_BLOCK explicitly to produce the fixed length.
Removing the value constants (NUM_BASE_PARITY_PER_ROOT_PARITY, NUM_MSGS_PER_BASE_PARITY)
left an @aztec/constants import whose members are all inline-type, which
@typescript-eslint/no-import-type-side-effects rejects. Convert to import type.
Replacing the parity base/root artifacts with the single variable-size
InboxParity ladder (64/256/1024) grew the playground main entrypoint to
1936.74 KB on CI, just over the 1925 KB hard limit. Bump with headroom,
following the existing bump-log pattern in vite.config.ts.
ParityPublicInputs requires inHash to be a 31-byte (top-byte-zero) sha frontier
root; the InboxParity circuit passes in_hash through unconstrained, so a raw
Fr.random() input reappears in the output and fails the constructor check.
Compute inHash from the messages instead.
@spalladino
spalladino force-pushed the spl/a-1375-msgs-only-block branch from eb88eba to 5f7c796 Compare July 17, 2026 20:04
@spalladino
spalladino force-pushed the spl/a-1427-inbox-parity branch from 1872323 to 347a6e1 Compare July 17, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant