Skip to content
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
2 changes: 1 addition & 1 deletion docs/docs/aztec/smart_contracts/functions/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ impl NoteHash for CustomNote {
)
}

unconstrained fn compute_nullifier_without_context(self, storage_slot: Field, contract_address: AztecAddress, note_nonce: Field) -> Field {
unconstrained fn compute_nullifier_unconstrained(self, storage_slot: Field, contract_address: AztecAddress, note_nonce: Field) -> Field {
// We set the note_hash_counter to 0 as the note is not transient and the concept of transient note does
// not make sense in an unconstrained context.
let retrieved_note = RetrievedNote { note: self, contract_address, nonce: note_nonce, note_hash_counter: 0 };
Expand Down
13 changes: 13 additions & 0 deletions docs/docs/migration_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ Aztec is in full-speed development. Literally every version breaks compatibility

## TBD

### [aztec-nr] `compute_nullifier_without_context` renamed

The `compute_nullifier_without_context` function from `NoteHash` (ex `NoteInterface`) is now called `compute_nullifier_unconstrained`, and instead of taking storage slot, contract address and nonce it takes a note hash for nullification (same as `compute_note_hash`). This makes writing this
function simpler:

```diff
- unconstrained fn compute_nullifier_without_context(self, storage_slot: Field, contract_address: AztecAddress, nonce: Field) -> Field {
- let note_hash_for_nullify = ...;
+ unconstrained fn compute_nullifier_unconstrained(self, note_hash_for_nullify: Field) -> Field {
...
}
```

### `U128` type replaced with native `u128`

The `U128` type has been replaced with the native `u128` type. This means that you can no longer use the `U128` type in your code. Instead, you should use the `u128` type.
Expand Down
9 changes: 7 additions & 2 deletions noir-projects/aztec-nr/aztec/src/discovery/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub global MAX_NOTE_PACKED_LEN: u32 = PRIVATE_LOG_SIZE_IN_FIELDS - NOTE_PRIVATE_
pub struct NoteHashAndNullifier {
/// The result of NoteHash::compute_note_hash
pub note_hash: Field,
/// The result of NullifiableNote::compute_nullifier_without_context
/// The result of NoteHash::compute_nullifier_unconstrained (since all of note discovery is unconstrained)
pub inner_nullifier: Field,
}

Expand All @@ -39,7 +39,12 @@ pub struct NoteHashAndNullifier {
/// let note = MyNoteType::unpack(aztec::utils::array::subarray(packed_note.storage(), 0));
///
/// let note_hash = note.compute_note_hash(storage_slot);
/// let inner_nullifier = note.compute_nullifier_without_context(storage_slot, contract_address, nonce);
/// let note_hash_for_nullify = aztec::note::utils::compute_note_hash_for_nullify(
/// RetrievedNote{ note, contract_address, metadata: SettledNoteMetadata::new(nonce).into() },
/// storage_slot
/// );
///
/// let inner_nullifier = note.compute_nullifier_unconstrained(note_hash_for_nullify);
///
/// Option::some(
/// aztec::discovery::NoteHashAndNullifier {
Expand Down
29 changes: 27 additions & 2 deletions noir-projects/aztec-nr/aztec/src/macros/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,18 @@ comptime fn generate_contract_library_method_compute_note_hash_and_nullifier() -
quote { unpack },
);

let compute_note_hash = get_trait_impl_method(
typ,
quote { crate::note::note_interface::NoteHash },
quote { compute_note_hash },
);

let compute_nullifier_unconstrained = get_trait_impl_method(
typ,
quote { crate::note::note_interface::NoteHash },
quote { compute_nullifier_unconstrained },
);

let if_or_else_if = if i == 0 {
quote { if }
} else {
Expand All @@ -177,8 +189,21 @@ comptime fn generate_contract_library_method_compute_note_hash_and_nullifier() -

let note = $unpack(aztec::utils::array::subarray(packed_note.storage(), 0));

let note_hash = note.compute_note_hash(storage_slot);
let inner_nullifier = note.compute_nullifier_without_context(storage_slot, contract_address, nonce);
let note_hash = $compute_note_hash(note, storage_slot);

// The note discovery process finds settled notes, that is, notes that were created in prior
// transactions and are therefore already part of the note hash tree. We therefore compute the
// nullification note hash by treating the note as a settled note with the provided nonce.
let note_hash_for_nullify = aztec::note::utils::compute_note_hash_for_nullify(
aztec::note::retrieved_note::RetrievedNote{
note,
contract_address,
metadata: aztec::note::note_metadata::SettledNoteMetadata::new(nonce).into()
},
storage_slot,
);

let inner_nullifier = $compute_nullifier_unconstrained(note, note_hash_for_nullify);

Option::some(
aztec::discovery::NoteHashAndNullifier {
Expand Down
42 changes: 7 additions & 35 deletions noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,7 @@ comptime fn generate_note_interface(s: StructDefinition, note_type_id: Field) ->
///
/// fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { ... }
///
/// unconstrained fn compute_nullifier_without_context(
/// self,
/// storage_slot: Field,
/// contract_address: AztecAddress,
/// note_nonce: Field,
/// ) -> Field { ... }
/// unconstrained fn compute_nullifier_unconstrained(note_hash_for_nullify: Field) -> Field { ... }
/// }
/// ```
comptime fn generate_note_hash_trait_impl(s: StructDefinition) -> Quoted {
Expand Down Expand Up @@ -112,18 +107,10 @@ comptime fn generate_note_hash_trait_impl(s: StructDefinition) -> Quoted {
)
}

unconstrained fn compute_nullifier_without_context(
unconstrained fn compute_nullifier_unconstrained(
self,
storage_slot: Field,
contract_address: aztec::prelude::AztecAddress,
note_nonce: Field,
note_hash_for_nullify: Field,
) -> Field {
let retrieved_note = aztec::prelude::RetrievedNote {
note: self,
contract_address,
metadata: aztec::note::note_metadata::SettledNoteMetadata::new(note_nonce).into(),
};
let note_hash_for_nullify = aztec::note::utils::compute_note_hash_for_nullify(retrieved_note, storage_slot);
let owner_npk_m = aztec::keys::getters::get_public_keys(self.owner).npk_m;
// We invoke hash as a static trait function rather than calling owner_npk_m.hash() directly
// in the quote to avoid "trait not in scope" compiler warnings.
Expand All @@ -149,14 +136,7 @@ comptime fn generate_note_hash_trait_impl(s: StructDefinition) -> Quoted {
/// ...
/// }
///
/// unconstrained fn compute_nullifier_without_context(
/// self,
/// storage_slot: Field,
/// contract_address: AztecAddress,
/// note_nonce: Field,
/// ) -> Field {
/// ...
/// }
/// unconstrained fn compute_nullifier_unconstrained(note_hash_for_nullify: Field) -> Field { ... }
/// }
///
/// # On differences from `generate_note_hash_trait_impl`
Expand Down Expand Up @@ -230,18 +210,10 @@ comptime fn generate_note_hash_trait_impl_for_partial_note(
)
}

unconstrained fn compute_nullifier_without_context(
unconstrained fn compute_nullifier_unconstrained(
self,
storage_slot: Field,
contract_address: aztec::prelude::AztecAddress,
note_nonce: Field,
note_hash_for_nullify: Field,
) -> Field {
let retrieved_note = aztec::prelude::RetrievedNote {
note: self,
contract_address,
metadata: aztec::note::note_metadata::SettledNoteMetadata::new(note_nonce).into(),
};
let note_hash_for_nullify = aztec::note::utils::compute_note_hash_for_nullify(retrieved_note, storage_slot);
let owner_npk_m = aztec::keys::getters::get_public_keys(self.owner).npk_m;
// We invoke hash as a static trait function rather than calling owner_npk_m.hash() directly in
// the quote to avoid "trait not in scope" compiler warnings.
Expand Down Expand Up @@ -1127,7 +1099,7 @@ pub comptime fn note(s: StructDefinition) -> Quoted {
///
/// // Custom nullifier computation...
/// fn compute_nullifier(...) -> Field { ... }
/// fn compute_nullifier_without_context(...) -> Field { ... }
/// fn compute_nullifier_unconstrained(...) -> Field { ... }
/// }
/// ```
pub comptime fn custom_note(s: StructDefinition) -> Quoted {
Expand Down
21 changes: 4 additions & 17 deletions noir-projects/aztec-nr/aztec/src/note/note_interface.nr
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,10 @@ pub trait NoteHash {
/// circuits.
fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field;

/// Like `compute_nullifier`, this function also computes a note's nullifier, but there are some key differences.
///
/// First and most importantly, this function is unconstrained: there are no guarantees on the returned value being
/// correct. Because of that it doesn't need to take a context (since it won't perform any kernel key validation
/// requests).
///
/// Second, it always computes the nullifier for a **settled** note, i.e. a note that has been created in a previous
/// transaction, which therefore has a nonce. This is typically fine, since this function will mostly be used in
/// unconstrained execution contexts, which exist outside of any transaction and therefore have no concept of
/// pending notes, only settled. This also causes this function to not need to take a note hash for nullification,
/// since it will just compute the unique note hash internally using the provided nonce.
unconstrained fn compute_nullifier_without_context(
self,
storage_slot: Field,
contract_address: AztecAddress,
note_nonce: Field,
) -> Field;
/// Like `compute_nullifier`, except this variant is unconstrained: there are no guarantees on the returned value
/// being correct. Because of that it doesn't need to take a context (since it won't perform any kernel key
/// validation requests).
unconstrained fn compute_nullifier_unconstrained(self, note_hash_for_nullify: Field) -> Field;
}
// docs:end:note_interfaces

Expand Down
3 changes: 2 additions & 1 deletion noir-projects/aztec-nr/aztec/src/note/utils.nr
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ where
}
}

/// Returns the note hash that must be used to compute a note's nullifier.
/// Returns the note hash that must be used to compute a note's nullifier when calling `NoteHash::compute_nullifier` or
/// `NoteHash::compute_nullifier_unconstrained`.
pub fn compute_note_hash_for_nullify<Note>(
retrieved_note: RetrievedNote<Note>,
storage_slot: Field,
Expand Down
20 changes: 2 additions & 18 deletions noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
use crate::{
context::PrivateContext,
note::{
note_interface::{NoteHash, NoteType},
note_metadata::SettledNoteMetadata,
retrieved_note::RetrievedNote,
utils::compute_note_hash_for_nullify,
},
note::{note_interface::{NoteHash, NoteType}, retrieved_note::RetrievedNote},
};

use dep::protocol_types::{
Expand Down Expand Up @@ -47,20 +42,9 @@ impl NoteHash for MockNote {
)
}

unconstrained fn compute_nullifier_without_context(
self,
storage_slot: Field,
contract_address: AztecAddress,
note_nonce: Field,
) -> Field {
let retrieved_note = RetrievedNote {
note: self,
contract_address,
metadata: SettledNoteMetadata::new(note_nonce).into(),
};
unconstrained fn compute_nullifier_unconstrained(self, note_hash_for_nullify: Field) -> Field {
// We don't use any kind of secret here since this is only a mock note and having it here would make tests
// more cumbersome
let note_hash_for_nullify = compute_note_hash_for_nullify(retrieved_note, storage_slot);
poseidon2_hash_with_separator(
[note_hash_for_nullify],
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use dep::aztec::{
macros::notes::custom_note,
note::note_interface::NoteHash,
protocol_types::{
address::AztecAddress, constants::GENERATOR_INDEX__NOTE_HASH,
hash::poseidon2_hash_with_separator, traits::Packable, utils::arrays::array_concat,
constants::GENERATOR_INDEX__NOTE_HASH, hash::poseidon2_hash_with_separator,
traits::Packable, utils::arrays::array_concat,
},
};

Expand All @@ -27,18 +27,14 @@ impl NoteHash for TestNote {
_context: &mut PrivateContext,
_note_hash_for_nullify: Field,
) -> Field {
// This note is never nullified so we don't care about having a real implementation here.
0
panic(f"Unimplemented")
}

unconstrained fn compute_nullifier_without_context(
unconstrained fn compute_nullifier_unconstrained(
_self: Self,
_storage_slot: Field,
_contract_address: AztecAddress,
_note_nonce: Field,
_note_hash_for_nullify: Field,
) -> Field {
// This note is never nullified so we don't care about having a real implementation here.
0
panic(f"Unimplemented")
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use dep::aztec::{
macros::notes::custom_note,
note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify},
prelude::{NoteHash, PrivateContext, RetrievedNote},
prelude::{NoteHash, PrivateContext},
protocol_types::{
address::AztecAddress,
constants::{GENERATOR_INDEX__NOTE_HASH, GENERATOR_INDEX__NOTE_NULLIFIER},
hash::poseidon2_hash_with_separator,
traits::Packable,
Expand Down Expand Up @@ -48,18 +46,7 @@ impl NoteHash for TransparentNote {
)
}

unconstrained fn compute_nullifier_without_context(
self,
storage_slot: Field,
contract_address: AztecAddress,
note_nonce: Field,
) -> Field {
let retrieved_note = RetrievedNote {
note: self,
contract_address,
metadata: SettledNoteMetadata::new(note_nonce).into(),
};
let note_hash_for_nullify = compute_note_hash_for_nullify(retrieved_note, storage_slot);
unconstrained fn compute_nullifier_unconstrained(self, note_hash_for_nullify: Field) -> Field {
// compute_nullifier ignores context so we can reuse it here
self.compute_nullifier(zeroed(), note_hash_for_nullify)
}
Expand Down