diff --git a/labs-patches/0015-feat-stdlib-add-InboxParity-rungs-for-4-and-16-messa.patch b/labs-patches/0015-feat-stdlib-add-InboxParity-rungs-for-4-and-16-messa.patch new file mode 100644 index 000000000000..49a647a797b0 --- /dev/null +++ b/labs-patches/0015-feat-stdlib-add-InboxParity-rungs-for-4-and-16-messa.patch @@ -0,0 +1,220 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Santiago Palladino +Date: Thu, 10 Sep 2026 14:22:47 -0300 +Subject: [PATCH] feat(stdlib): add InboxParity rungs for 4 and 16 messages + +The InboxParity ladder gains two smaller rungs in the protocol circuits, so the +node side has to know about them: `INBOX_PARITY_SIZES` grows to five entries +(ascending, so `pickInboxParitySize` keeps picking the smallest that fits), the +two artifacts join the server artifact union, the size-to-artifact map, the VK +index map and the plain-UltraHonk list in the bb-prover, and the codegen script +emits their input types. + +diff --git a/yarn-project/bb-prover/src/honk.ts b/yarn-project/bb-prover/src/honk.ts +index 5cac2075281bfe55bbfc2d8c73ae9026822d0ef4..6ed3dae2f0ff6e0edd55494795584359d938242d 100644 +--- a/yarn-project/bb-prover/src/honk.ts ++++ b/yarn-project/bb-prover/src/honk.ts +@@ -4,6 +4,8 @@ export type UltraHonkFlavor = 'ultra_honk' | 'ultra_keccak_honk' | 'ultra_starkn + + const UltraKeccakHonkCircuits = ['RootRollupArtifact'] as const satisfies ServerProtocolArtifact[]; + const UltraHonkCircuits = [ ++ 'InboxParity4Artifact', ++ 'InboxParity16Artifact', + 'InboxParity64Artifact', + 'InboxParity256Artifact', + 'InboxParity1024Artifact', +diff --git a/yarn-project/noir-protocol-circuits-types/src/artifacts/server.ts b/yarn-project/noir-protocol-circuits-types/src/artifacts/server.ts +index 2e8c9b9b695e3b94825d95208e0fb2143c38ae9a..86e3e6dfc20603c54ed758f678dd847a445ee4ac 100644 +--- a/yarn-project/noir-protocol-circuits-types/src/artifacts/server.ts ++++ b/yarn-project/noir-protocol-circuits-types/src/artifacts/server.ts +@@ -1,6 +1,8 @@ + import type { NoirCompiledCircuit, NoirCompiledCircuitWithName } from '@aztec-labs/stdlib/noir'; + + import PublicChonkVerifierJson from '../../artifacts/chonk_verifier_public.json' with { type: 'json' }; ++import InboxParity4Json from '../../artifacts/inbox_parity_4.json' with { type: 'json' }; ++import InboxParity16Json from '../../artifacts/inbox_parity_16.json' with { type: 'json' }; + import InboxParity64Json from '../../artifacts/inbox_parity_64.json' with { type: 'json' }; + import InboxParity256Json from '../../artifacts/inbox_parity_256.json' with { type: 'json' }; + import InboxParity1024Json from '../../artifacts/inbox_parity_1024.json' with { type: 'json' }; +@@ -25,6 +27,8 @@ import TxMergeRollupJson from '../../artifacts/rollup_tx_merge.json' with { type + import type { ServerProtocolArtifact } from './types.js'; + + export const ServerCircuitArtifacts: Record = { ++ InboxParity4Artifact: InboxParity4Json as NoirCompiledCircuit, ++ InboxParity16Artifact: InboxParity16Json as NoirCompiledCircuit, + InboxParity64Artifact: InboxParity64Json as NoirCompiledCircuit, + InboxParity256Artifact: InboxParity256Json as NoirCompiledCircuit, + InboxParity1024Artifact: InboxParity1024Json as NoirCompiledCircuit, +@@ -46,6 +50,8 @@ export const ServerCircuitArtifacts: Record = { + // No separate simulated build for the inbox parity ladder: they verify no child proofs, so the constrained + // artifacts are used for simulation too. ++ InboxParity4Artifact: InboxParity4Json as NoirCompiledCircuit, ++ InboxParity16Artifact: InboxParity16Json as NoirCompiledCircuit, + InboxParity64Artifact: InboxParity64Json as NoirCompiledCircuit, + InboxParity256Artifact: InboxParity256Json as NoirCompiledCircuit, + InboxParity1024Artifact: InboxParity1024Json as NoirCompiledCircuit, +diff --git a/yarn-project/noir-protocol-circuits-types/src/artifacts/types.ts b/yarn-project/noir-protocol-circuits-types/src/artifacts/types.ts +index 5809ad8add7ca1de37d88c5ab61d954ccaf9a018..f8d1febc568f130ab387d337c6e2974c5d4e6290 100644 +--- a/yarn-project/noir-protocol-circuits-types/src/artifacts/types.ts ++++ b/yarn-project/noir-protocol-circuits-types/src/artifacts/types.ts +@@ -27,6 +27,8 @@ export type ClientProtocolArtifact = + + // These are all circuits that should generate proofs with the `recursive` flag. + export type ServerProtocolArtifact = ++ | 'InboxParity4Artifact' ++ | 'InboxParity16Artifact' + | 'InboxParity64Artifact' + | 'InboxParity256Artifact' + | 'InboxParity1024Artifact' +@@ -58,6 +60,10 @@ export interface ArtifactProvider { + + export function mapProtocolArtifactNameToCircuitName(artifact: ProtocolArtifact): CircuitName { + switch (artifact) { ++ case 'InboxParity4Artifact': ++ return 'inbox-parity-4'; ++ case 'InboxParity16Artifact': ++ return 'inbox-parity-16'; + case 'InboxParity64Artifact': + return 'inbox-parity-64'; + case 'InboxParity256Artifact': +diff --git a/yarn-project/noir-protocol-circuits-types/src/artifacts/vks/server.ts b/yarn-project/noir-protocol-circuits-types/src/artifacts/vks/server.ts +index 99f2f9d1e34558f1aa0d804f788f0442b321e9e7..9bcb5592bac74317399a089cc0a826ade0ba156f 100644 +--- a/yarn-project/noir-protocol-circuits-types/src/artifacts/vks/server.ts ++++ b/yarn-project/noir-protocol-circuits-types/src/artifacts/vks/server.ts +@@ -9,6 +9,8 @@ import { + CHECKPOINT_ROOT_SINGLE_BLOCK_ROLLUP_VK_INDEX, + HIDING_KERNEL_TO_PUBLIC_VK_INDEX, + HIDING_KERNEL_TO_ROLLUP_VK_INDEX, ++ INBOX_PARITY_4_VK_INDEX, ++ INBOX_PARITY_16_VK_INDEX, + INBOX_PARITY_64_VK_INDEX, + INBOX_PARITY_256_VK_INDEX, + INBOX_PARITY_1024_VK_INDEX, +@@ -31,6 +33,8 @@ import { + import { VerificationKeyData } from '@aztec-labs/stdlib/vks'; + + import PublicChonkVerifier from '../../../artifacts/chonk_verifier_public.json' with { type: 'json' }; ++import InboxParity4 from '../../../artifacts/inbox_parity_4.json' with { type: 'json' }; ++import InboxParity16 from '../../../artifacts/inbox_parity_16.json' with { type: 'json' }; + import InboxParity64 from '../../../artifacts/inbox_parity_64.json' with { type: 'json' }; + import InboxParity256 from '../../../artifacts/inbox_parity_256.json' with { type: 'json' }; + import InboxParity1024 from '../../../artifacts/inbox_parity_1024.json' with { type: 'json' }; +@@ -55,6 +59,8 @@ import { abiToVKData } from '../../utils/vk_json.js'; + import type { ProtocolCircuitName, ServerProtocolCircuitName } from '../types.js'; + + export const ServerCircuitVks: Record = { ++ InboxParity4Artifact: abiToVKData(InboxParity4), ++ InboxParity16Artifact: abiToVKData(InboxParity16), + InboxParity64Artifact: abiToVKData(InboxParity64), + InboxParity256Artifact: abiToVKData(InboxParity256), + InboxParity1024Artifact: abiToVKData(InboxParity1024), +@@ -89,6 +95,8 @@ export const ProtocolCircuitVkIndexes: Record = { + HidingKernelToRollup: HIDING_KERNEL_TO_ROLLUP_VK_INDEX, + HidingKernelToPublic: HIDING_KERNEL_TO_PUBLIC_VK_INDEX, + PublicChonkVerifier: PUBLIC_CHONK_VERIFIER_VK_INDEX, ++ InboxParity4Artifact: INBOX_PARITY_4_VK_INDEX, ++ InboxParity16Artifact: INBOX_PARITY_16_VK_INDEX, + InboxParity64Artifact: INBOX_PARITY_64_VK_INDEX, + InboxParity256Artifact: INBOX_PARITY_256_VK_INDEX, + InboxParity1024Artifact: INBOX_PARITY_1024_VK_INDEX, +diff --git a/yarn-project/noir-protocol-circuits-types/src/execution/server.ts b/yarn-project/noir-protocol-circuits-types/src/execution/server.ts +index 9d3c870eba333ababe207d81b44ce7cb2ac522ad..a8c414261eba957920186b5b394113b9f25ece4c 100644 +--- a/yarn-project/noir-protocol-circuits-types/src/execution/server.ts ++++ b/yarn-project/noir-protocol-circuits-types/src/execution/server.ts +@@ -1,7 +1,13 @@ + import type { InputValue } from '@aztec-foundation/noir-noirc_abi'; + import type { InputMap } from '@aztec-foundation/noir-types'; + +-import { INBOX_PARITY_SIZE_LARGE, INBOX_PARITY_SIZE_MEDIUM, INBOX_PARITY_SIZE_SMALL } from '@aztec-labs/constants'; ++import { ++ INBOX_PARITY_SIZE_LARGE, ++ INBOX_PARITY_SIZE_MEDIUM, ++ INBOX_PARITY_SIZE_SMALL, ++ INBOX_PARITY_SIZE_XSMALL, ++ INBOX_PARITY_SIZE_XXSMALL, ++} from '@aztec-labs/constants'; + import { pushTestData } from '@aztec-labs/foundation/testing'; + import type { InboxParityPrivateInputs } from '@aztec-labs/stdlib/parity'; + import type { +@@ -63,6 +69,10 @@ export function convertInboxParityPrivateInputsToNoir(inputs: InboxParityPrivate + /** Maps an InboxParity ladder size to its server artifact. */ + export function inboxParityArtifactForSize(size: number): ServerProtocolArtifact { + switch (size) { ++ case INBOX_PARITY_SIZE_XXSMALL: ++ return 'InboxParity4Artifact'; ++ case INBOX_PARITY_SIZE_XSMALL: ++ return 'InboxParity16Artifact'; + case INBOX_PARITY_SIZE_SMALL: + return 'InboxParity64Artifact'; + case INBOX_PARITY_SIZE_MEDIUM: +diff --git a/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts b/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts +index 21911887c6d4623e3259441209264a0a66fad50b..1035e60c8fb2687bb028027f8c7b22414479f475 100644 +--- a/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts ++++ b/yarn-project/noir-protocol-circuits-types/src/scripts/generate_ts_from_abi.ts +@@ -8,6 +8,8 @@ import { promises as fs } from 'fs'; + const log = createConsoleLogger('autogenerate'); + + const circuits = [ ++ 'inbox_parity_4', ++ 'inbox_parity_16', + 'inbox_parity_64', + 'inbox_parity_256', + 'inbox_parity_1024', +diff --git a/yarn-project/prover-client/src/test/bb_prover_parity.test.ts b/yarn-project/prover-client/src/test/bb_prover_parity.test.ts +index 91f467c362a75c1d4d8dd035c9dba27ff39bb425..062571a4300529c54f5a3a54caba92d73512e237 100644 +--- a/yarn-project/prover-client/src/test/bb_prover_parity.test.ts ++++ b/yarn-project/prover-client/src/test/bb_prover_parity.test.ts +@@ -12,6 +12,8 @@ const logger = createLogger('prover-client:test:bb-prover-parity'); + + // Maps a ladder size to its server artifact name, mirroring the bb-prover's own selection. + const artifactForSize: Record = { ++ 4: 'InboxParity4Artifact', ++ 16: 'InboxParity16Artifact', + 64: 'InboxParity64Artifact', + 256: 'InboxParity256Artifact', + 1024: 'InboxParity1024Artifact', +diff --git a/yarn-project/stdlib/src/parity/inbox_parity_private_inputs.ts b/yarn-project/stdlib/src/parity/inbox_parity_private_inputs.ts +index cf0687ef9f7c3b6183b596b4299e854d79dc0064..dd96d2660fabb0afc7b61f2522fd22e75a5060d7 100644 +--- a/yarn-project/stdlib/src/parity/inbox_parity_private_inputs.ts ++++ b/yarn-project/stdlib/src/parity/inbox_parity_private_inputs.ts +@@ -1,4 +1,10 @@ +-import { INBOX_PARITY_SIZE_LARGE, INBOX_PARITY_SIZE_MEDIUM, INBOX_PARITY_SIZE_SMALL } from '@aztec-labs/constants'; ++import { ++ INBOX_PARITY_SIZE_LARGE, ++ INBOX_PARITY_SIZE_MEDIUM, ++ INBOX_PARITY_SIZE_SMALL, ++ INBOX_PARITY_SIZE_XSMALL, ++ INBOX_PARITY_SIZE_XXSMALL, ++} from '@aztec-labs/constants'; + import { padArrayEnd } from '@aztec-labs/foundation/collection'; + import { Fr } from '@aztec-labs/foundation/curves/bn254'; + import { bufferSchemaFor } from '@aztec-labs/foundation/schemas'; +@@ -6,7 +12,13 @@ import { BufferReader, serializeToBuffer } from '@aztec-labs/foundation/serializ + import { bufferToHex, hexToBuffer } from '@aztec-labs/foundation/string'; + + /** The InboxParity size ladder, ascending. One VK per size; the prover proves the smallest that fits. */ +-export const INBOX_PARITY_SIZES = [INBOX_PARITY_SIZE_SMALL, INBOX_PARITY_SIZE_MEDIUM, INBOX_PARITY_SIZE_LARGE] as const; ++export const INBOX_PARITY_SIZES = [ ++ INBOX_PARITY_SIZE_XXSMALL, ++ INBOX_PARITY_SIZE_XSMALL, ++ INBOX_PARITY_SIZE_SMALL, ++ INBOX_PARITY_SIZE_MEDIUM, ++ INBOX_PARITY_SIZE_LARGE, ++] as const; + + /** A valid InboxParity ladder size. */ + export type InboxParitySize = (typeof INBOX_PARITY_SIZES)[number]; +diff --git a/yarn-project/stdlib/src/stats/stats.ts b/yarn-project/stdlib/src/stats/stats.ts +index 276c1a70dbc6f8d87a55f6a1727f526e6fa51c0f..e1627a488af61e35e8846abf22b65f5e5333b4a7 100644 +--- a/yarn-project/stdlib/src/stats/stats.ts ++++ b/yarn-project/stdlib/src/stats/stats.ts +@@ -101,6 +101,8 @@ export type ClientCircuitName = + | 'app-circuit'; + + export type ServerCircuitName = ++ | 'inbox-parity-4' ++ | 'inbox-parity-16' + | 'inbox-parity-64' + | 'inbox-parity-256' + | 'inbox-parity-1024' diff --git a/noir-projects/fnd/noir-protocol-circuits/Nargo.template.toml b/noir-projects/fnd/noir-protocol-circuits/Nargo.template.toml index eee79fbd2d94..9e1a033b51cb 100644 --- a/noir-projects/fnd/noir-protocol-circuits/Nargo.template.toml +++ b/noir-projects/fnd/noir-protocol-circuits/Nargo.template.toml @@ -8,6 +8,8 @@ members = [ "crates/types", "crates/protocol-test-utils", "crates/blob", + "crates/inbox-parity-4", + "crates/inbox-parity-16", "crates/inbox-parity-64", "crates/inbox-parity-256", "crates/inbox-parity-1024", diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-16/Nargo.toml b/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-16/Nargo.toml new file mode 100644 index 000000000000..eca531020011 --- /dev/null +++ b/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-16/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "inbox_parity_16" +type = "bin" +authors = [""] +compiler_version = ">=0.18.0" + +[dependencies] +rollup_lib = { path = "../rollup-lib" } diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-16/src/main.nr b/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-16/src/main.nr new file mode 100644 index 000000000000..4c37ca940067 --- /dev/null +++ b/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-16/src/main.nr @@ -0,0 +1,5 @@ +use rollup_lib::parity::{inbox_parity, InboxParityPrivateInputs, ParityPublicInputs}; + +fn main(inputs: InboxParityPrivateInputs<16>) -> pub ParityPublicInputs { + inbox_parity::execute(inputs) +} diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-4/Nargo.toml b/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-4/Nargo.toml new file mode 100644 index 000000000000..bfe069618dfa --- /dev/null +++ b/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-4/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "inbox_parity_4" +type = "bin" +authors = [""] +compiler_version = ">=0.18.0" + +[dependencies] +rollup_lib = { path = "../rollup-lib" } diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-4/src/main.nr b/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-4/src/main.nr new file mode 100644 index 000000000000..9f3ee5e5d5e0 --- /dev/null +++ b/noir-projects/fnd/noir-protocol-circuits/crates/inbox-parity-4/src/main.nr @@ -0,0 +1,5 @@ +use rollup_lib::parity::{inbox_parity, InboxParityPrivateInputs, ParityPublicInputs}; + +fn main(inputs: InboxParityPrivateInputs<4>) -> pub ParityPublicInputs { + inbox_parity::execute(inputs) +} diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/protocol-test-utils/src/fixtures/vk_tree.nr b/noir-projects/fnd/noir-protocol-circuits/crates/protocol-test-utils/src/fixtures/vk_tree.nr index 11a21421a71b..b14b34176432 100644 --- a/noir-projects/fnd/noir-protocol-circuits/crates/protocol-test-utils/src/fixtures/vk_tree.nr +++ b/noir-projects/fnd/noir-protocol-circuits/crates/protocol-test-utils/src/fixtures/vk_tree.nr @@ -1,8 +1,9 @@ use crate::utils::pad_end; use types::{ constants::{ - HIDING_KERNEL_TO_PUBLIC_VK_INDEX, INBOX_PARITY_1024_VK_INDEX, INBOX_PARITY_256_VK_INDEX, - INBOX_PARITY_64_VK_INDEX, MEGA_KERNEL_VK_LENGTH_IN_FIELDS, PRIVATE_KERNEL_INIT_2_VK_INDEX, + HIDING_KERNEL_TO_PUBLIC_VK_INDEX, INBOX_PARITY_1024_VK_INDEX, INBOX_PARITY_16_VK_INDEX, + INBOX_PARITY_256_VK_INDEX, INBOX_PARITY_4_VK_INDEX, INBOX_PARITY_64_VK_INDEX, + MEGA_KERNEL_VK_LENGTH_IN_FIELDS, PRIVATE_KERNEL_INIT_2_VK_INDEX, PRIVATE_KERNEL_INIT_3_VK_INDEX, PRIVATE_KERNEL_INIT_4_VK_INDEX, PRIVATE_KERNEL_INIT_5_VK_INDEX, PRIVATE_KERNEL_INNER_2_VK_INDEX, PRIVATE_KERNEL_INNER_3_VK_INDEX, PRIVATE_KERNEL_INNER_4_VK_INDEX, @@ -76,6 +77,9 @@ pub global VK_MERKLE_TREE: MerkleTree = { // Honk // The inbox parity ladder circuits are plain UltraHonk (not rollup-honk) and live past the reset range. + leaves[INBOX_PARITY_4_VK_INDEX] = generate_fake_honk_vk_for_index(INBOX_PARITY_4_VK_INDEX).hash; + leaves[INBOX_PARITY_16_VK_INDEX] = + generate_fake_honk_vk_for_index(INBOX_PARITY_16_VK_INDEX).hash; leaves[INBOX_PARITY_64_VK_INDEX] = generate_fake_honk_vk_for_index(INBOX_PARITY_64_VK_INDEX).hash; leaves[INBOX_PARITY_256_VK_INDEX] = diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_rollup_public_inputs_composer.nr b/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_rollup_public_inputs_composer.nr index f32d2acf1bf3..c51540687a31 100644 --- a/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_rollup_public_inputs_composer.nr +++ b/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_rollup_public_inputs_composer.nr @@ -12,7 +12,6 @@ use types::{ constants::{ARCHIVE_HEIGHT, L1_TO_L2_MSG_TREE_HEIGHT}, merkle_tree::append_only_tree, traits::Hash, - utils::arrays::assert_trailing_zeros, }; pub struct BlockRollupPublicInputsComposer { @@ -143,9 +142,6 @@ impl BlockRollupPublicInputsComposer { self.previous_l1_to_l2 = previous_l1_to_l2; self.bundle_applied = true; - // Real messages occupy the leading lanes; everything past `num_msgs` is zero padding. - assert_trailing_zeros(bundle.messages, bundle.num_msgs); - // Append the real leaves to the l1-to-l2 message tree at its current (compact, unaligned) next-available index. self.new_l1_to_l2 = append_only_tree::append_leaves_to_snapshot::( previous_l1_to_l2, diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/checkpoint_root/components/validate_inbox_parity.nr b/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/checkpoint_root/components/validate_inbox_parity.nr index c8be40ed00b9..ab47c0dfb208 100644 --- a/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/checkpoint_root/components/validate_inbox_parity.nr +++ b/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/checkpoint_root/components/validate_inbox_parity.nr @@ -1,13 +1,16 @@ use crate::abis::ParityPublicInputs; use types::{ - constants::{INBOX_PARITY_1024_VK_INDEX, INBOX_PARITY_256_VK_INDEX, INBOX_PARITY_64_VK_INDEX}, + constants::{ + INBOX_PARITY_1024_VK_INDEX, INBOX_PARITY_16_VK_INDEX, INBOX_PARITY_256_VK_INDEX, + INBOX_PARITY_4_VK_INDEX, INBOX_PARITY_64_VK_INDEX, + }, proof::proof_data::UltraHonkProofData, }; /// Verify the checkpoint's `InboxParity` proof and vk, and check that its prover_id equals the one in the /// checkpoint's constants. The vk's membership is checked against the checkpoint's own vk tree root — `InboxParity` /// verifies no proofs itself, so it carries no vk_tree_root of its own. The proof may be any rung of the size -/// ladder, so the vk index is checked against the allowed `{64, 256, 1024}` set rather than a single value. +/// ladder, so the vk index is checked against the allowed `{4, 16, 64, 256, 1024}` set rather than a single value. pub fn validate_inbox_parity( data: UltraHonkProofData, vk_tree_root: Field, @@ -25,9 +28,15 @@ pub fn validate_inbox_parity( "The prover id of the inbox parity does not match the rollup's prover id", ); - // The proof may be any rung of the size ladder, so accept the whole `{64, 256, 1024}` vk-index set. + // The proof may be any rung of the size ladder, so accept the whole `{4, 16, 64, 256, 1024}` vk-index set. data.vk_data.validate_allowed_in_vk_tree( vk_tree_root, - [INBOX_PARITY_64_VK_INDEX, INBOX_PARITY_256_VK_INDEX, INBOX_PARITY_1024_VK_INDEX], + [ + INBOX_PARITY_4_VK_INDEX, + INBOX_PARITY_16_VK_INDEX, + INBOX_PARITY_64_VK_INDEX, + INBOX_PARITY_256_VK_INDEX, + INBOX_PARITY_1024_VK_INDEX, + ], ); } diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/checkpoint_root/tests/parity_tests.nr b/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/checkpoint_root/tests/parity_tests.nr index 6193da613971..dea2ee104641 100644 --- a/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/checkpoint_root/tests/parity_tests.nr +++ b/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/checkpoint_root/tests/parity_tests.nr @@ -1,13 +1,28 @@ use super::TestBuilder; use protocol_test_utils::fixtures::vk_tree::{update_vk_hash, VK_MERKLE_TREE}; use types::constants::{ - CHECKPOINT_ROOT_ROLLUP_VK_INDEX, INBOX_PARITY_256_VK_INDEX, INBOX_PARITY_64_VK_INDEX, + CHECKPOINT_ROOT_ROLLUP_VK_INDEX, INBOX_PARITY_16_VK_INDEX, INBOX_PARITY_256_VK_INDEX, + INBOX_PARITY_4_VK_INDEX, INBOX_PARITY_64_VK_INDEX, }; // --- Inbox parity proof / vk --- // The checkpoint root accepts any rung of the inbox parity size ladder. The default builder uses the 1024 rung; here -// we exercise the other two to prove the whole allowed set is accepted. +// we exercise the rest to prove the whole allowed set is accepted. +#[test] +fn accepts_ladder_vk_index_4() { + let mut builder = TestBuilder::default(); + builder.inbox_parity_vk_index = INBOX_PARITY_4_VK_INDEX; + let _ = builder.execute_with_mock(); +} + +#[test] +fn accepts_ladder_vk_index_16() { + let mut builder = TestBuilder::default(); + builder.inbox_parity_vk_index = INBOX_PARITY_16_VK_INDEX; + let _ = builder.execute_with_mock(); +} + #[test] fn accepts_ladder_vk_index_64() { let mut builder = TestBuilder::default(); diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/parity/inbox_parity.nr b/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/parity/inbox_parity.nr index 9dabcb9837aa..458a600ce687 100644 --- a/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/parity/inbox_parity.nr +++ b/noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/parity/inbox_parity.nr @@ -6,8 +6,8 @@ use types::utils::arrays::assert_trailing_zeros; /// Private inputs for the `InboxParity` circuit, generic over the message-bundle size `S`. /// -/// One `InboxParity` proof is produced per checkpoint. The prover picks the smallest ladder size `S ∈ {64, 256, 1024}` -/// with `S >= num_msgs`, so a checkpoint with few messages proves a small circuit. +/// One `InboxParity` proof is produced per checkpoint. The prover picks the smallest ladder size +/// `S ∈ {4, 16, 64, 256, 1024}` with `S >= num_msgs`, so a checkpoint with few messages proves a small circuit. pub struct InboxParityPrivateInputs { // The checkpoint's L1-to-L2 message leaves, padded with zeros beyond `num_msgs`. pub(crate) msgs: [Field; S], @@ -30,9 +30,10 @@ pub struct InboxParityPrivateInputs { /// checkpoint, so the start is always the empty sponge and is hard-coded rather than witnessed. /// - Asserts the padding lanes past `num_msgs` are zero so they cannot silently enter either accumulator /// -/// The output feeds the Checkpoint Root circuits, which verify this proof against the `{64, 256, 1024}` VK ladder. +/// The output feeds the Checkpoint Root circuits, which verify this proof against the `{4, 16, 64, 256, 1024}` VK +/// ladder. /// -/// VkIndex: INBOX_PARITY_{64,256,1024}_VK_INDEX +/// VkIndex: INBOX_PARITY_{4,16,64,256,1024}_VK_INDEX pub fn execute(inputs: InboxParityPrivateInputs) -> ParityPublicInputs { // Guard the padding lanes so they can't silently enter either accumulator (`num_msgs <= S` is asserted here too). assert_trailing_zeros(inputs.msgs, inputs.num_msgs); diff --git a/noir-projects/fnd/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/fnd/noir-protocol-circuits/crates/types/src/constants.nr index d69184212394..89512ea27427 100644 --- a/noir-projects/fnd/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/fnd/noir-protocol-circuits/crates/types/src/constants.nr @@ -148,10 +148,13 @@ pub global PRIVATE_KERNEL_INNER_4_VK_INDEX: u32 = 71; pub global PRIVATE_KERNEL_INNER_5_VK_INDEX: u32 = 72; // VK index 73 is intentionally unallocated: it was the message-only block root, merged into the no-txs block root. // The InboxParity size ladder: one VK per size, checked as an allowed set by the checkpoint root. Appended here -// (rather than reusing the freed 21/22) so the three sizes stay contiguous and read in order. +// (rather than reusing the freed 21/22) so the ladder stays clear of the reset range. Indices are allocated in the +// order the rungs were added, not in size order: 4 and 16 joined the ladder after the original three. pub global INBOX_PARITY_64_VK_INDEX: u32 = 74; pub global INBOX_PARITY_256_VK_INDEX: u32 = 75; pub global INBOX_PARITY_1024_VK_INDEX: u32 = 76; +pub global INBOX_PARITY_4_VK_INDEX: u32 = 77; +pub global INBOX_PARITY_16_VK_INDEX: u32 = 78; // Maximum number of apps absorbed by a single private kernel iteration. pub global MAX_APPS_PER_KERNEL: u32 = 5; @@ -607,6 +610,8 @@ pub global ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH: u32 = 1 /* previous_archive_root */ // The InboxParity size ladder: one variable-size parity proof is produced per checkpoint, and the prover picks the // smallest size >= the checkpoint's real message count. The largest rung equals the per-checkpoint message cap. +pub global INBOX_PARITY_SIZE_XXSMALL: u32 = 4; +pub global INBOX_PARITY_SIZE_XSMALL: u32 = 16; pub global INBOX_PARITY_SIZE_SMALL: u32 = 64; pub global INBOX_PARITY_SIZE_MEDIUM: u32 = 256; pub global INBOX_PARITY_SIZE_LARGE: u32 = 1024;