From 5007df14e26f9fce0315504e1025e0917cc3bc0f Mon Sep 17 00:00:00 2001 From: benesjan Date: Wed, 19 Jun 2024 13:22:18 +0000 Subject: [PATCH 1/4] refactor: destroy_note optimization --- .../aztec-nr/address-note/src/address_note.nr | 14 ++++---- .../aztec/src/context/private_context.nr | 2 ++ .../aztec/src/encrypted_logs/incoming_body.nr | 6 ++-- .../aztec-nr/aztec/src/note/lifecycle.nr | 32 +++++++++---------- .../aztec-nr/aztec/src/note/note_interface.nr | 4 +-- .../aztec-nr/aztec/src/note/utils.nr | 5 +-- .../aztec/src/state_vars/private_mutable.nr | 4 +-- .../aztec/src/test/mocks/mock_note.nr | 8 ++--- .../aztec-nr/value-note/src/value_note.nr | 14 ++++---- .../src/subscription_note.nr | 14 ++++---- .../contracts/claim_contract/src/main.nr | 3 +- .../src/types/card_note.nr | 14 ++++---- .../src/ecdsa_public_key_note.nr | 14 ++++---- .../src/public_key_note.nr | 14 ++++---- .../contracts/test_contract/src/test_note.nr | 8 ++--- .../src/types/token_note.nr | 19 +++++------ .../src/types/transparent_note.nr | 11 ++++--- .../token_contract/src/types/token_note.nr | 16 ++++++---- .../src/types/transparent_note.nr | 11 ++++--- 19 files changed, 115 insertions(+), 98 deletions(-) diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index e68afdd7bf8..26d494bed65 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -23,24 +23,26 @@ struct AddressNote { impl NoteInterface for AddressNote { - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 8d02ab3db00..674b180b73a 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -139,6 +139,8 @@ impl PrivateContext { self.new_note_hashes.push(NoteHash { value: note_hash, counter: self.next_counter() }); } + // Note: This function is called with non-zero note hash only in 1 of 25 cases in aztec-packages repo - consider + // creating a separate function with 1 arg for the zero note hash case. fn push_new_nullifier(&mut self, nullifier: Field, nullified_note_hash: Field) { self.new_nullifiers.push(Nullifier { value: nullifier, note_hash: nullified_note_hash, counter: self.next_counter() }); } diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr index 3d9c408afd7..48c0f5bfd69 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/incoming_body.nr @@ -66,9 +66,11 @@ mod test { fn set_header(&mut self, header: NoteHeader) {self.header = header; } - fn compute_nullifier(self, context: &mut PrivateContext) -> Field {1} + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { + (1, 1) + } - fn compute_nullifier_without_context(self) -> Field {1} + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) {(1,1)} fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN] { [self.address.to_field(), self.owner.to_field(), self.randomness]} diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index 2fc786ffc61..501decd69a9 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -57,25 +57,23 @@ pub fn destroy_note( context: &mut PrivateContext, note: Note ) where Note: NoteInterface { - let mut nullifier = 0; - let mut consumed_note_hash: Field = 0; - nullifier = note.compute_nullifier(context); + let (note_hash, nullifier) = note.compute_note_hash_and_nullifier(context); - // We also need the note hash corresponding to the "nullifier" - let header = note.get_header(); - - // A non-zero note hash counter implies that we're nullifying a transient note (i.e. one that has not yet been - // persisted in the trees and is instead if the pending new commitments array). In such a case we compute its hash - // to inform the kernel which note we're nullifyng so that it can find it and squash both the note and the - // nullifier. This value is unused when nullifying non transient notes - in that case the kernel simply persists - // the nullifier in the tree. - if (header.note_hash_counter != 0) { - // TODO(1718): Can we reuse the note hash computed in `compute_nullifier`? - consumed_note_hash = compute_note_hash_for_consumption(note); - } + let note_hash_counter = note.get_header().note_hash_counter; + let note_hash_for_consumption = if (note_hash_counter == 0) { + // Counter is zero, so we're nullifying a non-transient note and we don't populate the note_hash with real + // value (if we did so the `notifyNullifiedNote` oracle would throw). + 0 + } else { + // A non-zero note hash counter implies that we're nullifying a transient note (i.e. one that has not yet been + // persisted in the trees and is instead in the pending new note hashes array). In such a case we populate its + // hash with real value to inform the kernel which note we're nullifyng so that it can find it and squash both + // the note and the nullifier. + note_hash + }; let nullifier_counter = context.side_effect_counter; - assert(notify_nullified_note(nullifier, consumed_note_hash, nullifier_counter) == 0); + assert(notify_nullified_note(nullifier, note_hash_for_consumption, nullifier_counter) == 0); - context.push_new_nullifier(nullifier, consumed_note_hash) + context.push_new_nullifier(nullifier, note_hash_for_consumption) } diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index c9749de15f8..7206671e3dc 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -4,9 +4,9 @@ use dep::protocol_types::grumpkin_point::GrumpkinPoint; // docs:start:note_interface trait NoteInterface { - fn compute_nullifier(self, context: &mut PrivateContext) -> Field; + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field); - fn compute_nullifier_without_context(self) -> Field; + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field); // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn serialize_content(self) -> [Field; N]; diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index cc98cdf96a5..6c00104d611 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -57,7 +57,7 @@ pub fn compute_siloed_nullifier( context: &mut PrivateContext ) -> Field where Note: NoteInterface { let header = note_with_header.get_header(); - let inner_nullifier = note_with_header.compute_nullifier(context); + let (_, inner_nullifier) = note_with_header.compute_note_hash_and_nullifier(context); let input = [header.contract_address.to_field(), inner_nullifier]; pedersen_hash(input, GENERATOR_INDEX__OUTER_NULLIFIER) @@ -128,7 +128,8 @@ pub fn compute_note_hash_and_optionally_a_nullifier( let siloed_note_hash = compute_siloed_hash(note_header.contract_address, unique_note_hash); let inner_nullifier = if compute_nullifier { - note.compute_nullifier_without_context() + let (_, nullifier) = note.compute_note_hash_and_nullifier_without_context(); + nullifier } else { 0 }; diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index 56b752b6cef..cf0ee4d7aac 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -36,8 +36,8 @@ impl PrivateMutable { // Under such circumstances, such application developers might wish to _not_ use this state variable type. // This is especially dangerous for initial assignment to elements of a `Map` type (for example), because the storage slot often also identifies an actor. e.g. // the initial assignment to `my_map.at(msg.sender)` will leak: `msg.sender`, the fact that an element of `my_map` was assigned-to for the first time, and the contract_address. - // Note: subsequent nullification of this state variable, via the `replace` method will not be leaky, if the `compute_nullifier()` method of the underlying note is designed to ensure privacy. - // For example, if the `compute_nullifier()` method injects the secret key of a note owner into the computed nullifier's preimage. + // Note: subsequent nullification of this state variable, via the `replace` method will not be leaky, if the `compute_note_hash_and_nullifier()` method of the underlying note is designed to ensure privacy. + // For example, if the `compute_note_hash_and_nullifier()` method injects the secret key of a note owner into the computed nullifier's preimage. pub fn compute_initialization_nullifier(self) -> Field { pedersen_hash( [self.storage_slot], diff --git a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr index 8a7b853c794..3e320ec6559 100644 --- a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr +++ b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr @@ -39,12 +39,12 @@ impl NoteInterface for MockNote { 0 } - fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { - 0 + fn compute_note_hash_and_nullifier(self, _context: &mut PrivateContext) -> (Field, Field) { + (0, 0) } - fn compute_nullifier_without_context(self) -> Field { - 0 + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { + (0, 0) } fn to_be_bytes(self, storage_slot: Field) -> [u8; MOCK_NOTE_BYTES_LENGTH] { diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index d0bf0c65d04..409d6aaa9dc 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -24,26 +24,28 @@ struct ValueNote { impl NoteInterface for ValueNote { // docs:start:nullifier - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } // docs:end:nullifier - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index 389cf3278d5..fb19b8a912e 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -19,24 +19,26 @@ struct SubscriptionNote { } impl NoteInterface for SubscriptionNote { - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index 7a0b7a15ef0..d191ca8fe8a 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -38,7 +38,8 @@ contract Claim { // Note: Only the owner of the npk_m will be able to produce the nsk_app and compute this nullifier. // The nullifier is unique to the note and THIS contract because the protocol siloes all nullifiers with // the address of a contract it was emitted from. - context.push_new_nullifier(proof_note.compute_nullifier(&mut context), 0); + let (_, nullifier) = proof_note.compute_note_hash_and_nullifier(&mut context); + context.push_new_nullifier(nullifier, 0); // 4) Finally we mint the reward token to the sender of the transaction Token::at(storage.reward_token.read_private()).mint_public(recipient, proof_note.value).enqueue(&mut context); diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index b51eaecc668..f1c3bd6f080 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -30,24 +30,26 @@ impl CardNote { } impl NoteInterface for CardNote { - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index 0bc2689891e..1ca27ba7cdd 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -65,24 +65,26 @@ impl NoteInterface f EcdsaPublicKeyNote { x, y, npk_m_hash: serialized_note[4], header: NoteHeader::empty() } } - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index fdc55f5e363..33a50fb05fd 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -19,24 +19,26 @@ struct PublicKeyNote { } impl NoteInterface for PublicKeyNote { - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr index bcca5adbab6..5fc660079a4 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr @@ -18,14 +18,14 @@ struct TestNote { impl NoteInterface for TestNote { - fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, _context: &mut PrivateContext) -> (Field, Field) { // This note is expected to be shared between users and for this reason can't be nullified using a secret. - 0 + (0, 0) } - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { // This note is expected to be shared between users and for this reason can't be nullified using a secret. - 0 + (0, 0) } } diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 0a65ce2d54e..e3919f717d3 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -8,7 +8,6 @@ use dep::aztec::{ trait OwnedNote { fn new(amount: U128, owner_npk_m_hash: Field) -> Self; fn get_amount(self) -> U128; - fn get_owner_npk_m_hash(self) -> Field; } global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. @@ -27,25 +26,27 @@ struct TokenNote { impl NoteInterface for TokenNote { // docs:start:nullifier - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } // docs:end:nullifier - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } @@ -62,8 +63,4 @@ impl OwnedNote for TokenNote { fn get_amount(self) -> U128 { self.amount } - - fn get_owner_npk_m_hash(self) -> Field { - self.npk_m_hash - } } diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index c93b9b18956..1eada65f821 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -41,8 +41,8 @@ impl NoteInterface for Transpa } // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1386): Ensure nullifier collisions are prevented - fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { - self.compute_nullifier_without_context() + fn compute_note_hash_and_nullifier(self, _context: &mut PrivateContext) -> (Field, Field) { + self.compute_note_hash_and_nullifier_without_context() } // Computing a nullifier in a transparent note is not guarded by making secret a part of the nullifier preimage (as @@ -53,12 +53,13 @@ impl NoteInterface for Transpa // 3) the "get_notes" oracle constrains that the secret hash in the returned note matches the one computed in // circuit. // This achieves that the note can only be spent by the party that knows the secret. - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 2a797ec83e8..e3919f717d3 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash}, note::utils::compute_note_hash_for_consumption, oracle::unsafe_rand::unsafe_rand, - note::note_emission::NoteEmission, keys::getters::get_nsk_app + keys::getters::get_nsk_app }; trait OwnedNote { @@ -26,25 +26,27 @@ struct TokenNote { impl NoteInterface for TokenNote { // docs:start:nullifier - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } // docs:end:nullifier - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = get_nsk_app(self.npk_m_hash); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, secret, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index c93b9b18956..1eada65f821 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -41,8 +41,8 @@ impl NoteInterface for Transpa } // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1386): Ensure nullifier collisions are prevented - fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { - self.compute_nullifier_without_context() + fn compute_note_hash_and_nullifier(self, _context: &mut PrivateContext) -> (Field, Field) { + self.compute_note_hash_and_nullifier_without_context() } // Computing a nullifier in a transparent note is not guarded by making secret a part of the nullifier preimage (as @@ -53,12 +53,13 @@ impl NoteInterface for Transpa // 3) the "get_notes" oracle constrains that the secret hash in the returned note matches the one computed in // circuit. // This achieves that the note can only be spent by the party that knows the secret. - fn compute_nullifier_without_context(self) -> Field { + fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { let note_hash_for_nullify = compute_note_hash_for_consumption(self); - poseidon2_hash([ + let nullifier = poseidon2_hash([ note_hash_for_nullify, GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ]) + ]); + (note_hash_for_nullify, nullifier) } } From 54fd93393a0406a7893f465ad4504c96338567b3 Mon Sep 17 00:00:00 2001 From: benesjan Date: Wed, 19 Jun 2024 18:26:29 +0000 Subject: [PATCH 2/4] linking issue --- noir-projects/aztec-nr/aztec/src/context/private_context.nr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 674b180b73a..2bdc6b0a51f 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -139,8 +139,8 @@ impl PrivateContext { self.new_note_hashes.push(NoteHash { value: note_hash, counter: self.next_counter() }); } - // Note: This function is called with non-zero note hash only in 1 of 25 cases in aztec-packages repo - consider - // creating a separate function with 1 arg for the zero note hash case. + // TODO(#7112): This function is called with non-zero note hash only in 1 of 25 cases in aztec-packages repo + // - consider creating a separate function with 1 arg for the zero note hash case. fn push_new_nullifier(&mut self, nullifier: Field, nullified_note_hash: Field) { self.new_nullifiers.push(Nullifier { value: nullifier, note_hash: nullified_note_hash, counter: self.next_counter() }); } From 57c3f298f12701485bd946a337aa7ea2e730bd1d Mon Sep 17 00:00:00 2001 From: benesjan Date: Thu, 20 Jun 2024 08:04:08 +0000 Subject: [PATCH 3/4] migration notes --- docs/docs/migration_notes.md | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index ea8ee634133..c58147d18a3 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -6,6 +6,62 @@ 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` +`compute_nullifier` function was renamed to `compute_note_hash_and_nullifier` and now the function has to return not only the nullifier but also the note hash used to compute the nullifier. +The same change was done to `compute_nullifier_without_context` function. +These changes were done because having the note hash exposed allowed su to not having to re-compute it again in `destroy_note` function of Aztec.nr which led to significant decrease in gate counts (see the [optimization PR](https://github.com/AztecProtocol/aztec-packages/pull/7103) for more details). + + +```diff +- impl NoteInterface for ValueNote { +- fn compute_nullifier(self, context: &mut PrivateContext) -> Field { +- let note_hash_for_nullify = compute_note_hash_for_consumption(self); +- let secret = context.request_nsk_app(self.npk_m_hash); +- poseidon2_hash([ +- note_hash_for_nullify, +- secret, +- GENERATOR_INDEX__NOTE_NULLIFIER as Field, +- ]) +- } +- +- fn compute_nullifier_without_context(self) -> Field { +- let note_hash_for_nullify = compute_note_hash_for_consumption(self); +- let secret = get_nsk_app(self.npk_m_hash); +- poseidon2_hash([ +- note_hash_for_nullify, +- secret, +- GENERATOR_INDEX__NOTE_NULLIFIER as Field, +- ]) +- } +- } ++ impl NoteInterface for ValueNote { ++ fn compute_note_hash_and_nullifier(self, context: &mut PrivateContext) -> (Field, Field) { ++ let note_hash_for_nullify = compute_note_hash_for_consumption(self); ++ let secret = context.request_nsk_app(self.npk_m_hash); ++ let nullifier = poseidon2_hash([ ++ note_hash_for_nullify, ++ secret, ++ GENERATOR_INDEX__NOTE_NULLIFIER as Field, ++ ]); ++ (note_hash_for_nullify, nullifier) ++ } ++ ++ fn compute_note_hash_and_nullifier_without_context(self) -> (Field, Field) { ++ let note_hash_for_nullify = compute_note_hash_for_consumption(self); ++ let secret = get_nsk_app(self.npk_m_hash); ++ let nullifier = poseidon2_hash([ ++ note_hash_for_nullify, ++ secret, ++ GENERATOR_INDEX__NOTE_NULLIFIER as Field, ++ ]); ++ (note_hash_for_nullify, nullifier) ++ } ++ } +``` + + ## 0.43.0 ### [Aztec.nr] break `token.transfer()` into `transfer` and `transferFrom` From 63f97a4dcd15f3960fc4473804dfa99cd3e70d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Thu, 20 Jun 2024 11:17:40 +0200 Subject: [PATCH 4/4] Update docs/docs/migration_notes.md Co-authored-by: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> --- docs/docs/migration_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index c58147d18a3..35a9d71ba0c 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -11,7 +11,7 @@ Aztec is in full-speed development. Literally every version breaks compatibility ### [Aztec.nr] changes to `NoteInterface` `compute_nullifier` function was renamed to `compute_note_hash_and_nullifier` and now the function has to return not only the nullifier but also the note hash used to compute the nullifier. The same change was done to `compute_nullifier_without_context` function. -These changes were done because having the note hash exposed allowed su to not having to re-compute it again in `destroy_note` function of Aztec.nr which led to significant decrease in gate counts (see the [optimization PR](https://github.com/AztecProtocol/aztec-packages/pull/7103) for more details). +These changes were done because having the note hash exposed allowed us to not having to re-compute it again in `destroy_note` function of Aztec.nr which led to significant decrease in gate counts (see the [optimization PR](https://github.com/AztecProtocol/aztec-packages/pull/7103) for more details). ```diff