diff --git a/CHANGELOG.md b/CHANGELOG.md index abce5d8cf3..74fe23ee70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ - [BREAKING] Renamed `AccountHeader::commitment`, `Account::commitment` and `PartialAccount::commitment` to `to_commitment` ([#2442](https://github.com/0xMiden/miden-base/pull/2442)). - [BREAKING] Remove `BlockSigner` trait ([#2447](https://github.com/0xMiden/miden-base/pull/2447)). - Updated account schema commitment construction to accept borrowed schema iterators; added extension trait to enable `AccountBuilder::with_schema_commitment()` helper ([#2419](https://github.com/0xMiden/miden-base/pull/2419)). +- Introducing a dedicated AccountIdKey type to unify and centralize all AccountId → SMT and advice-map key conversions ([#2495](https://github.com/0xMiden/miden-base/pull/2495)). - [BREAKING] Renamed `SchemaTypeId` to `SchemaType` ([#2494](https://github.com/0xMiden/miden-base/pull/2494)). - Updated stale `miden-base` references to `protocol` across docs, READMEs, code comments, and Cargo.toml repository URL ([#2503](https://github.com/0xMiden/protocol/pull/2503)). - [BREAKING] Reverse the order of the transaction summary on the stack ([#2512](https://github.com/0xMiden/miden-base/pull/2512)). diff --git a/crates/miden-protocol/src/block/account_tree/account_id_key.rs b/crates/miden-protocol/src/block/account_tree/account_id_key.rs new file mode 100644 index 0000000000..277b083978 --- /dev/null +++ b/crates/miden-protocol/src/block/account_tree/account_id_key.rs @@ -0,0 +1,158 @@ +use miden_crypto::merkle::smt::LeafIndex; + +use super::AccountId; +use crate::Word; +use crate::block::account_tree::AccountIdPrefix; +use crate::crypto::merkle::smt::SMT_DEPTH; +use crate::errors::AccountIdError; + +/// The account ID encoded as a key for use in AccountTree and advice maps in +/// `TransactionAdviceInputs`. +/// +/// Canonical word layout: +/// +/// [0, 0, suffix, prefix] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AccountIdKey(AccountId); + +impl AccountIdKey { + // Indices in the word layout where the prefix and suffix are stored. + const KEY_SUFFIX_IDX: usize = 2; + const KEY_PREFIX_IDX: usize = 3; + + /// Create from AccountId + pub fn new(id: AccountId) -> Self { + Self(id) + } + + /// Returns the underlying AccountId + pub fn account_id(&self) -> AccountId { + self.0 + } + + // SMT WORD REPRESENTATION + //--------------------------------------------------------------------------------------------------- + + /// Returns `[0, 0, suffix, prefix]` + pub fn as_word(&self) -> Word { + let mut key = Word::empty(); + + key[Self::KEY_SUFFIX_IDX] = self.0.suffix(); + key[Self::KEY_PREFIX_IDX] = self.0.prefix().as_felt(); + + key + } + + /// Construct from SMT word representation. + /// + /// Validates structure before converting. + pub fn try_from_word(word: Word) -> Result { + AccountId::try_from_elements(word[Self::KEY_SUFFIX_IDX], word[Self::KEY_PREFIX_IDX]) + } + + // LEAF INDEX + //--------------------------------------------------------------------------------------------------- + + /// Converts to SMT leaf index used by AccountTree + pub fn to_leaf_index(&self) -> LeafIndex { + LeafIndex::from(self.as_word()) + } + +} + +impl From for AccountIdKey { + fn from(id: AccountId) -> Self { + Self(id) + } +} + +// TESTS +//--------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + + use miden_core::ZERO; + + use super::{AccountId, *}; + use crate::account::{AccountIdVersion, AccountStorageMode, AccountType}; + #[test] + fn test_as_word_layout() { + let id = AccountId::dummy( + [1u8; 15], + AccountIdVersion::Version0, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Private, + ); + let key = AccountIdKey::from(id); + let word = key.as_word(); + + assert_eq!(word[0], ZERO); + assert_eq!(word[1], ZERO); + assert_eq!(word[2], id.suffix()); + assert_eq!(word[3], id.prefix().as_felt()); + } + + #[test] + fn test_roundtrip_word_conversion() { + let id = AccountId::dummy( + [1u8; 15], + AccountIdVersion::Version0, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Private, + ); + + let key = AccountIdKey::from(id); + let recovered = + AccountIdKey::try_from_word(key.as_word()).expect("valid account id conversion"); + + assert_eq!(id, recovered); + } + + #[test] + fn test_leaf_index_consistency() { + let id = AccountId::dummy( + [1u8; 15], + AccountIdVersion::Version0, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Private, + ); + let key = AccountIdKey::from(id); + + let idx1 = key.to_leaf_index(); + let idx2 = key.to_leaf_index(); + + assert_eq!(idx1, idx2); + } + + #[test] + fn test_from_conversion() { + let id = AccountId::dummy( + [1u8; 15], + AccountIdVersion::Version0, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Private, + ); + let key: AccountIdKey = id.into(); + + assert_eq!(key.account_id(), id); + } + + #[test] + fn test_multiple_roundtrips() { + for _ in 0..100 { + let id = AccountId::dummy( + [1u8; 15], + AccountIdVersion::Version0, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Private, + ); + let key = AccountIdKey::from(id); + + let recovered = + AccountIdKey::try_from_word(key.as_word()).expect("valid account id conversion"); + + assert_eq!(id, recovered); + } + } +} diff --git a/crates/miden-protocol/src/block/account_tree/backend.rs b/crates/miden-protocol/src/block/account_tree/backend.rs index 67995decfa..58963f0e44 100644 --- a/crates/miden-protocol/src/block/account_tree/backend.rs +++ b/crates/miden-protocol/src/block/account_tree/backend.rs @@ -1,7 +1,7 @@ use alloc::boxed::Box; use alloc::vec::Vec; -use super::{AccountId, AccountIdPrefix, AccountTree, AccountTreeError, account_id_to_smt_key}; +use super::{AccountId, AccountIdKey, AccountIdPrefix, AccountTree, AccountTreeError}; use crate::Word; use crate::crypto::merkle::MerkleError; #[cfg(feature = "std")] @@ -203,7 +203,7 @@ impl AccountTree { let smt = Smt::with_entries( entries .into_iter() - .map(|(id, commitment)| (account_id_to_smt_key(id), commitment)), + .map(|(id, commitment)| (AccountIdKey::from(id).as_word(), commitment)), ) .map_err(|err| { let MerkleError::DuplicateValuesForIndex(leaf_idx) = err else { diff --git a/crates/miden-protocol/src/block/account_tree/mod.rs b/crates/miden-protocol/src/block/account_tree/mod.rs index 87c6fea85a..e594684be1 100644 --- a/crates/miden-protocol/src/block/account_tree/mod.rs +++ b/crates/miden-protocol/src/block/account_tree/mod.rs @@ -1,8 +1,6 @@ use alloc::string::ToString; use alloc::vec::Vec; -use miden_crypto::merkle::smt::LeafIndex; - use crate::Word; use crate::account::{AccountId, AccountIdPrefix}; use crate::crypto::merkle::MerkleError; @@ -25,39 +23,8 @@ pub use witness::AccountWitness; mod backend; pub use backend::AccountTreeBackend; -// FREE HELPER FUNCTIONS -// ================================================================================================ -// These module-level functions provide conversions between AccountIds and SMT keys. -// They avoid the need for awkward syntax like account_id_to_smt_key(). - -const KEY_SUFFIX_IDX: usize = 2; -const KEY_PREFIX_IDX: usize = 3; - -/// Converts an [`AccountId`] to an SMT key for use in account trees. -/// -/// The key is constructed with the account ID suffix at index 2 and prefix at index 3. -pub fn account_id_to_smt_key(account_id: AccountId) -> Word { - let mut key = Word::empty(); - key[KEY_SUFFIX_IDX] = account_id.suffix(); - key[KEY_PREFIX_IDX] = account_id.prefix().as_felt(); - key -} - -/// Recovers an [`AccountId`] from an SMT key. -/// -/// # Panics -/// -/// Panics if the key does not represent a valid account ID. This should never happen when used -/// with keys from account trees, as the tree only stores valid IDs. -pub fn smt_key_to_account_id(key: Word) -> AccountId { - AccountId::try_from_elements(key[KEY_SUFFIX_IDX], key[KEY_PREFIX_IDX]) - .expect("account tree should only contain valid IDs") -} - -/// Converts an AccountId to an SMT leaf index for use with MerkleStore operations. -pub fn account_id_to_smt_index(account_id: AccountId) -> LeafIndex { - account_id_to_smt_key(account_id).into() -} +mod account_id_key; +pub use account_id_key::AccountIdKey; // ACCOUNT TREE // ================================================================================================ @@ -110,7 +77,8 @@ where /// # Errors /// /// Returns an error if: - /// - The SMT contains duplicate account ID prefixes + /// - The SMT contains invalid account IDs. + /// - The SMT contains duplicate account ID prefixes. pub fn new(smt: S) -> Result { for (_leaf_idx, leaf) in smt.leaves() { match leaf { @@ -120,13 +88,19 @@ where }, SmtLeaf::Single((key, _)) => { // Single entry is good - verify it's a valid account ID - smt_key_to_account_id(key); + AccountIdKey::try_from_word(key).map_err(|err| { + AccountTreeError::InvalidAccountIdKey { key, source: err } + })?; }, SmtLeaf::Multiple(entries) => { // Multiple entries means duplicate prefixes // Extract one of the keys to identify the duplicate prefix if let Some((key, _)) = entries.first() { - let account_id = smt_key_to_account_id(*key); + let key = *key; + let account_id = AccountIdKey::try_from_word(key).map_err(|err| { + AccountTreeError::InvalidAccountIdKey { key, source: err } + })?; + return Err(AccountTreeError::DuplicateIdPrefix { duplicate_prefix: account_id.prefix(), }); @@ -164,7 +138,7 @@ where /// /// Panics if the SMT backend fails to open the leaf (only possible with `LargeSmt` backend). pub fn open(&self, account_id: AccountId) -> AccountWitness { - let key = account_id_to_smt_key(account_id); + let key = AccountIdKey::from(account_id).as_word(); let proof = self.smt.open(&key); AccountWitness::from_smt_proof(account_id, proof) @@ -172,7 +146,7 @@ where /// Returns the current state commitment of the given account ID. pub fn get(&self, account_id: AccountId) -> Word { - let key = account_id_to_smt_key(account_id); + let key = AccountIdKey::from(account_id).as_word(); self.smt.get_value(&key) } @@ -240,7 +214,7 @@ where .compute_mutations(Vec::from_iter( account_commitments .into_iter() - .map(|(id, commitment)| (account_id_to_smt_key(id), commitment)), + .map(|(id, commitment)| (AccountIdKey::from(id).as_word(), commitment)), )) .map_err(AccountTreeError::ComputeMutations)?; @@ -254,7 +228,9 @@ where // valid. If it does not match, then we would insert a duplicate. if existing_key != *id_key { return Err(AccountTreeError::DuplicateIdPrefix { - duplicate_prefix: smt_key_to_account_id(*id_key).prefix(), + duplicate_prefix: AccountIdKey::try_from_word(*id_key) + .expect("account tree should only contain valid IDs") + .prefix(), }); } }, @@ -287,7 +263,7 @@ where account_id: AccountId, state_commitment: Word, ) -> Result { - let key = account_id_to_smt_key(account_id); + let key = AccountIdKey::from(account_id).as_word(); // SAFETY: account tree should not contain multi-entry leaves and so the maximum number // of entries per leaf should never be exceeded. let prev_value = self.smt.insert(key, state_commitment) @@ -378,9 +354,10 @@ impl Deserializable for AccountTree { } // Create the SMT with validated entries - let smt = - Smt::with_entries(entries.into_iter().map(|(k, v)| (account_id_to_smt_key(k), v))) - .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?; + let smt = Smt::with_entries( + entries.into_iter().map(|(k, v)| (AccountIdKey::from(k).as_word(), v)), + ) + .map_err(|err| DeserializationError::InvalidValue(err.to_string()))?; Ok(Self::new_unchecked(smt)) } } @@ -562,7 +539,7 @@ pub(super) mod tests { assert_eq!(tree.num_accounts(), 2); for id in [id0, id1] { - let proof = tree.smt.open(&account_id_to_smt_key(id)); + let proof = tree.smt.open(&AccountIdKey::from(id).as_word()); let (control_path, control_leaf) = proof.into_parts(); let witness = tree.open(id); @@ -606,7 +583,10 @@ pub(super) mod tests { // Create AccountTree with LargeSmt backend let tree = LargeSmt::::with_entries( MemoryStorage::default(), - [(account_id_to_smt_key(id0), digest0), (account_id_to_smt_key(id1), digest1)], + [ + (AccountIdKey::from(id0).as_word(), digest0), + (AccountIdKey::from(id1).as_word(), digest1), + ], ) .map(AccountTree::new_unchecked) .unwrap(); @@ -623,7 +603,10 @@ pub(super) mod tests { // Test mutations let mut tree_mut = LargeSmt::::with_entries( MemoryStorage::default(), - [(account_id_to_smt_key(id0), digest0), (account_id_to_smt_key(id1), digest1)], + [ + (AccountIdKey::from(id0).as_word(), digest0), + (AccountIdKey::from(id1).as_word(), digest1), + ], ) .map(AccountTree::new_unchecked) .unwrap(); @@ -672,7 +655,10 @@ pub(super) mod tests { let mut tree = LargeSmt::with_entries( MemoryStorage::default(), - [(account_id_to_smt_key(id0), digest0), (account_id_to_smt_key(id1), digest1)], + [ + (AccountIdKey::from(id0).as_word(), digest0), + (AccountIdKey::from(id1).as_word(), digest1), + ], ) .map(AccountTree::new_unchecked) .unwrap(); @@ -703,7 +689,10 @@ pub(super) mod tests { // Create tree with LargeSmt backend let large_tree = LargeSmt::with_entries( MemoryStorage::default(), - [(account_id_to_smt_key(id0), digest0), (account_id_to_smt_key(id1), digest1)], + [ + (AccountIdKey::from(id0).as_word(), digest0), + (AccountIdKey::from(id1).as_word(), digest1), + ], ) .map(AccountTree::new_unchecked) .unwrap(); diff --git a/crates/miden-protocol/src/block/account_tree/partial.rs b/crates/miden-protocol/src/block/account_tree/partial.rs index 653ba18cbc..f663bf5405 100644 --- a/crates/miden-protocol/src/block/account_tree/partial.rs +++ b/crates/miden-protocol/src/block/account_tree/partial.rs @@ -1,6 +1,6 @@ use miden_crypto::merkle::smt::{PartialSmt, SmtLeaf}; -use super::{AccountWitness, account_id_to_smt_key}; +use super::{AccountIdKey, AccountWitness}; use crate::Word; use crate::account::AccountId; use crate::errors::AccountTreeError; @@ -68,7 +68,7 @@ impl PartialAccountTree { /// Returns an error if: /// - the account ID is not tracked by this account tree. pub fn open(&self, account_id: AccountId) -> Result { - let key = account_id_to_smt_key(account_id); + let key = AccountIdKey::from(account_id).as_word(); self.smt .open(&key) @@ -83,7 +83,7 @@ impl PartialAccountTree { /// Returns an error if: /// - the account ID is not tracked by this account tree. pub fn get(&self, account_id: AccountId) -> Result { - let key = account_id_to_smt_key(account_id); + let key = AccountIdKey::from(account_id).as_word(); self.smt .get_value(&key) .map_err(|source| AccountTreeError::UntrackedAccountId { id: account_id, source }) @@ -109,7 +109,7 @@ impl PartialAccountTree { /// witness. pub fn track_account(&mut self, witness: AccountWitness) -> Result<(), AccountTreeError> { let id_prefix = witness.id().prefix(); - let id_key = account_id_to_smt_key(witness.id()); + let id_key = AccountIdKey::from(witness.id()).as_word(); // If a leaf with the same prefix is already tracked by this partial tree, consider it an // error. @@ -165,7 +165,7 @@ impl PartialAccountTree { account_id: AccountId, state_commitment: Word, ) -> Result { - let key = account_id_to_smt_key(account_id); + let key = AccountIdKey::from(account_id).as_word(); // If there exists a tracked leaf whose key is _not_ the one we're about to overwrite, then // we would insert the new commitment next to an existing account ID with the same prefix, @@ -281,14 +281,14 @@ mod tests { // account IDs with the same prefix. let full_tree = Smt::with_entries( setup_duplicate_prefix_ids() - .map(|(id, commitment)| (account_id_to_smt_key(id), commitment)), + .map(|(id, commitment)| (AccountIdKey::from(id).as_word(), commitment)), ) .unwrap(); let [(id0, _), (id1, _)] = setup_duplicate_prefix_ids(); - let key0 = account_id_to_smt_key(id0); - let key1 = account_id_to_smt_key(id1); + let key0 = AccountIdKey::from(id0).as_word(); + let key1 = AccountIdKey::from(id1).as_word(); let proof0 = full_tree.open(&key0); let proof1 = full_tree.open(&key1); assert_eq!(proof0.leaf(), proof1.leaf()); diff --git a/crates/miden-protocol/src/block/account_tree/witness.rs b/crates/miden-protocol/src/block/account_tree/witness.rs index 8c819fc86c..98be6b8310 100644 --- a/crates/miden-protocol/src/block/account_tree/witness.rs +++ b/crates/miden-protocol/src/block/account_tree/witness.rs @@ -1,11 +1,11 @@ use alloc::string::ToString; -use miden_crypto::merkle::smt::{LeafIndex, SMT_DEPTH, SmtLeaf, SmtProof, SmtProofError}; +use miden_crypto::merkle::smt::{SMT_DEPTH, SmtLeaf, SmtProof, SmtProofError}; use miden_crypto::merkle::{InnerNodeInfo, SparseMerklePath}; use crate::Word; use crate::account::AccountId; -use crate::block::account_tree::{account_id_to_smt_key, smt_key_to_account_id}; +use crate::block::account_tree::AccountIdKey; use crate::errors::AccountTreeError; use crate::utils::serde::{ ByteReader, @@ -74,6 +74,7 @@ impl AccountWitness { /// # Panics /// /// Panics if: + /// - the proof contains an entry whose key contains an invalid account ID. /// - the merkle path in the proof does not have depth equal to [`SMT_DEPTH`]. /// - the proof contains an SmtLeaf::Multiple. pub(super) fn from_smt_proof(requested_account_id: AccountId, proof: SmtProof) -> Self { @@ -89,7 +90,8 @@ impl AccountWitness { SmtLeaf::Empty(_) => requested_account_id, SmtLeaf::Single((key_in_leaf, _)) => { // SAFETY: By construction, the tree only contains valid IDs. - smt_key_to_account_id(*key_in_leaf) + AccountIdKey::try_from_word(*key_in_leaf) + .expect("account tree should only contain valid IDs") }, SmtLeaf::Multiple(_) => { unreachable!("account tree should only contain zero or one entry per ID prefix") @@ -97,7 +99,7 @@ impl AccountWitness { }; let commitment = proof - .get(&account_id_to_smt_key(witness_id)) + .get(&AccountIdKey::from(witness_id).as_word()) .expect("we should have received a proof for the witness key"); // SAFETY: The proof is guaranteed to have depth SMT_DEPTH if it comes from one of @@ -138,10 +140,10 @@ impl AccountWitness { /// Returns the [`SmtLeaf`] of the account witness. pub fn leaf(&self) -> SmtLeaf { if self.commitment == Word::empty() { - let leaf_idx = LeafIndex::from(account_id_to_smt_key(self.id)); + let leaf_idx = AccountIdKey::from(self.id).to_leaf_index(); SmtLeaf::new_empty(leaf_idx) } else { - let key = account_id_to_smt_key(self.id); + let key = AccountIdKey::from(self.id).as_word(); SmtLeaf::new_single(key, self.commitment) } } diff --git a/crates/miden-protocol/src/errors/mod.rs b/crates/miden-protocol/src/errors/mod.rs index 2481ba51c8..8467111652 100644 --- a/crates/miden-protocol/src/errors/mod.rs +++ b/crates/miden-protocol/src/errors/mod.rs @@ -274,6 +274,8 @@ pub enum AccountTreeError { ApplyMutations(#[source] MerkleError), #[error("failed to compute account tree mutations")] ComputeMutations(#[source] MerkleError), + #[error("provided smt contains an invalid account ID in key {key}")] + InvalidAccountIdKey { key: Word, source: AccountIdError }, #[error("smt leaf's index is not a valid account ID prefix")] InvalidAccountIdPrefix(#[source] AccountIdError), #[error("account witness merkle path depth {0} does not match AccountTree::DEPTH")] diff --git a/crates/miden-protocol/src/testing/block.rs b/crates/miden-protocol/src/testing/block.rs index 1e03c32561..cb4fbc446f 100644 --- a/crates/miden-protocol/src/testing/block.rs +++ b/crates/miden-protocol/src/testing/block.rs @@ -4,7 +4,7 @@ use miden_crypto::rand::test_utils::rand_value; use crate::Word; use crate::account::Account; -use crate::block::account_tree::{AccountTree, account_id_to_smt_key}; +use crate::block::account_tree::{AccountIdKey, AccountTree}; use crate::block::{BlockHeader, BlockNumber, FeeParameters}; use crate::testing::account_id::ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET; use crate::testing::random_secret_key::random_secret_key; @@ -26,7 +26,7 @@ impl BlockHeader { let smt = Smt::with_entries( accounts .iter() - .map(|acct| (account_id_to_smt_key(acct.id()), acct.to_commitment())), + .map(|acct| (AccountIdKey::from(acct.id()).as_word(), acct.to_commitment())), ) .expect("failed to create account db"); let acct_db = AccountTree::new(smt).expect("failed to create account tree"); diff --git a/crates/miden-protocol/src/transaction/inputs/mod.rs b/crates/miden-protocol/src/transaction/inputs/mod.rs index fa7decdc57..d483fc657f 100644 --- a/crates/miden-protocol/src/transaction/inputs/mod.rs +++ b/crates/miden-protocol/src/transaction/inputs/mod.rs @@ -20,12 +20,12 @@ use crate::account::{ StorageSlotName, }; use crate::asset::{Asset, AssetVaultKey, AssetWitness, PartialVault}; -use crate::block::account_tree::{AccountWitness, account_id_to_smt_index}; +use crate::block::account_tree::{AccountIdKey, AccountWitness}; use crate::block::{BlockHeader, BlockNumber}; use crate::crypto::merkle::SparseMerklePath; use crate::errors::{TransactionInputError, TransactionInputsExtractionError}; use crate::note::{Note, NoteInclusionProof}; -use crate::transaction::{TransactionAdviceInputs, TransactionArgs, TransactionScript}; +use crate::transaction::{TransactionArgs, TransactionScript}; use crate::utils::serde::{ ByteReader, ByteWriter, @@ -365,12 +365,12 @@ impl TransactionInputs { Ok(asset) } - /// Reads AccountInputs for a foreign account from the advice inputs. + /// Reads `AccountInputs` for a foreign account from the advice inputs. /// - /// This function reverses the process of [`TransactionAdviceInputs::add_foreign_accounts`] by: + /// This function reverses the process of `TransactionAdviceInputs::add_foreign_accounts` by: /// 1. Reading the account header from the advice map using the account_id_key. - /// 2. Building a PartialAccount from the header and foreign account code. - /// 3. Creating an AccountWitness. + /// 2. Building a `PartialAccount` from the header and foreign account code. + /// 3. Creating an `AccountWitness`. pub fn read_foreign_account_inputs( &self, account_id: AccountId, @@ -380,11 +380,11 @@ impl TransactionInputs { } // Read the account header elements from the advice map. - let account_id_key = TransactionAdviceInputs::account_id_map_key(account_id); + let account_id_key = AccountIdKey::from(account_id); let header_elements = self .advice_inputs .map - .get(&account_id_key) + .get(&account_id_key.as_word()) .ok_or(TransactionInputsExtractionError::ForeignAccountNotFound(account_id))?; // Parse the header from elements. @@ -450,7 +450,7 @@ impl TransactionInputs { ) -> Result { // Get the account tree root from the block header. let account_tree_root = self.block_header.account_root(); - let leaf_index: NodeIndex = account_id_to_smt_index(header.id()).into(); + let leaf_index = AccountIdKey::from(header.id()).to_leaf_index().into(); // Get the Merkle path from the merkle store. let merkle_path = self.advice_inputs.store.get_path(account_tree_root, leaf_index)?; diff --git a/crates/miden-protocol/src/transaction/inputs/tests.rs b/crates/miden-protocol/src/transaction/inputs/tests.rs index 494f46a6f6..cc2fcee7a2 100644 --- a/crates/miden-protocol/src/transaction/inputs/tests.rs +++ b/crates/miden-protocol/src/transaction/inputs/tests.rs @@ -16,6 +16,7 @@ use crate::account::{ StorageSlotType, }; use crate::asset::PartialVault; +use crate::block::account_tree::AccountIdKey; use crate::errors::TransactionInputsExtractionError; use crate::testing::account_id::{ ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE, @@ -119,9 +120,10 @@ fn test_read_foreign_account_inputs_with_storage_data() { // Create advice inputs with both account header and storage header. let mut advice_inputs = crate::vm::AdviceInputs::default(); - let account_id_key = - crate::transaction::TransactionAdviceInputs::account_id_map_key(foreign_account_id); - advice_inputs.map.insert(account_id_key, foreign_header.to_elements()); + let account_id_key = AccountIdKey::from(foreign_account_id); + advice_inputs + .map + .insert(account_id_key.as_word(), foreign_header.to_elements().to_vec()); advice_inputs .map .insert(foreign_header.storage_commitment(), foreign_storage_header.to_elements()); @@ -232,10 +234,10 @@ fn test_read_foreign_account_inputs_with_proper_witness() { let mut advice_inputs = crate::vm::AdviceInputs::default(); // Add account header to advice map. - let account_id_key = - crate::transaction::TransactionAdviceInputs::account_id_map_key(foreign_account_id); - advice_inputs.map.insert(account_id_key, foreign_header.to_elements().to_vec()); - + let account_id_key = AccountIdKey::from(foreign_account_id); + advice_inputs + .map + .insert(account_id_key.as_word(), foreign_header.to_elements().to_vec()); // Add storage header to advice map. advice_inputs .map diff --git a/crates/miden-protocol/src/transaction/kernel/advice_inputs.rs b/crates/miden-protocol/src/transaction/kernel/advice_inputs.rs index d113944288..295a3ef03b 100644 --- a/crates/miden-protocol/src/transaction/kernel/advice_inputs.rs +++ b/crates/miden-protocol/src/transaction/kernel/advice_inputs.rs @@ -2,8 +2,8 @@ use alloc::vec::Vec; use miden_processor::advice::AdviceMutation; -use crate::account::{AccountHeader, AccountId, PartialAccount}; -use crate::block::account_tree::{AccountWitness, account_id_to_smt_key}; +use crate::account::{AccountHeader, PartialAccount}; +use crate::block::account_tree::{AccountIdKey, AccountWitness}; use crate::crypto::SequentialCommit; use crate::crypto::merkle::InnerNodeInfo; use crate::note::NoteAttachmentContent; @@ -56,8 +56,8 @@ impl TransactionAdviceInputs { // If a seed was provided, extend the map appropriately. if let Some(seed) = tx_inputs.account().seed() { // ACCOUNT_ID |-> ACCOUNT_SEED - let account_id_key = Self::account_id_map_key(partial_native_acc.id()); - inputs.add_map_entry(account_id_key, seed.to_vec()); + let account_id_key = AccountIdKey::from(partial_native_acc.id()); + inputs.add_map_entry(account_id_key.as_word(), seed.to_vec()); } // if the account is new, insert the storage map entries into the advice provider. @@ -104,14 +104,6 @@ impl TransactionAdviceInputs { // PUBLIC UTILITIES // -------------------------------------------------------------------------------------------- - /// Returns the advice map key where: - /// - the seed for native accounts is stored. - /// - the account header for foreign accounts is stored. - pub fn account_id_map_key(id: AccountId) -> Word { - // The format is equivalent to the SMT key format, so we avoid defining it twice. - account_id_to_smt_key(id) - } - // MUTATORS // -------------------------------------------------------------------------------------------- @@ -131,11 +123,11 @@ impl TransactionAdviceInputs { // for foreign accounts, we need to insert the id to state mapping // NOTE: keep this in sync with the account::load_from_advice procedure - let account_id_key = Self::account_id_map_key(foreign_acc.id()); + let account_id_key = AccountIdKey::from(foreign_acc.id()); let header = AccountHeader::from(foreign_acc.account()); // ACCOUNT_ID |-> [ID_AND_NONCE, VAULT_ROOT, STORAGE_COMMITMENT, CODE_COMMITMENT] - self.add_map_entry(account_id_key, header.to_elements()); + self.add_map_entry(account_id_key.as_word(), header.to_elements()); } } diff --git a/crates/miden-testing/src/kernel_tests/tx/test_prologue.rs b/crates/miden-testing/src/kernel_tests/tx/test_prologue.rs index 76f48b7b15..3cb661b3a2 100644 --- a/crates/miden-testing/src/kernel_tests/tx/test_prologue.rs +++ b/crates/miden-testing/src/kernel_tests/tx/test_prologue.rs @@ -15,6 +15,7 @@ use miden_protocol::account::{ StorageSlotName, }; use miden_protocol::asset::{FungibleAsset, NonFungibleAsset}; +use miden_protocol::block::account_tree::AccountIdKey; use miden_protocol::errors::tx_kernel::ERR_ACCOUNT_SEED_AND_COMMITMENT_DIGEST_MISMATCH; use miden_protocol::note::NoteId; use miden_protocol::testing::account_id::{ @@ -75,12 +76,7 @@ use miden_protocol::transaction::memory::{ VALIDATOR_KEY_COMMITMENT_PTR, VERIFICATION_BASE_FEE_IDX, }; -use miden_protocol::transaction::{ - ExecutedTransaction, - TransactionAdviceInputs, - TransactionArgs, - TransactionKernel, -}; +use miden_protocol::transaction::{ExecutedTransaction, TransactionArgs, TransactionKernel}; use miden_protocol::{EMPTY_WORD, WORD_SIZE}; use miden_standards::account::wallets::BasicWallet; use miden_standards::code_builder::CodeBuilder; @@ -637,7 +633,7 @@ pub async fn create_account_invalid_seed() -> anyhow::Result<()> { .expect("failed to get transaction inputs from mock chain"); // override the seed with an invalid seed to ensure the kernel fails - let account_seed_key = TransactionAdviceInputs::account_id_map_key(account.id()); + let account_seed_key = AccountIdKey::from(account.id()).as_word(); let adv_inputs = AdviceInputs::default().with_map([(account_seed_key, vec![ZERO; WORD_SIZE])]); let tx_context = TransactionContextBuilder::new(account)