Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
55 changes: 55 additions & 0 deletions docs/docs/migration_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,61 @@ keywords: [sandbox, aztec, notes, migration, updating, upgrading]

Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them.

### TBD

### [Aztec.nr] Changes to `NoteInterface`
We are in a process of discontinuing `NoteHeader` from notes.
This led us to do the following changes to `NoteInterface`:

```diff
pub trait NullifiableNote {
...
- unconstrained fn compute_nullifier_without_context(self) -> Field;
+ unconstrained fn compute_nullifier_without_context(self, storage_slot: Field) -> Field;
}

pub trait NoteInterface<let N: u32> {
- fn compute_note_hash(self) -> Field;
+ fn compute_note_hash(self, storage_slot: Field) -> Field;
}
```

If you are using `#[note]` or `#[partial_note(...)]` macros this should not affect you as these functions are auto-generated.
If you use `#[note_custom_interface]` macro you will need to update your notes.
These are the changes that needed to be done to our `EcdsaPublicKeyNote`:

```diff
+ use dep::aztec::protocol_types::utils::arrays::array_concat;

impl NoteInterface<ECDSA_PUBLIC_KEY_NOTE_LEN> for EcdsaPublicKeyNote {
...
- fn compute_note_hash(self) -> Field {
+ fn compute_note_hash(self, storage_slot: Field) -> Field {
- poseidon2_hash_with_separator(self.pack_content(), GENERATOR_INDEX__NOTE_HASH)
+ let inputs = array_concat(self.pack_content(), [storage_slot]);
poseidon2_hash_with_separator(inputs, GENERATOR_INDEX__NOTE_HASH)
}
}

impl NullifiableNote for EcdsaPublicKeyNote {
...
- unconstrained fn compute_nullifier_without_context(self) -> Field {
- let note_hash_for_nullify = compute_note_hash_for_nullify(self);
+ unconstrained fn compute_nullifier_without_context(self, storage_slot: Field) -> Field {
+ let note_hash_for_nullify = compute_note_hash_for_nullify(self, storage_slot);
let owner_npk_m_hash = get_public_keys(self.owner).npk_m.hash();
let secret = get_nsk_app(owner_npk_m_hash);
poseidon2_hash_with_separator(
[
note_hash_for_nullify,
secret
],
GENERATOR_INDEX__NOTE_NULLIFIER as Field
)
}
}
```

### 0.75.0

### Changes to `TokenBridge` interface
Expand Down
4 changes: 2 additions & 2 deletions noir-projects/aztec-nr/address-note/src/address_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ impl NullifiableNote for AddressNote {
)
}

