From ae2bdbde85f8d8e930a1afafb73db0d6503d2981 Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 25 Feb 2025 21:38:44 +0000 Subject: [PATCH 1/6] squashed monster commit --- boxes/boxes/react/src/contracts/src/main.nr | 2 +- boxes/boxes/vanilla/src/contracts/src/main.nr | 4 +- .../smart_contracts/functions/attributes.md | 36 ++- .../common_patterns/index.md | 6 +- .../writing_contracts/notes/address_note.md | 8 +- .../writing_contracts/notes/custom_note.md | 53 ---- .../notes/implementing_a_note.md | 41 +++ .../writing_contracts/notes/index.md | 3 +- .../writing_contracts/notes/value_note.md | 2 +- .../storage/private_state.md | 19 +- .../contract_tutorials/nft_contract.md | 6 +- docs/docs/migration_notes.md | 120 ++++----- .../aztec-nr/address-note/src/address_note.nr | 53 +--- .../aztec-nr/aztec/src/discovery/mod.nr | 6 +- .../default_aes128/note.nr | 14 +- .../aztec/src/history/note_inclusion.nr | 7 +- .../aztec/src/history/note_validity.nr | 6 +- .../aztec/src/history/nullifier_inclusion.nr | 8 +- .../src/history/nullifier_non_inclusion.nr | 8 +- .../macros/functions/call_interface_stubs.nr | 3 +- .../aztec-nr/aztec/src/macros/mod.nr | 4 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 234 +++++++++++++++--- .../aztec-nr/aztec/src/macros/utils.nr | 4 +- .../aztec-nr/aztec/src/note/lifecycle.nr | 10 +- .../aztec/src/note/note_getter/mod.nr | 14 +- .../aztec/src/note/note_getter_options.nr | 8 +- .../aztec-nr/aztec/src/note/note_interface.nr | 48 ++-- .../aztec/src/note/note_viewer_options.nr | 4 +- .../aztec-nr/aztec/src/note/utils.nr | 8 +- .../aztec/src/oracle/note_discovery.nr | 4 +- .../aztec-nr/aztec/src/oracle/notes.nr | 9 +- noir-projects/aztec-nr/aztec/src/prelude.nr | 2 +- .../aztec/src/state_vars/private_immutable.nr | 8 +- .../aztec/src/state_vars/private_mutable.nr | 6 +- .../aztec/src/state_vars/private_set.nr | 6 +- .../src/test/helpers/test_environment.nr | 6 +- .../aztec/src/test/mocks/mock_note.nr | 35 ++- .../aztec-nr/uint-note/src/uint_note.nr | 50 +--- .../aztec-nr/value-note/src/utils.nr | 19 +- .../aztec-nr/value-note/src/value_note.nr | 56 +---- .../src/subscription_note.nr | 46 +--- .../docs_example_contract/src/options.nr | 30 ++- .../src/types/card_note.nr | 65 +---- .../ecdsa_public_key_note/src/lib.nr | 34 +-- .../nft_contract/src/types/nft_note.nr | 49 +--- .../src/public_key_note.nr | 46 +--- .../spam_contract/src/types/balance_set.nr | 14 +- .../spam_contract/src/types/token_note.nr | 47 +--- .../contracts/test_contract/Nargo.toml | 2 +- .../contracts/test_contract/src/main.nr | 31 +-- .../contracts/test_contract/src/test.nr | 15 +- .../contracts/test_contract/src/test_note.nr | 47 ++-- .../token_blacklist_contract/src/main.nr | 6 +- .../src/types/balances_map.nr | 14 +- .../src/types/token_note.nr | 47 +--- .../src/types/transparent_note.nr | 22 +- .../crates/types/src/constants.nr | 2 +- .../crates/types/src/meta/mod.nr | 2 +- .../src/e2e_fees/fee_settings.test.ts | 3 +- .../src/client/private_execution.test.ts | 36 --- 60 files changed, 553 insertions(+), 945 deletions(-) delete mode 100644 docs/docs/developers/guides/smart_contracts/writing_contracts/notes/custom_note.md create mode 100644 docs/docs/developers/guides/smart_contracts/writing_contracts/notes/implementing_a_note.md diff --git a/boxes/boxes/react/src/contracts/src/main.nr b/boxes/boxes/react/src/contracts/src/main.nr index 54500fa57864..f827f3d9ee1b 100644 --- a/boxes/boxes/react/src/contracts/src/main.nr +++ b/boxes/boxes/react/src/contracts/src/main.nr @@ -5,7 +5,7 @@ contract BoxReact { use dep::aztec::{ encrypted_logs::log_assembly_strategies::default_aes128::note::encode_and_encrypt_note, macros::{functions::{initializer, private}, storage::storage}, - prelude::{AztecAddress, Map, NoteInterface, PrivateMutable}, + prelude::{AztecAddress, Map, PrivateMutable}, }; use dep::value_note::value_note::ValueNote; diff --git a/boxes/boxes/vanilla/src/contracts/src/main.nr b/boxes/boxes/vanilla/src/contracts/src/main.nr index 0151dbf83a29..3b5c162f9860 100644 --- a/boxes/boxes/vanilla/src/contracts/src/main.nr +++ b/boxes/boxes/vanilla/src/contracts/src/main.nr @@ -5,9 +5,9 @@ contract Vanilla { use dep::aztec::{ encrypted_logs::log_assembly_strategies::default_aes128::note::encode_and_encrypt_note, macros::{functions::{initializer, private}, storage::storage}, - prelude::{AztecAddress, Map, NoteInterface, PrivateMutable}, + prelude::{AztecAddress, Map, PrivateMutable}, }; - use dep::value_note::value_note::{VALUE_NOTE_LEN, ValueNote}; + use dep::value_note::value_note::ValueNote; #[storage] struct Storage { diff --git a/docs/docs/aztec/smart_contracts/functions/attributes.md b/docs/docs/aztec/smart_contracts/functions/attributes.md index 62d4a6334442..fa274fd7037a 100644 --- a/docs/docs/aztec/smart_contracts/functions/attributes.md +++ b/docs/docs/aztec/smart_contracts/functions/attributes.md @@ -178,30 +178,23 @@ This macro inserts a check at the beginning of the function to ensure that the c assert(context.msg_sender() == context.this_address(), "Function can only be called internally"); ``` -## Custom notes #[note] +## Implementing notes -The `#[note]` attribute is used to define custom note types in Aztec contracts. Learn more about notes [here](../../concepts/storage/index.md). +The `#[note]` attribute is used to define notes in Aztec contracts. Learn more about notes [here](../../concepts/storage/index.md). When a struct is annotated with `#[note]`, the Aztec macro applies a series of transformations and generates implementations to turn it into a note that can be used in contracts to store private data. -1. **NoteInterface Implementation**: The macro automatically implements most methods of the `NoteInterface` trait for the annotated struct. This includes: +1. **Note Interface Implementation**: The macro automatically implements the `NoteType`, `NoteHash` and `Packable` traits for the annotated struct. This includes the following methods: - - `pack_content` and `unpack_content` - - `get_header` and `set_header` - - `get_note_type_id` - - `compute_note_hiding_point` - - `to_be_bytes` - - A `properties` method in the note's implementation + - `get_id` + - `compute_note_hash` + - `compute_nullifier` + - `pack` + - `unpack` -2. **Automatic Header Field**: If the struct doesn't already have a `header` field of type `NoteHeader`, one is automatically created +2. **Property Metadata**: A separate struct is generated to describe the note's fields, which is used for efficient retrieval of note data -3. **Note Type ID Generation**: A unique `note_type_id` is automatically computed for the note type using a Keccak hash of the struct name - -4. **Serialization and Deserialization**: Methods for converting the note to and from a series of `Field` elements are generated, assuming each field can be converted to/from a `Field` - -5. **Property Metadata**: A separate struct is generated to describe the note's fields, which is used for efficient retrieval of note data - -6. **Export Information**: The note type and its ID are automatically exported +3. **Export Information**: The note type and its ID are automatically exported ### Before expansion @@ -218,19 +211,18 @@ struct CustomNote { ### After expansion ```rust -impl NoteInterface for CustomNote { - fn get_note_type_id() -> Field { +impl NoteType for CustomNote { + fn get_id() -> Field { // Assigned by macros by incrementing a counter 2 } +} +impl NoteHash for CustomNote { fn compute_note_hash(self, storage_slot: Field) -> Field { let inputs = array_concat(self.pack(), [storage_slot]); poseidon2_hash_with_separator(inputs, GENERATOR_INDEX__NOTE_HASH) } -} - -impl NullifiableNote for CustomNote { fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { let owner_npk_m_hash = get_public_keys(self.owner).npk_m.hash(); diff --git a/docs/docs/developers/guides/smart_contracts/writing_contracts/common_patterns/index.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/common_patterns/index.md index 367875a89084..041a4ed26cea 100644 --- a/docs/docs/developers/guides/smart_contracts/writing_contracts/common_patterns/index.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/common_patterns/index.md @@ -146,6 +146,8 @@ PS: when calling from private to public, `msg_sender` is the contract address wh In the [Prevent the same user flow from happening twice using nullifier](#prevent-the-same-user-flow-from-happening-twice-using-nullifiers), we recommended using nullifiers. But what you put in the nullifier is also as important. -E.g. for a voting contract, if your nullifier simply emits just the `user_address`, then privacy can easily be leaked as nullifiers are deterministic (have no randomness), especially if there are few users of the contract. So you need some kind of randomness. You can add the user's secret key into the nullifier to add randomness. We call this "nullifier secrets" as explained [here](../../../../../aztec/concepts/accounts/keys.md#nullifier-keys). E.g.: +E.g. for a voting contract, if your nullifier simply emits just the `user_address`, then privacy can easily be leaked via a preimage attack as nullifiers are deterministic (have no randomness), especially if there are few users of the contract. So you need some kind of randomness. You can add the user's secret key into the nullifier to add randomness. We call this "nullifier secrets" as explained [here](../../../../../aztec/concepts/accounts/keys.md#nullifier-keys). -#include_code nullifier /noir-projects/aztec-nr/value-note/src/value_note.nr rust +Here is an example from the voting contract: + +#include_code cast_vote /noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust diff --git a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/address_note.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/address_note.md index 956ac9195af9..153ac98eeaff 100644 --- a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/address_note.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/address_note.md @@ -3,13 +3,13 @@ title: Using Address Note in Aztec.nr tags: [contracts, notes] --- -Address notes hold one main property of the type `AztecAddress`. It also holds `npk_m_hash` and `randomness`, similar to other note types. +Address notes hold one main property of the type `AztecAddress`. It also holds `owner` and `randomness`, similar to other note types. ## AddressNote -This is the AddressNote struct: +This is the AddressNote: -#include_code address_note_struct noir-projects/aztec-nr/address-note/src/address_note.nr rust +#include_code address_note_def noir-projects/aztec-nr/address-note/src/address_note.nr rust ## Importing AddressNote @@ -39,5 +39,5 @@ In this example, `owner` is the `address` and the `npk_m_hash` of the donor was ## Learn more - [Keys, including nullifier keys and outgoing viewer](../../../../../aztec/concepts/accounts/keys.md) -- [How to write a custom note](./custom_note.md) +- [How to implement a note](./implementing_a_note.md) - [AddressNote reference](../../../../reference/smart_contract_reference/aztec-nr/address-note/address_note.md) diff --git a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/custom_note.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/custom_note.md deleted file mode 100644 index a3cfa178abff..000000000000 --- a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/custom_note.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Using custom note types in Aztec.nr -tags: [contracts, notes] -keywords: [custom note, note] ---- - -It may be useful to write a custom note type if you want to use a specific type of private data or struct that does not have a default implementation in Aztec.nr. If you create a note that uses a custom note type, you are able to nullify that note with one nullifier. This is more secure and less expensive than using multiple separate notes. - -As an example, if you are developing a card game, you may want to store multiple pieces of data in each card. Rather than storing each of these pieces of data in their own note, you can use a custom note to define the card, and then nullify (or exchange ownership of) the card when it has been used. - -If you want to work with values or addresses, you can check out [ValueNote](./value_note.md) or [AddressNote](./address_note.md). - -## Define a custom note type - -You will likely want to define your note in a new file and import it into your contract. - -A custom note type can be defined with the macro `#[note]` used on a struct: - -#include_code state_vars-CardNote noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr rust - -In this example, we are implementing a card note that holds a number of `points` as `u8`. - -`randomness` is not enforced by the protocol and should be implemented by the application developer. If you do not include `randomness`, and the note preimage can be guessed by an attacker, it makes the note vulnerable to preimage attacks. - -`npk_m_hash` is `nullifier public key, master, hash` which is the hash of the nullifier key owned by the user. It ensures that when the note is spent, only the owner of the `npk_m` can spend it. - -## Implement NoteInterface - -You will need to implement a note interface for your note. Most of this is automatically generated by the `#[note]` macro but can be overwritten. For your reference, this is what a note interface looks like: - -#include_code note_interface noir-projects/aztec-nr/aztec/src/note/note_interface.nr rust - -You will need to implement the functions `compute_nullifier(...)` and `compute_nullifier_without_context()` which tells Aztec how to compute nullifiers for your note. - -#include_code note_interface noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr rust - -In this example, these functions compute the note hash by using `compute_note_hash_for_nullify` and then generate a nullifier by hashing this note hash together with a secret. - -### Methods - -You will likely want to implement methods in order to use your note easily within contracts. For example, this may be what a `new` method can look like, for creating a new note: - -#include_code cardnote_impl noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr rust - -If you are also planning to be able to access the data with a note in public state, you will need to implement a method for serializing the note. This might look something like this: - -#include_code serialize noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr rust - -## Further reading - -- [What is `#[note]` actually doing? + functions such as serialize() and deserialize()](../../../../../aztec/smart_contracts/functions//attributes.md#custom-notes-note) -- [Macros reference](../../../../reference/smart_contract_reference/macros.md) -- [Keys, including npk_m_hash (nullifier public key master)](../../../../../aztec/concepts/accounts/keys.md) diff --git a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/implementing_a_note.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/implementing_a_note.md new file mode 100644 index 000000000000..16c4f4c75727 --- /dev/null +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/implementing_a_note.md @@ -0,0 +1,41 @@ +--- +title: Implementing a note in Aztec.nr +tags: [contracts, notes] +keywords: [implementing note, note] +--- + +You may want to create your own note type if you need to use a specific type of private data or struct that is not already implemented in Aztec.nr, or if you want to experiment with custom note hashing and nullifier schemes. For custom hashing and nullifier schemes, use the `#[custom_note]` macro instead of `#[note]`, as it does not automatically derive the `NoteHash` trait. + +For example, if you are developing a card game, you may want to store multiple pieces of data in each card. Rather than storing each piece of data in its own note, you can define a card note type that contains all the data, and then nullify (or exchange ownership of) the card when it has been used. + +If you want to work with values, addresses or integers, you can check out [ValueNote](./value_note.md), [AddressNote](./address_note.md) or `UintNote`. + +## Define a note type + +You will likely want to define your note in a new file and import it into your contract. + +A note type can be defined with the macro `#[note]` used on a struct: + +#include_code state_vars-CardNote noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr rust + +In this example, we are implementing a card note that holds a number of `points` as `u8`. + +`randomness` is not enforced by the protocol and should be implemented by the application developer. If you do not include `randomness`, and the note preimage can be guessed by an attacker, it makes the note vulnerable to preimage attacks. + +`owner` is used when nullifying the note to obtain a nullifer secret key. +It ensures that when a note is spent, only the owner can spend it and the note sender cannot figure out that the note has been spent! +Providing the `owner` with improved privacy. + +Why is it delivering privacy from sender? + +Because a sender cannot derive a note nullifier. +We could derive the nullifier based solely on the note itself (for example, by computing `hash([note.points, note.owner, note.randomness], NULLIFIER_SEPARATOR)`). +This would work since the nullifier would be unique and only the note recipient could spend it (as contract logic typically only allows the note owner to obtain a note, e.g. from a `Map<...>`). +However, if we did this, the sender could also derive the nullifier off-chain and monitor the nullifier tree for its inclusion, allowing them to determine when a note has been spent. +This would leak privacy. + +## Further reading + +- [What is `#[note]` actually doing? + functions such as serialize() and deserialize()](../../../../../aztec/smart_contracts/functions//attributes.md#implementing-notes-note) +- [Macros reference](../../../../reference/smart_contract_reference/macros.md) +- [Keys, including npk_m_hash (nullifier public key master)](../../../../../aztec/concepts/accounts/keys.md) diff --git a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/index.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/index.md index ce0602c8a1c7..c26dc38e0791 100644 --- a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/index.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/index.md @@ -6,4 +6,5 @@ tags: [contracts, notes] Notes are the fundamental data structure in Aztec when working with private state. Using Aztec.nr, developers can define note types which allow flexibility in how notes are stored and nullified. -In this section there are guides about how to work with `AddressNote`, `ValueNote`, and custom notes in Aztec.nr. You can learn more about notes in the [concepts section](../../../../../aztec/concepts/storage/notes.md). +In this section there are guides about how to work with `AddressNote`, `ValueNote` from Aztec.nr and how to implement your own notes. +You can learn more about notes in the [concepts section](../../../../../aztec/concepts/storage/notes.md). diff --git a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/value_note.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/value_note.md index 0a639f59574c..e96f296252d7 100644 --- a/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/value_note.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/value_note.md @@ -59,5 +59,5 @@ The `decrement` function works similarly except the `amount` is the number that ## Learn more - [Keys, including nullifier keys and outgoing viewer](../../../../../aztec/concepts/accounts/keys.md) -- [How to write a custom note](./custom_note.md) +- [How to implement a note](./implementing_a_note.md) - [ValueNote reference](../../../../reference/smart_contract_reference/aztec-nr/value-note/value_note.md) diff --git a/docs/docs/developers/reference/smart_contract_reference/storage/private_state.md b/docs/docs/developers/reference/smart_contract_reference/storage/private_state.md index 62bfa64e7931..e9b25762f415 100644 --- a/docs/docs/developers/reference/smart_contract_reference/storage/private_state.md +++ b/docs/docs/developers/reference/smart_contract_reference/storage/private_state.md @@ -32,21 +32,20 @@ Unlike public state variables, which can be arbitrary types, private state varia Notes are the fundamental elements in the private world. -A note should implement the following traits: +A note has to implement the following traits: -#include_code note_interface /noir-projects/aztec-nr/aztec/src/note/note_interface.nr rust - -#include_code serialize /noir-projects/noir-protocol-circuits/crates/types/src/traits.nr rust - -#include_code deserialize /noir-projects/noir-protocol-circuits/crates/types/src/traits.nr rust +#include_code note_interfaces /noir-projects/aztec-nr/aztec/src/note/note_interface.nr rust The interplay between a private state variable and its notes can be confusing. Here's a summary to aid intuition: -A private state variable (of type `PrivateMutable`, `PrivateImmutable` or `PrivateSet`) may be declared in storage. - -Every note contains a header, which contains the contract address and storage slot of the state variable to which it is associated. A note is associated with a private state variable if the storage slot of the private state variable matches the storage slot contained in the note's header. The header provides information that helps the user interpret the note's data. +A private state variable (of type `PrivateMutable`, `PrivateImmutable` or `PrivateSet`) may be declared in storage and the purpose of private state variables is to manage notes (inserting their note hashes into the note hash tree, obtaining the notes, grouping the notes together using the storage slot etc.). -Management of the header is abstracted-away from developers who use the `PrivateImmutable`, `PrivateMutable` and `PrivateSet` types. +:::info +Note that storage slots in private state are not real. +They do not point to a specific leaf in a merkle tree (as is the case in public). +Instead, in the case of notes they can be understood only as a tag that is used to associate notes with a private state variable. +The state variable storage slot can commonly represent an owner, as is the case when using the `at(...)` function of a `Map<>` with an `AztecAddress` as the key. +::: A private state variable points to one or many notes (depending on the type). The note(s) are all valid private state if the note(s) haven't yet been nullified. diff --git a/docs/docs/developers/tutorials/codealong/contract_tutorials/nft_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/nft_contract.md index fefa4bf7ed45..6b404884d000 100644 --- a/docs/docs/developers/tutorials/codealong/contract_tutorials/nft_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/nft_contract.md @@ -172,16 +172,12 @@ Below the dependencies, paste the following Storage struct: ## Custom Notes -The contract storage uses a [custom note](../../../guides/smart_contracts/writing_contracts/notes/custom_note.md) implementation. Custom notes are useful for defining your own data types. You can think of a custom note as a "chunk" of private data, the entire thing is added, updated or nullified (deleted) together. This NFT note is very simple and stores only the owner and the `token_id` and uses `randomness` to hide its contents. +The contract storage uses a [custom note](../../../guides/smart_contracts/writing_contracts/notes/implementing_a_note.md) implementation. Custom notes are useful for defining your own data types. You can think of a custom note as a "chunk" of private data, the entire thing is added, updated or nullified (deleted) together. This NFT note is very simple and stores only the owner and the `token_id` and uses `randomness` to hide its contents. Randomness is required because notes are stored as commitments (hashes) in the note hash tree. Without randomness, the contents of a note may be derived through brute force (e.g. without randomness, if you know my Aztec address, you may be able to figure out which note hash in the tree is mine by hashing my address with many potential `token_id`s). #include_code nft_note /noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr rust -The custom note implementation also includes the nullifier computation function. This tells the protocol how the note should be nullified. - -#include_code compute_nullifier /noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr rust - ## Functions Copy and paste the body of each function into the appropriate place in your project if you are following along. diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index 2df484f4128c..2ccbdfc438bf 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -85,8 +85,11 @@ The 3 test accounts deployed in the sandbox are pre-funded with 10 ^ 22 fee juic In addition to the native fee juice, users can pay the transaction fees using tokens that have a corresponding FPC contract. The sandbox now includes `BananaCoin` and `BananaFPC`. Users can use a funded test account to mint banana coin for a new account. The new account can then start sending transactions and pay fees with banana coin. ```typescript -import { getDeployedTestAccountsWallets } from '@aztec/accounts/testing'; -import { getDeployedBananaCoinAddress, getDeployedBananaFPCAddress } from '@aztec/aztec'; +import { getDeployedTestAccountsWallets } from "@aztec/accounts/testing"; +import { + getDeployedBananaCoinAddress, + getDeployedBananaFPCAddress, +} from "@aztec/aztec"; // Fetch the funded test accounts. const [fundedWallet] = await getDeployedTestAccountsWallets(pxe); @@ -105,21 +108,29 @@ await alice.deploy({ deployWallet: fundedWallet }).wait(); const bananaCoinAddress = await getDeployedBananaCoinAddress(pxe); const bananaCoin = await TokenContract.at(bananaCoinAddress, fundedWallet); const mintAmount = 10n ** 20n; -await bananaCoin.methods.mint_to_private(fundedWallet.getAddress(), aliceAddress, mintAmount).send().wait(); +await bananaCoin.methods + .mint_to_private(fundedWallet.getAddress(), aliceAddress, mintAmount) + .send() + .wait(); // Use the new account to send a tx and pay with banana coin. const transferAmount = 100n; const bananaFPCAddress = await getDeployedBananaFPCAddress(pxe); -const paymentMethod = new PrivateFeePaymentMethod(bananaFPCAddress, aliceWallet); +const paymentMethod = new PrivateFeePaymentMethod( + bananaFPCAddress, + aliceWallet +); const receipt = await bananaCoin - .withWallet(aliceWallet) - .methods.transfer(recipient, transferAmount) - .send({ fee: { paymentMethod } }) - .wait(); + .withWallet(aliceWallet) + .methods.transfer(recipient, transferAmount) + .send({ fee: { paymentMethod } }) + .wait(); const transactionFee = receipt.transactionFee!; // Check the new account's balance. -const aliceBalance = await bananaCoin.methods.balance_of_private(aliceAddress).simulate(); +const aliceBalance = await bananaCoin.methods + .balance_of_private(aliceAddress) + .simulate(); expect(aliceBalance).toEqual(mintAmount - transferAmount - transactionFee); ``` @@ -151,62 +162,54 @@ The new check an indexed tree allows is non-membership of addresses of non proto + ); ``` -### [Aztec.nr] Changes to `NoteInterface` -We removed `NoteHeader` from notes, we've introduced a `RetrievedNote` struct and instead of the `pack_content` and `unpack_content` functions we make notes implement the standard `Packable` trait. -This led us to do the following changes to `NoteInterface`: +### [Aztec.nr] Changes to note interfaces and note macros -```diff -pub trait NullifiableNote { -... -- unconstrained fn compute_nullifier_without_context(self) -> Field; -+ unconstrained fn fn compute_nullifier_without_context(self, storage_slot: Field, contract_address: AztecAddress, note_nonce: Field) -> Field; -} +In this releases we decided to do a large refactor of notes which resulted in the following changes: + +1. We removed `NoteHeader` and we've introduced a `RetrievedNote` struct that contains a note and the information originally stored in the `NoteHeader`. +2. We removed the `pack_content` and `unpack_content` functions from the `NoteInterface`and made notes implement the standard `Packable` trait. +3. We renamed the `NullifiableNote` trait to `NoteHash` and we've moved the `compute_note_hash` function to this trait from the `NoteInterface` trait. +4. We renamed `NoteInterface` trait as `NoteType` and `get_note_type_id` function as `get_id`. +5. The `#[note]` and `#[partial_note]` macros now generate both the `NoteType` and `NoteHash` traits. +6. `#[custom_note_interface]` macro has been renamed to `#[custom_note]` and it now implements the `NoteInterface` trait. +This led us to do the following changes to the interfaces: + +```diff -pub trait NoteInterface { -+pub trait NoteInterface { ++pub trait NoteType { + fn get_id() -> Field; - fn pack_content(self) -> [Field; N]; - fn unpack_content(fields: [Field; N]) -> Self; - fn get_header(self) -> NoteHeader; - fn set_header(&mut self, header: NoteHeader) -> (); - 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`: +pub trait NoteHash { ++ fn compute_note_hash(self, storage_slot: Field) -> Field; -```diff -+ use dep::aztec::protocol_types::utils::arrays::array_concat; --use dep::aztec::prelude::{NoteHeader}; -+use dep::aztec::prelude::{RetrievedNote}; + fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field; -- impl NoteInterface for EcdsaPublicKeyNote { -+ impl NoteInterface for EcdsaPublicKeyNote { -- fn pack_content(self) -> [Field; ECDSA_PUBLIC_KEY_NOTE_LEN] { -- ... -- } +- unconstrained fn compute_nullifier_without_context(self) -> Field; ++ unconstrained fn fn compute_nullifier_without_context(self, storage_slot: Field, contract_address: AztecAddress, note_nonce: Field) -> Field; +} +``` -- fn unpack_content(packed_content: [Field; ECDSA_PUBLIC_KEY_NOTE_LEN]) -> EcdsaPublicKeyNote { -- ... -- } +If you are using `#[note]` or `#[partial_note(...)]` macros you will need to delete the implementations of the `NullifiableNote` (now `NoteHash`) trait as it now gets auto-generated. +Your note will also need to have an `owner` (a note struct field called owner) as its used in the auto-generated nullifier functions. -- fn get_header(self) -> NoteHeader { -- self.header -- } +If you need a custom implementation of the `NoteHash` interface use the `#[custom_note]` macro. -- fn set_header(&mut self, header: NoteHeader) { -- self.header = header; -- } +If you used `#[note_custom_interface]` macro before you will need to update your notes by using the `#[custom_note]` macro and implementing the `compute_note_hash` function. +If you have no need for a custom implementation of the `compute_note_hash` function copy the default one: -- 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) - } +``` +fn compute_note_hash(self, storage_slot: Field) -> Field { + let inputs = aztec::protocol_types::utils::arrays::array_concat(self.pack(), [storage_slot]); + aztec::protocol_types::hash::poseidon2_hash_with_separator(inputs, aztec::protocol_types::constants::GENERATOR_INDEX__NOTE_HASH) } +``` If you need to keep the custom implementation of the packing functionality, manually implement the `Packable` trait: @@ -226,27 +229,8 @@ If you need to keep the custom implementation of the packing functionality, manu If you don't provide a custom implementation of the `Packable` trait, a default one will be generated. -```diff -impl NullifiableNote for EcdsaPublicKeyNote { -... -- unconstrained fn compute_nullifier_without_context(self, storage_slot: Field) -> Field { -- let note_hash_for_nullify = compute_note_hash_for_nullify(self, storage_slot); -+ 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, nonce: note_nonce, note_hash_counter: 0 }; -+ let note_hash_for_nullify = compute_note_hash_for_nullify(retrieved_note, 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 - ) - } -} -``` ### [Aztec.nr] Changes to state variables + Since we've removed `NoteHeader` from notes we no longer need to modify the header in the notes when working with state variables. This means that we no longer need to be passing a mutable note reference which led to the following changes in the API. 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 93251b61a2b1..01991d5e19ac 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -1,64 +1,17 @@ use dep::aztec::{ - context::PrivateContext, - keys::getters::{get_nsk_app, get_public_keys}, macros::notes::note, - note::{ - note_interface::NullifiableNote, note_metadata::SettledNoteMetadata, - retrieved_note::RetrievedNote, utils::compute_note_hash_for_nullify, - }, oracle::random::random, - protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, traits::Serialize, - }, + protocol_types::{address::AztecAddress, traits::Serialize}, }; // docs:start:address_note_def -// docs:start:address_note_struct -// Stores an address #[note] -#[derive(Eq, Serialize)] +#[derive(Eq)] pub struct AddressNote { address: AztecAddress, owner: AztecAddress, randomness: Field, } -// docs:end:address_note_struct - -impl NullifiableNote for AddressNote { - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - - 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); - 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, - ) - } -} impl AddressNote { pub fn new(address: AztecAddress, owner: AztecAddress) -> Self { @@ -69,5 +22,5 @@ impl AddressNote { let randomness = unsafe { random() }; AddressNote { address, owner, randomness } } - // docs:end:address_note_def } +// docs:end:address_note_def diff --git a/noir-projects/aztec-nr/aztec/src/discovery/mod.nr b/noir-projects/aztec-nr/aztec/src/discovery/mod.nr index 08a06c0e9b3c..23e11b0bc147 100644 --- a/noir-projects/aztec-nr/aztec/src/discovery/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/discovery/mod.nr @@ -17,7 +17,7 @@ global NOTE_PRIVATE_LOG_RESERVED_FIELDS: u32 = 2; pub global MAX_NOTE_PACKED_LEN: u32 = PRIVATE_LOG_SIZE_IN_FIELDS - NOTE_PRIVATE_LOG_RESERVED_FIELDS; pub struct NoteHashAndNullifier { - /// The result of NoteInterface::compute_note_hash + /// The result of NoteHash::compute_note_hash pub note_hash: Field, /// The result of NullifiableNote::compute_nullifier_without_context pub inner_nullifier: Field, @@ -33,7 +33,7 @@ pub struct NoteHashAndNullifier { /// /// ``` /// |packed_note_content, contract_address, nonce, storage_slot, note_type_id| { -/// if note_type_id == MyNoteType::get_note_type_id() { +/// if note_type_id == MyNoteType::get_id() { /// assert(packed_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH); /// /// let note = MyNoteType::unpack(aztec::utils::array::subarray(packed_note.storage(), 0)); @@ -46,7 +46,7 @@ pub struct NoteHashAndNullifier { /// note_hash, inner_nullifier /// } /// ) -/// } else if note_type_id == MyOtherNoteType::get_note_type_id() { +/// } else if note_type_id == MyOtherNoteType::get_id() { /// ... // Similar to above but calling MyOtherNoteType::unpack_content /// } else { /// Option::none() // Unknown note type ID diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr index ad150a36e6bf..7143c544338a 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr @@ -5,7 +5,7 @@ use crate::{ ecdh_shared_secret::derive_ecdh_shared_secret_using_aztec_address, ephemeral::generate_ephemeral_key_pair, }, - note::{note_emission::NoteEmission, note_interface::NoteInterface}, + note::{note_emission::NoteEmission, note_interface::NoteType}, oracle::{ notes::{get_app_tag_as_sender, increment_app_tagging_secret_index_as_sender}, random::random, @@ -218,14 +218,14 @@ fn compute_note_plaintext_for_this_strategy( storage_slot: Field, ) -> [u8; N * 32 + 64] where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { let packed_note = note.pack(); let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); // TODO(#10952): The following can be reduced to 7 bits - let note_type_id_bytes: [u8; 32] = Note::get_note_type_id().to_be_bytes(); + let note_type_id_bytes: [u8; 32] = Note::get_id().to_be_bytes(); // We combine all the bytes into plaintext_bytes: let mut plaintext_bytes: [u8; N * 32 + 64] = [0; N * 32 + 64]; @@ -252,7 +252,7 @@ fn compute_log( sender: AztecAddress, ) -> [Field; PRIVATE_LOG_SIZE_IN_FIELDS] where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { // ***************************************************************************** // Compute the shared secret @@ -416,7 +416,7 @@ unconstrained fn compute_log_unconstrained( sender: AztecAddress, ) -> [Field; PRIVATE_LOG_SIZE_IN_FIELDS] where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { compute_log(context, note, storage_slot, recipient, sender) } @@ -431,7 +431,7 @@ pub fn encode_and_encrypt_note( sender: AztecAddress, ) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](NoteEmission) -> () where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { |e: NoteEmission| { let note = e.note; @@ -454,7 +454,7 @@ pub fn encode_and_encrypt_note_unconstrained( sender: AztecAddress, ) -> fn[(&mut PrivateContext, AztecAddress, AztecAddress)](NoteEmission) -> () where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { |e: NoteEmission| { let note = e.note; diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index 638257716598..cf2cb4da0d1d 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -3,8 +3,7 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use crate::{ note::{ - note_interface::{NoteInterface, NullifiableNote}, - retrieved_note::RetrievedNote, + note_interface::NoteHash, retrieved_note::RetrievedNote, utils::compute_note_hash_for_nullify, }, oracle::get_membership_witness::get_note_hash_membership_witness, @@ -17,13 +16,13 @@ trait ProveNoteInclusion { storage_slot: Field, ) where - Note: NoteInterface + NullifiableNote; + Note: NoteHash; } impl ProveNoteInclusion for BlockHeader { fn prove_note_inclusion(self, retrieved_note: RetrievedNote, storage_slot: Field) where - Note: NoteInterface + NullifiableNote, + Note: NoteHash, { let note_hash = compute_note_hash_for_nullify(retrieved_note, storage_slot); diff --git a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr index 8911bf543944..50e0be5bcf45 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_validity.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_validity.nr @@ -1,6 +1,6 @@ use crate::{ context::PrivateContext, - note::{note_interface::{NoteInterface, NullifiableNote}, retrieved_note::RetrievedNote}, + note::{note_interface::NoteHash, retrieved_note::RetrievedNote}, }; use dep::protocol_types::block_header::BlockHeader; @@ -13,7 +13,7 @@ trait ProveNoteValidity { context: &mut PrivateContext, ) where - Note: NoteInterface + NullifiableNote; + Note: NoteHash; } impl ProveNoteValidity for BlockHeader { @@ -24,7 +24,7 @@ impl ProveNoteValidity for BlockHeader { context: &mut PrivateContext, ) where - Note: NoteInterface + NullifiableNote, + Note: NoteHash, { self.prove_note_inclusion(retrieved_note, storage_slot); self.prove_note_not_nullified(retrieved_note, storage_slot, context); diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index 0a4df5183c3e..084cc5b035e9 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -4,9 +4,7 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use crate::{ context::PrivateContext, note::{ - note_interface::{NoteInterface, NullifiableNote}, - retrieved_note::RetrievedNote, - utils::compute_siloed_note_nullifier, + note_interface::NoteHash, retrieved_note::RetrievedNote, utils::compute_siloed_note_nullifier, }, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, }; @@ -50,7 +48,7 @@ trait ProveNoteIsNullified { context: &mut PrivateContext, ) where - Note: NoteInterface + NullifiableNote; + Note: NoteHash; } impl ProveNoteIsNullified for BlockHeader { @@ -62,7 +60,7 @@ impl ProveNoteIsNullified for BlockHeader { context: &mut PrivateContext, ) where - Note: NoteInterface + NullifiableNote, + Note: NoteHash, { let nullifier = compute_siloed_note_nullifier(retrieved_note, storage_slot, context); diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index 1e68f7f6b79a..741011541795 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -1,9 +1,7 @@ use crate::{ context::PrivateContext, note::{ - note_interface::{NoteInterface, NullifiableNote}, - retrieved_note::RetrievedNote, - utils::compute_siloed_note_nullifier, + note_interface::NoteHash, retrieved_note::RetrievedNote, utils::compute_siloed_note_nullifier, }, oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness, }; @@ -63,7 +61,7 @@ trait ProveNoteNotNullified { context: &mut PrivateContext, ) where - Note: NoteInterface + NullifiableNote; + Note: NoteHash; } impl ProveNoteNotNullified for BlockHeader { @@ -75,7 +73,7 @@ impl ProveNoteNotNullified for BlockHeader { context: &mut PrivateContext, ) where - Note: NoteInterface + NullifiableNote, + Note: NoteHash, { let nullifier = compute_siloed_note_nullifier(retrieved_note, storage_slot, context); diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/call_interface_stubs.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/call_interface_stubs.nr index 4b2cf4a7082d..16154d0bb705 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/call_interface_stubs.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/call_interface_stubs.nr @@ -1,6 +1,5 @@ use crate::macros::utils::{ - add_to_field_slice, AsStrQuote, compute_fn_selector, get_trait_impl_method, is_fn_private, - is_fn_view, + add_to_field_slice, AsStrQuote, compute_fn_selector, is_fn_private, is_fn_view, }; use std::meta::{type_of, unquote}; diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 97877ad8567c..624fc275b53b 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -147,8 +147,8 @@ comptime fn generate_contract_library_method_compute_note_hash_and_nullifier() - let get_note_type_id = get_trait_impl_method( typ, - quote { crate::note::note_interface::NoteInterface }, - quote { get_note_type_id }, + quote { crate::note::note_interface::NoteType }, + quote { get_id }, ); let unpack = get_trait_impl_method( typ, diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index cfb3821aa423..b6910aef1eaf 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -50,14 +50,10 @@ comptime fn derive_packable_if_not_implemented_and_get_len(s: StructDefinition) } } -/// Generates default `NoteInterface` implementation for a given note struct `s` and returns it as a quote. +/// Generates default `NoteType` implementation for a given note struct `s` and returns it as a quote. /// -/// impl NoteInterface for NoteStruct { -/// fn get_note_type_id() -> Field { -/// ... -/// } -/// -/// fn compute_note_hash(self, storage_slot: Field) -> Field { +/// impl NoteType for NoteStruct { +/// fn get_id() -> Field { /// ... /// } /// } @@ -65,32 +61,102 @@ comptime fn generate_note_interface(s: StructDefinition, note_type_id: Field) -> let name = s.name(); quote { - impl aztec::note::note_interface::NoteInterface for $name { - fn get_note_type_id() -> Field { + impl aztec::note::note_interface::NoteType for $name { + fn get_id() -> Field { $note_type_id } + } + } +} +/// Generates default `NoteHash` trait implementation for a given note struct `s` and returns it as a quote. +/// +/// # Generated Implementation +/// ``` +/// impl NoteHash for NoteStruct { +/// fn compute_note_hash(self, storage_slot: Field) -> 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 { ... } +/// } +/// ``` +comptime fn generate_note_hashing(s: StructDefinition) -> Quoted { + let name = s.name(); + + quote { + impl aztec::note::note_interface::NoteHash for $name { fn compute_note_hash(self, storage_slot: Field) -> Field { let inputs = aztec::protocol_types::utils::arrays::array_concat(self.pack(), [storage_slot]); aztec::protocol_types::hash::poseidon2_hash_with_separator(inputs, aztec::protocol_types::constants::GENERATOR_INDEX__NOTE_HASH) } + + fn compute_nullifier( + self, + context: &mut aztec::prelude::PrivateContext, + note_hash_for_nullify: Field, + ) -> Field { + 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. + let owner_npk_m_hash = aztec::protocol_types::traits::Hash::hash(owner_npk_m); + let secret = context.request_nsk_app(owner_npk_m_hash); + aztec::protocol_types::hash::poseidon2_hash_with_separator( + [note_hash_for_nullify, secret], + aztec::protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER as Field, + ) + } + + unconstrained fn compute_nullifier_without_context( + self, + storage_slot: Field, + contract_address: aztec::prelude::AztecAddress, + note_nonce: Field, + ) -> Field { + // We set the note_hash_counter to 0 as the note is assumed to be committed (and hence not transient). + let retrieved_note = + aztec::prelude::RetrievedNote { note: self, contract_address, nonce: note_nonce, note_hash_counter: 0 }; + 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. + let owner_npk_m_hash = aztec::protocol_types::traits::Hash::hash(owner_npk_m); let secret = aztec::keys::getters::get_nsk_app(owner_npk_m_hash); + aztec::protocol_types::hash::poseidon2_hash_with_separator( + [note_hash_for_nullify, secret], + aztec::protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER as Field, + ) + } } } } -/// Generates default `NoteInterface` implementation for a given partial note struct `s` and returns it as a quote. +/// Generates default `NoteHash` implementation for a given partial note struct `s` and returns it as a quote. /// -/// impl NoteInterface for NoteStruct { -/// fn get_note_type_id() -> Field { +/// impl NoteHash for NoteStruct { +/// fn compute_note_hash(self, storage_slot: Field) -> Field { /// ... /// } /// -/// fn compute_note_hash(self, storage_slot: Field) -> 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 { /// ... /// } /// } /// -/// # On differences from `generate_note_interface` +/// # On differences from `generate_note_hashing` /// We use multi-scalar multiplication (MSM) instead of Poseidon2 here since this is a partial note and therefore /// does require MSM's additive homomorphism property (the property is used to add to the commitment in public). /// We don't use this implementation for standard notes as well because Poseidon2 is significantly cheaper @@ -108,9 +174,8 @@ comptime fn generate_note_interface(s: StructDefinition, note_type_id: Field) -> /// /// Since -l would be -3 (an extraordinarily large number that cannot be a valid preimage length), /// including the length protects against these collisions. -comptime fn generate_note_interface_for_partial_note( +comptime fn generate_note_hashing_for_partial_note( s: StructDefinition, - note_type_id: Field, indexed_fixed_fields: [(Quoted, Type, u32)], indexed_nullable_fields: [(Quoted, Type, u32)], ) -> Quoted { @@ -136,11 +201,7 @@ comptime fn generate_note_interface_for_partial_note( .join(quote {,}); quote { - impl aztec::note::note_interface::NoteInterface for $name { - fn get_note_type_id() -> Field { - $note_type_id - } - + impl aztec::note::note_interface::NoteHash for $name { fn compute_note_hash(self, storage_slot: Field) -> Field { $new_aux_vars let point = std::embedded_curve_ops::multi_scalar_mul( @@ -149,6 +210,43 @@ comptime fn generate_note_interface_for_partial_note( ); point.x } + + fn compute_nullifier( + self, + context: &mut aztec::prelude::PrivateContext, + note_hash_for_nullify: Field, + ) -> Field { + 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. + let owner_npk_m_hash = aztec::protocol_types::traits::Hash::hash(owner_npk_m); + let secret = context.request_nsk_app(owner_npk_m_hash); + aztec::protocol_types::hash::poseidon2_hash_with_separator( + [note_hash_for_nullify, secret], + aztec::protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER as Field, + ) + } + + unconstrained fn compute_nullifier_without_context( + self, + storage_slot: Field, + contract_address: aztec::prelude::AztecAddress, + note_nonce: Field, + ) -> Field { + // We set the note_hash_counter to 0 as the note is assumed to be committed (and hence not transient). + let retrieved_note = + aztec::prelude::RetrievedNote { note: self, contract_address, nonce: note_nonce, note_hash_counter: 0 }; + 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. + let owner_npk_m_hash = aztec::protocol_types::traits::Hash::hash(owner_npk_m); + let secret = aztec::keys::getters::get_nsk_app(owner_npk_m_hash); + aztec::protocol_types::hash::poseidon2_hash_with_separator( + [note_hash_for_nullify, secret], + aztec::protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER as Field, + ) + } } } } @@ -406,7 +504,7 @@ comptime fn generate_multi_scalar_mul( /// ); /// /// let let storage_slot_bytes = storage_slot.to_be_bytes(); -/// let let note_type_id_bytes = TokenNote::get_note_type_id().to_be_bytes(); +/// let let note_type_id_bytes = TokenNote::get_id().to_be_bytes(); /// /// for i in 0..32 { /// log_plaintext[i] = storage_slot_bytes[i]; @@ -511,7 +609,7 @@ comptime fn generate_setup_payload( } } - pub fn encrypt_log(self, context: &mut PrivateContext, recipient: aztec::protocol_types::address::AztecAddress, sender: aztec::protocol_types::address::AztecAddress) -> [Field; $encrypted_log_fields_length] { + pub fn encrypt_log(self, context: &mut aztec::prelude::PrivateContext, recipient: aztec::protocol_types::address::AztecAddress, sender: aztec::protocol_types::address::AztecAddress) -> [Field; $encrypted_log_fields_length] { aztec::encrypted_logs::log_assembly_strategies::default_aes128::partial_note::compute_partial_public_log_payload( context.this_address(), self.log_plaintext, @@ -561,7 +659,7 @@ comptime fn get_setup_log_plaintext_body( let mut log_plaintext: [u8; $log_plaintext_length] = [0; $log_plaintext_length]; let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); - let note_type_id_bytes: [u8; 32] = $name::get_note_type_id().to_be_bytes(); + let note_type_id_bytes: [u8; 32] = $name::get_id().to_be_bytes(); for i in 0..32 { log_plaintext[i] = storage_slot_bytes[i]; @@ -902,8 +1000,8 @@ comptime fn index_note_fields( /// - SetupPayload /// - FinalizationPayload /// - PartialNote trait implementation -/// - NoteExport -/// - NoteInterface trait implementation +/// - NoteType trait implementation +/// - NoteHash trait implementation /// - Packable implementation /// /// Registers the note in the global `NOTES` map. @@ -914,6 +1012,8 @@ comptime fn index_note_fields( /// in the partial note are nullable. #[varargs] pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { + assert_has_owner(s); + // We separate struct members into fixed ones and nullable ones and we store info about the start index of each // member in the packed note array. let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, nullable_fields); @@ -924,12 +1024,9 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> generate_setup_payload(s, indexed_fixed_fields, indexed_nullable_fields); let (finalization_payload_impl, finalization_payload_name) = generate_finalization_payload(s, indexed_fixed_fields, indexed_nullable_fields); - let note_interface_impl = generate_note_interface_for_partial_note( - s, - note_type_id, - indexed_fixed_fields, - indexed_nullable_fields, - ); + let note_interface_impl = generate_note_interface(s, note_type_id); + let note_hashing_impl = + generate_note_hashing_for_partial_note(s, indexed_fixed_fields, indexed_nullable_fields); let partial_note_impl = generate_partial_note_impl(s, setup_payload_name, finalization_payload_name); let (packable_impl, note_packed_len) = derive_packable_if_not_implemented_and_get_len(s); @@ -947,6 +1044,7 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> $setup_payload_impl $finalization_payload_impl $note_interface_impl + $note_hashing_impl $partial_note_impl $packable_impl } @@ -954,18 +1052,22 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> /// Generates the following: /// - NoteTypeProperties -/// - NoteInterface trait implementation +/// - NoteType trait implementation +/// - NoteHash trait implementation /// - Packable implementation /// /// Registers the note in the global `NOTES` map. /// /// For more details on the generated code, see the individual functions. pub comptime fn note(s: StructDefinition) -> Quoted { + assert_has_owner(s); + let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, &[]); let note_properties = generate_note_properties(s); let note_type_id = get_next_note_type_id(); let note_interface_impl = generate_note_interface(s, note_type_id); + let note_hashing_impl = generate_note_hashing(s); let (packable_impl, note_packed_len) = derive_packable_if_not_implemented_and_get_len(s); register_note( @@ -979,20 +1081,50 @@ pub comptime fn note(s: StructDefinition) -> Quoted { quote { $note_properties $note_interface_impl + $note_hashing_impl $packable_impl } } -/// Generates the following: -/// - NoteTypeProperties -/// - Packable implementation +/// Generates code for a custom note implementation that requires specialized note hash or nullifier computation. /// -/// Registers the note in the global `NOTES` map. +/// # Generated Code +/// - NoteTypeProperties: Defines the structure and properties of note fields +/// - NoteType trait implementation: Provides the note type ID +/// - Packable implementation: Enables serialization/deserialization of the note /// -/// For more details on the generated code, see the individual functions. -pub comptime fn note_custom_interface(s: StructDefinition) -> Quoted { +/// # Registration +/// Registers the note in the global `NOTES` map with: +/// - Note type ID +/// - Packed length +/// - Field indices and nullability +/// +/// # Use Cases +/// Use this macro when implementing a note that needs custom: +/// - Note hash computation logic +/// - Nullifier computation logic +/// +/// The macro omits generating default NoteHash trait implementation, allowing you to provide your own. +/// +/// # Example +/// ``` +/// #[custom_note] +/// struct CustomNote { +/// value: Field, +/// metadata: Field +/// } +/// +/// impl NoteHash for CustomNote { +/// // Custom note hash computation... +/// fn compute_note_hash(...) -> Field { ... } +/// +/// // Custom nullifier computation... +/// fn compute_nullifier(...) -> Field { ... } +/// fn compute_nullifier_without_context(...) -> Field { ... } +/// } +/// ``` +pub comptime fn custom_note(s: StructDefinition) -> Quoted { let (packable_impl, note_packed_len) = derive_packable_if_not_implemented_and_get_len(s); - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/12012): This is broken let note_type_id = get_next_note_type_id(); let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, &[]); @@ -1005,9 +1137,31 @@ pub comptime fn note_custom_interface(s: StructDefinition) -> Quoted { ); let note_properties = generate_note_properties(s); + let note_interface_impl = generate_note_interface(s, note_type_id); quote { $note_properties + $note_interface_impl $packable_impl } } + +/// Asserts that the note has an 'owner' field. +/// +/// We require notes implemented with #[note] macro and #[partial_note] macro to have an 'owner' field because our +/// auto-generated nullifier functions expect it. This requirement is most likely only temporary. +comptime fn assert_has_owner(note: StructDefinition) { + let fields = note.fields_as_written(); + let mut has_owner = false; + for i in 0..fields.len() { + let (field_name, _) = fields[i]; + if field_name == quote { owner } { + has_owner = true; + break; + } + } + assert( + has_owner, + "Note must have an 'owner' field. If your notes have no owner, use #[custom_note] insteadof #[note] and implement the NoteHashing trait manually.", + ); +} diff --git a/noir-projects/aztec-nr/aztec/src/macros/utils.nr b/noir-projects/aztec-nr/aztec/src/macros/utils.nr index aabd6be83fb2..ecd42051abeb 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/utils.nr @@ -252,7 +252,7 @@ pub(crate) comptime fn is_note(typ: Type) -> bool { let (def, _) = struc; def.has_named_attribute("note") | def.has_named_attribute("partial_note") - | def.has_named_attribute("note_custom_interface") + | def.has_named_attribute("custom_note") }) } @@ -266,7 +266,7 @@ pub(crate) comptime fn is_note(typ: Type) -> bool { /// A copy of this function exists in `noir-protocol-circuits/crates/types/src/meta/mod.nr`. We maintain separate /// copies because importing it here from there would cause the `target_trait` to be interpreted in the context /// of the protocol circuits types crate, making it impossible to compile code for traits from this crate -/// (e.g. NoteInterface). +/// (e.g. NoteType). pub(crate) comptime fn get_trait_impl_method( typ: Type, target_trait: Quoted, diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index 2e9a7c4544e9..f4569bcef910 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -1,7 +1,7 @@ use crate::context::PrivateContext; use crate::note::{ note_emission::NoteEmission, - note_interface::{NoteInterface, NullifiableNote}, + note_interface::{NoteHash, NoteType}, retrieved_note::RetrievedNote, utils::{compute_note_hash_for_nullify_from_read_request, compute_note_hash_for_read_request}, }; @@ -14,7 +14,7 @@ pub fn create_note( note: Note, ) -> NoteEmission where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { let note_hash_counter = context.side_effect_counter; @@ -23,7 +23,7 @@ where let packed_note = Note::pack(note); notify_created_note( storage_slot, - Note::get_note_type_id(), + Note::get_id(), packed_note, note_hash, note_hash_counter, @@ -41,7 +41,7 @@ pub fn destroy_note( storage_slot: Field, ) where - Note: NoteInterface + NullifiableNote, + Note: NoteHash, { let note_hash_for_read_request = compute_note_hash_for_read_request(retrieved_note, storage_slot); @@ -55,7 +55,7 @@ pub fn destroy_note_unsafe( note_hash_for_read_request: Field, ) where - Note: NoteInterface + NullifiableNote, + Note: NoteHash, { let note_hash_for_nullify = compute_note_hash_for_nullify_from_read_request(retrieved_note, note_hash_for_read_request); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index 08143796c153..54d8e8b47bd7 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -2,7 +2,7 @@ use crate::context::PrivateContext; use crate::note::{ constants::{GET_NOTE_ORACLE_RETURN_LENGTH, VIEW_NOTE_ORACLE_RETURN_LENGTH}, note_getter_options::{NoteGetterOptions, NoteStatus, PropertySelector, Select, Sort, SortOrder}, - note_interface::{NoteInterface, NullifiableNote}, + note_interface::{NoteHash, NoteType}, note_viewer_options::NoteViewerOptions, retrieved_note::RetrievedNote, utils::compute_note_hash_for_read_request, @@ -76,7 +76,7 @@ pub fn get_note( storage_slot: Field, ) -> (RetrievedNote, Field) where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { // Safety: Constraining that we got a valid note from the oracle is fairly straightforward: all we need to do // is check that the metadata is correct, and that the note exists. @@ -105,7 +105,7 @@ pub fn get_notes( options: NoteGetterOptions, ) -> (BoundedVec, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL>, BoundedVec) where - Note: NoteInterface + NullifiableNote + Eq + Packable, + Note: NoteType + NoteHash + Eq + Packable, { // Safety: The notes are constrained below. let opt_notes = unsafe { get_notes_internal(storage_slot, options) }; @@ -130,7 +130,7 @@ fn constrain_get_notes_internal, ) -> (BoundedVec, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL>, BoundedVec) where - Note: NoteInterface + NullifiableNote + Eq + Packable, + Note: NoteType + NoteHash + Eq + Packable, { // The filter is applied first to avoid pushing note read requests for notes we're not interested in. Note that // while the filter function can technically mutate the notes (as opposed to simply removing some), the private @@ -183,7 +183,7 @@ where unconstrained fn get_note_internal(storage_slot: Field) -> RetrievedNote where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { let placeholder_note = [Option::none()]; let placeholder_fields = [0; GET_NOTE_ORACLE_RETURN_LENGTH]; @@ -215,7 +215,7 @@ unconstrained fn get_notes_internal, ) -> [Option>; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { // This function simply performs some transformations from NoteGetterOptions into the types required by the oracle. let (num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order) = @@ -252,7 +252,7 @@ pub unconstrained fn view_notes( options: NoteViewerOptions, ) -> BoundedVec where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { let (num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order) = flatten_options(options.selects, options.sorts); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr index 66432e4f5555..e161da906216 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr @@ -1,4 +1,4 @@ -use crate::note::{note_interface::NoteInterface, retrieved_note::RetrievedNote}; +use crate::note::{note_interface::NoteType, retrieved_note::RetrievedNote}; use dep::protocol_types::{ constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, traits::{Packable, ToField}, @@ -137,7 +137,7 @@ impl NoteGetterOptions NoteGetterOptions where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { // This function initializes a NoteGetterOptions that simply returns the maximum number of notes allowed in a call. pub fn new() -> Self { @@ -157,7 +157,7 @@ where impl NoteGetterOptions where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { // This function initializes a NoteGetterOptions with a preprocessor, which takes the notes returned from // the database and preprocessor_args as its parameters. @@ -182,7 +182,7 @@ where impl NoteGetterOptions where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { // This function initializes a NoteGetterOptions with a filter, which takes // the notes returned from the database and filter_args as its parameters. 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 4d58d126319b..7338d9e1a1f8 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -1,21 +1,22 @@ use crate::context::PrivateContext; use dep::protocol_types::address::AztecAddress; use dep::protocol_types::traits::Empty; -pub trait NoteProperties { - fn properties() -> T; -} - -pub trait PartialNote -where - S: Empty, - F: Empty, -{ - fn setup_payload() -> S; - fn finalization_payload() -> F; +// Autogenerated by the #[note] macro +// docs:start:note_interfaces +pub trait NoteType { + /// Returns the unique identifier for the note type. This is typically used when processing note logs. + fn get_id() -> Field; } -pub trait NullifiableNote { +pub trait NoteHash { + /// Returns the non-siloed note hash, i.e. the inner hash computed by the contract during private execution. Note + /// hashes are later siloed by contract address and nonce by the kernels before being committed to the state tree. + /// + /// This should be a commitment to the packed note, including the storage slot (for indexing) and some random + /// value (to prevent brute force trial-hashing attacks). + fn compute_note_hash(self, storage_slot: Field) -> Field; + /// Returns the non-siloed nullifier (also called inner-nullifier), which will be later siloed by contract address /// by the kernels before being committed to the state tree. /// @@ -47,17 +48,18 @@ pub trait NullifiableNote { note_nonce: Field, ) -> Field; } +// docs:end:note_interfaces -// docs:start:note_interface -// Autogenerated by the #[note] macro -pub trait NoteInterface { - fn get_note_type_id() -> Field; +pub trait NoteProperties { + fn properties() -> T; +} - /// Returns the non-siloed note hash, i.e. the inner hash computed by the contract during private execution. Note - /// hashes are later siloed by contract address and nonce by the kernels before being committed to the state tree. - /// - /// This should be a commitment to the packed note, including the storage slot (for indexing) and some random - /// value (to prevent brute force trial-hashing attacks). - fn compute_note_hash(self, storage_slot: Field) -> Field; +pub trait PartialNote +where + S: Empty, + F: Empty, +{ + fn setup_payload() -> S; + + fn finalization_payload() -> F; } -// docs:end:note_interface diff --git a/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr index fb93b8d9498c..5150e5284724 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr @@ -1,6 +1,6 @@ use crate::note::constants::MAX_NOTES_PER_PAGE; use crate::note::note_getter_options::{NoteStatus, PropertySelector, Select, Sort}; -use crate::note::note_interface::NoteInterface; +use crate::note::note_interface::NoteType; use dep::protocol_types::traits::{Packable, ToField}; use std::option::Option; @@ -17,7 +17,7 @@ pub struct NoteViewerOptions { impl NoteViewerOptions { pub fn new() -> NoteViewerOptions where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { NoteViewerOptions { selects: BoundedVec::new(), diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 9b67cf8728bb..9cc1c5990bff 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -1,6 +1,6 @@ use crate::{ context::PrivateContext, - note::{note_interface::{NoteInterface, NullifiableNote}, retrieved_note::RetrievedNote}, + note::{note_interface::NoteHash, retrieved_note::RetrievedNote}, }; use dep::protocol_types::hash::{ @@ -13,7 +13,7 @@ pub fn compute_note_hash_for_read_request( storage_slot: Field, ) -> Field where - Note: NoteInterface, + Note: NoteHash, { let note_hash = retrieved_note.note.compute_note_hash(storage_slot); @@ -39,7 +39,7 @@ pub fn compute_note_hash_for_nullify( storage_slot: Field, ) -> Field where - Note: NoteInterface + NullifiableNote, + Note: NoteHash, { compute_note_hash_for_nullify_from_read_request( retrieved_note, @@ -80,7 +80,7 @@ pub fn compute_siloed_note_nullifier( context: &mut PrivateContext, ) -> Field where - Note: NoteInterface + NullifiableNote, + Note: NoteHash, { let note_hash_for_nullify = compute_note_hash_for_nullify(retrieved_note, storage_slot); let inner_nullifier = retrieved_note.note.compute_nullifier(context, note_hash_for_nullify); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/note_discovery.nr b/noir-projects/aztec-nr/aztec/src/oracle/note_discovery.nr index 3a7d2579301c..35d34e3ae113 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/note_discovery.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/note_discovery.nr @@ -18,8 +18,8 @@ unconstrained fn sync_notes_oracle() {} /// /// The packed note is what `getNotes` will later return. PXE indexes notes by `storage_slot`, so this value /// is typically used to filter notes that correspond to different state variables. `note_hash` and `nullifier` are -/// the inner hashes, i.e. the raw hashes returned by `NoteInterface::compute_note_hash` and -/// `NullifiableNote::compute_nullifier`. PXE will verify that the siloed unique note hash was inserted into the tree +/// the inner hashes, i.e. the raw hashes returned by `NoteHash::compute_note_hash` and +/// `NoteHash::compute_nullifier`. PXE will verify that the siloed unique note hash was inserted into the tree /// at `tx_hash`, and will store the nullifier to later check for nullification. /// /// `recipient` is the account to which the note was sent to. Other accounts will not be able to access this note (e.g. diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index b8c319e9b0ce..121855ff2821 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -1,9 +1,4 @@ -use crate::{ - note::{ - note_interface::NoteInterface, note_metadata::NoteMetadata, retrieved_note::RetrievedNote, - }, - utils::array, -}; +use crate::{note::{note_interface::NoteType, retrieved_note::RetrievedNote}, utils::array}; use dep::protocol_types::{ address::AztecAddress, @@ -168,7 +163,7 @@ pub unconstrained fn get_notes [Option>; S] where - Note: NoteInterface + Packable, + Note: NoteType + Packable, { let fields = get_notes_oracle_wrapper( storage_slot, diff --git a/noir-projects/aztec-nr/aztec/src/prelude.nr b/noir-projects/aztec-nr/aztec/src/prelude.nr index b62e61ca3588..5cc3a143c572 100644 --- a/noir-projects/aztec-nr/aztec/src/prelude.nr +++ b/noir-projects/aztec-nr/aztec/src/prelude.nr @@ -3,7 +3,7 @@ pub use crate::{ context::{PrivateContext, PublicContext, ReturnsHash}, note::{ note_getter_options::NoteGetterOptions, - note_interface::{NoteInterface, NullifiableNote}, + note_interface::{NoteHash, NoteType}, note_viewer_options::NoteViewerOptions, retrieved_note::RetrievedNote, }, diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index dab695e717c6..da9da820e683 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -8,7 +8,7 @@ use crate::note::{ lifecycle::create_note, note_emission::NoteEmission, note_getter::{get_note, view_notes}, - note_interface::{NoteInterface, NullifiableNote}, + note_interface::{NoteHash, NoteType}, note_viewer_options::NoteViewerOptions, }; use crate::oracle::notes::check_nullifier_exists; @@ -56,7 +56,7 @@ impl PrivateImmutable { // docs:start:initialize pub fn initialize(self, note: Note) -> NoteEmission where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); @@ -69,7 +69,7 @@ impl PrivateImmutable { // docs:start:get_note pub fn get_note(self) -> Note where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { let storage_slot = self.storage_slot; let retrieved_note = get_note(self.context, storage_slot).0; @@ -94,7 +94,7 @@ impl PrivateImmutable { // docs:start:view_note pub unconstrained fn view_note(self) -> Note where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { let mut options = NoteViewerOptions::new(); view_notes(self.storage_slot, options.set_limit(1)).get(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 f0164aee7ef8..01a2d40aea7b 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 @@ -8,7 +8,7 @@ use crate::note::{ lifecycle::{create_note, destroy_note_unsafe}, note_emission::NoteEmission, note_getter::{get_note, view_notes}, - note_interface::{NoteInterface, NullifiableNote}, + note_interface::{NoteHash, NoteType}, note_viewer_options::NoteViewerOptions, }; use crate::note::retrieved_note::RetrievedNote; @@ -59,7 +59,7 @@ impl PrivateMutable { impl PrivateMutable where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { // docs:start:initialize pub fn initialize(self, note: Note) -> NoteEmission { @@ -127,7 +127,7 @@ where impl PrivateMutable where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { pub unconstrained fn is_initialized(self) -> bool { let nullifier = self.compute_initialization_nullifier(); diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index 33946f1f2745..7188f4a7b6fe 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -5,7 +5,7 @@ use crate::note::{ note_emission::NoteEmission, note_getter::{get_notes, view_notes}, note_getter_options::NoteGetterOptions, - note_interface::{NoteInterface, NullifiableNote}, + note_interface::{NoteHash, NoteType}, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_request, }; @@ -43,7 +43,7 @@ impl PrivateSet { impl PrivateSet where - Note: NoteInterface + NullifiableNote + Eq + Packable, + Note: NoteType + NoteHash + Eq + Packable, { // docs:start:insert pub fn insert(self, note: Note) -> NoteEmission { @@ -97,7 +97,7 @@ where impl PrivateSet where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { // docs:start:view_notes pub unconstrained fn view_notes( diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index 712ecd912269..85a32eee87b5 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -6,7 +6,7 @@ use crate::context::{ use crate::hash::hash_args; use crate::test::helpers::{cheatcodes, utils::Deployer}; -use crate::note::note_interface::{NoteInterface, NullifiableNote}; +use crate::note::note_interface::{NoteHash, NoteType}; use crate::oracle::{ execution::{get_block_number, get_contract_address}, notes::notify_created_note, @@ -158,7 +158,7 @@ impl TestEnvironment { contract_address: AztecAddress, ) where - Note: NoteInterface + NullifiableNote + Packable, + Note: NoteType + NoteHash + Packable, { let original_contract_address = get_contract_address(); cheatcodes::set_contract_address(contract_address); @@ -168,7 +168,7 @@ impl TestEnvironment { let packed_note = Note::pack(note); notify_created_note( storage_slot, - Note::get_note_type_id(), + Note::get_id(), packed_note, note_hash, note_hash_counter, 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 c71d1a6a210d..a67e195dda25 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 @@ -1,12 +1,12 @@ use crate::{ context::PrivateContext, note::{ - note_interface::NoteInterface, note_metadata::SettledNoteMetadata, - retrieved_note::RetrievedNote, utils::compute_note_hash_for_nullify, + note_interface::{NoteHash, NoteType}, note_metadata::SettledNoteMetadata, + retrieved_note::RetrievedNote, + utils::compute_note_hash_for_nullify, }, }; -use crate::note::note_interface::NullifiableNote; use dep::protocol_types::{ address::AztecAddress, constants::{GENERATOR_INDEX__NOTE_HASH, GENERATOR_INDEX__NOTE_NULLIFIER}, @@ -20,7 +20,19 @@ pub(crate) struct MockNote { pub(crate) value: Field, } -impl NullifiableNote for MockNote { +impl NoteType for MockNote { + fn get_id() -> Field { + // randomly chosen note type id --> has to fit within 7 bits + 76 + } +} + +impl NoteHash for MockNote { + fn compute_note_hash(self: Self, storage_slot: Field) -> Field { + let input = array_concat(self.pack(), [storage_slot]); + poseidon2_hash_with_separator(input, GENERATOR_INDEX__NOTE_HASH) + } + fn compute_nullifier( _self: Self, _context: &mut PrivateContext, @@ -55,21 +67,6 @@ impl NullifiableNote for MockNote { } } -impl NoteInterface for MockNote { - fn get_note_type_id() -> Field { - // randomly chosen note type id --> has to fit within 7 bits - 76 - } - - fn compute_note_hash(self: Self, storage_slot: Field) -> Field { - // We use Poseidon2 instead of multi-scalar multiplication (MSM) here since this is not a partial note - // and therefore does not require MSM's additive homomorphism property. Additionally, Poseidon2 uses fewer - // constraints. - let input = array_concat(self.pack(), [storage_slot]); - poseidon2_hash_with_separator(input, GENERATOR_INDEX__NOTE_HASH) - } -} - pub(crate) struct MockNoteBuilder { value: Field, contract_address: Option, diff --git a/noir-projects/aztec-nr/uint-note/src/uint_note.nr b/noir-projects/aztec-nr/uint-note/src/uint_note.nr index 923a29de886e..0254bf949f27 100644 --- a/noir-projects/aztec-nr/uint-note/src/uint_note.nr +++ b/noir-projects/aztec-nr/uint-note/src/uint_note.nr @@ -1,16 +1,14 @@ use dep::aztec::{ - keys::getters::{get_nsk_app, get_public_keys}, macros::notes::partial_note, - note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, oracle::random::random, - prelude::{NullifiableNote, PrivateContext, RetrievedNote}, - protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, traits::Serialize, - }, + protocol_types::{address::AztecAddress, traits::Serialize}, }; +// TODO(#12008): Remove the need for the manual import of `Packable` trait here. This is a bug in macros. +use aztec::protocol_types::traits::Packable; + // docs:start:UintNote +// We derive the Serialize trait because in some cases notes are used as parameters to contract functions. #[partial_note(quote {value})] #[derive(Eq, Serialize)] pub struct UintNote { @@ -21,44 +19,6 @@ pub struct UintNote { randomness: Field, } // docs:end:UintNote - -impl NullifiableNote for UintNote { - // docs:start:nullifier - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - // docs:end:nullifier - - 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); - 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, - ) - } -} - impl UintNote { pub fn new(value: U128, owner: AztecAddress) -> Self { // Safety: We use the randomness to preserve the privacy of the note recipient by preventing brute-forcing, diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index 98c354402cdb..0ab3e483c1e2 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -1,13 +1,20 @@ -use crate::{filter::filter_notes_min_sum, value_note::{VALUE_NOTE_LEN, ValueNote}}; -use dep::aztec::encrypted_logs::log_assembly_strategies::default_aes128::note::encode_and_encrypt_note; -use dep::aztec::note::note_getter_options::SortOrder; -use dep::aztec::prelude::{AztecAddress, NoteGetterOptions, PrivateContext, PrivateSet}; +use crate::{filter::filter_notes_min_sum, value_note::ValueNote}; + +use aztec::{ + encrypted_logs::log_assembly_strategies::default_aes128::note::encode_and_encrypt_note, + note::note_getter_options::SortOrder, + prelude::{AztecAddress, NoteGetterOptions, PrivateContext, PrivateSet}, + protocol_types::traits::Packable, +}; // Sort the note values (0th field) in descending order. // Pick the fewest notes whose sum is equal to or greater than `amount`. -pub fn create_note_getter_options_for_decreasing_balance( +pub fn create_note_getter_options_for_decreasing_balance( amount: Field, -) -> NoteGetterOptions { +) -> NoteGetterOptions +where + ValueNote: Packable, +{ NoteGetterOptions::with_filter(filter_notes_min_sum, amount).sort( ValueNote::properties().value, SortOrder.DESC, 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 ba5bdf4c0699..408081fed90a 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -1,19 +1,4 @@ -use dep::aztec::{ - context::PrivateContext, - keys::getters::{get_nsk_app, get_public_keys}, - macros::notes::note, - note::{ - note_interface::NullifiableNote, note_metadata::SettledNoteMetadata, - retrieved_note::RetrievedNote, utils::compute_note_hash_for_nullify, - }, - oracle::random::random, - protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, - }, -}; - -pub(crate) global VALUE_NOTE_LEN: u32 = 3; // 3 plus a header. +use aztec::{macros::notes::note, oracle::random::random, protocol_types::address::AztecAddress}; // docs:start:value-note-def #[note] @@ -25,45 +10,6 @@ pub struct ValueNote { } // docs:end:value-note-def -impl NullifiableNote for ValueNote { - // docs:start:nullifier - - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash: Field = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - - // docs:end:nullifier - - 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); - let owner_npk_m_hash: Field = 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, - ) - } -} - impl ValueNote { pub fn new(value: Field, owner: AztecAddress) -> Self { // Safety: We use the randomness to preserve the privacy of the note recipient by preventing brute-forcing, 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 f1ff8936dd60..a180f621a52a 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 @@ -1,14 +1,5 @@ use dep::aztec::{ - hash::poseidon2_hash_with_separator, - keys::getters::{get_nsk_app, get_public_keys}, - macros::notes::note, - note::{ - note_metadata::SettledNoteMetadata, retrieved_note::RetrievedNote, - utils::compute_note_hash_for_nullify, - }, - oracle::random::random, - prelude::{NullifiableNote, PrivateContext}, - protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER}, + macros::notes::note, oracle::random::random, protocol_types::address::AztecAddress, }; #[note] @@ -20,41 +11,6 @@ pub struct SubscriptionNote { randomness: Field, } -impl NullifiableNote for SubscriptionNote { - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash: Field = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - - 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); - let owner_npk_m_hash: Field = 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, - ) - } -} - impl SubscriptionNote { pub fn new(owner: AztecAddress, expiry_block_number: Field, remaining_txs: Field) -> Self { // Safety: We use the randomness to preserve the privacy of the note recipient by preventing brute-forcing, diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr index dc35cc5db7bf..a562087a5457 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr @@ -1,18 +1,21 @@ -use crate::types::card_note::{CARD_NOTE_LEN, CardNote}; +use crate::types::card_note::CardNote; use dep::aztec::prelude::{NoteGetterOptions, RetrievedNote}; use dep::aztec::{note::note_getter_options::SortOrder, utils::comparison::Comparator}; use dep::aztec::protocol_types::{ - address::AztecAddress, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, + address::AztecAddress, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, traits::Packable, }; // Shows how to use NoteGetterOptions and query for notes. // docs:start:state_vars-NoteGetterOptionsSelectSortOffset -pub fn create_npk_card_getter_options( +pub fn create_npk_card_getter_options( account: AztecAddress, offset: u32, -) -> NoteGetterOptions { +) -> NoteGetterOptions +where + CardNote: Packable, +{ let mut options = NoteGetterOptions::new(); options .select(CardNote::properties().owner, Comparator.EQ, account) @@ -22,11 +25,14 @@ pub fn create_npk_card_getter_options( // docs:end:state_vars-NoteGetterOptionsSelectSortOffset // docs:start:state_vars-NoteGetterOptionsMultiSelects -pub fn create_exact_card_getter_options( +pub fn create_exact_card_getter_options( points: u8, secret: Field, account: AztecAddress, -) -> NoteGetterOptions { +) -> NoteGetterOptions +where + CardNote: Packable, +{ let mut options = NoteGetterOptions::new(); options .select(CardNote::properties().points, Comparator.EQ, points as Field) @@ -53,9 +59,12 @@ pub fn filter_min_points( // docs:end:state_vars-OptionFilter // docs:start:state_vars-NoteGetterOptionsFilter -pub fn create_cards_with_min_points_getter_options( +pub fn create_cards_with_min_points_getter_options( min_points: u8, -) -> NoteGetterOptions { +) -> NoteGetterOptions +where + CardNote: Packable, +{ NoteGetterOptions::with_filter(filter_min_points, min_points).sort( CardNote::properties().points, SortOrder.ASC, @@ -64,7 +73,10 @@ pub fn create_cards_with_min_points_getter_options( // docs:end:state_vars-NoteGetterOptionsFilter // docs:start:state_vars-NoteGetterOptionsPickOne -pub fn create_largest_card_getter_options() -> NoteGetterOptions { +pub fn create_largest_card_getter_options() -> NoteGetterOptions +where + CardNote: Packable, +{ let mut options = NoteGetterOptions::new(); options.sort(CardNote::properties().points, SortOrder.DESC).set_limit(1) } 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 725101d6af7c..b5b8155854ad 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 @@ -1,19 +1,11 @@ -use dep::aztec::{ - keys::getters::{get_nsk_app, get_public_keys}, - macros::notes::note, - note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, - prelude::{NullifiableNote, PrivateContext, RetrievedNote}, - protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, traits::Serialize, - }, -}; +use dep::aztec::{macros::notes::note, protocol_types::{address::AztecAddress, traits::Serialize}}; // docs:start:state_vars-CardNote -global CARD_NOTE_LEN: u32 = 3; // 3 plus a header. - +// We derive the Serialize trait because this struct is returned from a contract function. When returned, +// the struct is serialized using the Serialize trait and added to a hasher via the `add_to_hasher` utility. +// We use a hash rather than the serialized struct itself to keep circuit inputs constant. #[note] -#[derive(Eq)] +#[derive(Eq, Serialize)] pub struct CardNote { points: u8, randomness: Field, @@ -21,55 +13,8 @@ pub struct CardNote { } // docs:end:state_vars-CardNote -// docs:start:cardnote_impl impl CardNote { pub fn new(points: u8, randomness: Field, owner: AztecAddress) -> Self { CardNote { points, randomness, owner } } } -// docs:end:cardnote_impl - -// docs:start:note_interface -impl NullifiableNote for CardNote { - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash: Field = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - - 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); - let owner_npk_m_hash: Field = 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, - ) - } -} -// docs:end:note_interface - -// docs:start:serialize -impl Serialize<3> for CardNote { - fn serialize(self) -> [Field; 3] { - [self.points.to_field(), self.randomness, self.owner.to_field()] - } -} -// docs:end:serialize diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index d5928253c422..55ab066539b2 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -1,8 +1,5 @@ -use dep::aztec::prelude::{NullifiableNote, PrivateContext, RetrievedNote}; - use dep::aztec::{ - note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, keys::getters::{get_nsk_app, get_public_keys}, - protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator, traits::Packable}, + protocol_types::{address::AztecAddress, traits::Packable}, macros::notes::note }; @@ -15,35 +12,6 @@ pub struct EcdsaPublicKeyNote { owner: AztecAddress, } -impl NullifiableNote for EcdsaPublicKeyNote { - - fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { - let owner_npk_m_hash = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [ - note_hash_for_nullify, - secret - ], - GENERATOR_INDEX__NOTE_NULLIFIER as Field - ) - } - - 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); - 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 - ) - } -} - impl EcdsaPublicKeyNote { pub fn new(x: [u8; 32], y: [u8; 32], owner: AztecAddress) -> Self { EcdsaPublicKeyNote { x, y, owner } diff --git a/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr b/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr index ee101fc87954..77baf7856a27 100644 --- a/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr +++ b/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr @@ -1,14 +1,4 @@ -use dep::aztec::{ - keys::getters::{get_nsk_app, get_public_keys}, - macros::notes::partial_note, - note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, - oracle::random::random, - prelude::{NullifiableNote, PrivateContext, RetrievedNote}, - protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, - }, -}; +use aztec::{macros::notes::partial_note, oracle::random::random, prelude::AztecAddress}; // docs:start:nft_note #[partial_note(quote { token_id})] @@ -23,43 +13,6 @@ pub struct NFTNote { } // docs:end:nft_note -impl NullifiableNote for NFTNote { - // docs:start:compute_nullifier - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash: Field = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - // docs:end:compute_nullifier - - 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); - let owner_npk_m_hash: Field = 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, - ) - } -} - impl NFTNote { pub fn new(token_id: Field, owner: AztecAddress) -> Self { // Safety: We use the randomness to preserve the privacy of the note recipient by preventing brute-forcing, 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 1e7b41ac7a70..c954d3dcb601 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 @@ -1,13 +1,4 @@ -use aztec::{ - keys::getters::{get_nsk_app, get_public_keys}, - macros::notes::note, - note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, - prelude::{NullifiableNote, PrivateContext, RetrievedNote}, - protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, - }, -}; +use aztec::{macros::notes::note, protocol_types::address::AztecAddress}; // Stores a public key composed of two fields // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? @@ -18,41 +9,6 @@ pub struct PublicKeyNote { owner: AztecAddress, } -impl NullifiableNote for PublicKeyNote { - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash: Field = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - - 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); - let owner_npk_m_hash: Field = 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, - ) - } -} - impl PublicKeyNote { pub fn new(x: Field, y: Field, owner: AztecAddress) -> Self { PublicKeyNote { x, y, owner } diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr index d18d9a99dd78..b5817b639f02 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/balance_set.nr @@ -8,7 +8,7 @@ use dep::aztec::{ }, }; use dep::aztec::prelude::{ - NoteGetterOptions, NoteInterface, NoteViewerOptions, NullifiableNote, PrivateSet, RetrievedNote, + NoteGetterOptions, NoteHash, NoteType, NoteViewerOptions, PrivateSet, RetrievedNote, }; pub struct BalanceSet { @@ -25,14 +25,14 @@ impl BalanceSet { impl BalanceSet { pub unconstrained fn balance_of(self: Self) -> U128 where - Note: NoteInterface + NullifiableNote + OwnedNote + Packable, + Note: NoteType + NoteHash + OwnedNote + Packable, { self.balance_of_with_offset(0) } pub unconstrained fn balance_of_with_offset(self: Self, offset: u32) -> U128 where - Note: NoteInterface + NullifiableNote + OwnedNote + Packable, + Note: NoteType + NoteHash + OwnedNote + Packable, { let mut balance = U128::from_integer(0); // docs:start:view_notes @@ -55,7 +55,7 @@ impl BalanceSet { impl BalanceSet { pub fn add(self: Self, owner: AztecAddress, addend: U128) -> OuterNoteEmission where - Note: NoteInterface + NullifiableNote + OwnedNote + Eq + Packable, + Note: NoteType + NoteHash + OwnedNote + Eq + Packable, { if addend == U128::from_integer(0) { OuterNoteEmission::new(Option::none()) @@ -70,7 +70,7 @@ impl BalanceSet { pub fn sub(self: Self, owner: AztecAddress, amount: U128) -> OuterNoteEmission where - Note: NoteInterface + NullifiableNote + OwnedNote + Eq + Packable, + Note: NoteType + NoteHash + OwnedNote + Eq + Packable, { let subtracted = self.try_sub(amount, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL); @@ -91,7 +91,7 @@ impl BalanceSet { // `try_sub` subtracting an amount smaller than `target_amount`. pub fn try_sub(self: Self, target_amount: U128, max_notes: u32) -> U128 where - Note: NoteInterface + NullifiableNote + OwnedNote + Eq + Packable, + Note: NoteType + NoteHash + OwnedNote + Eq + Packable, { // We are using a preprocessor here (filter applied in an unconstrained context) instead of a filter because // we do not need to prove correct execution of the preprocessor. @@ -124,7 +124,7 @@ pub fn preprocess_notes_min_sum( min_sum: U128, ) -> [Option>; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where - Note: NoteInterface + NullifiableNote + OwnedNote, + Note: NoteType + NoteHash + OwnedNote, { let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(0); diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr index 8f3422f1e456..54e80a1b931e 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr @@ -1,13 +1,5 @@ use dep::aztec::{ - keys::getters::{get_nsk_app, get_public_keys}, - macros::notes::note, - note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, - oracle::random::random, - prelude::{NullifiableNote, PrivateContext, RetrievedNote}, - protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, - }, + macros::notes::note, oracle::random::random, protocol_types::address::AztecAddress, }; trait OwnedNote { @@ -27,43 +19,6 @@ pub struct TokenNote { } // docs:end:TokenNote -impl NullifiableNote for TokenNote { - // docs:start:nullifier - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash: Field = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - // docs:end:nullifier - - 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); - let owner_npk_m_hash: Field = 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, - ) - } -} - impl OwnedNote for TokenNote { fn new(amount: U128, owner: AztecAddress) -> Self { // Safety: We use the randomness to preserve the privacy of the note recipient by preventing brute-forcing, diff --git a/noir-projects/noir-contracts/contracts/test_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/test_contract/Nargo.toml index 3a38c679cbb6..67df1830a353 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/test_contract/Nargo.toml @@ -6,6 +6,6 @@ type = "contract" [dependencies] aztec = { path = "../../../aztec-nr/aztec" } +address_note = { path = "../../../aztec-nr/address-note" } value_note = { path = "../../../aztec-nr/value-note" } -uint_note = { path = "../../../aztec-nr/uint-note" } token_portal_content_hash_lib = { path = "../token_portal_content_hash_lib" } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 1f4c8de3fa37..0fb8600dfcfc 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -33,28 +33,26 @@ pub contract Test { use dep::aztec::{ deploy::deploy_contract as aztec_deploy_contract, discovery::private_logs::do_process_log, - hash::{ArgsHasher, compute_secret_hash, pedersen_hash}, + hash::{ArgsHasher, pedersen_hash}, macros::{events::event, functions::{internal, private, public}, storage::storage}, note::{ lifecycle::{create_note, destroy_note_unsafe}, note_getter::{get_notes, view_notes}, note_getter_options::NoteStatus, - note_interface::NoteInterface, + note_interface::NoteType, retrieved_note::RetrievedNote, }, test::mocks::mock_struct::MockStruct, - utils::comparison::Comparator, }; use dep::token_portal_content_hash_lib::{ get_mint_to_private_content_hash, get_mint_to_public_content_hash, }; - use dep::value_note::value_note::ValueNote; use std::meta::derive; + // We are importing different kinds of notes to test the note type ids use crate::test_note::TestNote; - - // Imported just to test note type ids - use dep::uint_note::uint_note::UintNote; + use address_note::address_note::AddressNote; + use value_note::value_note::ValueNote; #[derive(Serialize)] #[event] @@ -83,7 +81,7 @@ pub contract Test { struct Storage { example_constant: PrivateImmutable, example_struct_in_shared_mutable: SharedMutable, - example_set: PrivateSet, + example_set: PrivateSet, example_struct: PrivateImmutable, example_struct_in_public_immutable: PublicImmutable, example_struct_in_map: Map, Context>, @@ -448,9 +446,10 @@ pub contract Test { ) { // do_process_log expects a standard aztec-nr encoded note, which has the following shape: // [ storage_slot, note_type_id, ...packed_note ] + let note = TestNote::new(value); let log_plaintext = BoundedVec::from_array(array_concat( - [Test::storage_layout().example_constant.slot, TestNote::get_note_type_id()], + [Test::storage_layout().example_constant.slot, TestNote::get_id()], note.pack(), )); @@ -504,21 +503,9 @@ pub contract Test { aztec_deploy_contract(&mut context, target); } - #[private] - // Adapted from TokenContract#redeem_shield but without an initcheck so it can be run in simulator/src/client/private_execution.test.ts - fn consume_note_from_secret(secret: Field) { - let notes_set = storage.example_set; - let secret_hash = compute_secret_hash(secret); - let mut options = NoteGetterOptions::new(); - options = - options.select(TestNote::properties().value, Comparator.EQ, secret_hash).set_limit(1); - let notes = notes_set.pop_notes(options); - assert(notes.len() == 1, "note not popped"); - } - unconstrained fn get_constant() -> pub Field { let constant = storage.example_constant.view_note(); - constant.value + constant.get_value() } #[private] diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/test.nr b/noir-projects/noir-contracts/contracts/test_contract/src/test.nr index eda9fefa15f5..0222d8345854 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/test.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/test.nr @@ -1,15 +1,16 @@ use crate::Test; use crate::test_note::TestNote; -use dep::uint_note::uint_note::UintNote; -use dep::value_note::value_note::ValueNote; +use address_note::address_note::AddressNote; +use aztec::note::note_interface::NoteType; +use value_note::value_note::ValueNote; #[test] unconstrained fn test_note_type_id() { // The order in which the note types are sorted seems arbitrary and an implementation detail of Noir, // but the important thing is that they are sequential and start from 0. - assert_eq(UintNote::get_note_type_id(), 0, "UintNote type id should be 0"); - assert_eq(ValueNote::get_note_type_id(), 1, "ValueNote type id should be 1"); - assert_eq(TestNote::get_note_type_id(), 2, "TestNote type id should be 2"); + assert_eq(AddressNote::get_id(), 0, "AddressNote type id should be 0"); + assert_eq(ValueNote::get_id(), 1, "ValueNote type id should be 1"); + assert_eq(TestNote::get_id(), 2, "TestNote type id should be 2"); } #[test] @@ -24,7 +25,7 @@ unconstrained fn test_storage_slot_allocation() { // struct Storage { // example_constant: PrivateImmutable, // example_struct_in_shared_mutable: SharedMutable, - // example_set: PrivateSet, + // example_set: PrivateSet, // example_struct: PrivateImmutable, // example_struct_in_public_immutable: PublicImmutable, // example_struct_in_map: Map, Context>, @@ -38,7 +39,7 @@ unconstrained fn test_storage_slot_allocation() { // The first slot is always 1. let mut expected_slot = 1; assert_eq(Test::storage_layout().example_constant.slot, expected_slot); - // Even though example_constant holds TestNote, which packs to a length larger than 1, notes always reserve a + // Even though example_constant holds AddressNote, which packs to a length larger than 1, notes always reserve a // single slot. expected_slot += 1; 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 ce76fcaede25..c40e23275b1b 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 @@ -1,54 +1,33 @@ use dep::aztec::{ context::PrivateContext, - macros::notes::note_custom_interface, - note::note_interface::{NoteInterface, NullifiableNote}, + macros::notes::custom_note, + note::note_interface::NoteHash, protocol_types::{ - address::AztecAddress, - constants::GENERATOR_INDEX__NOTE_HASH, - hash::poseidon2_hash_with_separator, - traits::{Deserialize, Serialize}, - utils::arrays::array_concat, + address::AztecAddress, constants::GENERATOR_INDEX__NOTE_HASH, + hash::poseidon2_hash_with_separator, traits::Packable, utils::arrays::array_concat, }, }; -// TODO(#12008): Remove the need for the manual import of `Packable` trait here. This is a bug in macros. -use aztec::protocol_types::traits::Packable; - -/// A note which stores a field and is expected to be passed around using the `addNote` function. -/// -/// WARNING: This Note is not private as it does not contain randomness, making it vulnerable to -/// note hash preimage attacks. This note was developed purely for testing purposes so it could be -/// easily added to PXE manually. Do not use for real applications. -/// -/// Note: We are using `#[note_custom_interface]` here even though we don't need a custom implementation, -/// just to test that the macro works (it's not used anywhere else so far). -#[note_custom_interface] -#[derive(Eq, Deserialize, Serialize)] +/// A note used only for testing purposes. +#[custom_note] pub struct TestNote { value: Field, } -impl NoteInterface for TestNote { - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/12012): This is broken - fn get_note_type_id() -> Field { - // id has to fit within 7 bits - 2 - } - +impl NoteHash for TestNote { fn compute_note_hash(self, storage_slot: Field) -> Field { + // The note is inserted into the state in the Test contract so we provide a real compute_note_hash + // implementation. let inputs = array_concat(self.pack(), [storage_slot]); poseidon2_hash_with_separator(inputs, GENERATOR_INDEX__NOTE_HASH) } -} - -impl NullifiableNote for TestNote { fn compute_nullifier( _self: Self, _context: &mut PrivateContext, _note_hash_for_nullify: Field, ) -> Field { - // This note is expected to be shared between users and fstructor this reason can't be nullified using a secret. + // This note is never nullified so we don't care about having a real implementation here. 0 } @@ -58,7 +37,7 @@ impl NullifiableNote for TestNote { _contract_address: AztecAddress, _note_nonce: Field, ) -> Field { - // This note is expected to be shared between users and for this reason can't be nullified using a secret. + // This note is never nullified so we don't care about having a real implementation here. 0 } } @@ -67,4 +46,8 @@ impl TestNote { pub fn new(value: Field) -> Self { TestNote { value } } + + pub fn get_value(self) -> Field { + self.value + } } diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 400031c011c1..351f2f1df1fd 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -24,7 +24,6 @@ pub contract TokenBlacklist { }, hash::compute_secret_hash, macros::{functions::{initializer, internal, private, public, view}, storage::storage}, - note::note_interface::NoteInterface, prelude::{AztecAddress, Map, NoteGetterOptions, PrivateSet, PublicMutable, SharedMutable}, utils::comparison::Comparator, }; @@ -322,10 +321,7 @@ pub contract TokenBlacklist { // [ storage_slot, note_type_id, ...packed_note ] let note = TransparentNote::new(amount, secret_hash); let log_plaintext = BoundedVec::from_array(array_concat( - [ - TokenBlacklist::storage_layout().pending_shields.slot, - TransparentNote::get_note_type_id(), - ], + [TokenBlacklist::storage_layout().pending_shields.slot, TransparentNote::get_id()], note.pack(), )); diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index b646c3bf4fbc..e845cdb4a730 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -5,8 +5,8 @@ use dep::aztec::{ protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, traits::Packable}, }; use dep::aztec::prelude::{ - AztecAddress, Map, NoteGetterOptions, NoteInterface, NoteViewerOptions, NullifiableNote, - PrivateSet, RetrievedNote, + AztecAddress, Map, NoteGetterOptions, NoteHash, NoteType, NoteViewerOptions, PrivateSet, + RetrievedNote, }; pub struct BalancesMap { @@ -29,7 +29,7 @@ impl BalancesMap { impl BalancesMap { pub unconstrained fn balance_of(self: Self, owner: AztecAddress) -> U128 where - Note: NoteInterface + NullifiableNote + OwnedNote + Packable, + Note: NoteType + NoteHash + OwnedNote + Packable, { self.balance_of_with_offset(owner, 0) } @@ -40,7 +40,7 @@ impl BalancesMap { offset: u32, ) -> U128 where - Note: NoteInterface + NullifiableNote + OwnedNote + Packable, + Note: NoteType + NoteHash + OwnedNote + Packable, { let mut balance = U128::from_integer(0); // docs:start:view_notes @@ -64,7 +64,7 @@ impl BalancesMap { pub fn add(self: Self, owner: AztecAddress, addend: U128) -> OuterNoteEmission where - Note: NoteInterface + NullifiableNote + OwnedNote + Eq + Packable, + Note: NoteType + NoteHash + OwnedNote + Eq + Packable, { if addend == U128::from_integer(0) { OuterNoteEmission::new(Option::none()) @@ -83,7 +83,7 @@ impl BalancesMap { subtrahend: U128, ) -> OuterNoteEmission where - Note: NoteInterface + NullifiableNote + OwnedNote + Eq + Packable, + Note: NoteType + NoteHash + OwnedNote + Eq + Packable, { let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend); let notes = self.map.at(owner).pop_notes(options); @@ -110,7 +110,7 @@ pub fn filter_notes_min_sum( min_sum: U128, ) -> [Option>; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where - Note: NoteInterface + OwnedNote, + Note: NoteType + OwnedNote, { let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(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 5bd7e611cbc9..6f64f0f5ffeb 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 @@ -1,13 +1,5 @@ use dep::aztec::{ - keys::getters::{get_nsk_app, get_public_keys}, - macros::notes::note, - note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, - oracle::random::random, - prelude::{NullifiableNote, PrivateContext, RetrievedNote}, - protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, - }, + macros::notes::note, oracle::random::random, protocol_types::address::AztecAddress, }; trait OwnedNote { @@ -25,43 +17,6 @@ pub struct TokenNote { randomness: Field, } -impl NullifiableNote for TokenNote { - // docs:start:nullifier - fn compute_nullifier( - self, - context: &mut PrivateContext, - note_hash_for_nullify: Field, - ) -> Field { - let owner_npk_m_hash: Field = get_public_keys(self.owner).npk_m.hash(); - let secret = context.request_nsk_app(owner_npk_m_hash); - poseidon2_hash_with_separator( - [note_hash_for_nullify, secret], - GENERATOR_INDEX__NOTE_NULLIFIER as Field, - ) - } - // docs:end:nullifier - - 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); - let owner_npk_m_hash: Field = 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, - ) - } -} - impl OwnedNote for TokenNote { fn new(amount: U128, owner: AztecAddress) -> Self { // Safety: We use the randomness to preserve the privacy of the note recipient by preventing brute-forcing, 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 16146ca67b4a..8d1760b622c7 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 @@ -1,27 +1,33 @@ use dep::aztec::{ - macros::notes::note, - note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, - prelude::{NullifiableNote, PrivateContext, RetrievedNote}, + macros::notes::custom_note, +note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, prelude::{NoteHash, PrivateContext, RetrievedNote}, protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, traits::Packable, + address::AztecAddress, + constants::{GENERATOR_INDEX__NOTE_HASH, GENERATOR_INDEX__NOTE_NULLIFIER}, + hash::poseidon2_hash_with_separator, + traits::Packable, + utils::arrays::array_concat, }, }; - use dep::std::mem::zeroed; // Transparent note represents a note that is created in the clear (public execution), but can only be spent by those // that know the preimage of the "secret_hash" (the secret). This is typically used when shielding a token balance. // Owner of the tokens provides a "secret_hash" as an argument to the public "shield" function and then the tokens // can be redeemed in private by presenting the preimage of the "secret_hash" (the secret). -#[note] +#[custom_note] #[derive(Eq)] pub struct TransparentNote { amount: Field, secret_hash: Field, } -impl NullifiableNote for TransparentNote { +impl NoteHash for TransparentNote { + fn compute_note_hash(self, storage_slot: Field) -> Field { + let inputs = array_concat(self.pack(), [storage_slot]); + poseidon2_hash_with_separator(inputs, GENERATOR_INDEX__NOTE_HASH) + } + // Computing a nullifier in a transparent note is not guarded by making secret a part of the nullifier preimage (as // is common in other cases) and instead is guarded by the functionality of "redeem_shield" function. There we do // the following: diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 7a50b3a00204..496bdbb2dcef 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -507,7 +507,7 @@ pub global AVM_PUBLIC_COLUMN_MAX_SIZE: u32 = 1024; pub global AVM_PUBLIC_INPUTS_FLATTENED_SIZE: u32 = 2 * AVM_PUBLIC_COLUMN_MAX_SIZE + PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH; -// Note hash generator index which can be used by custom implementations of NoteInterface::compute_note_hash +// Note hash generator index which can be used by custom implementations of NoteHash::compute_note_hash pub global GENERATOR_INDEX__NOTE_HASH: u32 = 1; pub global GENERATOR_INDEX__NOTE_HASH_NONCE: u32 = 2; pub global GENERATOR_INDEX__UNIQUE_NOTE_HASH: u32 = 3; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 0025d4658315..c24fb6856034 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -9,7 +9,7 @@ use super::traits::{Deserialize, Packable, Serialize}; /// # Note /// A copy of this function exists in `aztec-nr/aztec/src/macros/utils.nr`. We maintain separate copies /// because importing it there from here would cause the `target_trait` to be interpreted in the context -/// of this crate, making it impossible to compile code for traits from that crate (e.g. NoteInterface). +/// of this crate, making it impossible to compile code for traits from that crate (e.g. NoteType). comptime fn get_trait_impl_method( typ: Type, target_trait: Quoted, diff --git a/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts b/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts index 9d18968026de..8c41fecf0533 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fee_settings.test.ts @@ -70,7 +70,8 @@ describe('e2e_fees fee settings', () => { return tx; }; - it('handles base fee spikes with default padding', async () => { + // TODO(#12258): This test is currently broken on master. Fix it. + it.skip('handles base fee spikes with default padding', async () => { // Prepare two txs using the current L2 base fees: one with no padding and one with default padding const txWithNoPadding = await sendTx(0); const txWithDefaultPadding = await sendTx(undefined); diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index f0f4a60ffb57..60d0c1a59e80 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -40,7 +40,6 @@ import { import { GasFees, GasSettings } from '@aztec/stdlib/gas'; import { computeNoteHashNonce, - computeSecretHash, computeUniqueNoteHash, computeVarArgsHash, deriveStorageSlotInMap, @@ -830,41 +829,6 @@ describe('Private Execution test suite', () => { ).rejects.toThrow('Message not in state'); }); }); - - it('Should be able to consume a dummy public to private message', async () => { - const secret = new Fr(1n); - const secretHash = await computeSecretHash(secret); - const note = new Note([secretHash]); - const storageSlot = TestContractArtifact.storageLayout['example_set'].slot; - oracle.syncTaggedLogs.mockResolvedValue(new Map()); - oracle.processTaggedLogs.mockResolvedValue(); - oracle.getNotes.mockResolvedValue([ - { - contractAddress, - storageSlot, - nonce: Fr.random(), - note, - noteHash: Fr.ZERO, - siloedNullifier: Fr.random(), - index: 1n, - }, - ]); - - const { entrypoint: result } = await runSimulator({ - artifact: TestContractArtifact, - functionName: 'consume_note_from_secret', - args: [secret], - contractAddress, - }); - - // Check a nullifier has been inserted. - const nullifiers = getNonEmptyItems(result.publicInputs.nullifiers); - expect(nullifiers).toHaveLength(1); - - // Check the commitment read request was created successfully. - const readRequests = getNonEmptyItems(result.publicInputs.noteHashReadRequests); - expect(readRequests).toHaveLength(1); - }); }); describe('enqueued calls', () => { From 9fa0f4c459090215d9f6e606783a54342200d766 Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 25 Feb 2025 21:46:43 +0000 Subject: [PATCH 2/6] fmt --- .../aztec-nr/aztec/src/history/nullifier_inclusion.nr | 3 ++- .../aztec-nr/aztec/src/history/nullifier_non_inclusion.nr | 3 ++- noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr | 3 ++- .../token_blacklist_contract/src/types/transparent_note.nr | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index 084cc5b035e9..5d14bf624af1 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -4,7 +4,8 @@ use dep::protocol_types::merkle_tree::root::root_from_sibling_path; use crate::{ context::PrivateContext, note::{ - note_interface::NoteHash, retrieved_note::RetrievedNote, utils::compute_siloed_note_nullifier, + note_interface::NoteHash, retrieved_note::RetrievedNote, + utils::compute_siloed_note_nullifier, }, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, }; diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index 741011541795..2c2e88abdc0a 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -1,7 +1,8 @@ use crate::{ context::PrivateContext, note::{ - note_interface::NoteHash, retrieved_note::RetrievedNote, utils::compute_siloed_note_nullifier, + note_interface::NoteHash, retrieved_note::RetrievedNote, + utils::compute_siloed_note_nullifier, }, oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness, }; 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 a67e195dda25..8e3390a4943c 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 @@ -1,7 +1,8 @@ use crate::{ context::PrivateContext, note::{ - note_interface::{NoteHash, NoteType}, note_metadata::SettledNoteMetadata, + note_interface::{NoteHash, NoteType}, + note_metadata::SettledNoteMetadata, retrieved_note::RetrievedNote, utils::compute_note_hash_for_nullify, }, 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 8d1760b622c7..b5a1b72d3603 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 @@ -1,6 +1,7 @@ use dep::aztec::{ macros::notes::custom_note, -note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, prelude::{NoteHash, PrivateContext, RetrievedNote}, + note::{note_metadata::SettledNoteMetadata, utils::compute_note_hash_for_nullify}, + prelude::{NoteHash, PrivateContext, RetrievedNote}, protocol_types::{ address::AztecAddress, constants::{GENERATOR_INDEX__NOTE_HASH, GENERATOR_INDEX__NOTE_NULLIFIER}, From 5b28f843586bb73745ad3844805e07f9a4bcb04e Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 25 Feb 2025 21:47:09 +0000 Subject: [PATCH 3/6] WIP --- noir-projects/aztec-nr/uint-note/src/uint_note.nr | 3 --- 1 file changed, 3 deletions(-) diff --git a/noir-projects/aztec-nr/uint-note/src/uint_note.nr b/noir-projects/aztec-nr/uint-note/src/uint_note.nr index 0254bf949f27..3e0517a92e81 100644 --- a/noir-projects/aztec-nr/uint-note/src/uint_note.nr +++ b/noir-projects/aztec-nr/uint-note/src/uint_note.nr @@ -4,9 +4,6 @@ use dep::aztec::{ protocol_types::{address::AztecAddress, traits::Serialize}, }; -// TODO(#12008): Remove the need for the manual import of `Packable` trait here. This is a bug in macros. -use aztec::protocol_types::traits::Packable; - // docs:start:UintNote // We derive the Serialize trait because in some cases notes are used as parameters to contract functions. #[partial_note(quote {value})] From 091ad682d142de6700f3deed395cb8cf945194d7 Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 25 Feb 2025 21:53:31 +0000 Subject: [PATCH 4/6] fixes after rebase --- .../aztec-nr/aztec/src/macros/notes/mod.nr | 19 ++++++++++++------- .../aztec-nr/aztec/src/oracle/notes.nr | 5 ++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index b6910aef1eaf..23f9becd2b00 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -118,14 +118,17 @@ comptime fn generate_note_hashing(s: StructDefinition) -> Quoted { contract_address: aztec::prelude::AztecAddress, note_nonce: Field, ) -> Field { - // We set the note_hash_counter to 0 as the note is assumed to be committed (and hence not transient). - let retrieved_note = - aztec::prelude::RetrievedNote { note: self, contract_address, nonce: note_nonce, note_hash_counter: 0 }; + 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. - let owner_npk_m_hash = aztec::protocol_types::traits::Hash::hash(owner_npk_m); let secret = aztec::keys::getters::get_nsk_app(owner_npk_m_hash); + let owner_npk_m_hash = aztec::protocol_types::traits::Hash::hash(owner_npk_m); + let secret = aztec::keys::getters::get_nsk_app(owner_npk_m_hash); aztec::protocol_types::hash::poseidon2_hash_with_separator( [note_hash_for_nullify, secret], aztec::protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER as Field, @@ -233,9 +236,11 @@ comptime fn generate_note_hashing_for_partial_note( contract_address: aztec::prelude::AztecAddress, note_nonce: Field, ) -> Field { - // We set the note_hash_counter to 0 as the note is assumed to be committed (and hence not transient). - let retrieved_note = - aztec::prelude::RetrievedNote { note: self, contract_address, nonce: note_nonce, note_hash_counter: 0 }; + 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 diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index 121855ff2821..ec91033854a7 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -1,4 +1,7 @@ -use crate::{note::{note_interface::NoteType, retrieved_note::RetrievedNote}, utils::array}; +use crate::{ + note::{note_interface::NoteType, note_metadata::NoteMetadata, retrieved_note::RetrievedNote}, + utils::array, +}; use dep::protocol_types::{ address::AztecAddress, From 5a7e4a8f2f2dadb34910d3e6a2fd369d8a19fd1c Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 25 Feb 2025 21:55:42 +0000 Subject: [PATCH 5/6] typo --- noir-projects/aztec-nr/aztec/src/note/utils.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 9cc1c5990bff..a8bc843dfd9a 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_note_hash_for_nullify_from_read_request( // There is just one instance in which the note hash for nullification does not match the note hash used for a read // request, which is when dealing with pending previous phase notes. These had their existence proven using their // non-siloed note hash along with the note hash counter (like all pending notes), but since they will be - // uncondtionally inserted in the note hash tree (since they cannot be squashed) they must be nullified using the + // unconditionally inserted in the note hash tree (since they cannot be squashed) they must be nullified using the // *unique* note hash. // If we didn't, it'd be possible to emit a second different nullifier for the same note in a follow up transaction, // once the note is settled, resulting in a double spend. From a81141bb5fcf1690907a79a553ce487338aec03b Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 25 Feb 2025 21:58:20 +0000 Subject: [PATCH 6/6] naming fix --- .../aztec-nr/aztec/src/macros/notes/mod.nr | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 23f9becd2b00..90c9ca77b0d2 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -86,7 +86,7 @@ comptime fn generate_note_interface(s: StructDefinition, note_type_id: Field) -> /// ) -> Field { ... } /// } /// ``` -comptime fn generate_note_hashing(s: StructDefinition) -> Quoted { +comptime fn generate_note_hash_trait_impl(s: StructDefinition) -> Quoted { let name = s.name(); quote { @@ -159,7 +159,7 @@ comptime fn generate_note_hashing(s: StructDefinition) -> Quoted { /// } /// } /// -/// # On differences from `generate_note_hashing` +/// # On differences from `generate_note_hash_trait_impl` /// We use multi-scalar multiplication (MSM) instead of Poseidon2 here since this is a partial note and therefore /// does require MSM's additive homomorphism property (the property is used to add to the commitment in public). /// We don't use this implementation for standard notes as well because Poseidon2 is significantly cheaper @@ -177,7 +177,7 @@ comptime fn generate_note_hashing(s: StructDefinition) -> Quoted { /// /// Since -l would be -3 (an extraordinarily large number that cannot be a valid preimage length), /// including the length protects against these collisions. -comptime fn generate_note_hashing_for_partial_note( +comptime fn generate_note_hash_trait_impl_for_partial_note( s: StructDefinition, indexed_fixed_fields: [(Quoted, Type, u32)], indexed_nullable_fields: [(Quoted, Type, u32)], @@ -1030,8 +1030,11 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> let (finalization_payload_impl, finalization_payload_name) = generate_finalization_payload(s, indexed_fixed_fields, indexed_nullable_fields); let note_interface_impl = generate_note_interface(s, note_type_id); - let note_hashing_impl = - generate_note_hashing_for_partial_note(s, indexed_fixed_fields, indexed_nullable_fields); + let note_hash_impl = generate_note_hash_trait_impl_for_partial_note( + s, + indexed_fixed_fields, + indexed_nullable_fields, + ); let partial_note_impl = generate_partial_note_impl(s, setup_payload_name, finalization_payload_name); let (packable_impl, note_packed_len) = derive_packable_if_not_implemented_and_get_len(s); @@ -1049,7 +1052,7 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> $setup_payload_impl $finalization_payload_impl $note_interface_impl - $note_hashing_impl + $note_hash_impl $partial_note_impl $packable_impl } @@ -1072,7 +1075,7 @@ pub comptime fn note(s: StructDefinition) -> Quoted { let note_properties = generate_note_properties(s); let note_type_id = get_next_note_type_id(); let note_interface_impl = generate_note_interface(s, note_type_id); - let note_hashing_impl = generate_note_hashing(s); + let note_hash_impl = generate_note_hash_trait_impl(s); let (packable_impl, note_packed_len) = derive_packable_if_not_implemented_and_get_len(s); register_note( @@ -1086,7 +1089,7 @@ pub comptime fn note(s: StructDefinition) -> Quoted { quote { $note_properties $note_interface_impl - $note_hashing_impl + $note_hash_impl $packable_impl } }