From ad081d0003da723a4a6afae9cc66b7adfff86242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Sat, 7 Mar 2026 05:35:26 +0000 Subject: [PATCH 1/7] fix claim contract em itting raw nullifier --- .../contracts/app/claim_contract/src/main.nr | 75 ++++++++++--------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr index 79257cb8b8a9..757a85b1a6f1 100644 --- a/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr @@ -11,69 +11,72 @@ pub contract Claim { HintedNote, note_interface::NoteHash, utils::compute_confirmed_note_hash_for_nullification, }, - protocol::address::AztecAddress, - state_vars::PublicImmutable, + protocol::{address::AztecAddress, traits::Packable}, + state_vars::{Map, Owned, PublicImmutable, SingleUseClaim}, }; use token::Token; use uint_note::UintNote; - // TODO: This can be optimized by storing the addresses in Config struct in 1 PublicImmutable (less merkle proofs). - #[storage] - struct Storage { + #[derive(Eq, Packable)] + struct ClaimConfig { // Address of a contract based on whose notes we distribute the rewards - target_contract: PublicImmutable, + target_contract: AztecAddress, // Token to be distributed as a reward when claiming - reward_token: PublicImmutable, + reward_token: AztecAddress, + } + + #[storage] + struct Storage { + config: PublicImmutable, + note_hash_claims: Map, Context>, Context>, } #[external("public")] #[initializer] fn constructor(target_contract: AztecAddress, reward_token: AztecAddress) { - self.storage.target_contract.initialize(target_contract); - self.storage.reward_token.initialize(reward_token); + self.storage.config.initialize(ClaimConfig { target_contract, reward_token }); } #[external("private")] fn claim(hinted_note: HintedNote, recipient: AztecAddress) { - // 1) Check that the note corresponds to the target contract - let target_address = self.storage.target_contract.read(); + // 1) Prove that the note exists + // docs:start:prove_note_inclusion + let header = self.context.get_anchor_block_header(); + let confirmed_note = assert_note_existed_by(header, hinted_note); + // docs:end:prove_note_inclusion + + let config = self.storage.config.read(); + + // 2) Check that the note corresponds to the target contract assert( - target_address == hinted_note.contract_address, + config.target_contract == confirmed_note.contract_address, "Note does not correspond to the target contract", ); - // 2) Check that the note is owned by the msg_sender - assert(hinted_note.owner == self.msg_sender(), "Note is not owned by the msg_sender"); + // 3) Check that the note is owned by the msg_sender + assert(confirmed_note.owner == self.msg_sender(), "Note is not owned by the msg_sender"); // Given that there is only 1 state variable in the Crowdfunding contract we don't need to constrain the storage // slot of the note as there is no risk of claiming with a note that is not a donation note. - // 3) Prove that the note hash exists in the note hash tree - // docs:start:prove_note_inclusion - let header = self.context.get_anchor_block_header(); - let confirmed_note = assert_note_existed_by(header, hinted_note); - // docs:end:prove_note_inclusion - - // 4) Compute and emit a nullifier which is unique to the note and this contract to ensure the reward can be - // claimed only once with the given note. - // Note: Only the owner of the npk_m will be able to produce the nhk_app and compute this nullifier. - // The nullifier is unique to the note and THIS contract because the protocol siloes all nullifiers with - // the address of a contract it was emitted from. - // TODO(#7775): manually computing the hash and passing it to compute_nullifier func is not great as note could - // handle it on its own or we could make assert_note_existed_by return note_hash_for_nullification. + // 4) Consume the claim of this note, ensuring the reward can be claimed only once with the given note. + // Note: we're using the note's hash as the claim identifier, as it serves as a unique identifier (because we + // know the know is settled, and hence its note hash unique). This is not the same thing as nullifying the note + // however, which can only be done from the contract that emitted the note. From the point of view of the + // Crowdfunding contract, the note is still active. let note_hash_for_nullification = compute_confirmed_note_hash_for_nullification(confirmed_note); - let nullifier = hinted_note.note.compute_nullifier( - self.context, - hinted_note.owner, - note_hash_for_nullification, - ); - self.context.push_nullifier(nullifier); + self + .storage + .note_hash_claims + .at(note_hash_for_nullification) + .at(confirmed_note.owner) + .claim(); - // 5) Finally we mint the reward token to the sender of the transaction - self.enqueue(Token::at(self.storage.reward_token.read()).mint_to_public( + // 5) Finally we mint the reward token to the requested recipient + self.enqueue(Token::at(config.reward_token).mint_to_public( recipient, - hinted_note.note.value, + confirmed_note.note.value, )); } } From 3154123870b6c1213dcd9132e7bca5c870ae3617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Sat, 7 Mar 2026 06:33:38 +0000 Subject: [PATCH 2/7] improve docs for nullifs --- .../aztec/src/context/private_context.nr | 85 ++++++++----------- .../aztec-nr/aztec/src/nullifier/mod.nr | 28 ++++++ .../contracts/app/claim_contract/src/main.nr | 7 +- 3 files changed, 68 insertions(+), 52 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 2b8652f05367..7f56a6492a96 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -351,71 +351,56 @@ impl PrivateContext { self.note_hashes.push(Counted::new(note_hash, self.next_counter())); } - /// Pushes a new nullifier to the Aztec blockchain's global Nullifier Tree (a state tree). + /// Creates a new [nullifier](crate::nullifier). /// - /// See also: `push_nullifier_for_note_hash`. + /// ## Safety /// - /// Low-level function: Ordinarily, smart contract developers will not need to manually call this. Aztec-nr's state - /// variables (see `../state_vars/`) are designed to understand when to create and push new nullifiers. - /// - /// A nullifier can only be emitted once. Duplicate nullifier insertions are rejected by the protocol. - /// - /// Generally, a nullifier is emitted to prevent an action from happening more than once, in such a way that the - /// action cannot be linked (by an observer of the blockchain) to any earlier transactions. - /// - /// I.e. a nullifier is a random-looking, but deterministic record of a private, one-time action, which does not - /// leak what action has been taken, and which preserves the property of "tx unlinkability". + /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state. + /// Instead of calling this function, consider using the higher-level [`crate::state_vars::SingleUseClaim`]. /// - /// Usually, a nullifier will be emitted to "spend" a note (a piece of private state), without revealing which - /// specific note is being spent. + /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that + /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a + /// variable as initialized). Only [`PrivateContext::push_nullifier_for_note_hash`] should be used for note + /// nullifiers, never this one. /// - /// (Important: in such cases, use the below `push_nullifier_for_note_hash`). - /// - /// Sometimes, a nullifier might be emitted completely unrelated to any notes. Examples include initialization of a - /// new contract; initialization of a PrivateMutable, or signalling in Semaphore-like applications. This - /// `push_nullifier` function serves such use cases. - /// - /// # Arguments - /// * `nullifier` - /// - /// # Advanced - /// From here, the protocol's kernel circuits will take over and insert the nullifier into the protocol's - /// "nullifier tree" (in the Base Rollup circuit). Before insertion, the protocol will: - /// - "Silo" the `nullifier` with the contract address of this function, to yield a `siloed_nullifier`. This - /// prevents state collisions between different smart contracts. - /// - Ensure the `siloed_nullifier` is unique (the nullifier tree is an indexed merkle tree which supports - /// efficient non-membership proofs). + /// ## Advanced /// + /// The raw `nullifier` is not what is inserted into the Aztec state tree: it will be first siloed by contract + /// address via [`crate::protocol::hash::compute_siloed_nullifier`] in order to prevent accidental or malicious + /// interference of nullifiers from different contracts. pub fn push_nullifier(&mut self, nullifier: Field) { notify_created_nullifier(nullifier); self.nullifiers.push(Nullifier { value: nullifier, note_hash: 0 }.count(self.next_counter())); } - /// Pushes a nullifier that corresponds to a specific note hash. + /// Creates a new [nullifier](crate::nullifier) associated with a note. /// - /// Low-level function: Ordinarily, smart contract developers will not need to manually call this. Aztec-nr's state - /// variables (see `../state_vars/`) are designed to understand when to create and push new nullifiers. + /// This is a variant of [`PrivateContext::push_nullifier`] that is used for note nullifiers, i.e. nullifiers that + /// correspond to a note. If a note and its nullifier are created in the same transaction, then the private kernels + /// will 'squash' these values, deleting them both as if they never existed and reducing transaction fees. /// - /// This is a specialized version of `push_nullifier` that links a nullifier to the specific note hash it's - /// nullifying. This is the most common usage pattern for nullifiers. See `push_nullifier` for more explanation on - /// nullifiers. + /// The `nullification_note_hash` must be the result of calling + /// [`crate::note::utils::compute_confirmed_note_hash_for_nullification`] for pending notes, and `0` for settled + /// notes (which cannot be squashed). /// - /// # Arguments - /// * `nullifier` - /// * `nullified_note_hash` - The note hash of the note being nullified + /// ## Safety /// - /// # Advanced - ///Important: usage of this function doesn't mean that the world will _see_ that this nullifier relates to the - /// given nullified_note_hash (as that would violate "tx unlinkability"); it simply informs the user's PXE about - /// the relationship (via `notify_nullified_note`). The PXE can then use this information to feed hints to the - /// kernel circuits for "squashing" purposes: If a note is nullified during the same tx which created it, we can - /// "squash" (delete) the note and nullifier (and any private logs associated with the note), to save on data - /// emission costs. - /// - pub fn push_nullifier_for_note_hash(&mut self, nullifier: Field, nullified_note_hash: Field) { + /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state. + /// Instead of calling this function, consider using the higher-level [`crate::note::lifecycle::destroy_note`]. + /// + /// The precautions listed for [`PrivateContext::push_nullifier`] apply here as well, and callers should + /// additionally ensure `nullification_note_hash` corresponds to a note emitted by this contract, with its hash + /// computed in the same transaction execution phase as the call to this function. Finally, only this function + /// should be used for note nullifiers, never [`PrivateContext::push_nullifier`]. + /// + /// Failure to do these things can result in unprovable contexts, accidental deletion of notes, or double-spend + /// attacks. + pub fn push_nullifier_for_note_hash(&mut self, nullifier: Field, nullification_note_hash: Field) { let nullifier_counter = self.next_counter(); - notify_nullified_note(nullifier, nullified_note_hash, nullifier_counter); - self.nullifiers.push(Nullifier { value: nullifier, note_hash: nullified_note_hash }.count(nullifier_counter)); + notify_nullified_note(nullifier, nullification_note_hash, nullifier_counter); + self.nullifiers.push(Nullifier { value: nullifier, note_hash: nullification_note_hash }.count( + nullifier_counter, + )); } /// Returns the anchor block header - the historical block header that this private function is reading from. diff --git a/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr b/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr index ba98535fe8e6..44d87461bcc2 100644 --- a/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr @@ -1,3 +1,31 @@ //! Nullifier-related utilities. +//! +//! Nullifiers are one of the key primitives of private state. A nullifier is a `Field` value that is stored in one of +//! Aztec state trees: the nullifier tree. Only unique values can be inserted into this tree: attempting to create an +//! already existing nullifier (a duplicate nullifier) will result in either the transaction being unprovable, invalid, +//! or reverting, depending on exactly when the duplicate is created. +//! +//! Generally, nullifiers are used to prevent an action from happening more than once, or to more generally 'consume' a +//! resource. This can include preventing re-initialization of contracts, replay attacks of signatures, repeated claims +//! of a deposit, double-spends of received funds, etc. To achieve this, nullifiers must be computed +//! **deterministically** from the resource they're consuming. For example a contract initialization nullifier might +//! use +//! its address, or a signature replay protection could use the signature hash. +//! +//! One of the key properties of nullifiers is that they can be created by private functions, resulting in transactions +//! that do not reveal which actions they've performed. Their computation often involves a **secret parameter**, often +//! derived from a nullifier hiding key (`nhk`) which prevents linking of the resource that was consumed from the +//! nullifier. For example, it is not possible to determine which nullifier corresponds to a given note hash without +//! knowledge of the `nhk`, and so the transactions that created the note and nullifier remain unlinked. +//! +//! In other words, a nullifier is (in most cases) a random-looking but deterministic record of a private, one-time +//! action, which does not leak what action has been taken, and which preserves the property of transaction +//! unlinkability. +//! +//! In some cases, nullifiers cannot be secret as knowledge of them **must** be public information. For example, +//! contracts used by multiple people (like tokens) cannot have secrets in their initialization nullifiers: for users +//! to +//! use the contract they must prove that it has been initialized, and this requires them being able to compute the +//! initialization nullifier. pub mod utils; diff --git a/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr index 757a85b1a6f1..a8cc2255b539 100644 --- a/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr @@ -59,9 +59,12 @@ pub contract Claim { // Given that there is only 1 state variable in the Crowdfunding contract we don't need to constrain the storage // slot of the note as there is no risk of claiming with a note that is not a donation note. - // 4) Consume the claim of this note, ensuring the reward can be claimed only once with the given note. + // 4) Consume the claim of this note, ensuring the reward can be claimed only once with the given note. Each + // claim being tied to their owner results in unlinkability of the claim's nullifier and the underlying note + // hash via the owner's nullifier hiding key (`nhk`). + // // Note: we're using the note's hash as the claim identifier, as it serves as a unique identifier (because we - // know the know is settled, and hence its note hash unique). This is not the same thing as nullifying the note + // know the note is settled, and hence its note hash unique). This is not the same thing as nullifying the note // however, which can only be done from the contract that emitted the note. From the point of view of the // Crowdfunding contract, the note is still active. let note_hash_for_nullification = From 68fa603711f3ffb16c8eef0bf11d251ce9e15033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Sat, 7 Mar 2026 06:46:51 +0000 Subject: [PATCH 3/7] add links --- .../aztec/src/context/public_context.nr | 28 +++++++++++-------- .../aztec-nr/aztec/src/nullifier/mod.nr | 20 ++++++++++++- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index a084674ba3df..a6fd8092881d 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -366,22 +366,26 @@ impl PublicContext { unsafe { avm::emit_note_hash(note_hash) }; } - /// Adds a new nullifier to the Aztec blockchain's global Nullifier Tree. + /// Creates a new [nullifier](crate::nullifier). /// - /// Whilst nullifiers are primarily intended as a _privacy-preserving_ record of a one-time action, they can also - /// be used to efficiently record _public_ one-time actions too. Hence why you're seeing this function within the - /// PublicContext. An example is to check whether a contract has been published: we emit a nullifier that is - /// deterministic, but whose preimage is _not_ private. + /// While nullifiers are primarily intended as a _privacy-preserving_ record of a one-time action, they can also + /// be used to efficiently record _public_ one-time actions. This function allows creating nullifiers from public + /// contract functions, which behave just like those created from private functions. /// - /// # Arguments - /// * `nullifier` - A unique field element that represents the consumed state + /// ## Safety /// - /// # Advanced - /// * Nullifier is immediately added to the global nullifier tree - /// * Emitted nullifiers are immediately visible to all subsequent transactions in the same block - /// * Automatically siloed with the contract address by the protocol - /// * Used for preventing double-spending and ensuring one-time actions + /// This is a low-level function that must be used with great care to avoid subtle corruption of contract state. + /// + /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that + /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a + /// variable as initialized). Only [`PrivateContext::push_nullifier_for_note_hash`] should be used for note + /// nullifiers, never this one. + /// + /// ## Advanced /// + /// The raw `nullifier` is not what is inserted into the Aztec state tree: it will be first siloed by contract + /// address via [`crate::protocol::hash::compute_siloed_nullifier`] in order to prevent accidental or malicious + /// interference of nullifiers from different contracts. pub fn push_nullifier(_self: Self, nullifier: Field) { // Safety: AVM opcodes are constrained by the AVM itself unsafe { avm::emit_nullifier(nullifier) }; diff --git a/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr b/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr index 44d87461bcc2..8393c15cef73 100644 --- a/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr @@ -27,5 +27,23 @@ //! to //! use the contract they must prove that it has been initialized, and this requires them being able to compute the //! initialization nullifier. - +//! +//! ## Nullfier Creation +//! +//! The low-level mechanisms to create new nullifiers are [`crate::context::PrivateContext::push_nullifier`] and +//! [`crate::context::PublicContext::push_nullifier`], but these require care and can be hard to use correctly. +//! Higher-level abstractions exist which safely create nullifiers, such as [`crate::note::lifecycle::destroy_note`] +//! and +//! [`crate::state_vars::SingleUseClaim`]. +//! +//! ## Reading Nullifiers +//! +//! Private functions can prove that nullifiers have been created via +//! [`crate::context::PrivateContext::assert_nullifier_exists`] and +//! [`crate::history::nullifier::assert_nullifier_existed_by`], but the only general mechanism to privately prove that +//! a +//! nullifier _does not_ exist is to create it - which can only be done once. +//! +//! Public function on the other hand can prove both nullifier existence and non-existence via +//! [`crate::context::PublicContext::nullifier_exists_unsafe`]. pub mod utils; From 9a167619aec8acbbefa2cbc2f55e3939799cfc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 11 Mar 2026 20:03:58 +0000 Subject: [PATCH 4/7] fix typos and improve docs clarity Co-Authored-By: Claude Opus 4.6 --- noir-projects/aztec-nr/aztec/src/context/public_context.nr | 4 ++-- noir-projects/aztec-nr/aztec/src/nullifier/mod.nr | 7 ++++--- .../contracts/app/claim_contract/src/main.nr | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index a6fd8092881d..f83fa33f679c 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -378,8 +378,8 @@ impl PublicContext { /// /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a - /// variable as initialized). Only [`PrivateContext::push_nullifier_for_note_hash`] should be used for note - /// nullifiers, never this one. + /// variable as initialized). Note nullifiers should only be created via + /// [`PrivateContext::push_nullifier_for_note_hash`]. /// /// ## Advanced /// diff --git a/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr b/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr index 8393c15cef73..68b1453f5260 100644 --- a/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/nullifier/mod.nr @@ -1,7 +1,8 @@ //! Nullifier-related utilities. //! //! Nullifiers are one of the key primitives of private state. A nullifier is a `Field` value that is stored in one of -//! Aztec state trees: the nullifier tree. Only unique values can be inserted into this tree: attempting to create an +//! the Aztec state trees: the nullifier tree. Only unique values can be inserted into this tree: attempting to create +//! an //! already existing nullifier (a duplicate nullifier) will result in either the transaction being unprovable, invalid, //! or reverting, depending on exactly when the duplicate is created. //! @@ -28,7 +29,7 @@ //! use the contract they must prove that it has been initialized, and this requires them being able to compute the //! initialization nullifier. //! -//! ## Nullfier Creation +//! ## Nullifier Creation //! //! The low-level mechanisms to create new nullifiers are [`crate::context::PrivateContext::push_nullifier`] and //! [`crate::context::PublicContext::push_nullifier`], but these require care and can be hard to use correctly. @@ -44,6 +45,6 @@ //! a //! nullifier _does not_ exist is to create it - which can only be done once. //! -//! Public function on the other hand can prove both nullifier existence and non-existence via +//! Public functions on the other hand can prove both nullifier existence and non-existence via //! [`crate::context::PublicContext::nullifier_exists_unsafe`]. pub mod utils; diff --git a/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr index a8cc2255b539..1833bbd4522e 100644 --- a/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr @@ -28,6 +28,7 @@ pub contract Claim { #[storage] struct Storage { config: PublicImmutable, + // Maps a note hash to owner-specific single-use claims, preventing double-claiming of rewards. note_hash_claims: Map, Context>, Context>, } @@ -60,7 +61,7 @@ pub contract Claim { // slot of the note as there is no risk of claiming with a note that is not a donation note. // 4) Consume the claim of this note, ensuring the reward can be claimed only once with the given note. Each - // claim being tied to their owner results in unlinkability of the claim's nullifier and the underlying note + // claim being tied to its owner results in unlinkability of the claim's nullifier and the underlying note // hash via the owner's nullifier hiding key (`nhk`). // // Note: we're using the note's hash as the claim identifier, as it serves as a unique identifier (because we From bd78b0b69fc65126af185da31519ae0ece0e4d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 11 Mar 2026 20:09:24 +0000 Subject: [PATCH 5/7] remove unused NoteHash import, fix cspell and doc link paths Co-Authored-By: Claude Opus 4.6 --- cspell.json | 2 +- noir-projects/aztec-nr/aztec/src/context/public_context.nr | 2 +- .../noir-contracts/contracts/app/claim_contract/src/main.nr | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cspell.json b/cspell.json index dc2183f8f52e..0c64bcaf57a8 100644 --- a/cspell.json +++ b/cspell.json @@ -235,7 +235,6 @@ "noirup", "allow_phase_change", "nophasecheck", - "nullifer", "Nullifiable", "offchain", "onchain", @@ -367,6 +366,7 @@ "unfinalized", "uniquified", "uniquify", + "unlinkability", "unkonstrained", "unnullify", "unpadded", diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index f83fa33f679c..ad9e91c0ada4 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -379,7 +379,7 @@ impl PublicContext { /// In particular, callers must ensure all nullifiers created by a contract are properly domain-separated, so that /// unrelated components don't interfere with one another (e.g. a transaction nullifier accidentally marking a /// variable as initialized). Note nullifiers should only be created via - /// [`PrivateContext::push_nullifier_for_note_hash`]. + /// [`crate::context::PrivateContext::push_nullifier_for_note_hash`]. /// /// ## Advanced /// diff --git a/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr index 1833bbd4522e..4a54aac54faa 100644 --- a/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app/claim_contract/src/main.nr @@ -7,10 +7,7 @@ pub contract Claim { // docs:end:history_import use aztec::{ macros::{functions::{external, initializer}, storage::storage}, - note::{ - HintedNote, note_interface::NoteHash, - utils::compute_confirmed_note_hash_for_nullification, - }, + note::{HintedNote, utils::compute_confirmed_note_hash_for_nullification}, protocol::{address::AztecAddress, traits::Packable}, state_vars::{Map, Owned, PublicImmutable, SingleUseClaim}, }; From 41af90c906269d6aacf52cd19249123aaa39a9f3 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 11 Mar 2026 21:58:03 +0000 Subject: [PATCH 6/7] fix: update e2e test expectation after hinted_note -> confirmed_note rename --- yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts index 1b99f2b3657e..68711711b23b 100644 --- a/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts +++ b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts @@ -208,7 +208,7 @@ describe('e2e_crowdfunding_and_claim', () => { // docs:start:local-tx-fails await expect( claimContract.methods.claim(anotherDonationNote, donorAddress).send({ from: unrelatedAddress }), - ).rejects.toThrow('hinted_note.owner == self.msg_sender()'); + ).rejects.toThrow('confirmed_note.owner == self.msg_sender()'); // docs:end:local-tx-fails }); From b62709c81356aa087fc2d1f45c64c1be4c4d1745 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 12 Mar 2026 03:31:47 +0000 Subject: [PATCH 7/7] fix: typo nullifer -> nullifier in migration_notes.md --- .../docs/resources/migration_notes.md | 2 +- .../docs/resources/migration_notes.md | 2 +- docs/docs-developers/docs/resources/migration_notes.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/developer_versioned_docs/version-v4.0.0-devnet.2-patch.1/docs/resources/migration_notes.md b/docs/developer_versioned_docs/version-v4.0.0-devnet.2-patch.1/docs/resources/migration_notes.md index a1f24190c2db..e3875c824554 100644 --- a/docs/developer_versioned_docs/version-v4.0.0-devnet.2-patch.1/docs/resources/migration_notes.md +++ b/docs/developer_versioned_docs/version-v4.0.0-devnet.2-patch.1/docs/resources/migration_notes.md @@ -2689,7 +2689,7 @@ Doing the changes is as straightforward as: `UintNote` has also been updated to use the native `u128` type. -### [aztec-nr] Removed `compute_note_hash_and_optionally_a_nullifer` +### [aztec-nr] Removed `compute_note_hash_and_optionally_a_nullifier` This function is no longer mandatory for contracts, and the `#[aztec]` macro no longer injects it. diff --git a/docs/developer_versioned_docs/version-v5.0.0-nightly.20260311/docs/resources/migration_notes.md b/docs/developer_versioned_docs/version-v5.0.0-nightly.20260311/docs/resources/migration_notes.md index 389b42ab8107..c048dd40bb16 100644 --- a/docs/developer_versioned_docs/version-v5.0.0-nightly.20260311/docs/resources/migration_notes.md +++ b/docs/developer_versioned_docs/version-v5.0.0-nightly.20260311/docs/resources/migration_notes.md @@ -2948,7 +2948,7 @@ Doing the changes is as straightforward as: `UintNote` has also been updated to use the native `u128` type. -### [aztec-nr] Removed `compute_note_hash_and_optionally_a_nullifer` +### [aztec-nr] Removed `compute_note_hash_and_optionally_a_nullifier` This function is no longer mandatory for contracts, and the `#[aztec]` macro no longer injects it. diff --git a/docs/docs-developers/docs/resources/migration_notes.md b/docs/docs-developers/docs/resources/migration_notes.md index 9a342de45a2f..c1209c424eeb 100644 --- a/docs/docs-developers/docs/resources/migration_notes.md +++ b/docs/docs-developers/docs/resources/migration_notes.md @@ -2948,7 +2948,7 @@ Doing the changes is as straightforward as: `UintNote` has also been updated to use the native `u128` type. -### [aztec-nr] Removed `compute_note_hash_and_optionally_a_nullifer` +### [aztec-nr] Removed `compute_note_hash_and_optionally_a_nullifier` This function is no longer mandatory for contracts, and the `#[aztec]` macro no longer injects it.