Skip to content

Commit

Permalink
feat: private kernel output validator (#6892)
Browse files Browse the repository at this point in the history
Please read [contributing guidelines](CONTRIBUTING.md) and remove this
line.
  • Loading branch information
LeilaWang authored Jun 5, 2024
1 parent fc6ec3f commit 0435e9a
Show file tree
Hide file tree
Showing 38 changed files with 1,517 additions and 299 deletions.
6 changes: 1 addition & 5 deletions noir-projects/aztec-nr/aztec/src/hash.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use dep::protocol_types::{
GENERATOR_INDEX__SECRET_HASH, GENERATOR_INDEX__MESSAGE_NULLIFIER, ARGS_HASH_CHUNK_COUNT,
GENERATOR_INDEX__FUNCTION_ARGS, ARGS_HASH_CHUNK_LENGTH
},
traits::Hash, hash::{pedersen_hash, silo_nullifier, sha256_to_field}
traits::Hash, hash::{pedersen_hash, compute_siloed_nullifier, sha256_to_field}
};
use crate::oracle::logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog};

Expand Down Expand Up @@ -78,10 +78,6 @@ pub fn compute_message_nullifier(message_hash: Field, secret: Field, leaf_index:
)
}

pub fn compute_siloed_nullifier(address: AztecAddress, nullifier: Field) -> Field {
silo_nullifier(address, nullifier)
}

struct ArgsHasher {
fields: [Field],
}
Expand Down
13 changes: 8 additions & 5 deletions noir-projects/aztec-nr/aztec/src/history/contract_inclusion.nr
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use dep::protocol_types::{header::Header, address::AztecAddress, hash::silo_nullifier, constants::DEPLOYER_CONTRACT_ADDRESS};
use dep::protocol_types::{
header::Header, address::AztecAddress, hash::compute_siloed_nullifier,
constants::DEPLOYER_CONTRACT_ADDRESS
};

