Skip to content

Commit

Permalink
feat!: nullifier read requests in private (#4764)
Browse files Browse the repository at this point in the history
Emitting nullifier read requests from app private functions. Checking
that the corresponding pending or settled nullifiers exist in the tail
circuit.
  • Loading branch information
LeilaWang authored Feb 29, 2024
1 parent cf8bd85 commit a049d1f
Show file tree
Hide file tree
Showing 60 changed files with 3,602 additions and 1,399 deletions.
8 changes: 4 additions & 4 deletions l1-contracts/slither_output.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,15 @@ src/core/messagebridge/Inbox.sol#L148-L153
Impact: Informational
Confidence: Medium
- [ ] ID-31
Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L125) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L118)
Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L127) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L120)

src/core/libraries/ConstantsGen.sol#L125
src/core/libraries/ConstantsGen.sol#L127


- [ ] ID-32
Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L105) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L106)
Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L107) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L108)

src/core/libraries/ConstantsGen.sol#L105
src/core/libraries/ConstantsGen.sol#L107


- [ ] ID-33
Expand Down
6 changes: 4 additions & 2 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ library Constants {
uint256 internal constant MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL = 16;
uint256 internal constant MAX_PUBLIC_DATA_READS_PER_CALL = 16;
uint256 internal constant MAX_READ_REQUESTS_PER_CALL = 32;
uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 2;
uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 1;
uint256 internal constant MAX_NEW_NOTE_HASHES_PER_TX = 64;
uint256 internal constant MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX = 8;
Expand All @@ -44,6 +45,7 @@ library Constants {
uint256 internal constant MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2;
uint256 internal constant MAX_NEW_CONTRACTS_PER_TX = 1;
uint256 internal constant MAX_READ_REQUESTS_PER_TX = 128;
uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_TX = 8;
uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4;
uint256 internal constant NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1;
uint256 internal constant NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1;
Expand Down Expand Up @@ -108,8 +110,8 @@ library Constants {
uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4;
uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5;
uint256 internal constant PARTIAL_STATE_REFERENCE_LENGTH = 8;
uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 219;
uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 214;
uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 223;
uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 218;
uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 194;
uint256 internal constant STATE_REFERENCE_LENGTH = 10;
uint256 internal constant TX_CONTEXT_DATA_LENGTH = 11;
Expand Down
16 changes: 13 additions & 3 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ use dep::protocol_types::{
private_circuit_public_inputs::PrivateCircuitPublicInputs,
public_call_stack_item::PublicCallStackItem,
public_circuit_public_inputs::PublicCircuitPublicInputs,
read_request::ReadRequest,
side_effect::{SideEffect, SideEffectLinkedToNoteHash}
},
address::{AztecAddress, EthAddress},
constants::{
MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL,
MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,
MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256,
RETURN_VALUES_LENGTH
MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH
},
contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest},
grumpkin_private_key::GrumpkinPrivateKey, hash::hash_args, header::Header,
Expand All @@ -48,6 +49,7 @@ struct PrivateContext {
return_values : BoundedVec<Field, RETURN_VALUES_LENGTH>,

read_requests: BoundedVec<SideEffect, MAX_READ_REQUESTS_PER_CALL>,
nullifier_read_requests: BoundedVec<ReadRequest, MAX_NULLIFIER_READ_REQUESTS_PER_CALL>,
nullifier_key_validation_requests: BoundedVec<NullifierKeyValidationRequest, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL>,

new_note_hashes: BoundedVec<SideEffect, MAX_NEW_NOTE_HASHES_PER_CALL>,
Expand Down Expand Up @@ -120,6 +122,7 @@ impl PrivateContext {
args_hash,
return_values: BoundedVec::new(),
read_requests: BoundedVec::new(),
nullifier_read_requests: BoundedVec::new(),
nullifier_key_validation_requests: BoundedVec::new(),
new_note_hashes: BoundedVec::new(),
new_nullifiers: BoundedVec::new(),
Expand Down Expand Up @@ -169,6 +172,7 @@ impl PrivateContext {
// the above checks should be doable after we figure out fee payments for contract deployments
min_revertible_side_effect_counter: self.min_revertible_side_effect_counter,
read_requests: self.read_requests.storage,
nullifier_read_requests: self.nullifier_read_requests.storage,
nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage,
new_note_hashes: self.new_note_hashes.storage,
new_nullifiers: self.new_nullifiers.storage,
Expand Down Expand Up @@ -196,7 +200,13 @@ impl PrivateContext {
let side_effect = SideEffect { value: read_request, counter: self.side_effect_counter };
self.read_requests.push(side_effect);
self.side_effect_counter = self.side_effect_counter + 1;
}
}

pub fn push_nullifier_read_request(&mut self, nullifier: Field) {
let request = ReadRequest { value: nullifier, counter: self.side_effect_counter };
self.nullifier_read_requests.push(request);
self.side_effect_counter = self.side_effect_counter + 1;
}

pub fn request_nullifier_secret_key(&mut self, account: AztecAddress) -> GrumpkinPrivateKey {
let key_pair = if self.nullifier_key.is_none() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use dep::types::{
call_request::CallRequest, accumulated_data::CombinedAccumulatedData, function_data::FunctionData,
kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputsBuilder,
membership_witness::ReadRequestMembershipWitness, new_contract_data::NewContractData,
nullifier_key_validation_request::NullifierKeyValidationRequestContext,
private_circuit_public_inputs::PrivateCircuitPublicInputs,
private_kernel::private_call_data::PrivateCallData,
kernel_data::{PrivateKernelInnerData, PrivateKernelTailData},
Expand All @@ -15,14 +14,14 @@ use dep::types::{
constants::{
MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL,
MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL,
MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL
MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL
},
grumpkin_private_key::GrumpkinPrivateKey,
hash::{
compute_constructor_hash, compute_l2_to_l1_hash, compute_logs_hash,
compute_new_contract_address_hash, contract_tree_root_from_siblings,
function_tree_root_from_siblings, pedersen_hash, private_functions_root_from_siblings,
read_request_root_from_siblings, silo_note_hash, silo_nullifier,
root_from_sibling_path, silo_note_hash, silo_nullifier,
stdlib_recursion_verification_key_compress_native_vk
},
utils::{arrays::{array_length, array_to_bounded_vec, validate_array}},
Expand All @@ -36,6 +35,7 @@ pub fn validate_arrays(app_public_inputs: PrivateCircuitPublicInputs) {

validate_array(app_public_inputs.return_values);
validate_array(app_public_inputs.read_requests);
validate_array(app_public_inputs.nullifier_read_requests);
validate_array(app_public_inputs.nullifier_key_validation_requests);
validate_array(app_public_inputs.new_note_hashes);
validate_array(app_public_inputs.new_nullifiers);
Expand Down Expand Up @@ -73,7 +73,7 @@ pub fn validate_read_requests(
// but we use the leaf index as a placeholder to detect a 'pending note read'.

if (read_request != 0) & (witness.is_transient == false) {
let root_for_read_request = read_request_root_from_siblings(read_request, witness.leaf_index, witness.sibling_path);
let root_for_read_request = root_from_sibling_path(read_request, witness.leaf_index, witness.sibling_path);
assert(root_for_read_request == historical_note_hash_tree_root, "note hash tree root mismatch");
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1354): do we need to enforce
// that a non-transient read_request was derived from the proper/current contract address?
Expand All @@ -93,6 +93,7 @@ pub fn initialize_end_values(
let start = previous_kernel.public_inputs.end;

public_inputs.end.read_requests = array_to_bounded_vec(start.read_requests);
public_inputs.end.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests);
public_inputs.end.nullifier_key_validation_requests = array_to_bounded_vec(start.nullifier_key_validation_requests);

public_inputs.end.new_note_hashes = array_to_bounded_vec(start.new_note_hashes);
Expand Down Expand Up @@ -175,18 +176,12 @@ pub fn update_end_values(

let private_call_public_inputs = private_call.call_stack_item.public_inputs;

let read_requests = private_call_public_inputs.read_requests;
let read_request_membership_witnesses = private_call.read_request_membership_witnesses;

let nullifier_key_validation_requests = private_call_public_inputs.nullifier_key_validation_requests;

let new_note_hashes = private_call_public_inputs.new_note_hashes;
let new_nullifiers = private_call_public_inputs.new_nullifiers;

let storage_contract_address = private_call_public_inputs.call_context.storage_contract_address;

// Transient read requests and witnesses are accumulated in public_inputs.end
// We silo the read requests (domain separation per contract address)
let read_requests = private_call_public_inputs.read_requests;
let read_request_membership_witnesses = private_call.read_request_membership_witnesses;
let mut siloed_read_requests: BoundedVec<SideEffect, MAX_READ_REQUESTS_PER_CALL> = BoundedVec::new();
for i in 0..MAX_READ_REQUESTS_PER_CALL {
let read_request = read_requests[i].value;
Expand All @@ -199,7 +194,17 @@ pub fn update_end_values(
}
public_inputs.end.read_requests.extend_from_bounded_vec(siloed_read_requests);

// Nullifier read request.
let nullifier_read_requests = private_call_public_inputs.nullifier_read_requests;
for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL {
let request = nullifier_read_requests[i];
if !is_empty(request) {
public_inputs.end.nullifier_read_requests.push(request.to_context(storage_contract_address));
}
}

// Nullifier key validation requests.
let nullifier_key_validation_requests = private_call_public_inputs.nullifier_key_validation_requests;
for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL {
let request = nullifier_key_validation_requests[i];
if !is_empty(request) {
Expand All @@ -210,6 +215,7 @@ pub fn update_end_values(
// Enhance commitments and nullifiers with domain separation whereby domain is the contract.
//
// nullifiers
let new_nullifiers = private_call_public_inputs.new_nullifiers;
let mut siloed_new_nullifiers: BoundedVec<SideEffectLinkedToNoteHash, MAX_NEW_NULLIFIERS_PER_CALL> = BoundedVec::new();
for i in 0..MAX_NEW_NULLIFIERS_PER_CALL {
let new_nullifier = new_nullifiers[i];
Expand All @@ -231,6 +237,7 @@ pub fn update_end_values(
public_inputs.end.new_nullifiers.extend_from_bounded_vec(siloed_new_nullifiers);

// note hashes
let new_note_hashes = private_call_public_inputs.new_note_hashes;
let mut siloed_new_note_hashes: BoundedVec<SideEffect, MAX_NEW_NOTE_HASHES_PER_CALL> = BoundedVec::new();
for i in 0..MAX_NEW_NOTE_HASHES_PER_CALL {
let new_note_hash = new_note_hashes[i].value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ use private_kernel_tail::PrivateKernelTailCircuitPrivateInputs;

// TODO: rename to be precise as to what its common to.
mod common;
mod read_request_reset;
mod nullifier_read_request_reset;
Loading

0 comments on commit a049d1f

Please sign in to comment.