Skip to content

Commit

Permalink
refactor!(aztec-nr): move nullifier testing inside contexts
Browse files Browse the repository at this point in the history
  • Loading branch information
fcarreiro committed Mar 20, 2024
1 parent 75c43c6 commit f08db39
Show file tree
Hide file tree
Showing 18 changed files with 210 additions and 161 deletions.
12 changes: 9 additions & 3 deletions noir-projects/aztec-nr/aztec/src/context/avm_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ impl AVMContext {
pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> bool {
l1_to_l2_msg_exists(msg_hash, msg_leaf_index) == 1
}
pub fn nullifier_exists(self, nullifier: Field) -> bool {
nullifier_exists(nullifier) == 1
}

fn call_public_function_raw<ARGS_COUNT, RET_COUNT>(
self: &mut Self,
Expand Down Expand Up @@ -201,6 +198,15 @@ impl ContextInterface for AVMContext {
assert(false, "'get_args_hash' not implemented!");
0
}
fn nullifier_exists(self, nullifier: Field) -> bool {
nullifier_exists(nullifier) == 1
}
fn nullifier_valid_inclusion(self, nullifier: Field) -> bool {
self.nullifier_exists(nullifier) == false
}
fn nullifier_valid_non_inclusion(self, nullifier: Field) -> bool {
self.nullifier_exists(nullifier) == true
}
}

// AVM oracles (opcodes) follow, do not use directly.
Expand Down
4 changes: 4 additions & 0 deletions noir-projects/aztec-nr/aztec/src/context/interface.nr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ trait ContextInterface {
fn selector(self) -> FunctionSelector;
fn get_args_hash(self) -> Field;
fn get_header(self) -> Header;
// nullifiers
fn nullifier_exists(self, nullifier: Field) -> bool;
fn nullifier_valid_inclusion(self, nullifier: Field) -> bool;
fn nullifier_valid_non_inclusion(self, nullifier: Field) -> bool;
}

// TEMPORARY: This trait is to promote sharing of the current public context
Expand Down
40 changes: 40 additions & 0 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{
context::{inputs::PrivateContextInputs, interface::ContextInterface},
key::nullifier_key::validate_nullifier_key_against_address, messaging::process_l1_to_l2_message,
history::nullifier_inclusion::nullifier_valid_inclusion,
history::nullifier_non_inclusion::nullifier_valid_non_inclusion,
oracle::{
arguments, call_private_function::call_private_function_internal,
enqueue_public_function_call::enqueue_public_function_call_internal, context::get_portal_address,
Expand Down Expand Up @@ -114,6 +116,26 @@ impl ContextInterface for PrivateContext {
self.new_nullifiers.push(side_effect);
self.side_effect_counter = self.side_effect_counter + 1;
}

fn nullifier_exists(self, nullifier: Field) -> bool {
let header = self.get_header();
let not_in = nullifier_valid_inclusion(nullifier, header);
let is_in = nullifier_valid_non_inclusion(nullifier, header);
// We want to ensure that the user could not just make the nullifier inclusion
// fail with a bad path, therefore it must either be in or not
let xor = (not_in | is_in) - (not_in & is_in);
xor == false
}

fn nullifier_valid_inclusion(self, nullifier: Field) -> bool {
let header = self.get_header();
nullifier_valid_inclusion(nullifier, header)
}

fn nullifier_valid_non_inclusion(self, nullifier: Field) -> bool {
let header = self.get_header();
nullifier_valid_non_inclusion(nullifier, header)
}
}

impl PrivateContext {
Expand Down Expand Up @@ -151,6 +173,24 @@ impl PrivateContext {
get_header_at(block_number, self)
}

pub fn nullifier_valid_inclusion_at(
self,
nullifier: Field,
block_number: u32 // The block at which we'll prove that the nullifier exists in the nullifier tree
) -> bool {
let header = self.get_header_at(block_number);
nullifier_valid_inclusion(nullifier, header)
}

pub fn nullifier_valid_non_inclusion_at(
self,
nullifier: Field,
block_number: u32 // The block at which we'll prove that the nullifier does not exist in the nullifier tree
) -> bool {
let header = self.get_header_at(block_number);
nullifier_valid_non_inclusion(nullifier, header)
}

pub fn finish(self) -> PrivateCircuitPublicInputs {
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)
let encrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256];
Expand Down
23 changes: 22 additions & 1 deletion noir-projects/aztec-nr/aztec/src/context/public_context.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::{
context::{inputs::PublicContextInputs, interface::ContextInterface, interface::PublicContextInterface},
messaging::process_l1_to_l2_message, oracle::{arguments, public_call::call_public_function_internal}
messaging::process_l1_to_l2_message,
oracle::{arguments, public_call::call_public_function_internal},
history::nullifier_inclusion::nullifier_valid_inclusion,
history::nullifier_non_inclusion::nullifier_valid_non_inclusion
};
use dep::protocol_types::{
abis::{
Expand Down Expand Up @@ -197,6 +200,24 @@ impl ContextInterface for PublicContext {
self.new_nullifiers.push(side_effect);
self.side_effect_counter = self.side_effect_counter + 1;
}

fn nullifier_exists(self, nullifier: Field) -> bool {
let header = self.get_header();
let not_in = nullifier_valid_inclusion(nullifier, header);
let is_in = nullifier_valid_non_inclusion(nullifier, header);
// We want to ensure that the user could not just make the nullifier inclusion
// fail with a bad path, therefore it must either be in or not
let xor = (not_in | is_in) - (not_in & is_in);
xor == false
}

fn nullifier_valid_inclusion(self, nullifier: Field) -> bool {
nullifier_valid_inclusion(nullifier, self.get_header())
}

fn nullifier_valid_non_inclusion(self, nullifier: Field) -> bool {
nullifier_valid_non_inclusion(nullifier, self.get_header())
}
}

impl PublicContextInterface for PublicContext {
Expand Down
65 changes: 27 additions & 38 deletions noir-projects/aztec-nr/aztec/src/history/contract_inclusion.nr
Original file line number Diff line number Diff line change
@@ -1,64 +1,53 @@
use dep::protocol_types::{
address::{AztecAddress, EthAddress},
contract_class_id::ContractClassId,
grumpkin_point::GrumpkinPoint,
hash::silo_nullifier,
constants::DEPLOYER_CONTRACT_ADDRESS
address::{AztecAddress, EthAddress}, contract_class_id::ContractClassId,
grumpkin_point::GrumpkinPoint, hash::silo_nullifier, constants::DEPLOYER_CONTRACT_ADDRESS
};
use dep::std::merkle::compute_merkle_root;

use crate::{
context::PrivateContext,
history::{
nullifier_inclusion::prove_nullifier_inclusion_at,
nullifier_non_inclusion::prove_nullifier_not_included_at,
}
};
use crate::context::PrivateContext;

pub fn prove_contract_deployment_at(
contract_address: AztecAddress,
block_number: u32,
context: PrivateContext
) {
pub fn prove_contract_deployment_at(contract_address: AztecAddress, block_number: u32, context: PrivateContext) {
// Compute deployment nullifier
let nullifier = silo_nullifier(AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS), contract_address.to_field());
let nullifier = silo_nullifier(
AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS),
contract_address.to_field()
);

// Prove its inclusion
prove_nullifier_inclusion_at(nullifier, block_number, context);
assert(
context.nullifier_valid_inclusion_at(nullifier, block_number), "Cannot prove contract deployment nullifier inclusion"
);
}

pub fn prove_contract_non_deployment_at(
contract_address: AztecAddress,
block_number: u32,
context: PrivateContext
) {
pub fn prove_contract_non_deployment_at(contract_address: AztecAddress, block_number: u32, context: PrivateContext) {
// Compute deployment nullifier
let nullifier = silo_nullifier(AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS), contract_address.to_field());
let nullifier = silo_nullifier(
AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS),
contract_address.to_field()
);

// Prove its non-inclusion
prove_nullifier_not_included_at(nullifier, block_number, context);
assert(
context.nullifier_valid_non_inclusion_at(nullifier, block_number), "Cannot prove contract deployment nullifier non-inclusion"
);
}

pub fn prove_contract_initialization_at(
contract_address: AztecAddress,
block_number: u32,
context: PrivateContext
) {
pub fn prove_contract_initialization_at(contract_address: AztecAddress, block_number: u32, context: PrivateContext) {
// Compute initialization nullifier
let nullifier = silo_nullifier(contract_address, contract_address.to_field());

// Prove its inclusion
prove_nullifier_inclusion_at(nullifier, block_number, context);
assert(
context.nullifier_valid_inclusion_at(nullifier, block_number), "Cannot prove contract initialization nullifier inclusion"
);
}

pub fn prove_contract_non_initialization_at(
contract_address: AztecAddress,
block_number: u32,
context: PrivateContext
) {
pub fn prove_contract_non_initialization_at(contract_address: AztecAddress, block_number: u32, context: PrivateContext) {
// Compute initialization nullifier
let nullifier = silo_nullifier(contract_address, contract_address.to_field());

// Prove its non-inclusion
prove_nullifier_not_included_at(nullifier, block_number, context);
assert(
context.nullifier_valid_non_inclusion_at(nullifier, block_number), "Cannot prove contract initialization nullifier non-inclusion"
);
}
5 changes: 3 additions & 2 deletions noir-projects/aztec-nr/aztec/src/history/note_validity.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::{
context::PrivateContext,
history::{
note_inclusion::prove_note_inclusion, note_inclusion::_note_inclusion,
nullifier_non_inclusion::prove_note_not_nullified, nullifier_non_inclusion::_nullifier_non_inclusion
nullifier_non_inclusion::prove_note_not_nullified,
nullifier_non_inclusion::nullifier_valid_non_inclusion
},
note::{utils::compute_siloed_nullifier, note_interface::NoteInterface}
};
Expand All @@ -23,5 +24,5 @@ pub fn prove_note_validity_at<Note, N>(
_note_inclusion(note, header);

let nullifier = compute_siloed_nullifier(note, context);
_nullifier_non_inclusion(nullifier, header);
assert(nullifier_valid_non_inclusion(nullifier, header), "Proving nullifier non-inclusion failed!");
}
67 changes: 18 additions & 49 deletions noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,31 @@ use dep::protocol_types::header::Header;

use crate::{
context::{PrivateContext, ContextInterface},
oracle::get_nullifier_membership_witness::get_nullifier_membership_witness,
oracle::get_nullifier_membership_witness::{get_nullifier_membership_witness, NullifierMembershipWitness},
note::{utils::compute_siloed_nullifier, note_interface::NoteInterface}
};

fn _nullifier_inclusion(nullifier: Field, header: Header) {
/**
* This function checks if a nullifier is included in the nullifier tree at a given header.
* IMPORTANT: If the function returns false, you don't have a proof of non-inclusion.
*
* @param nullifier The nullifier to prove inclusion of
* @param header The header at which we'll prove that the nullifier exists in the nullifier tree
* @return true if the nullifier is included in the nullifier tree, false otherwise
*/
pub fn nullifier_valid_inclusion(nullifier: Field, header: Header) -> bool {
// 1) Get the membership witness of the nullifier
let witness = get_nullifier_membership_witness(header.global_variables.block_number as u32, nullifier);

get_nullifier_membership_witness(header.global_variables.block_number as u32, nullifier)
// 2) Check that the witness we obtained matches the nullifier
assert(witness.leaf_preimage.nullifier == nullifier, "Nullifier does not match value in witness");

.filter(|witness: NullifierMembershipWitness| witness.leaf_preimage.nullifier == nullifier)
// 3) Compute the nullifier tree leaf
let nullifier_leaf = witness.leaf_preimage.hash();

// 4) Prove that the nullifier is in the nullifier tree
assert(
.filter(|witness: NullifierMembershipWitness| {
let nullifier_leaf = witness.leaf_preimage.hash();
header.state.partial.nullifier_tree.root
== compute_merkle_root(nullifier_leaf, witness.index, witness.path), "Proving nullifier inclusion failed"
);
== compute_merkle_root(nullifier_leaf, witness.index, witness.path)
})
// --> Now we have traversed the trees all the way up to archive root and verified that the nullifier
// was included in the nullifier tree.
}

pub fn prove_nullifier_inclusion<TContext>(
nullifier: Field,
context: TContext
) where TContext: ContextInterface {
_nullifier_inclusion(nullifier, context.get_header());
}

pub fn prove_nullifier_inclusion_at(
nullifier: Field,
block_number: u32, // The block at which we'll prove that the nullifier exists in the nullifier tree
context: PrivateContext
) {
let header = context.get_header_at(block_number);

_nullifier_inclusion(nullifier, header);
}

pub fn prove_note_is_nullified<Note, N>(
note: Note,
context: &mut PrivateContext
) where Note: NoteInterface<N> {
let nullifier = compute_siloed_nullifier(note, context);

_nullifier_inclusion(nullifier, context.historical_header);
}

pub fn prove_note_is_nullified_at<Note, N>(
note: Note,
block_number: u32,
context: &mut PrivateContext
) where Note: NoteInterface<N> {
let nullifier = compute_siloed_nullifier(note, context);
let header = context.get_header_at(block_number);

_nullifier_inclusion(nullifier, header);
// was included in the nullifier tree.
.is_some()
}
Loading

0 comments on commit f08db39

Please sign in to comment.