Skip to content

Commit

Permalink
nullifier non-inclusion libraryfied
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Dec 12, 2023
1 parent 1de8f5c commit 6bcfd45
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 58 deletions.
3 changes: 2 additions & 1 deletion yarn-project/aztec-nr/aztec/src/history.nr
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mod note_inclusion;
mod note_inclusion;
mod nullifier_non_inclusion;
64 changes: 64 additions & 0 deletions yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use dep::protocol_types::constants::NOTE_HASH_TREE_HEIGHT;
use dep::std::merkle::compute_merkle_root;

use crate::{
context::PrivateContext,
note::{
utils::compute_siloed_nullifier,
note_header::NoteHeader,
note_interface::NoteInterface,
},
oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness,
utils::{
full_field_less_than,
full_field_greater_than,
},
};

pub fn prove_nullifier_non_inclusion(
nullifier: Field,
block_number: u32, // The block at which we'll prove that the nullifier does not exists
context: PrivateContext
) {
// 1) Get block header from oracle and ensure that the block is included in the archive.
let block_header = context.get_block_header(block_number);

// 2) Get the membership witness of a low nullifier of the nullifier
let witness = get_low_nullifier_membership_witness(block_number, nullifier);

// 3) Prove that the nullifier is not included in the nullifier tree

// 3.a) Compute the low nullifier leaf and prove that it is in the nullifier tree
let low_nullifier_leaf = witness.leaf_data.hash();
assert(
block_header.nullifier_tree_root == compute_merkle_root(low_nullifier_leaf, witness.index, witness.path),
"Proving nullifier non-inclusion failed: Could not prove low nullifier inclusion"
);

// 3.b) Prove that the low nullifier is smaller than the nullifier
assert(
full_field_less_than(witness.leaf_data.value, nullifier),
"Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed"
);

// 3.c) Prove that the low nullifier is pointing "over" the nullifier to prove that the nullifier is not
// included in the nullifier tree (or to 0 if the to-be-inserted nullifier is the largest of all)
assert(
full_field_greater_than(witness.leaf_data.next_value, nullifier) | (witness.leaf_data.next_index == 0),
"Proving nullifier non-inclusion failed: low_nullifier.next_value > nullifier.value check failed"
);

// --> Now we have traversed the trees all the way up to archive root and verified that the nullifier
// was not yet included in the nullifier tree.
}

pub fn prove_note_not_nullified<Note, N>(
note_interface: NoteInterface<Note, N>,
note_with_header: Note,
block_number: u32, // The block at which we'll prove that the note was not nullified
context: PrivateContext
) {
let nullifier = compute_siloed_nullifier(note_interface, note_with_header);

prove_nullifier_non_inclusion(nullifier, block_number, context);
}
12 changes: 12 additions & 0 deletions yarn-project/aztec-nr/aztec/src/utils.nr
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,15 @@ pub fn field_from_bytes<N>(bytes: [u8; N], big_endian: bool) -> Field {

as_field
}

// TODO(#3470): Copied over from https://github.com/AztecProtocol/aztec-packages/blob/a07c4bd47313be6aa604a63f37857eb0136b41ba/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr#L599
// move to a shared place?

// TODO to radix returns u8, so we cannot use bigger radixes. It'd be ideal to use a radix of the maximum range-constrained integer noir supports
pub fn full_field_less_than(lhs: Field, rhs: Field) -> bool {
dep::std::eddsa::lt_bytes32(lhs, rhs)
}

pub fn full_field_greater_than(lhs: Field, rhs: Field) -> bool {
dep::std::eddsa::lt_bytes32(rhs, lhs)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
mod utils;

// A demonstration of inclusion and non-inclusion proofs.
contract InclusionProofs {
use dep::protocol_types::constants::{
Expand Down Expand Up @@ -32,24 +30,23 @@ contract InclusionProofs {
},
get_sibling_path::get_sibling_path,
get_nullifier_membership_witness::{
get_low_nullifier_membership_witness,
get_nullifier_membership_witness,
NullifierMembershipWitness,
},
},
hash::pedersen_hash,
history::note_inclusion::{
prove_note_inclusion,
prove_note_commitment_inclusion,
history::{
note_inclusion::{
prove_note_commitment_inclusion,
prove_note_inclusion,
},
nullifier_non_inclusion::{
prove_nullifier_non_inclusion,
prove_note_not_nullified,
},
},
};
use dep::value_note::value_note::{ValueNote, ValueNoteMethods, VALUE_NOTE_LEN};

use crate::utils::{
full_field_less_than,
full_field_greater_than,
};

struct Storage {
private_values: Map<Set<ValueNote, VALUE_NOTE_LEN>>,
public_value: PublicState<Field, 1>,
Expand Down Expand Up @@ -126,50 +123,19 @@ contract InclusionProofs {
block_number: u32, // The block at which we'll prove that the nullifier does not exists
spare_nullifier: Field, // This is only used when the note is not found --> used to test the failure case
) {
// 1) Get block header from oracle and ensure that the block hash is included in the archive.
let block_header = context.get_block_header(block_number);

// 2) Get the note from PXE
let private_values = storage.private_values.at(owner.address);
let options = NoteGetterOptions::new().select(1, owner.address).set_limit(1);
let notes = private_values.get_notes(options);
let maybe_note = notes[0];

// 3) Compute the nullifier from the note
let nullifier = if maybe_note.is_some() {
note_utils::compute_siloed_nullifier(ValueNoteMethods, maybe_note.unwrap_unchecked())
if maybe_note.is_some() {
prove_note_not_nullified(ValueNoteMethods, maybe_note.unwrap_unchecked(), block_number, context);
} else {
// Note was not found so we will use the spare nullifier
spare_nullifier
prove_nullifier_non_inclusion(spare_nullifier, block_number, context);
};

// 4) Get the membership witness of a low nullifier of the nullifier
let witness = get_low_nullifier_membership_witness(block_number, nullifier);

// 5) Prove that the nullifier is not included in the nullifier tree

// 5.a) Compute the low nullifier leaf and prove that it is in the nullifier tree
let low_nullifier_leaf = witness.leaf_data.hash();
assert(
block_header.nullifier_tree_root == compute_merkle_root(low_nullifier_leaf, witness.index, witness.path),
"Proving nullifier non-inclusion failed: Could not prove low nullifier inclusion"
);

// 5.b) Prove that the low nullifier is smaller than the nullifier
assert(
full_field_less_than(witness.leaf_data.value, nullifier),
"Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed"
);

// 5.c) Prove that the low nullifier is pointing "over" the nullifier to prove that the nullifier is not
// included in the nullifier tree (or to 0 if the to-be-inserted nullifier is the largest of all)
assert(
full_field_greater_than(witness.leaf_data.next_value, nullifier) | (witness.leaf_data.next_index == 0),
"Proving nullifier non-inclusion failed: low_nullifier.next_value > nullifier.value check failed"
);

// --> Now we have traversed the trees all the way up to blocks tree root and verified that the nullifier
// was not yet included in the nullifier tree.
}

#[aztec(private)]
Expand Down

This file was deleted.

0 comments on commit 6bcfd45

Please sign in to comment.