trait ProveContractDeployment {
fn prove_contract_deployment(header: Header, contract_address: AztecAddress);
Expand All @@ -7,7 +10,7 @@ trait ProveContractDeployment {
impl ProveContractDeployment for Header {
fn prove_contract_deployment(self, contract_address: AztecAddress) {
// Compute deployment nullifier
let nullifier = silo_nullifier(
let nullifier = compute_siloed_nullifier(
AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS),
contract_address.to_field()
);
Expand All @@ -23,7 +26,7 @@ trait ProveContractNonDeployment {
impl ProveContractNonDeployment for Header {
fn prove_contract_non_deployment(self, contract_address: AztecAddress) {
// Compute deployment nullifier
let nullifier = silo_nullifier(
let nullifier = compute_siloed_nullifier(
AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS),
contract_address.to_field()
);
Expand All @@ -39,7 +42,7 @@ trait ProveContractInitialization {
impl ProveContractInitialization for Header {
fn prove_contract_initialization(self, contract_address: AztecAddress) {
// Compute initialization nullifier
let nullifier = silo_nullifier(contract_address, contract_address.to_field());
let nullifier = compute_siloed_nullifier(contract_address, contract_address.to_field());

self.prove_nullifier_inclusion(nullifier);
}
Expand All @@ -52,7 +55,7 @@ trait ProveContractNonInitialization {
impl ProveContractNonInitialization for Header {
fn prove_contract_non_initialization(self, contract_address: AztecAddress) {
// Compute initialization nullifier
let nullifier = silo_nullifier(contract_address, contract_address.to_field());
let nullifier = compute_siloed_nullifier(contract_address, contract_address.to_field());

self.prove_nullifier_non_inclusion(nullifier);
}
Expand Down
4 changes: 2 additions & 2 deletions noir-projects/aztec-nr/aztec/src/initializer.nr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use dep::protocol_types::{
address::AztecAddress, hash::{silo_nullifier, pedersen_hash},
address::AztecAddress, hash::{compute_siloed_nullifier, pedersen_hash},
constants::GENERATOR_INDEX__CONSTRUCTOR, abis::function_selector::FunctionSelector
};

Expand Down Expand Up @@ -30,7 +30,7 @@ pub fn assert_is_initialized_private(context: &mut PrivateContext) {
}

fn compute_contract_initialization_nullifier(address: AztecAddress) -> Field {
silo_nullifier(
compute_siloed_nullifier(
address,
compute_unsiloed_contract_initialization_nullifier(address)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
mod kernel_circuit_output_hints;
mod kernel_circuit_output_validator;
mod kernel_circuit_public_inputs_composer;
mod previous_kernel_validator;
mod private_call_data_validator;
mod private_kernel_circuit_output_validator;
mod private_kernel_circuit_public_inputs_composer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use dep::types::{
abis::{
kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs,
log_hash::{LogHash, NoteLogHash, ScopedLogHash, ScopedEncryptedLogHash}
},
constants::{
MAX_ENCRYPTED_LOGS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX,
MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX
},
hash::{
silo_encrypted_log_hash, silo_l2_to_l1_message, silo_note_hash, silo_nullifier,
silo_unencrypted_log_hash
},
messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::{Empty, is_empty},
utils::arrays::{OrderHint, sort_by_counters_asc, sort_get_order_hints_asc}
};

struct Hints {
// Note hashes.
sorted_note_hash_hints: [OrderHint; MAX_NEW_NOTE_HASHES_PER_TX],
siloed_note_hashes: [Field; MAX_NEW_NOTE_HASHES_PER_TX],
// Nullifiers.
sorted_nullifier_hints: [OrderHint; MAX_NEW_NULLIFIERS_PER_TX],
siloed_nullifiers: [Field; MAX_NEW_NULLIFIERS_PER_TX],
// L2 to l1 msgs.
sorted_l2_to_l1_msg_hints: [OrderHint; MAX_NEW_L2_TO_L1_MSGS_PER_TX],
siloed_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX],
// Note encrypted log hashes.
note_encrypted_log_hashes: [LogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX],
sorted_note_encrypted_log_hashes: [LogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX],
sorted_note_encrypted_log_hash_hints: [OrderHint; MAX_NOTE_ENCRYPTED_LOGS_PER_TX],
// Encrypted log hashes.
siloed_encrypted_log_hashes: [LogHash; MAX_ENCRYPTED_LOGS_PER_TX],
sorted_siloed_encrypted_log_hashes: [LogHash; MAX_ENCRYPTED_LOGS_PER_TX],
sorted_encrypted_log_hash_hints: [OrderHint; MAX_ENCRYPTED_LOGS_PER_TX],
// Unencrypted log hashes.
siloed_unencrypted_log_hashes: [LogHash; MAX_UNENCRYPTED_LOGS_PER_TX],
sorted_siloed_unencrypted_log_hashes: [LogHash; MAX_UNENCRYPTED_LOGS_PER_TX],
sorted_unencrypted_log_hash_hints: [OrderHint; MAX_UNENCRYPTED_LOGS_PER_TX],
}

unconstrained pub fn generate_hints(previous_kernel: PrivateKernelCircuitPublicInputs) -> Hints {
// note_hashes
let sorted_note_hash_hints = sort_get_order_hints_asc(previous_kernel.end.new_note_hashes);

let mut siloed_note_hashes = [0; MAX_NEW_NOTE_HASHES_PER_TX];
let first_nullifier = previous_kernel.end.new_nullifiers[0].value();
let unsiloed_note_hashes = previous_kernel.end.new_note_hashes;
for i in 0..unsiloed_note_hashes.len() {
siloed_note_hashes[i] = silo_note_hash(unsiloed_note_hashes[i], first_nullifier, i);
}

// nullifiers
let sorted_nullifier_hints = sort_get_order_hints_asc(previous_kernel.end.new_nullifiers);
let siloed_nullifiers = previous_kernel.end.new_nullifiers.map(silo_nullifier);

// l2_to_l1_msgs
let sorted_l2_to_l1_msg_hints = sort_get_order_hints_asc(previous_kernel.end.new_l2_to_l1_msgs);

let tx_context = previous_kernel.constants.tx_context;
let siloed_l2_to_l1_msgs = previous_kernel.end.new_l2_to_l1_msgs.map(
|m: ScopedL2ToL1Message| silo_l2_to_l1_message(
m,
tx_context.version,
tx_context.chain_id,
)
);

// note_encrypted_logs
let note_encrypted_log_hashes = previous_kernel.end.note_encrypted_logs_hashes.map(|h: NoteLogHash| h.expose_to_public());
let sorted_note_encrypted_log_hashes = sort_by_counters_asc(previous_kernel.end.note_encrypted_logs_hashes).map(|h: NoteLogHash| h.expose_to_public());
let sorted_note_encrypted_log_hash_hints = sort_get_order_hints_asc(previous_kernel.end.note_encrypted_logs_hashes);

// encrypted_logs
let mut siloed_log_hashes = previous_kernel.end.encrypted_logs_hashes;
for i in 0..siloed_log_hashes.len() {
siloed_log_hashes[i].log_hash.value = silo_encrypted_log_hash(previous_kernel.end.encrypted_logs_hashes[i]);
}
let sorted_siloed_encrypted_log_hashes = sort_by_counters_asc(siloed_log_hashes).map(|h: ScopedEncryptedLogHash| h.expose_to_public());
let siloed_encrypted_log_hashes = siloed_log_hashes.map(|h: ScopedEncryptedLogHash| h.expose_to_public());
let sorted_encrypted_log_hash_hints = sort_get_order_hints_asc(previous_kernel.end.encrypted_logs_hashes);

// unencrypted_logs
let mut siloed_log_hashes = previous_kernel.end.unencrypted_logs_hashes;
for i in 0..siloed_log_hashes.len() {
siloed_log_hashes[i].log_hash.value = silo_unencrypted_log_hash(previous_kernel.end.unencrypted_logs_hashes[i]);
}
let sorted_siloed_unencrypted_log_hashes = sort_by_counters_asc(siloed_log_hashes).map(|h: ScopedLogHash| h.inner());
let siloed_unencrypted_log_hashes = siloed_log_hashes.map(|h: ScopedLogHash| h.inner());
let sorted_unencrypted_log_hash_hints = sort_get_order_hints_asc(previous_kernel.end.unencrypted_logs_hashes);

Hints {
sorted_note_hash_hints,
siloed_note_hashes,
sorted_nullifier_hints,
siloed_nullifiers,
sorted_l2_to_l1_msg_hints,
siloed_l2_to_l1_msgs,
note_encrypted_log_hashes,
sorted_note_encrypted_log_hashes,
sorted_siloed_encrypted_log_hashes,
sorted_note_encrypted_log_hash_hints,
siloed_encrypted_log_hashes,
sorted_encrypted_log_hash_hints,
siloed_unencrypted_log_hashes,
sorted_siloed_unencrypted_log_hashes,
sorted_unencrypted_log_hash_hints
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
use crate::components::{kernel_circuit_output_hints::{Hints, OrderHint}};
use dep::types::{
abis::{
kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputs},
log_hash::{LogHash, NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash}
},
constants::MAX_NEW_NOTE_HASHES_PER_TX,
hash::{
compute_tx_logs_hash, compute_tx_note_logs_hash, silo_encrypted_log_hash, silo_l2_to_l1_message,
silo_note_hash, silo_nullifier, silo_unencrypted_log_hash
},
traits::{Empty, is_empty}, utils::arrays::assert_sorted_transformed_value_array
};

fn validate_transformed_value_array<T, S, N, Env>(
original_array: [T; N],
transformed_value_array: [S; N],
is_transformed: fn[Env](T, S) -> bool
) {
for i in 0..N {
assert(is_transformed(original_array[i], transformed_value_array[i]), "invalid transformed value");
}
}

fn validate_siloed_value_array<T, S, N, Env>(
original_array: [T; N],
transformed_value_array: [S; N],
silo_value: fn[Env](T) -> S
) where S: Empty + Eq {
validate_transformed_value_array(
original_array,
transformed_value_array,
|original: T, transformed: S| transformed == silo_value(original)
);
}

struct KernelCircuitOutputValidator {
output: KernelCircuitPublicInputs,
previous_kernel: PrivateKernelCircuitPublicInputs
}

impl KernelCircuitOutputValidator {
pub fn new(
output: KernelCircuitPublicInputs,
previous_kernel: PrivateKernelCircuitPublicInputs
) -> Self {
KernelCircuitOutputValidator { output, previous_kernel }
}

pub fn validate<N>(self, hints: Hints) {
self.validate_empty_values();
self.validate_propagated_values();
self.validate_propagated_sorted_siloed_values(hints);
self.validate_accumulated_values(hints);
}

fn validate_empty_values(self) {
assert(is_empty(self.output.start_state), "start_state must be empty");
assert_eq(self.output.revert_code, 0, "revert_code must be empty");
}

fn validate_propagated_values(self) {
assert_eq(self.output.constants, self.previous_kernel.constants, "mismatch constants");

assert_eq(
self.output.rollup_validation_requests, self.previous_kernel.validation_requests.for_rollup, "mismatch rollup_validation_requests"
);

assert_eq(self.output.fee_payer, self.previous_kernel.fee_payer, "mismatch fee_payer");
}

fn validate_propagated_sorted_siloed_values(self, hints: Hints) {
// new_note_hashes
let first_nullifier = self.output.end.new_nullifiers[0];
let unsiloed_note_hashes = self.previous_kernel.end.new_note_hashes;
for i in 0..unsiloed_note_hashes.len() {
let siloed_note_hash = silo_note_hash(unsiloed_note_hashes[i], first_nullifier, i);
assert_eq(hints.siloed_note_hashes[i], siloed_note_hash, "mismatch siloed note hashes");
}

assert_sorted_transformed_value_array(
self.previous_kernel.end.new_note_hashes,
hints.siloed_note_hashes,
self.output.end.new_note_hashes,
hints.sorted_note_hash_hints
);

// new_nullifiers
validate_siloed_value_array(
self.previous_kernel.end.new_nullifiers,
hints.siloed_nullifiers,
silo_nullifier
);

assert_sorted_transformed_value_array(
self.previous_kernel.end.new_nullifiers,
hints.siloed_nullifiers,
self.output.end.new_nullifiers,
hints.sorted_nullifier_hints
);

// new_l2_to_l1_msgs
let tx_context = self.previous_kernel.constants.tx_context;
validate_siloed_value_array(
self.previous_kernel.end.new_l2_to_l1_msgs,
hints.siloed_l2_to_l1_msgs,
|msg| silo_l2_to_l1_message(msg, tx_context.version, tx_context.chain_id)
);

assert_sorted_transformed_value_array(
self.previous_kernel.end.new_l2_to_l1_msgs,
hints.siloed_l2_to_l1_msgs,
self.output.end.new_l2_to_l1_msgs,
hints.sorted_l2_to_l1_msg_hints
);
}

fn validate_accumulated_values(self, hints: Hints) {
// note_encrypted_log_hashes
validate_transformed_value_array(
self.previous_kernel.end.note_encrypted_logs_hashes,
hints.note_encrypted_log_hashes,
|nlh: NoteLogHash, lh: LogHash| (nlh.value == lh.value) & (nlh.length == lh.length)
);

assert_sorted_transformed_value_array(
self.previous_kernel.end.note_encrypted_logs_hashes,
hints.note_encrypted_log_hashes,
hints.sorted_note_encrypted_log_hashes,
hints.sorted_note_encrypted_log_hash_hints
);

let hash = compute_tx_note_logs_hash(hints.sorted_note_encrypted_log_hashes);
assert_eq(hash, self.output.end.note_encrypted_logs_hash, "mismatch note_encrypted_logs_hash");

// encrypted_log_hashes
validate_transformed_value_array(
self.previous_kernel.end.encrypted_logs_hashes,
hints.siloed_encrypted_log_hashes,
|slh: ScopedEncryptedLogHash, lh: LogHash| (lh.value == silo_encrypted_log_hash(slh)) & (lh.length == slh.log_hash.length)
);

assert_sorted_transformed_value_array(
self.previous_kernel.end.encrypted_logs_hashes,
hints.siloed_encrypted_log_hashes,
hints.sorted_siloed_encrypted_log_hashes,
hints.sorted_encrypted_log_hash_hints
);

let hash = compute_tx_logs_hash(hints.sorted_siloed_encrypted_log_hashes);
assert_eq(hash, self.output.end.encrypted_logs_hash, "mismatch encrypted_logs_hash");

// unencrypted_log_hashes
validate_transformed_value_array(
self.previous_kernel.end.unencrypted_logs_hashes,
hints.siloed_unencrypted_log_hashes,
|slh: ScopedLogHash, lh: LogHash| (lh.value == silo_unencrypted_log_hash(slh)) & (lh.length == slh.log_hash.length)
);

assert_sorted_transformed_value_array(
self.previous_kernel.end.unencrypted_logs_hashes,
hints.siloed_unencrypted_log_hashes,
hints.sorted_siloed_unencrypted_log_hashes,
hints.sorted_unencrypted_log_hash_hints
);

let hash = compute_tx_logs_hash(hints.sorted_siloed_unencrypted_log_hashes);
assert_eq(hash, self.output.end.unencrypted_logs_hash, "mismatch unencrypted_logs_hash");
}
}
Loading

0 comments on commit 0435e9a

Please sign in to comment.