From 2848dcb3f57bd156a5938be9f0c62249724457e7 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 29 Jan 2026 10:03:26 +0100 Subject: [PATCH 1/6] chore: use `ExecError` in `CodeExecutor` --- crates/miden-testing/src/executor.rs | 21 ++++++++++--------- .../src/kernel_tests/tx/test_account.rs | 7 +++---- .../miden-testing/src/tx_context/context.rs | 1 - 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/crates/miden-testing/src/executor.rs b/crates/miden-testing/src/executor.rs index b5b9b1e085..c7a417250b 100644 --- a/crates/miden-testing/src/executor.rs +++ b/crates/miden-testing/src/executor.rs @@ -1,10 +1,12 @@ #[cfg(test)] use miden_processor::DefaultHost; use miden_processor::fast::{ExecutionOutput, FastProcessor}; -use miden_processor::{AdviceInputs, AsyncHost, ExecutionError, Program, StackInputs}; +use miden_processor::{AdviceInputs, AsyncHost, Program, StackInputs}; #[cfg(test)] use miden_protocol::assembly::Assembler; +use crate::ExecError; + // CODE EXECUTOR // ================================================================================================ @@ -37,11 +39,8 @@ impl CodeExecutor { } /// Compiles and runs the desired code in the host and returns the [`Process`] state. - /// - /// To improve the error message quality, convert the returned [`ExecutionError`] into a - /// [`Report`](miden_protocol::assembly::diagnostics::Report). #[cfg(test)] - pub async fn run(self, code: &str) -> Result { + pub async fn run(self, code: &str) -> Result { use alloc::borrow::ToOwned; use alloc::sync::Arc; @@ -64,10 +63,7 @@ impl CodeExecutor { /// /// To improve the error message quality, convert the returned [`ExecutionError`] into a /// [`Report`](miden_protocol::assembly::diagnostics::Report). - pub async fn execute_program( - mut self, - program: Program, - ) -> Result { + pub async fn execute_program(mut self, program: Program) -> Result { // This reverses the stack inputs (even though it doesn't look like it does) because the // fast processor expects the reverse order. // @@ -79,7 +75,8 @@ impl CodeExecutor { let processor = FastProcessor::new_debug(stack_inputs.as_slice(), self.advice_inputs); - let execution_output = processor.execute(&program, &mut self.host).await?; + let execution_output = + processor.execute(&program, &mut self.host).await.map_err(ExecError::new)?; Ok(execution_output) } @@ -88,12 +85,16 @@ impl CodeExecutor { #[cfg(test)] impl CodeExecutor { pub fn with_default_host() -> Self { + use miden_core_lib::CoreLibrary; use miden_protocol::ProtocolLib; use miden_protocol::transaction::TransactionKernel; use miden_standards::StandardsLib; let mut host = DefaultHost::default(); + let core_lib = CoreLibrary::default(); + host.load_library(core_lib.mast_forest()).unwrap(); + let standards_lib = StandardsLib::default(); host.load_library(standards_lib.mast_forest()).unwrap(); diff --git a/crates/miden-testing/src/kernel_tests/tx/test_account.rs b/crates/miden-testing/src/kernel_tests/tx/test_account.rs index d315b9c7c0..b27b34e6ba 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_account.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_account.rs @@ -64,6 +64,7 @@ use crate::kernel_tests::tx::ExecutionOutputExt; use crate::utils::create_public_p2any_note; use crate::{ Auth, + ExecError, MockChain, TransactionContextBuilder, TxContextInput, @@ -265,7 +266,7 @@ async fn test_account_validate_id() -> anyhow::Result<()> { .run(code) .await; - match (result, expected_error) { + match (result.map_err(ExecError::into_execution_error), expected_error) { (Ok(_), None) => (), (Ok(_), Some(err)) => { anyhow::bail!("expected error {err} but validation was successful") @@ -324,9 +325,7 @@ async fn test_is_faucet_procedure() -> anyhow::Result<()> { prefix = account_id.prefix().as_felt(), ); - let exec_output = CodeExecutor::with_default_host().run(&code).await.map_err(|err| { - anyhow::anyhow!("failed to execute is_faucet procedure: {}", PrintDiagnostic::new(&err)) - })?; + let exec_output = CodeExecutor::with_default_host().run(&code).await?; let is_faucet = account_id.is_faucet(); assert_eq!( diff --git a/crates/miden-testing/src/tx_context/context.rs b/crates/miden-testing/src/tx_context/context.rs index bffab5f566..1ff68e6280 100644 --- a/crates/miden-testing/src/tx_context/context.rs +++ b/crates/miden-testing/src/tx_context/context.rs @@ -175,7 +175,6 @@ impl TransactionContext { .extend_advice_inputs(advice_inputs) .execute_program(program) .await - .map_err(ExecError::new) } /// Executes the transaction through a [TransactionExecutor] From 5936732b83e997e9341d87d2caeb39836792f665 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 29 Jan 2026 10:03:44 +0100 Subject: [PATCH 2/6] feat: Implement `note_tag::create_account_target` MASM --- .../miden-agglayer/asm/bridge/bridge_out.masm | 3 +- crates/miden-protocol/asm/protocol/note.masm | 30 ------ crates/miden-protocol/src/note/note_tag.rs | 17 +--- .../asm/standards/note_tag/mod.masm | 92 +++++++++++++++++++ .../miden-standards/src/errors/standards.rs | 3 + .../src/kernel_tests/tx/test_note.rs | 44 --------- crates/miden-testing/src/standards/mod.rs | 1 + .../miden-testing/src/standards/note_tag.rs | 76 +++++++++++++++ 8 files changed, 178 insertions(+), 88 deletions(-) create mode 100644 crates/miden-standards/asm/standards/note_tag/mod.masm create mode 100644 crates/miden-testing/src/standards/note_tag.rs diff --git a/crates/miden-agglayer/asm/bridge/bridge_out.masm b/crates/miden-agglayer/asm/bridge/bridge_out.masm index 449955ce6c..9d8641aab8 100644 --- a/crates/miden-agglayer/asm/bridge/bridge_out.masm +++ b/crates/miden-agglayer/asm/bridge/bridge_out.masm @@ -1,5 +1,6 @@ use miden::protocol::active_note use miden::protocol::note +use miden::standards::note_tag use miden::protocol::output_note use miden::core::crypto::hashes::keccak256 use miden::core::crypto::hashes::rpo256 @@ -56,7 +57,7 @@ proc create_burn_note movup.2 drop movup.2 drop # => [faucet_id_prefix, faucet_id_suffix, ASSET] - exec.note::build_note_tag_for_network_account + exec.note_tag::create_account_target # => [network_faucet_tag, ASSET] loc_store.5 diff --git a/crates/miden-protocol/asm/protocol/note.masm b/crates/miden-protocol/asm/protocol/note.masm index cf8132ae72..15f4fced50 100644 --- a/crates/miden-protocol/asm/protocol/note.masm +++ b/crates/miden-protocol/asm/protocol/note.masm @@ -1,6 +1,5 @@ use miden::protocol::account_id use miden::core::crypto::hashes::rpo256 -use miden::core::math::u64 use miden::core::mem # Re-export the max inputs per note constant. @@ -238,32 +237,3 @@ pub proc extract_attachment_info_from_metadata u32split # => [attachment_kind, attachment_scheme] end - -#! Computes the tag for a network note for a given network account such that it is -#! picked up by the network transaction builder. -#! -#! This procedure implements the same logic as in Rust in NoteTag::from_network_account_id(). -#! Note: This procedure does not check if the account id is a network account id. -#! -#! Inputs: [account_id_prefix, account_id_suffix] -#! Outputs: [network_account_tag] -#! -#! Where: -#! - account_id_prefix, account_id_suffix is the account id to compute the note tag for. -#! - network_account_tag is the computed network note tag. -#! -#! Invocation: exec -pub proc build_note_tag_for_network_account - swap drop - # => [account_id_prefix] - - u32split - # => [a_hi, a_lo] - - # mask out the 14 (NoteTag::DEFAULT_ACCOUNT_TARGET_TAG_LENGTH) most significant bits - u32and.0xfffc0000 - # => [a_hi_masked, a_lo] - - swap drop - # => [network_account_tag] -end diff --git a/crates/miden-protocol/src/note/note_tag.rs b/crates/miden-protocol/src/note/note_tag.rs index 5e63212bc8..65b0b306d4 100644 --- a/crates/miden-protocol/src/note/note_tag.rs +++ b/crates/miden-protocol/src/note/note_tag.rs @@ -78,15 +78,8 @@ impl NoteTag { /// Constructs a note tag that targets the given `account_id`. /// - /// The tag is a 32-bit value constructed as follows: - /// - /// - The tag is derived from the account ID *prefix*. - /// - The most significant `DEFAULT_ACCOUNT_TARGET_TAG_LENGTH` bits of the 32-bit prefix are - /// preserved. - /// - All remaining least significant bits are set to `0`. - /// - /// The number of account-prefix bits included in the tag is determined by - /// `DEFAULT_ACCOUNT_TARGET_TAG_LENGTH`. + /// The tag is a u32 constructed by taking the [`NoteTag::DEFAULT_ACCOUNT_TARGET_TAG_LENGTH`] + /// most significant bits of the account ID prefix and setting the remaining bits to zero. pub fn with_account_target(account_id: AccountId) -> Self { Self::with_custom_account_target(account_id, Self::DEFAULT_ACCOUNT_TARGET_TAG_LENGTH) .expect("default account target tag length must be valid") @@ -94,10 +87,8 @@ impl NoteTag { /// Constructs a note tag that targets the given `account_id` with a custom `tag_len`. /// - /// The tag is constructed by: - /// - Setting the two most significant bits to zero. - /// - The next `tag_len` bits are set to the most significant bits of the account ID prefix. - /// - The remaining bits are set to zero. + /// The tag is a u32 constructed by taking the `tag_len` most significant bits of the account ID + /// prefix and setting the remaining bits to zero. /// /// # Errors /// diff --git a/crates/miden-standards/asm/standards/note_tag/mod.masm b/crates/miden-standards/asm/standards/note_tag/mod.masm new file mode 100644 index 0000000000..f814a186a0 --- /dev/null +++ b/crates/miden-standards/asm/standards/note_tag/mod.masm @@ -0,0 +1,92 @@ +use miden::core::math::u64 + +# ERRORS +# ================================================================================================= + +const ERR_NOTE_TAG_MAX_ACCOUNT_TARGET_LENGTH_EXCEEDED="note tag length can be at most 32" + +# CONSTANTS +# ================================================================================================= + +# The maximum account target tag length. +const MAX_ACCOUNT_TARGET_TAG_LENGTH = 32 + +# The default account target tag length. +const DEFAULT_ACCOUNT_TARGET_TAG_LENGTH = 14 + +# PROCEDURES +# ================================================================================================= + +#! Constructs a note tag that targets the given account_id_prefix with the default tag_len of 14. +#! +#! The tag is a u32 constructed by taking the 14 most significant bits of the account ID prefix and +#! setting the remaining bits to zero. +#! +#! Inputs: [account_id_prefix] +#! Outputs: [note_tag] +#! +#! Where: +#! - account_id_prefix is the account id prefix to compute the note tag for. +#! - note_tag is the created note tag. +#! +#! Invocation: exec +pub proc create_account_target + push.DEFAULT_ACCOUNT_TARGET_TAG_LENGTH + exec.create_custom_account_target + # => [note_tag] +end + +#! Constructs a note tag that targets the given account_id_prefix with the provided tag_len. +#! +#! The tag is a u32 constructed by taking the `tag_len` most significant bits of the account ID +#! prefix and setting the remaining bits to zero. +#! +#! Inputs: [tag_len, account_id_prefix] +#! Outputs: [note_tag] +#! +#! Where: +#! - account_id_prefix is the account id prefix to compute the note tag for. +#! - note_tag is the created note tag. +#! - tag_len is the number of most significant bits from the account ID prefix that should be used +#! for the tag. +#! +#! Panics if: +#! - the tag_len exceeds 32. +#! +#! Invocation: exec +pub proc create_custom_account_target + u32assert.err=ERR_NOTE_TAG_MAX_ACCOUNT_TARGET_LENGTH_EXCEEDED + # => [tag_len, account_id_prefix] + + dup u32lte.MAX_ACCOUNT_TARGET_TAG_LENGTH + assert.err=ERR_NOTE_TAG_MAX_ACCOUNT_TARGET_LENGTH_EXCEEDED + # => [tag_len, account_id_prefix] + + # create a bit mask that zeros out the lower (32 - tag_len) bits. + # since u32shl panics for a 32 shift, we need to use u64::shl in case tag_len is 0 + + # push u32::MAX as a u64 + push.0 push.0xffffffff + # => [u32::MAX, 0, tag_len, account_id_prefix] + + # compute "number of bits in u32" - tag_len + push.32 movup.3 sub + # => [shift_by, u32::MAX, 0, account_id_prefix] + + exec.u64::shl + # => [bit_mask_hi, bit_mask_lo, account_id_prefix] + + # discard the lo part + swap drop + # => [bit_mask, account_id_prefix] + + swap u32split + # => [account_id_prefix_hi, account_id_prefix_lo, bit_mask] + + # discard the lo part of the ID prefix + swap drop + # => [account_id_prefix_hi, bit_mask] + + u32and + # => [note_tag] +end diff --git a/crates/miden-standards/src/errors/standards.rs b/crates/miden-standards/src/errors/standards.rs index 410f0358a5..7a8d6a4567 100644 --- a/crates/miden-standards/src/errors/standards.rs +++ b/crates/miden-standards/src/errors/standards.rs @@ -26,6 +26,9 @@ pub const ERR_MALFORMED_MULTISIG_CONFIG: MasmError = MasmError::from_static_str( /// Error Message: "MINT script expects exactly 12 storage items for private or 16+ storage items for public output notes" pub const ERR_MINT_UNEXPECTED_NUMBER_OF_STORAGE_ITEMS: MasmError = MasmError::from_static_str("MINT script expects exactly 12 storage items for private or 16+ storage items for public output notes"); +/// Error Message: "note tag length can be at most 32" +pub const ERR_NOTE_TAG_MAX_ACCOUNT_TARGET_LENGTH_EXCEEDED: MasmError = MasmError::from_static_str("note tag length can be at most 32"); + /// Error Message: "failed to reclaim P2IDE note because the reclaiming account is not the sender" pub const ERR_P2IDE_RECLAIM_ACCT_IS_NOT_SENDER: MasmError = MasmError::from_static_str("failed to reclaim P2IDE note because the reclaiming account is not the sender"); /// Error Message: "P2IDE reclaim is disabled" diff --git a/crates/miden-testing/src/kernel_tests/tx/test_note.rs b/crates/miden-testing/src/kernel_tests/tx/test_note.rs index 82a2a78261..36fb76b3f3 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_note.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_note.rs @@ -20,7 +20,6 @@ use miden_protocol::note::{ NoteType, }; use miden_protocol::testing::account_id::{ - ACCOUNT_ID_NETWORK_FUNGIBLE_FAUCET, ACCOUNT_ID_REGULAR_PRIVATE_ACCOUNT_UPDATABLE_CODE, ACCOUNT_ID_SENDER, }; @@ -540,46 +539,3 @@ async fn test_public_key_as_note_input() -> anyhow::Result<()> { tx_context.execute().await?; Ok(()) } - -#[tokio::test] -async fn test_build_note_tag_for_network_account() -> anyhow::Result<()> { - let tx_context = TransactionContextBuilder::with_existing_mock_account().build()?; - - let account_id = AccountId::try_from(ACCOUNT_ID_NETWORK_FUNGIBLE_FAUCET)?; - - // Network account rule: top 30 bits of the prefix - let prefix: u64 = account_id.prefix().into(); - let expected_tag = NoteTag::with_account_target(account_id); - let suffix: u64 = account_id.suffix().into(); - - let code = format!( - " - use miden::core::sys - use miden::protocol::note - - begin - push.{suffix}.{prefix} - - exec.note::build_note_tag_for_network_account - # => [network_account_tag] - - exec.sys::truncate_stack - end - ", - suffix = suffix, - prefix = prefix, - ); - - let exec_output = tx_context.execute_code(&code).await?; - let actual_tag = exec_output.stack[0].as_int(); - - assert_eq!( - actual_tag, - expected_tag.as_u32() as u64, - "Expected tag {:#010x}, got {:#010x}", - expected_tag.as_u32(), - actual_tag - ); - - Ok(()) -} diff --git a/crates/miden-testing/src/standards/mod.rs b/crates/miden-testing/src/standards/mod.rs index 288c3ee84c..76cf06a85d 100644 --- a/crates/miden-testing/src/standards/mod.rs +++ b/crates/miden-testing/src/standards/mod.rs @@ -1 +1,2 @@ mod network_account_target; +mod note_tag; diff --git a/crates/miden-testing/src/standards/note_tag.rs b/crates/miden-testing/src/standards/note_tag.rs new file mode 100644 index 0000000000..0f476cb37c --- /dev/null +++ b/crates/miden-testing/src/standards/note_tag.rs @@ -0,0 +1,76 @@ +use miden_protocol::note::NoteTag; +use miden_protocol::testing::account_id::AccountIdBuilder; +use miden_standards::errors::standards::ERR_NOTE_TAG_MAX_ACCOUNT_TARGET_LENGTH_EXCEEDED; + +use crate::assert_execution_error; +use crate::executor::CodeExecutor; + +#[rstest::rstest] +#[case::tag_len_0(0)] +#[case::tag_len_20(20)] +#[case::tag_len_32(32)] +#[tokio::test] +async fn test_note_tag_account_target(#[case] tag_len: u8) -> anyhow::Result<()> { + let account_id = AccountIdBuilder::new().build_with_seed([20; 32]); + let id_prefix = account_id.prefix().as_felt(); + + let expected_tag = NoteTag::with_custom_account_target(account_id, tag_len)?; + + let code = format!( + " + use miden::core::sys + use miden::standards::note_tag + + begin + push.{id_prefix} + push.{tag_len} + + exec.note_tag::create_custom_account_target + # => [note_tag] + + exec.sys::truncate_stack + end + " + ); + + let exec_output = CodeExecutor::with_default_host().run(&code).await?; + let actual_tag = exec_output.stack[0].as_int(); + + assert_eq!( + actual_tag, + expected_tag.as_u32() as u64, + "Expected tag {:#010x}, got {:#010x}", + expected_tag.as_u32(), + actual_tag + ); + + Ok(()) +} + +#[tokio::test] +async fn test_note_tag_account_target_fails_for_large_tag_len() -> anyhow::Result<()> { + let tag_len = NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH + 1; + let code = format!( + " + use miden::core::sys + use miden::standards::note_tag + + begin + # account ID prefix doesn't matter for this test + push.0 + push.{tag_len} + + exec.note_tag::create_custom_account_target + # => [note_tag] + + exec.sys::truncate_stack + end + " + ); + + let exec_output = CodeExecutor::with_default_host().run(&code).await; + + assert_execution_error!(exec_output, ERR_NOTE_TAG_MAX_ACCOUNT_TARGET_LENGTH_EXCEEDED); + + Ok(()) +} From 3c9f4b1b1a6bcd305a3110794393500b89080e21 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 29 Jan 2026 10:09:59 +0100 Subject: [PATCH 3/6] chore: remove unused error; improve docs --- crates/miden-protocol/src/address/mod.rs | 3 --- crates/miden-protocol/src/errors/mod.rs | 6 +----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/crates/miden-protocol/src/address/mod.rs b/crates/miden-protocol/src/address/mod.rs index 225fb1b0a4..1804f56c3f 100644 --- a/crates/miden-protocol/src/address/mod.rs +++ b/crates/miden-protocol/src/address/mod.rs @@ -78,9 +78,6 @@ impl Address { } /// Sets the routing parameters of the address. - /// Validation of tag length, interface, and encryption key is handled - /// internally by [`RoutingParameters`]. This method simply attaches the - /// provided parameters to the address. pub fn with_routing_parameters(mut self, routing_params: RoutingParameters) -> Self { self.routing_params = Some(routing_params); self diff --git a/crates/miden-protocol/src/errors/mod.rs b/crates/miden-protocol/src/errors/mod.rs index 329156c301..4f8309a6a8 100644 --- a/crates/miden-protocol/src/errors/mod.rs +++ b/crates/miden-protocol/src/errors/mod.rs @@ -301,10 +301,6 @@ pub enum AccountTreeError { #[derive(Debug, Error)] pub enum AddressError { - #[error("tag length {0} should be {expected} bits for network accounts", - expected = NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH - )] - CustomTagLengthNotAllowedForNetworkAccounts(u8), #[error("tag length {0} is too large, must be less than or equal to {max}", max = NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH )] @@ -320,7 +316,7 @@ pub enum AddressError { #[error("{error_msg}")] DecodeError { error_msg: Box, - // thiserror will return this when calling Error::source on NoteError. + // thiserror will return this when calling Error::source on AddressError. source: Option>, }, #[error("found unknown routing parameter key {0}")] From 1498788b66a8ca87d39b91762dfa2eedb3b1d9f4 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 29 Jan 2026 10:11:15 +0100 Subject: [PATCH 4/6] chore: add changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c85213598..89cea2c46a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ - [BREAKING] refactored `TransactionAuthenticator::get_public_key()` method to return `Arc `instead of `&PublicKey` ([#2304](https://github.com/0xMiden/miden-base/pull/2304)). - [BREAKING] Renamed `NoteInputs` to `NoteStorage` to better reflect that values are stored data associated with a note rather than inputs ([#1662](https://github.com/0xMiden/miden-base/issues/1662), [#2316](https://github.com/0xMiden/miden-base/issues/2316)). - Removed `NoteType::Encrypted` ([#2315](https://github.com/0xMiden/miden-base/pull/2315)). -- Updated note tag length to support up to 32 bits ([#2329](https://github.com/0xMiden/miden-base/pull/2329)). +- [BREAKING] Updated note tag length to support up to 32 bits ([#2329](https://github.com/0xMiden/miden-base/pull/2329)). +- [BREAKING] Added `miden::standards::note_tag` module for account target note tags ([#2366](https://github.com/0xMiden/miden-base/pull/2366)). ## 0.13.3 (2026-01-27) From 56081c43e9919709fae70562d6af6e8d6b79a908 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 29 Jan 2026 10:15:45 +0100 Subject: [PATCH 5/6] fix: docs and use constants instead of magic numbers --- crates/miden-protocol/src/address/mod.rs | 7 ++++--- crates/miden-protocol/src/address/routing_parameters.rs | 4 ++-- crates/miden-protocol/src/note/note_tag.rs | 6 ++++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/crates/miden-protocol/src/address/mod.rs b/crates/miden-protocol/src/address/mod.rs index 1804f56c3f..06e3ceba6a 100644 --- a/crates/miden-protocol/src/address/mod.rs +++ b/crates/miden-protocol/src/address/mod.rs @@ -98,7 +98,7 @@ impl Address { /// Returns the preferred tag length. /// - /// This is guaranteed to be in range `0..=32` (e.g. the maximum of + /// This is guaranteed to be in range `0..=32` (i.e. at most /// [`NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH `]). pub fn note_tag_len(&self) -> u8 { self.routing_params @@ -495,10 +495,11 @@ mod tests { .build_with_rng(&mut rand::rng()); let address = Address::new(account_id).with_routing_parameters( - RoutingParameters::new(AddressInterface::BasicWallet).with_note_tag_len(32)?, + RoutingParameters::new(AddressInterface::BasicWallet) + .with_note_tag_len(NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH)?, ); - assert_eq!(address.note_tag_len(), 32); + assert_eq!(address.note_tag_len(), NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH); Ok(()) } diff --git a/crates/miden-protocol/src/address/routing_parameters.rs b/crates/miden-protocol/src/address/routing_parameters.rs index 24789f8acf..c10d8792d2 100644 --- a/crates/miden-protocol/src/address/routing_parameters.rs +++ b/crates/miden-protocol/src/address/routing_parameters.rs @@ -107,8 +107,8 @@ impl RoutingParameters { /// Returns the note tag length preference. /// - /// This is guaranteed to be in range `0..=32` (e.g. the maximum of - /// [`NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH`]). + /// This is guaranteed to be in range `0..=32` (i.e. at most + /// [`NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH `]). pub fn note_tag_len(&self) -> Option { self.note_tag_len } diff --git a/crates/miden-protocol/src/note/note_tag.rs b/crates/miden-protocol/src/note/note_tag.rs index 65b0b306d4..1378ab2d77 100644 --- a/crates/miden-protocol/src/note/note_tag.rs +++ b/crates/miden-protocol/src/note/note_tag.rs @@ -249,9 +249,11 @@ mod tests { #[test] fn from_custom_account_target() -> anyhow::Result<()> { let account_id = AccountId::try_from(ACCOUNT_ID_SENDER)?; - let len = 32; - let tag = NoteTag::with_custom_account_target(account_id, len)?; + let tag = NoteTag::with_custom_account_target( + account_id, + NoteTag::MAX_ACCOUNT_TARGET_TAG_LENGTH, + )?; assert_eq!( (account_id.prefix().as_u64() >> 32) as u32, From 2fdcdad1bcbcd9a2591801f5486d05ebdfec80cb Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 30 Jan 2026 09:10:17 +0100 Subject: [PATCH 6/6] chore: add note on meaning of tag length --- crates/miden-standards/asm/standards/note_tag/mod.masm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/miden-standards/asm/standards/note_tag/mod.masm b/crates/miden-standards/asm/standards/note_tag/mod.masm index f814a186a0..f13b0556d3 100644 --- a/crates/miden-standards/asm/standards/note_tag/mod.masm +++ b/crates/miden-standards/asm/standards/note_tag/mod.masm @@ -41,6 +41,8 @@ end #! The tag is a u32 constructed by taking the `tag_len` most significant bits of the account ID #! prefix and setting the remaining bits to zero. #! +#! See the Rust `NoteTag` documentation for what changing the tag length means. +#! #! Inputs: [tag_len, account_id_prefix] #! Outputs: [note_tag] #!