Skip to content

Commit

Permalink
feat: Empty block root circuit
Browse files Browse the repository at this point in the history
Introduces a new circuit that outputs the same as block root but
representing an empty block. To be used for padding epochs with only
zero or one blocks.
  • Loading branch information
spalladino committed Sep 26, 2024
1 parent c78b2cb commit 2a47209
Show file tree
Hide file tree
Showing 30 changed files with 373 additions and 17 deletions.
3 changes: 2 additions & 1 deletion l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ library Constants {
uint256 internal constant BLOCK_ROOT_ROLLUP_INDEX = 22;
uint256 internal constant BLOCK_MERGE_ROLLUP_INDEX = 23;
uint256 internal constant ROOT_ROLLUP_INDEX = 24;
uint256 internal constant BLOCK_ROOT_ROLLUP_FINAL_INDEX = 25;
uint256 internal constant BLOCK_ROOT_ROLLUP_EMPTY_INDEX = 25;
uint256 internal constant BLOCK_ROOT_ROLLUP_FINAL_INDEX = 26;
uint256 internal constant FUNCTION_SELECTOR_NUM_BYTES = 4;
uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000000000;
uint256 internal constant INITIAL_L2_BLOCK_NUM = 1;
Expand Down
1 change: 1 addition & 0 deletions noir-projects/noir-protocol-circuits/Nargo.template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ members = [
"crates/rollup-base-simulated",
"crates/rollup-block-merge",
"crates/rollup-block-root",
"crates/rollup-block-root-empty",
"crates/rollup-block-root-final",
"crates/rollup-root",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "rollup_block_root_empty"
type = "bin"
authors = [""]
compiler_version = ">=0.18.0"

[dependencies]
rollup_lib = { path = "../rollup-lib" }
types = { path = "../types" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use rollup_lib::block_root::{EmptyBlockRootRollupInputs, BlockRootOrBlockMergePublicInputs};

#[recursive]
fn main(inputs: EmptyBlockRootRollupInputs) -> pub BlockRootOrBlockMergePublicInputs {
inputs.empty_block_root_rollup_circuit()
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ pub struct BlockRootOrBlockMergePublicInputs {
prover_id: Field, // TODO(#7346): Temporarily added prover_id while we verify block-root proofs on L1
}

impl BlockRootOrBlockMergePublicInputs {
fn is_padding(self) -> bool {
self.previous_archive == self.new_archive
}
}

impl Empty for BlockRootOrBlockMergePublicInputs {
fn empty() -> Self {
BlockRootOrBlockMergePublicInputs {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::abis::block_root_or_block_merge_public_inputs::BlockRootOrBlockMergePublicInputs;
use types::{abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, global_variables::GlobalVariables}};
use crate::abis::block_root_or_block_merge_public_inputs::FeeRecipient;

pub struct EmptyBlockRootRollupInputs {
archive: AppendOnlyTreeSnapshot,
block_hash: Field,
global_variables: GlobalVariables,
out_hash: Field,
vk_tree_root: Field,
// TODO(#7346): Temporarily added prover_id while we verify block-root proofs on L1
prover_id: Field,
}

impl EmptyBlockRootRollupInputs {
pub fn empty_block_root_rollup_circuit(self) -> BlockRootOrBlockMergePublicInputs {
BlockRootOrBlockMergePublicInputs {
previous_archive: self.archive,
new_archive: self.archive,
previous_block_hash: self.block_hash,
end_block_hash: self.block_hash,
start_global_variables: self.global_variables,
end_global_variables: self.global_variables,
out_hash: self.out_hash,
fees: [FeeRecipient::empty(); 32],
vk_tree_root: self.vk_tree_root,
prover_id: self.prover_id
}
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod block_root_rollup_inputs;
mod empty_block_root_rollup_inputs;

// Re-exports
pub use block_root_rollup_inputs::BlockRootRollupInputs;
pub use empty_block_root_rollup_inputs::EmptyBlockRootRollupInputs;
pub use crate::abis::block_root_or_block_merge_public_inputs::BlockRootOrBlockMergePublicInputs;

mod tests {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,22 @@ pub fn assert_prev_block_rollups_follow_on_from_each_other(
assert(
left.end_global_variables.version == right.start_global_variables.version, "input blocks have different chain version"
);
assert(
left.end_global_variables.block_number + 1 == right.start_global_variables.block_number, "input block numbers do not follow on from each other"
);
assert(
left.end_global_variables.timestamp < right.start_global_variables.timestamp, "input block timestamps do not follow on from each other"
);

if right.is_padding() {
assert(
left.end_global_variables.block_number == right.start_global_variables.block_number, "input block numbers do not match"
);
assert(
left.end_global_variables.timestamp == right.start_global_variables.timestamp, "input block timestamps do not match"
);
} else {
assert(
left.end_global_variables.block_number + 1 == right.start_global_variables.block_number, "input block numbers do not follow on from each other"
);
assert(
left.end_global_variables.timestamp < right.start_global_variables.timestamp, "input block timestamps do not follow on from each other"
);
}
}

pub fn accumulate_fees(left: BaseOrMergeRollupPublicInputs, right: BaseOrMergeRollupPublicInputs) -> Field {
Expand Down Expand Up @@ -134,12 +144,16 @@ pub fn compute_out_hash(previous_rollup_data: [PreviousRollupData; 2]) -> Field
}
// TODO(Miranda): combine fns?
pub fn compute_blocks_out_hash(previous_rollup_data: [PreviousRollupBlockData; 2]) -> Field {
accumulate_sha256(
[
previous_rollup_data[0].block_root_or_block_merge_public_inputs.out_hash,
previous_rollup_data[1].block_root_or_block_merge_public_inputs.out_hash
]
)
if previous_rollup_data[1].block_root_or_block_merge_public_inputs.is_padding() {
previous_rollup_data[0].block_root_or_block_merge_public_inputs.out_hash
} else {
accumulate_sha256(
[
previous_rollup_data[0].block_root_or_block_merge_public_inputs.out_hash,
previous_rollup_data[1].block_root_or_block_merge_public_inputs.out_hash
]
)
}
}

pub fn compute_kernel_out_hash(l2_to_l1_msgs: [Field; MAX_L2_TO_L1_MSGS_PER_TX]) -> Field {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ global MERGE_ROLLUP_INDEX: u32 = 21;
global BLOCK_ROOT_ROLLUP_INDEX: u32 = 22;
global BLOCK_MERGE_ROLLUP_INDEX: u32 = 23;
global ROOT_ROLLUP_INDEX: u32 = 24;
global BLOCK_ROOT_ROLLUP_FINAL_INDEX: u32 = 25;
global BLOCK_ROOT_ROLLUP_EMPTY_INDEX: u32 = 25;
global BLOCK_ROOT_ROLLUP_FINAL_INDEX: u32 = 26;

// MISC CONSTANTS
global FUNCTION_SELECTOR_NUM_BYTES: Field = 4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::constants::{
EMPTY_NESTED_INDEX, PRIVATE_KERNEL_EMPTY_INDEX, PUBLIC_KERNEL_INNER_INDEX,
PUBLIC_KERNEL_MERGE_INDEX, PUBLIC_KERNEL_TAIL_INDEX, BASE_PARITY_INDEX, ROOT_PARITY_INDEX,
BASE_ROLLUP_INDEX, MERGE_ROLLUP_INDEX, BLOCK_ROOT_ROLLUP_INDEX, BLOCK_MERGE_ROLLUP_INDEX,
ROOT_ROLLUP_INDEX, PRIVATE_KERNEL_RESET_TINY_INDEX, BLOCK_ROOT_ROLLUP_FINAL_INDEX
ROOT_ROLLUP_INDEX, PRIVATE_KERNEL_RESET_TINY_INDEX, BLOCK_ROOT_ROLLUP_EMPTY_INDEX,
BLOCK_ROOT_ROLLUP_FINAL_INDEX
};
use crate::merkle_tree::merkle_tree::MerkleTree;

Expand Down Expand Up @@ -41,7 +42,8 @@ pub fn get_vk_merkle_tree() -> MerkleTree<VK_TREE_WIDTH> {
leaves[BLOCK_ROOT_ROLLUP_INDEX] = 22;
leaves[BLOCK_MERGE_ROLLUP_INDEX] = 23;
leaves[ROOT_ROLLUP_INDEX] = 24;
leaves[BLOCK_ROOT_ROLLUP_FINAL_INDEX] = 25;
leaves[BLOCK_ROOT_ROLLUP_EMPTY_INDEX] = 25;
leaves[BLOCK_ROOT_ROLLUP_FINAL_INDEX] = 26;

MerkleTree::new(leaves)
}
25 changes: 25 additions & 0 deletions yarn-project/bb-prover/src/prover/bb_prover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
type BlockMergeRollupInputs,
type BlockRootOrBlockMergePublicInputs,
type BlockRootRollupInputs,
type EmptyBlockRootRollupInputs,
EmptyNestedCircuitInputs,
EmptyNestedData,
Fr,
Expand Down Expand Up @@ -57,6 +58,7 @@ import {
convertBlockMergeRollupOutputsFromWitnessMap,
convertBlockRootRollupInputsToWitnessMap,
convertBlockRootRollupOutputsFromWitnessMap,
convertEmptyBlockRootRollupInputsToWitnessMap,
convertMergeRollupInputsToWitnessMap,
convertMergeRollupOutputsFromWitnessMap,
convertPrivateKernelEmptyInputsToWitnessMap,
Expand Down Expand Up @@ -380,6 +382,29 @@ export class BBNativeRollupProver implements ServerCircuitProver {
return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
}

/**
* Simulates the empty block root rollup circuit from its inputs.
* @param input - Inputs to the circuit.
* @returns The public inputs as outputs of the simulation.
*/
public async getEmptyBlockRootRollupProof(
input: EmptyBlockRootRollupInputs,
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>> {
const { circuitOutput, proof } = await this.createRecursiveProof(
input,
'EmptyBlockRootRollupArtifact',
RECURSIVE_PROOF_LENGTH,
convertEmptyBlockRootRollupInputsToWitnessMap,
convertBlockRootRollupOutputsFromWitnessMap,
);

const verificationKey = await this.getVerificationKeyDataForCircuit('BlockRootRollupArtifact');

await this.verifyProof('BlockRootRollupArtifact', proof.binaryProof);

return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
}

/**
* Simulates the block root rollup circuit from its inputs.
* Returns a non-recursive proof to verify on L1.
Expand Down
2 changes: 2 additions & 0 deletions yarn-project/bb-prover/src/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export function mapProtocolArtifactNameToCircuitName(
return 'merge-rollup';
case 'BlockRootRollupArtifact':
return 'block-root-rollup';
case 'EmptyBlockRootRollupArtifact':
return 'empty-block-root-rollup';
case 'BlockMergeRollupArtifact':
return 'block-merge-rollup';
case 'RootRollupArtifact':
Expand Down
37 changes: 37 additions & 0 deletions yarn-project/bb-prover/src/test/test_circuit_prover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
type BlockMergeRollupInputs,
type BlockRootOrBlockMergePublicInputs,
type BlockRootRollupInputs,
type EmptyBlockRootRollupInputs,
EmptyNestedData,
type KernelCircuitPublicInputs,
type MergeRollupInputs,
Expand Down Expand Up @@ -52,6 +53,7 @@ import {
convertBlockMergeRollupOutputsFromWitnessMap,
convertBlockRootRollupInputsToWitnessMap,
convertBlockRootRollupOutputsFromWitnessMap,
convertEmptyBlockRootRollupInputsToWitnessMap,
convertMergeRollupInputsToWitnessMap,
convertMergeRollupOutputsFromWitnessMap,
convertPrivateKernelEmptyInputsToWitnessMap,
Expand Down Expand Up @@ -347,6 +349,41 @@ export class TestCircuitProver implements ServerCircuitProver {
);
}

/**
* Simulates the empty block root rollup circuit from its inputs.
* @param input - Inputs to the circuit.
* @returns The public inputs as outputs of the simulation.
*/
@trackSpan('TestCircuitProver.getEmptyBlockRootRollupProof')
public async getEmptyBlockRootRollupProof(
input: EmptyBlockRootRollupInputs,
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>> {
const timer = new Timer();
const witnessMap = convertEmptyBlockRootRollupInputsToWitnessMap(input);

// use WASM here as it is faster for small circuits
const witness = await this.wasmSimulator.simulateCircuit(
witnessMap,
SimulatedServerCircuitArtifacts.EmptyBlockRootRollupArtifact,
);

const result = convertBlockRootRollupOutputsFromWitnessMap(witness);

this.instrumentation.recordDuration('simulationDuration', 'empty-block-root-rollup', timer);
emitCircuitSimulationStats(
'empty-block-root-rollup',
timer.ms(),
input.toBuffer().length,
result.toBuffer().length,
this.logger,
);
return makePublicInputsAndRecursiveProof(
result,
makeEmptyRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH),
ProtocolCircuitVks['EmptyBlockRootRollupArtifact'],
);
}

public getBlockRootRollupFinalProof(
input: BlockRootRollupInputs,
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>> {
Expand Down
9 changes: 9 additions & 0 deletions yarn-project/circuit-types/src/interfaces/proving-job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type BlockMergeRollupInputs,
type BlockRootOrBlockMergePublicInputs,
type BlockRootRollupInputs,
type EmptyBlockRootRollupInputs,
type KernelCircuitPublicInputs,
type MergeRollupInputs,
type NESTED_RECURSIVE_PROOF_LENGTH,
Expand Down Expand Up @@ -75,6 +76,7 @@ export enum ProvingRequestType {

BASE_ROLLUP,
MERGE_ROLLUP,
EMPTY_BLOCK_ROOT_ROLLUP,
BLOCK_ROOT_ROLLUP,
BLOCK_ROOT_ROLLUP_FINAL,
BLOCK_MERGE_ROLLUP,
Expand Down Expand Up @@ -102,6 +104,8 @@ export function mapProvingRequestTypeToCircuitName(type: ProvingRequestType): Ci
return 'base-rollup';
case ProvingRequestType.MERGE_ROLLUP:
return 'merge-rollup';
case ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP:
return 'empty-block-root-rollup';
case ProvingRequestType.BLOCK_ROOT_ROLLUP:
return 'block-root-rollup';
case ProvingRequestType.BLOCK_ROOT_ROLLUP_FINAL:
Expand Down Expand Up @@ -164,6 +168,10 @@ export type ProvingRequest =
type: ProvingRequestType.BLOCK_ROOT_ROLLUP;
inputs: BlockRootRollupInputs;
}
| {
type: ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP;
inputs: EmptyBlockRootRollupInputs;
}
| {
type: ProvingRequestType.BLOCK_ROOT_ROLLUP_FINAL;
inputs: BlockRootRollupInputs;
Expand Down Expand Up @@ -195,6 +203,7 @@ export type ProvingRequestPublicInputs = {

[ProvingRequestType.BASE_ROLLUP]: PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs>;
[ProvingRequestType.MERGE_ROLLUP]: PublicInputsAndRecursiveProof<BaseOrMergeRollupPublicInputs>;
[ProvingRequestType.EMPTY_BLOCK_ROOT_ROLLUP]: PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>;
[ProvingRequestType.BLOCK_ROOT_ROLLUP]: PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>;
[ProvingRequestType.BLOCK_ROOT_ROLLUP_FINAL]: PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>;
[ProvingRequestType.BLOCK_MERGE_ROLLUP]: PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>;
Expand Down
11 changes: 11 additions & 0 deletions yarn-project/circuit-types/src/interfaces/server_circuit_prover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
type BlockMergeRollupInputs,
type BlockRootOrBlockMergePublicInputs,
type BlockRootRollupInputs,
type EmptyBlockRootRollupInputs,
type KernelCircuitPublicInputs,
type MergeRollupInputs,
type NESTED_RECURSIVE_PROOF_LENGTH,
Expand Down Expand Up @@ -105,6 +106,16 @@ export interface ServerCircuitProver {
epochNumber?: number,
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>>;

/**
* Creates a proof for the given input.
* @param input - Input to the circuit.
*/
getEmptyBlockRootRollupProof(
input: EmptyBlockRootRollupInputs,
signal?: AbortSignal,
epochNumber?: number,
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>>;

/**
* Creates a proof for the given input.
* @param input - Input to the circuit.
Expand Down
1 change: 1 addition & 0 deletions yarn-project/circuit-types/src/stats/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export type CircuitName =
| 'base-rollup'
| 'merge-rollup'
| 'block-root-rollup'
| 'empty-block-root-rollup'
| 'block-root-rollup-final'
| 'block-merge-rollup'
| 'root-rollup'
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/circuits.js/src/constants.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ export const MERGE_ROLLUP_INDEX = 21;
export const BLOCK_ROOT_ROLLUP_INDEX = 22;
export const BLOCK_MERGE_ROLLUP_INDEX = 23;
export const ROOT_ROLLUP_INDEX = 24;
export const BLOCK_ROOT_ROLLUP_FINAL_INDEX = 25;
export const BLOCK_ROOT_ROLLUP_EMPTY_INDEX = 25;
export const BLOCK_ROOT_ROLLUP_FINAL_INDEX = 26;
export const FUNCTION_SELECTOR_NUM_BYTES = 4;
export const INITIALIZATION_SLOT_SEPARATOR = 1000000000;
export const INITIAL_L2_BLOCK_NUM = 1;
Expand Down
1 change: 1 addition & 0 deletions yarn-project/circuits.js/src/structs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export * from './rollup/base_or_merge_rollup_public_inputs.js';
export * from './rollup/base_rollup.js';
export * from './rollup/block_merge_rollup.js';
export * from './rollup/block_root_or_block_merge_public_inputs.js';
export * from './rollup/empty_block_root_rollup_inputs.js';
export * from './rollup/block_root_rollup.js';
export * from './rollup/merge_rollup.js';
export * from './rollup/previous_rollup_block_data.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { makeEmptyBlockRootRollupInputs } from '../../tests/factories.js';
import { EmptyBlockRootRollupInputs } from './empty_block_root_rollup_inputs.js';

describe('EmptyBlockRootRollupInputs', () => {
it(`serializes a EmptyBlockRootRollupInputs to buffer and deserializes it back`, () => {
const expected = makeEmptyBlockRootRollupInputs();
const buffer = expected.toBuffer();
const res = EmptyBlockRootRollupInputs.fromBuffer(buffer);
expect(res).toEqual(expected);
});

it(`serializes a EmptyBlockRootRollupInputs to hex string and deserializes it back`, () => {
const expected = makeEmptyBlockRootRollupInputs();
const str = expected.toString();
const res = EmptyBlockRootRollupInputs.fromString(str);
expect(res).toEqual(expected);
});
});
Loading

0 comments on commit 2a47209

Please sign in to comment.