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: Extend Historical Access APIs #4179 #4375

Merged
merged 19 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
31 changes: 28 additions & 3 deletions yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@ pub fn prove_contract_inclusion(
contract_class_id: ContractClassId,
initialization_hash: Field,
portal_contract_address: EthAddress,
block_number: u32, // The block at which we'll prove that the public value exists
context: PrivateContext
) -> AztecAddress {
// 1) Get block header from oracle and ensure that the block is included in the archive.
// let block_header = context.get_header.at(block_number);
// 1) Get block header from context
// let block_header = context.historical_header;
sklppy88 marked this conversation as resolved.
Show resolved Hide resolved

// 2) Compute the contract address
let contract_address = AztecAddress::compute_from_public_key(
Expand Down Expand Up @@ -64,3 +63,29 @@ pub fn prove_contract_inclusion(

contract_address
}

pub fn prove_contract_inclusion_at(
public_key: GrumpkinPoint,
contract_address_salt: Field,
contract_class_id: ContractClassId,
initialization_hash: Field,
portal_contract_address: EthAddress,
block_number: u32,
context: PrivateContext
) -> AztecAddress {
// 1) Get block header from oracle and ensure that the block is included in the archive.
let header = context.get_header_at(block_number);

// 2) Compute the contract address
let contract_address = AztecAddress::compute_from_public_key(
public_key,
contract_class_id,
contract_address_salt,
initialization_hash,
portal_contract_address
);

// TODO(@spalladino): See above func to impl

contract_address
}
37 changes: 24 additions & 13 deletions yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,42 @@ use crate::{
oracle::get_membership_witness::get_note_hash_membership_witness,
};

pub fn prove_note_commitment_inclusion(
note_commitment: Field,
block_number: u32, // The block at which we'll prove that the note exists
pub fn prove_note_inclusion<Note, N>(
sklppy88 marked this conversation as resolved.
Show resolved Hide resolved
note_with_header: Note,
context: PrivateContext
) {
// 1) Get block header from oracle and ensure that the block is included in the archive.
let header = context.get_header_at(block_number);
) where Note: NoteInterface {
let note_commitment = compute_note_hash_for_consumption(note_with_header);

// 2) Get the membership witness of the note in the note hash tree
let witness = get_note_hash_membership_witness(block_number, note_commitment);
// 1) Get the membership witness of the note in the note hash tree
let witness = get_note_hash_membership_witness(
context.historical_header.global_variables.block_number as u32,
note_commitment
);

// 3) Prove that the commitment is in the note hash tree
// 2) Prove that the commitment is in the note hash tree
assert(
header.state.partial.note_hash_tree.root
context.historical_header.state.partial.note_hash_tree.root
== compute_merkle_root(note_commitment, witness.index, witness.path), "Proving note inclusion failed"
);
// --> Now we have traversed the trees all the way up to archive root.
}

pub fn prove_note_inclusion<Note, N>(
pub fn prove_note_inclusion_at<Note, N>(
note_with_header: Note,
block_number: u32, // The block at which we'll prove that the note exists
context: PrivateContext
) where Note: NoteInterface {
let note_commitment = compute_note_hash_for_consumption(note_with_header);

prove_note_commitment_inclusion(note_commitment, block_number, context);
// 1) Get block header from oracle and ensure that the block is included in the archive.
let header = context.get_header_at(block_number);

// 2) Get the membership witness of the note in the note hash tree
let witness = get_note_hash_membership_witness(block_number, note_commitment);

// 3) Prove that the commitment is in the note hash tree
assert(
header.state.partial.note_hash_tree.root
== compute_merkle_root(note_commitment, witness.index, witness.path), "Proving note inclusion failed"
);
// --> Now we have traversed the trees all the way up to archive root.
}
18 changes: 14 additions & 4 deletions yarn-project/aztec-nr/aztec/src/history/note_validity.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,27 @@ use crate::{
context::PrivateContext,
history::{
note_inclusion::prove_note_inclusion,
note_inclusion::prove_note_inclusion_at,
nullifier_non_inclusion::prove_note_not_nullified,
nullifier_non_inclusion::prove_note_not_nullified_at,
},
note::note_interface::NoteInterface,
};

// A helper function that proves that a note is valid at the given block number
pub fn prove_note_validity<Note, N>(
note_with_header: Note,
block_number: u32, // The block at which we'll prove that the note exists
context: &mut PrivateContext
) where Note: NoteInterface {
prove_note_inclusion(note_with_header, block_number, *context);
prove_note_not_nullified(note_with_header, block_number, context);
prove_note_inclusion(note_with_header, *context);
prove_note_not_nullified(note_with_header, context);
}

// A helper function that proves that a note is valid at the given block number
pub fn prove_note_validity_at<Note, N>(
note_with_header: Note,
block_number: u32,
context: &mut PrivateContext
) where Note: NoteInterface {
prove_note_inclusion_at(note_with_header, block_number, *context);
prove_note_not_nullified_at(note_with_header, block_number, context);
}
24 changes: 23 additions & 1 deletion yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,29 @@ use crate::{
oracle::get_nullifier_membership_witness::get_nullifier_membership_witness,
};

pub fn prove_nullifier_inclusion(
pub fn prove_nullifier_inclusion(nullifier: Field, context: PrivateContext) {
// 1) Get the membership witness of the nullifier
sklppy88 marked this conversation as resolved.
Show resolved Hide resolved
let witness = get_nullifier_membership_witness(
context.historical_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");

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

// 4) Prove that the nullifier is in the nullifier tree
assert(
context.historical_header.state.partial.nullifier_tree.root
== compute_merkle_root(nullifier_leaf, witness.index, witness.path), "Proving nullifier inclusion 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_nullifier_inclusion_at(
nullifier: Field,
block_number: u32, // The block at which we'll prove that the note exists
context: PrivateContext
Expand Down
50 changes: 39 additions & 11 deletions yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,24 @@ use crate::{
},
};

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 header = context.get_header_at(block_number);
pub fn prove_note_not_nullified<Note, N>(
sklppy88 marked this conversation as resolved.
Show resolved Hide resolved
note_with_header: Note,
context: &mut PrivateContext
) where Note: NoteInterface {
let nullifier = compute_siloed_nullifier(note_with_header, context);

// 2) Get the membership witness of a low nullifier of the nullifier
let witness = get_low_nullifier_membership_witness(block_number, nullifier);
let witness = get_low_nullifier_membership_witness(
context.historical_header.global_variables.block_number as u32,
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_preimage.hash();
assert(
header.state.partial.nullifier_tree.root
context.historical_header.state.partial.nullifier_tree.root
== compute_merkle_root(low_nullifier_leaf, witness.index, witness.path), "Proving nullifier non-inclusion failed: Could not prove low nullifier inclusion"
);

Expand All @@ -49,12 +50,39 @@ pub fn prove_nullifier_non_inclusion(
// was not yet included in the nullifier tree.
}

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

prove_nullifier_non_inclusion(nullifier, block_number, *context);
// 1) Get block header from oracle and ensure that the block is included in the archive.
let header = context.get_header_at(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_preimage.hash();
assert(
header.state.partial.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_preimage.nullifier, 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_preimage.next_nullifier, nullifier)
| (witness.leaf_preimage.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.
}
44 changes: 44 additions & 0 deletions yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,50 @@ use crate::{
};

pub fn prove_public_value_inclusion(
value: Field, // The value that we want to prove is in the public data tree
storage_slot: Field, // The storage slot in which the value is stored
context: PrivateContext
) {
sklppy88 marked this conversation as resolved.
Show resolved Hide resolved
// 1) Compute the leaf slot by siloing the storage slot with our own address
let public_value_leaf_slot = pedersen_hash(
[context.this_address().to_field(), storage_slot],
GENERATOR_INDEX__PUBLIC_LEAF_INDEX
);

// 2) Get the membership witness of the slot
let witness = get_public_data_witness(
context.historical_header.global_variables.block_number as u32,
public_value_leaf_slot
);

// 3) Check that the witness matches the corresponding public_value
let preimage = witness.leaf_preimage;

// Here we have two cases. Code based on same checks in `validate_public_data_reads` in `base_rollup_inputs`
// 1. The value is the same as the one in the witness
// 2. The value was never initialized and is zero
let is_less_than_slot = full_field_less_than(preimage.slot, public_value_leaf_slot);
let is_next_greater_than = full_field_less_than(public_value_leaf_slot, preimage.next_slot);
let is_max = ((preimage.next_index == 0) & (preimage.next_slot == 0));
let is_in_range = is_less_than_slot & (is_next_greater_than | is_max);

if is_in_range {
assert_eq(value, 0, "Non-existant public data leaf value is non-zero");
} else {
assert_eq(preimage.slot, public_value_leaf_slot, "Public data slot don't match witness");
assert_eq(preimage.value, value, "Public value does not match the witness");
}

// 4) Prove that the leaf we validated is in the public data tree
assert(
context.historical_header.state.partial.public_data_tree.root
== compute_merkle_root(preimage.hash(), witness.index, witness.path), "Proving public value inclusion failed"
);
// --> Now we have traversed the trees all the way up to archive root and that way verified that a specific
// `value` was really set in a given contract storage slot at block `block_number` in public data tree.
}

pub fn prove_public_value_inclusion_at(
value: Field, // The value that we want to prove is in the public data tree
storage_slot: Field, // The storage slot in which the value is stored
block_number: u32, // The block at which we'll prove that the note exists
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,14 @@ impl<T> StablePublicState<T> {
// Read the value from storage (using the public tree)
let fields = storage_read(self.storage_slot);

// TODO: The block_number here can be removed when using the current header in the membership proof.
let block_number = private_context.get_header().global_variables.block_number;

// Loop over the fields and prove their inclusion in the public tree
for i in 0..fields.len() {
// TODO: Update membership proofs to use current header (Requires #4179)
// Currently executing unnecessary computation:
// - a membership proof of the header(block_number) in the history
sklppy88 marked this conversation as resolved.
Show resolved Hide resolved
// - a membership proof of the value in the public tree of the header
prove_public_value_inclusion(
fields[i],
self.storage_slot + i,
block_number as u32,
(*private_context),
)
}
Expand Down
Loading
Loading