miden-protocol 0.15.0

Core components of the Miden protocol
Documentation
use alloc::vec::Vec;

use crate::account::account_id::AccountIdVersion;
use crate::account::account_id::v1::{compute_digest, validate_prefix};
use crate::account::{AccountIdV1, AccountType};
use crate::errors::AccountError;
use crate::{Felt, Word};

/// Finds and returns a seed suitable for creating an account ID for the specified account type
/// using the provided initial seed as a starting point.
///
/// This currently always uses a single thread. This method used to either use a single- or
/// multi-threaded implementation based on a compile-time feature flag. The multi-threaded
/// implementation was removed in commit dab6159318832fc537bb35abf251870a9129ac8c in PR 1061.
pub(super) fn compute_account_seed(
    init_seed: [u8; 32],
    account_type: AccountType,
    version: AccountIdVersion,
    code_commitment: Word,
    storage_commitment: Word,
) -> Result<Word, AccountError> {
    compute_account_seed_single(
        init_seed,
        account_type,
        version,
        code_commitment,
        storage_commitment,
    )
}

fn compute_account_seed_single(
    init_seed: [u8; 32],
    account_type: AccountType,
    version: AccountIdVersion,
    code_commitment: Word,
    storage_commitment: Word,
) -> Result<Word, AccountError> {
    let init_seed: Vec<[u8; 8]> =
        init_seed.chunks(8).map(|chunk| chunk.try_into().unwrap()).collect();
    let mut current_seed: Word = Word::from([
        Felt::new_unchecked(u64::from_le_bytes(init_seed[0])),
        Felt::new_unchecked(u64::from_le_bytes(init_seed[1])),
        Felt::new_unchecked(u64::from_le_bytes(init_seed[2])),
        Felt::new_unchecked(u64::from_le_bytes(init_seed[3])),
    ]);
    let mut current_digest = compute_digest(current_seed, code_commitment, storage_commitment);

    // loop until we have a seed that satisfies the specified account parameters.
    loop {
        // Check if the seed satisfies the specified account type and version. Additionally, the
        // most significant bit of the suffix must be zero to ensure felt validity.
        let suffix = current_digest[AccountIdV1::SEED_DIGEST_SUFFIX_ELEMENT_IDX];
        let prefix = current_digest[AccountIdV1::SEED_DIGEST_PREFIX_ELEMENT_IDX];
        let is_suffix_msb_zero = suffix.as_canonical_u64() >> 63 == 0;

        if let Ok((computed_account_type, computed_version)) = validate_prefix(prefix)
            && computed_account_type == account_type
            && computed_version == version
            && is_suffix_msb_zero
        {
            return Ok(current_seed);
        };

        current_seed = current_digest;
        current_digest = compute_digest(current_seed, code_commitment, storage_commitment);
    }
}