unconstrained fn compute_nullifier_without_context(self) -> Field {
let note_hash_for_nullify = compute_note_hash_for_nullify(self);
unconstrained fn compute_nullifier_without_context(self, storage_slot: Field) -> Field {
let note_hash_for_nullify = compute_note_hash_for_nullify(self, storage_slot);
let owner_npk_m_hash = get_public_keys(self.owner).npk_m.hash();
let secret = get_nsk_app(owner_npk_m_hash);
poseidon2_hash_with_separator(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,16 @@ where
/// note_id and the storage_slot) to be converted into bytes, because the aes function
/// operates on bytes; not fields.
/// NB: The extra `+ 64` bytes is for the note_id and the storage_slot of the note:
fn compute_note_plaintext_for_this_strategy<Note, let N: u32>(note: Note) -> [u8; N * 32 + 64]
fn compute_note_plaintext_for_this_strategy<Note, let N: u32>(
note: Note,
storage_slot: Field,
) -> [u8; N * 32 + 64]
where
Note: NoteInterface<N>,
{
let packed_note = note.pack_content();

let note_header = note.get_header();
let storage_slot = note_header.storage_slot;
let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes();

// TODO(#10952): The following can be reduced to 7 bits
Expand All @@ -250,6 +252,7 @@ where
fn compute_log<Note, let N: u32>(
context: PrivateContext,
note: Note,
storage_slot: Field,
recipient: AztecAddress,
sender: AztecAddress,
) -> [Field; PRIVATE_LOG_SIZE_IN_FIELDS]
Expand All @@ -272,7 +275,7 @@ where
// Compute the plaintext
// *****************************************************************************

let final_plaintext_bytes = compute_note_plaintext_for_this_strategy(note);
let final_plaintext_bytes = compute_note_plaintext_for_this_strategy(note, storage_slot);

// *****************************************************************************
// Convert the plaintext into whatever format the encryption function expects
Expand Down Expand Up @@ -413,13 +416,14 @@ where
unconstrained fn compute_log_unconstrained<Note, let N: u32>(
context: PrivateContext,
note: Note,
storage_slot: Field,
recipient: AztecAddress,
sender: AztecAddress,
) -> [Field; PRIVATE_LOG_SIZE_IN_FIELDS]
where
Note: NoteInterface<N>,
{
compute_log(context, note, recipient, sender)
compute_log(context, note, storage_slot, recipient, sender)
}

// This function seems to be affected by the following Noir bug:
Expand All @@ -436,11 +440,12 @@ where
{
|e: NoteEmission<Note>| {
let note = e.note;
let storage_slot = e.storage_slot;
assert_note_exists(*context, note);

let note_hash_counter = note.get_header().note_hash_counter;

let encrypted_log = compute_log(*context, note, recipient, sender);
let encrypted_log = compute_log(*context, note, storage_slot, recipient, sender);
context.emit_raw_note_log(encrypted_log, note_hash_counter);
}
}
Expand All @@ -459,6 +464,7 @@ where
{
|e: NoteEmission<Note>| {
let note = e.note;
let storage_slot = e.storage_slot;
assert_note_exists(*context, note);

let note_hash_counter = note.get_header().note_hash_counter;
Expand All @@ -473,7 +479,8 @@ where
// It's important here that we do not
// return the log from this function to the app, otherwise it could try to do stuff with it and then that might
// be wrong.
let encrypted_log = unsafe { compute_log_unconstrained(*context, note, recipient, sender) };
let encrypted_log =
unsafe { compute_log_unconstrained(*context, note, storage_slot, recipient, sender) };
context.emit_raw_note_log(encrypted_log, note_hash_counter);
}
}
Expand All @@ -496,18 +503,15 @@ mod test {
); // This is an address copied to match the typescript one.

let storage_slot = 42;
let note = MockNote::new(1234)
.contract_address(context.this_address())
.storage_slot(storage_slot)
.build();
let note = MockNote::new(1234).contract_address(context.this_address()).build();
let contract_address = context.this_address();

// All the values in this test were copied over from `encrypted_log_payload.test.ts`
let contract_address = AztecAddress::from_field(
0x10f48cd9eff7ae5b209c557c70de2e657ee79166868676b787e9417e19260e04,
);

let plaintext = super::compute_note_plaintext_for_this_strategy(note);
let plaintext = super::compute_note_plaintext_for_this_strategy(note, storage_slot);

let eph_sk = 0x1358d15019d4639393d62b97e1588c095957ce74a1c32d6ec7d62fe6705d9538;
let _ = OracleMock::mock("getRandomField").returns(eph_sk).times(1);
Expand All @@ -527,7 +531,7 @@ mod test {

let _ = OracleMock::mock("incrementAppTaggingSecretIndexAsSender").returns(());

let payload = super::compute_log(context, note, recipient, sender);
let payload = super::compute_log(context, note, storage_slot, recipient, sender);

// The following value was generated by `encrypted_log_payload.test.ts`
// --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data.
Expand Down
6 changes: 3 additions & 3 deletions noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ use crate::{
};

trait ProveNoteInclusion {
fn prove_note_inclusion<Note, let N: u32>(header: BlockHeader, note: Note)
fn prove_note_inclusion<Note, let N: u32>(header: BlockHeader, note: Note, storage_slot: Field)
where
Note: NoteInterface<N> + NullifiableNote;
}

impl ProveNoteInclusion for BlockHeader {
fn prove_note_inclusion<Note, let N: u32>(self, note: Note)
fn prove_note_inclusion<Note, let N: u32>(self, note: Note, storage_slot: Field)
where
Note: NoteInterface<N> + NullifiableNote,
{
let note_hash = compute_note_hash_for_nullify(note);
let note_hash = compute_note_hash_for_nullify(note, storage_slot);

/// Safety: The witness is only used as a "magical value" that makes the merkle proof below pass. Hence it's safe.
let witness = unsafe {
Expand Down
12 changes: 9 additions & 3 deletions noir-projects/aztec-nr/aztec/src/history/note_validity.nr
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,25 @@ trait ProveNoteValidity {
fn prove_note_validity<Note, let N: u32>(
header: BlockHeader,
note: Note,
storage_slot: Field,
context: &mut PrivateContext,
)
where
Note: NoteInterface<N> + NullifiableNote;
}

impl ProveNoteValidity for BlockHeader {
fn prove_note_validity<Note, let N: u32>(self, note: Note, context: &mut PrivateContext)
fn prove_note_validity<Note, let N: u32>(
self,
note: Note,
storage_slot: Field,
context: &mut PrivateContext,
)
where
Note: NoteInterface<N> + NullifiableNote,
{
self.prove_note_inclusion(note);
self.prove_note_not_nullified(note, context);
self.prove_note_inclusion(note, storage_slot);
self.prove_note_not_nullified(note, storage_slot, context);
}
}

10 changes: 8 additions & 2 deletions noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ trait ProveNoteIsNullified {
fn prove_note_is_nullified<Note, let N: u32>(
header: BlockHeader,
note: Note,
storage_slot: Field,
context: &mut PrivateContext,
)
where
Expand All @@ -50,11 +51,16 @@ trait ProveNoteIsNullified {

impl ProveNoteIsNullified for BlockHeader {
// docs:start:prove_note_is_nullified
fn prove_note_is_nullified<Note, let N: u32>(self, note: Note, context: &mut PrivateContext)
fn prove_note_is_nullified<Note, let N: u32>(
self,
note: Note,
storage_slot: Field,
context: &mut PrivateContext,
)
where
Note: NoteInterface<N> + NullifiableNote,
{
let nullifier = compute_siloed_nullifier(note, context);
let nullifier = compute_siloed_nullifier(note, storage_slot, context);

self.prove_nullifier_inclusion(nullifier);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ trait ProveNoteNotNullified {
fn prove_note_not_nullified<Note, let N: u32>(
header: BlockHeader,
note: Note,
storage_slot: Field,
context: &mut PrivateContext,
)
where
Expand All @@ -63,11 +64,16 @@ trait ProveNoteNotNullified {

impl ProveNoteNotNullified for BlockHeader {
// docs:start:prove_note_not_nullified
fn prove_note_not_nullified<Note, let N: u32>(self, note: Note, context: &mut PrivateContext)
fn prove_note_not_nullified<Note, let N: u32>(
self,
note: Note,
storage_slot: Field,
context: &mut PrivateContext,
)
where
Note: NoteInterface<N> + NullifiableNote,
{
let nullifier = compute_siloed_nullifier(note, context);
let nullifier = compute_siloed_nullifier(note, storage_slot, context);

self.prove_nullifier_non_inclusion(nullifier);
}
Expand Down
13 changes: 7 additions & 6 deletions noir-projects/aztec-nr/aztec/src/macros/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted {
if_statements_list = if_statements_list.push_back(
quote {
$if_or_else_if note_type_id == $typ::get_note_type_id() {
aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, compute_nullifier, packed_note_content)
aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, compute_nullifier, storage_slot, packed_note_content)
}
},
);
Expand All @@ -147,10 +147,10 @@ comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted {
let if_statements = if_statements_list.join(quote {});

quote {
let note_header = aztec::prelude::NoteHeader::new(contract_address, nonce, storage_slot);
let note_header = aztec::prelude::NoteHeader::new(contract_address, nonce);
$if_statements
else {
panic(f"Unknown note type ID")
panic(f"Unknown note type ID: {note_type_id}")
}
}
} else {
Expand Down Expand Up @@ -184,13 +184,14 @@ comptime fn generate_process_log() -> Quoted {

// A typical implementation of the lambda looks something like this:
// ```
// |packed_note_content: BoundedVec<Field, MAX_NOTE_SERIALIZED_LEN>, note_header: NoteHeader, note_type_id: Field| {
// |packed_note_content: BoundedVec<Field, MAX_NOTE_SERIALIZED_LEN>, note_header: NoteHeader, storage_slot: Field, note_type_id: Field| {
// let hashes = if note_type_id == MyNoteType::get_note_type_id() {
// assert(packed_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH);
// dep::aztec::note::utils::compute_note_hash_and_optionally_a_nullifier(
// MyNoteType::unpack_content,
// note_header,
// true,
// storage_slot,
// packed_note_content.storage(),
// )
// } else {
Expand Down Expand Up @@ -234,7 +235,7 @@ comptime fn generate_process_log() -> Quoted {
f"Expected note content of length {expected_len} but got {actual_len} for note type id {note_type_id}"
);

aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, true, packed_note_content.storage())
aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, true, storage_slot, packed_note_content.storage())
}
},
);
Expand All @@ -256,7 +257,7 @@ comptime fn generate_process_log() -> Quoted {
unique_note_hashes_in_tx,
first_nullifier_in_tx,
recipient,
|packed_note_content: BoundedVec<Field, _>, note_header, note_type_id| {
|packed_note_content: BoundedVec<Field, _>, note_header, storage_slot, note_type_id| {
let hashes = $if_note_type_id_match_statements
else {
panic(f"Unknown note type id {note_type_id}")
Expand Down
6 changes: 3 additions & 3 deletions noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ comptime fn get_next_note_type_id() -> Field {
/// ...
/// }
///
/// fn compute_note_hash(self) -> Field {
/// fn compute_note_hash(self, storage_slot: Field) -> Field {
/// ...
/// }
/// }
Expand Down Expand Up @@ -123,7 +123,7 @@ comptime fn generate_note_interface(

let merged_fields_len = merged_fields.len() + 1; // +1 for the storage slot appended below
let new_scalars = new_scalars_list
.push_back(quote { std::hash::from_field_unsafe(self.header.storage_slot) })
.push_back(quote { std::hash::from_field_unsafe(storage_slot) })
.push_back(quote { std::hash::from_field_unsafe($merged_fields_len) })
.join(quote {,});

Expand Down Expand Up @@ -151,7 +151,7 @@ comptime fn generate_note_interface(
self.header
}

fn compute_note_hash(self) -> Field {
fn compute_note_hash(self, storage_slot: Field) -> Field {
$new_aux_vars
let point = std::embedded_curve_ops::multi_scalar_mul(
[$new_generators],
Expand Down
Loading