Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: reset circuit variants #8876

Merged
merged 12 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 19 additions & 24 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ library Constants {
uint256 internal constant MAX_ENCRYPTED_LOGS_PER_CALL = 4;
uint256 internal constant MAX_UNENCRYPTED_LOGS_PER_CALL = 4;
uint256 internal constant ARCHIVE_HEIGHT = 16;
uint256 internal constant VK_TREE_HEIGHT = 5;
uint256 internal constant VK_TREE_HEIGHT = 6;
uint256 internal constant FUNCTION_TREE_HEIGHT = 5;
uint256 internal constant NOTE_HASH_TREE_HEIGHT = 32;
uint256 internal constant PUBLIC_DATA_TREE_HEIGHT = 40;
Expand Down Expand Up @@ -71,29 +71,24 @@ library Constants {
uint256 internal constant MAX_UNENCRYPTED_LOGS_PER_TX = 8;
uint256 internal constant MAX_PUBLIC_DATA_HINTS = 128;
uint256 internal constant NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16;
uint256 internal constant PRIVATE_KERNEL_INIT_INDEX = 0;
uint256 internal constant PRIVATE_KERNEL_INNER_INDEX = 1;
uint256 internal constant PRIVATE_KERNEL_RESET_FULL_INDEX = 2;
uint256 internal constant PRIVATE_KERNEL_RESET_FULL_INNER_INDEX = 3;
uint256 internal constant PRIVATE_KERNEL_RESET_BIG_INDEX = 4;
uint256 internal constant PRIVATE_KERNEL_RESET_MEDIUM_INDEX = 5;
uint256 internal constant PRIVATE_KERNEL_RESET_SMALL_INDEX = 6;
uint256 internal constant PRIVATE_KERNEL_RESET_TINY_INDEX = 7;
uint256 internal constant PRIVATE_KERNEL_TAIL_INDEX = 10;
uint256 internal constant PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX = 11;
uint256 internal constant EMPTY_NESTED_INDEX = 12;
uint256 internal constant PRIVATE_KERNEL_EMPTY_INDEX = 13;
uint256 internal constant PUBLIC_KERNEL_INNER_INDEX = 15;
uint256 internal constant PUBLIC_KERNEL_MERGE_INDEX = 16;
uint256 internal constant PUBLIC_KERNEL_TAIL_INDEX = 17;
uint256 internal constant BASE_PARITY_INDEX = 18;
uint256 internal constant ROOT_PARITY_INDEX = 19;
uint256 internal constant BASE_ROLLUP_INDEX = 20;
uint256 internal constant MERGE_ROLLUP_INDEX = 21;
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_EMPTY_INDEX = 25;
uint256 internal constant EMPTY_NESTED_INDEX = 0;
uint256 internal constant PRIVATE_KERNEL_EMPTY_INDEX = 1;
uint256 internal constant PRIVATE_KERNEL_INIT_INDEX = 2;
uint256 internal constant PRIVATE_KERNEL_INNER_INDEX = 3;
uint256 internal constant PRIVATE_KERNEL_TAIL_INDEX = 4;
uint256 internal constant PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX = 5;
uint256 internal constant PUBLIC_KERNEL_MERGE_INDEX = 6;
uint256 internal constant PUBLIC_KERNEL_TAIL_INDEX = 7;
uint256 internal constant PUBLIC_KERNEL_INNER_INDEX = 8;
uint256 internal constant BASE_PARITY_INDEX = 10;
uint256 internal constant ROOT_PARITY_INDEX = 11;
uint256 internal constant BASE_ROLLUP_INDEX = 12;
uint256 internal constant MERGE_ROLLUP_INDEX = 13;
uint256 internal constant BLOCK_ROOT_ROLLUP_INDEX = 14;
uint256 internal constant BLOCK_MERGE_ROLLUP_INDEX = 15;
uint256 internal constant ROOT_ROLLUP_INDEX = 16;
uint256 internal constant BLOCK_ROOT_ROLLUP_EMPTY_INDEX = 17;
uint256 internal constant PRIVATE_KERNEL_RESET_INDEX = 20;
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
4 changes: 2 additions & 2 deletions noir-projects/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ format:
FROM +source

WORKDIR /usr/src/noir-projects/noir-protocol-circuits
RUN yarn && node ./generate_variants.js
RUN yarn && node ./scripts/generate_variants.js
RUN nargo fmt --check

WORKDIR /usr/src/noir-projects/mock-protocol-circuits
Expand All @@ -113,7 +113,7 @@ gates-report:
COPY ../barretenberg/cpp/+preset-release/bin/bb /usr/src/barretenberg/cpp/build/bin/bb
ENV BB_BIN /usr/src/barretenberg/cpp/build/bin/bb

RUN cd noir-protocol-circuits && yarn && node ./generate_variants.js && nargo compile --silence-warnings
RUN cd noir-protocol-circuits && yarn && node ./scripts/generate_variants.js tiny && nargo compile --silence-warnings

COPY ./gates_report.sh ./gates_report.sh
RUN ./gates_report.sh
Expand Down
3 changes: 2 additions & 1 deletion noir-projects/noir-protocol-circuits/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ Prover.toml
Verifier.toml
target
crates/autogenerated
/Nargo.toml
/Nargo.toml
/private_kernel_reset_dimensions.json
2 changes: 1 addition & 1 deletion noir-projects/noir-protocol-circuits/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ if [ -n "$CMD" ]; then
fi

yarn
node ./generate_variants.js
node ./scripts/generate_variants.js

echo "Compiling protocol circuits..."
NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,30 @@ mod previous_kernel_validator_hints;

use crate::components::previous_kernel_validator::previous_kernel_validator_hints::{generate_previous_kernel_validator_hints, PreviousKernelValidatorHints};
use dep::types::{
abis::{kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, log_hash::ScopedEncryptedLogHash},
abis::{log_hash::ScopedEncryptedLogHash, private_kernel_data::PrivateKernelData},
address::AztecAddress, traits::is_empty, utils::arrays::array_length
};

pub struct PreviousKernelValidator {
previous_kernel: PrivateKernelCircuitPublicInputs,
previous_kernel: PrivateKernelData,
hints: PreviousKernelValidatorHints,
}

impl PreviousKernelValidator {
pub fn new(previous_kernel: PrivateKernelCircuitPublicInputs) -> Self {
pub fn new(previous_kernel: PrivateKernelData) -> Self {
let hints = unsafe {
generate_previous_kernel_validator_hints(previous_kernel)
generate_previous_kernel_validator_hints(previous_kernel.public_inputs)
};
PreviousKernelValidator { previous_kernel, hints }
}

pub fn validate_proof<let N: u32>(_self: Self, _allowed_indices: [u32; N]) {
if !dep::std::runtime::is_unconstrained() {
// TODO(#7410) currently stubbed out until tube vk handled
// self.previous_kernel.validate_in_vk_tree(allowed_indices);
}
}

pub fn validate_for_private_tail(self) {
self.validate_common();
self.validate_empty_data();
Expand All @@ -39,90 +46,92 @@ impl PreviousKernelValidator {
fn validate_empty_private_call_stack(self) {
// Only need to check the first item as the kernel circuits always append items to the arrays properly.
assert(
is_empty(self.previous_kernel.end.private_call_stack[0]), "Private call stack must be empty when executing the tail circuit"
is_empty(self.previous_kernel.public_inputs.end.private_call_stack[0]), "Private call stack must be empty when executing the tail circuit"
);
}

fn validate_empty_data(self) {
assert(
is_empty(self.previous_kernel.end.public_call_requests[0]), "Public call stack must be empty when executing the tail circuit"
is_empty(self.previous_kernel.public_inputs.end.public_call_requests[0]), "Public call stack must be empty when executing the tail circuit"
);
assert(
is_empty(self.previous_kernel.public_teardown_call_request), "Public teardown call request must be empty when executing the tail circuit"
is_empty(self.previous_kernel.public_inputs.public_teardown_call_request), "Public teardown call request must be empty when executing the tail circuit"
);

if self.previous_kernel.validation_requests.split_counter.is_some() {
if self.previous_kernel.public_inputs.validation_requests.split_counter.is_some() {
// Even when min_revertible_side_effect_counter could be non-zero in a pure private tx.
// The split counter must be 0 to ensure that all the transient data are squashed.
assert_eq(
self.previous_kernel.validation_requests.split_counter.unwrap_unchecked(), 0, "split_counter must be 0 for pure private tx"
self.previous_kernel.public_inputs.validation_requests.split_counter.unwrap_unchecked(), 0, "split_counter must be 0 for pure private tx"
);
}
}

fn validate_non_empty_data(self) {
assert(
!is_empty(self.previous_kernel.end.public_call_requests[0])
| !is_empty(self.previous_kernel.public_teardown_call_request), "Must have public calls when exporting public kernel data from the tail circuit"
!is_empty(self.previous_kernel.public_inputs.end.public_call_requests[0])
| !is_empty(self.previous_kernel.public_inputs.public_teardown_call_request), "Must have public calls when exporting public kernel data from the tail circuit"
);

assert(
self.previous_kernel.min_revertible_side_effect_counter != 0, "min_revertible_side_effect_counter must not be 0"
self.previous_kernel.public_inputs.min_revertible_side_effect_counter != 0, "min_revertible_side_effect_counter must not be 0"
);

if self.previous_kernel.validation_requests.split_counter.is_some() {
if self.previous_kernel.public_inputs.validation_requests.split_counter.is_some() {
assert_eq(
self.previous_kernel.validation_requests.split_counter.unwrap_unchecked(), self.previous_kernel.min_revertible_side_effect_counter, "split_counter does not match min_revertible_side_effect_counter"
self.previous_kernel.public_inputs.validation_requests.split_counter.unwrap_unchecked(), self.previous_kernel.public_inputs.min_revertible_side_effect_counter, "split_counter does not match min_revertible_side_effect_counter"
);
}
}

fn verify_empty_validation_requests(self) {
assert(
is_empty(self.previous_kernel.validation_requests.note_hash_read_requests[0]), "Non empty note hash read requests"
is_empty(self.previous_kernel.public_inputs.validation_requests.note_hash_read_requests[0]), "Non empty note hash read requests"
);
assert(
is_empty(self.previous_kernel.validation_requests.nullifier_read_requests[0]), "Non empty nullifier read requests"
is_empty(self.previous_kernel.public_inputs.validation_requests.nullifier_read_requests[0]), "Non empty nullifier read requests"
);
assert(
is_empty(self.previous_kernel.validation_requests.scoped_key_validation_requests_and_generators[0]), "Non empty key validation requests"
is_empty(
self.previous_kernel.public_inputs.validation_requests.scoped_key_validation_requests_and_generators[0]
), "Non empty key validation requests"
);
}

fn verify_sorted_siloed_values(self) {
// Check that the data are already siloed and/or sorted in the reset circuit.
// Any unprocessed data added after the last reset with siloing was called should be caught here.

let num_note_hashes = array_length(self.previous_kernel.end.note_hashes);
let num_note_hashes = array_length(self.previous_kernel.public_inputs.end.note_hashes);
if num_note_hashes != 0 {
let note_hash = self.previous_kernel.end.note_hashes[num_note_hashes - 1];
let note_hash = self.previous_kernel.public_inputs.end.note_hashes[num_note_hashes - 1];
assert_eq(
note_hash.contract_address, AztecAddress::zero(), "note hashes have not been siloed in a reset"
);
}

let num_nullifiers = array_length(self.previous_kernel.end.nullifiers);
let nullifier = self.previous_kernel.end.nullifiers[num_nullifiers - 1]; // - 1 without checking because there's at least 1 nullifier.
let num_nullifiers = array_length(self.previous_kernel.public_inputs.end.nullifiers);
let nullifier = self.previous_kernel.public_inputs.end.nullifiers[num_nullifiers - 1]; // - 1 without checking because there's at least 1 nullifier.
assert_eq(
nullifier.contract_address, AztecAddress::zero(), "nullifiers have not been siloed in a reset"
);

// Note logs are not siloed, but they are sorted and their note_hash_counter should've been set to 0 in the reset circuit.
let num_note_logs = array_length(self.previous_kernel.end.note_encrypted_logs_hashes);
let num_note_logs = array_length(self.previous_kernel.public_inputs.end.note_encrypted_logs_hashes);
if num_note_logs != 0 {
let note_log = self.previous_kernel.end.note_encrypted_logs_hashes[num_note_logs - 1];
let note_log = self.previous_kernel.public_inputs.end.note_encrypted_logs_hashes[num_note_logs - 1];
assert_eq(note_log.note_hash_counter, 0, "note logs have not been sorted in a reset");
}

// We need to check the entire array because randomness can be 0 for encrypted logs if the app wants to reveal the actual contract address.
assert(
self.previous_kernel.end.encrypted_logs_hashes.all(|h: ScopedEncryptedLogHash| h.log_hash.randomness == 0), "encrypted logs have not been siloed in a reset"
self.previous_kernel.public_inputs.end.encrypted_logs_hashes.all(|h: ScopedEncryptedLogHash| h.log_hash.randomness == 0), "encrypted logs have not been siloed in a reset"
);
}

fn validate_no_transient_data(self) {
let nullifiers = self.previous_kernel.end.nullifiers;
let note_hashes = self.previous_kernel.end.note_hashes;
let nullifiers = self.previous_kernel.public_inputs.end.nullifiers;
let note_hashes = self.previous_kernel.public_inputs.end.note_hashes;
let note_hash_indexes_for_nullifiers = self.hints.note_hash_indexes_for_nullifiers;
for i in 0..nullifiers.len() {
let nullifier = nullifiers[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,7 @@ impl<

self.validation_request_processor.validate(self.output.validation_requests);

verify_squashed_transient_data(
self.previous_kernel.end.note_hashes,
self.previous_kernel.end.nullifiers,
self.previous_kernel.end.note_encrypted_logs_hashes,
self.hints.kept_note_hashes,
self.hints.kept_nullifiers,
self.hints.kept_note_encrypted_log_hashes,
self.transient_data_index_hints,
self.hints.transient_or_propagated_note_hash_indexes_for_logs,
self.output.validation_requests.split_counter.unwrap_unchecked()
);
self.validate_transient_data();

self.validate_sorted_siloed_data();
}
Expand All @@ -96,6 +86,29 @@ impl<
assert_eq(self.output.end.private_call_stack, self.previous_kernel.end.private_call_stack);
}

fn validate_transient_data(self) {
if NUM_TRANSIENT_DATA_INDEX_HINTS == 0 {
assert_eq(
self.hints.kept_note_hashes, self.previous_kernel.end.note_hashes, "mismatch kept note hashes"
);
assert_eq(
self.hints.kept_nullifiers, self.previous_kernel.end.nullifiers, "mismatch kept nullifiers"
);
} else {
verify_squashed_transient_data(
self.previous_kernel.end.note_hashes,
self.previous_kernel.end.nullifiers,
self.previous_kernel.end.note_encrypted_logs_hashes,
self.hints.kept_note_hashes,
self.hints.kept_nullifiers,
self.hints.kept_note_encrypted_log_hashes,
self.transient_data_index_hints,
self.hints.transient_or_propagated_note_hash_indexes_for_logs,
self.output.validation_requests.split_counter.unwrap_unchecked()
);
}
}

fn validate_sorted_siloed_data(self) {
// note_hashes
// note_encrypted_logs_hashes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
components::{
previous_kernel_validator::PreviousKernelValidator,
private_call_data_validator::PrivateCallDataValidator,
private_kernel_circuit_output_validator::PrivateKernelCircuitOutputValidator,
private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer
Expand All @@ -10,21 +11,13 @@ use dep::types::{
kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputs, PrivateKernelCircuitPublicInputsArrayLengths},
private_kernel_data::PrivateKernelData, private_kernel::private_call_data::PrivateCallData
},
constants::{
PRIVATE_KERNEL_INIT_INDEX, PRIVATE_KERNEL_INNER_INDEX, PRIVATE_KERNEL_RESET_FULL_INDEX,
PRIVATE_KERNEL_RESET_BIG_INDEX, PRIVATE_KERNEL_RESET_MEDIUM_INDEX, PRIVATE_KERNEL_RESET_SMALL_INDEX,
PRIVATE_KERNEL_RESET_TINY_INDEX
}
constants::{PRIVATE_KERNEL_INIT_INDEX, PRIVATE_KERNEL_INNER_INDEX, PRIVATE_KERNEL_RESET_INDEX}
};

global ALLOWED_PREVIOUS_CIRCUITS = [
PRIVATE_KERNEL_INIT_INDEX,
PRIVATE_KERNEL_INNER_INDEX,
PRIVATE_KERNEL_RESET_FULL_INDEX,
PRIVATE_KERNEL_RESET_BIG_INDEX,
PRIVATE_KERNEL_RESET_MEDIUM_INDEX,
PRIVATE_KERNEL_RESET_SMALL_INDEX,
PRIVATE_KERNEL_RESET_TINY_INDEX,
PRIVATE_KERNEL_RESET_INDEX,
];

pub struct PrivateKernelInnerCircuitPrivateInputs {
Expand All @@ -47,17 +40,16 @@ impl PrivateKernelInnerCircuitPrivateInputs {
};

// Validate inputs.
let previous_kernel_validator = PreviousKernelValidator::new(self.previous_kernel);
previous_kernel_validator.validate_proof(ALLOWED_PREVIOUS_CIRCUITS);

let private_call_data_validator = PrivateCallDataValidator::new(self.private_call);
let previous_kernel_array_lengths = PrivateKernelCircuitPublicInputsArrayLengths::new(self.previous_kernel.public_inputs);
let private_call_stack_size = previous_kernel_array_lengths.private_call_stack;
let call_request = self.previous_kernel.public_inputs.end.private_call_stack[private_call_stack_size - 1];
private_call_data_validator.validate_against_call_request(call_request);
private_call_data_validator.validate_against_previous_kernel(self.previous_kernel.public_inputs);
private_call_data_validator.validate(output.end.note_hashes);
if !std::runtime::is_unconstrained() {
// TODO(#7410) currently stubbed out until tube vk handled
// self.previous_kernel.validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS);
}

// Validate output.
if dep::types::validate::should_validate_output() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::components::{
previous_kernel_validator::PreviousKernelValidator,
reset_output_composer::{ResetOutputComposer, ResetOutputHints},
reset_output_validator::ResetOutputValidator
};
Expand All @@ -8,12 +9,14 @@ use dep::reset_kernel_lib::{
};
use dep::types::{
abis::private_kernel_data::PrivateKernelData,
constants::{PRIVATE_KERNEL_INIT_INDEX, PRIVATE_KERNEL_INNER_INDEX}, PrivateKernelCircuitPublicInputs
constants::{PRIVATE_KERNEL_INIT_INDEX, PRIVATE_KERNEL_INNER_INDEX, PRIVATE_KERNEL_RESET_INDEX},
PrivateKernelCircuitPublicInputs
};

global ALLOWED_PREVIOUS_CIRCUITS = [
PRIVATE_KERNEL_INIT_INDEX,
PRIVATE_KERNEL_INNER_INDEX,
PRIVATE_KERNEL_RESET_INDEX
];

pub struct PrivateKernelResetHints<let NH_RR_PENDING: u32, let NH_RR_SETTLED: u32, let NLL_RR_PENDING: u32, let NLL_RR_SETTLED: u32, let KEY_VALIDATION_REQUESTS: u32, let TRANSIENT_DATA_AMOUNT: u32> {
Expand Down Expand Up @@ -85,10 +88,8 @@ impl<
};

// Validate inputs.
if !std::runtime::is_unconstrained() {
// TODO(#7410) currently stubbed out until tube vk handled
// self.previous_kernel.validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS);
}
let previous_kernel_validator = PreviousKernelValidator::new(self.previous_kernel);
previous_kernel_validator.validate_proof(ALLOWED_PREVIOUS_CIRCUITS);

// Validate output.
if dep::types::validate::should_validate_output() {
Expand Down
Loading
Loading