use miden_crypto::merkle::smt::LeafIndex;
use super::AccountId;
use crate::Word;
use crate::crypto::merkle::smt::SMT_DEPTH;
use crate::errors::AccountIdError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AccountIdKey(AccountId);
impl AccountIdKey {
const KEY_SUFFIX_IDX: usize = 2;
const KEY_PREFIX_IDX: usize = 3;
pub fn new(id: AccountId) -> Self {
Self(id)
}
pub fn account_id(&self) -> AccountId {
self.0
}
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
}
pub fn try_from_word(word: Word) -> Result<AccountId, AccountIdError> {
AccountId::try_from_elements(word[Self::KEY_SUFFIX_IDX], word[Self::KEY_PREFIX_IDX])
}
pub fn to_leaf_index(&self) -> LeafIndex<SMT_DEPTH> {
LeafIndex::from(self.as_word())
}
}
impl From<AccountId> for AccountIdKey {
fn from(id: AccountId) -> Self {
Self(id)
}
}
#[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);
}
}
}