miden-protocol 0.16.0-alpha.4

Core components of the Miden protocol
Documentation
# ERRORS
# =================================================================================================

const ERR_ACCOUNT_ID_UNKNOWN_VERSION = "unknown version in account ID"

const ERR_ACCOUNT_ID_SUFFIX_MOST_SIGNIFICANT_BIT_MUST_BE_ZERO =
    "most significant bit of the account ID suffix must be zero"

const ERR_ACCOUNT_ID_SUFFIX_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO =
    "least significant byte of the account ID suffix must be zero"

const ERR_ACCOUNT_ID_VERSION_MUST_BE_NONZERO = "account ID version must be non-zero"

# CONSTANTS
# =================================================================================================

# Given the least significant 32 bits of an account id's prefix, this mask defines the bits used
# to determine the account version.
const ACCOUNT_VERSION_MASK_U32 = 0x0f # 0b1111

# Given the least significant 32 bits of an account id's prefix, this mask defines the bit used to
# determine whether assets issued by the account trigger callbacks.
const ACCOUNT_ASSET_CALLBACK_FLAG_MASK_U32 = 0x20 # 0b10_0000

# Version 1 of the account ID.
const VERSION_1 = 1

# PROCEDURES
# =================================================================================================

#! Returns a boolean indicating whether the given account_ids are equal.
#!
#! Inputs:  [account_id_suffix, account_id_prefix, other_account_id_suffix, other_account_id_prefix]
#! Outputs: [is_id_equal]
#!
#! Where:
#! - account_id_{suffix,prefix} are the suffix and prefix felts of an account ID.
#! - other_account_id_{suffix,prefix} are the suffix and prefix felts of the other account ID to
#!   compare against.
#! - is_id_equal is a boolean indicating whether the account IDs are equal.
pub proc eq
    movup.2 eq
    # => [is_suffix_equal, account_id_prefix, other_account_id_prefix]
    movdn.2 eq
    # => [is_prefix_equal, is_suffix_equal]
    and
    # => [is_id_equal]
end

#! Returns a boolean indicating whether the given account ID is the zero address `(0, 0)`, without
#! consuming the ID.
#!
#! The zero address is not a valid account ID, so this can be used to detect an unassigned or
#! cleared account ID.
#!
#! Inputs:  [account_id_suffix, account_id_prefix]
#! Outputs: [is_zero, account_id_suffix, account_id_prefix]
#!
#! Where:
#! - account_id_{suffix,prefix} are the suffix and prefix felts of the account ID.
#! - is_zero is a boolean indicating whether the account ID is the zero address.
pub proc testz
    dup.1 eq.0 dup.1 eq.0 and
    # => [is_zero, account_id_suffix, account_id_prefix]
end

#! Returns a boolean indicating whether the given account ID is the zero ID, consuming the inputs.
#!
#! Inputs:  [account_id_suffix, account_id_prefix]
#! Outputs: [is_zero]
#!
#! Where:
#! - account_id_{suffix,prefix} are the suffix and prefix felts of an account ID.
#! - is_zero is a boolean indicating whether both felts of the account ID are zero.
pub proc eqz
    eq.0 swap eq.0 and
    # => [is_zero]
end

#! Validates the structural requirements of an account ID, independent of its version.
#!
#! Note that this does not validate anything about the account type, since any 1-bit pattern is a
#! valid account type, and it does not constrain the account ID version beyond requiring it to be
#! non-zero so that the zero account ID remains invalid.
#!
#! Inputs:  [account_id_suffix, account_id_prefix]
#! Outputs: []
#!
#! Where:
#! - account_id_{suffix,prefix} are the suffix and prefix felts of the account ID.
#!
#! Panics if:
#! - account_id_prefix has a zero version.
#! - account_id_suffix does not have its most significant bit set to zero.
#! - account_id_suffix does not have its lower 8 bits set to zero.
pub proc validate_structure
    # Validate the version is non-zero, so that the zero account ID remains invalid.
    # ---------------------------------------------------------------------------------------------
    dup.1 exec.id_version neq.0
    # => [is_version_nonzero, account_id_suffix, account_id_prefix]
    assert.err=ERR_ACCOUNT_ID_VERSION_MUST_BE_NONZERO
    # => [account_id_suffix, account_id_prefix]

    # Validate lower 8 bits of suffix are zero.
    # ---------------------------------------------------------------------------------------------

    u32split
    # => [account_id_suffix_lo, account_id_suffix_hi, account_id_prefix]
    u32and.0xff eq.0
    # => [is_least_significant_byte_zero, account_id_suffix_hi, account_id_prefix]
    assert.err=ERR_ACCOUNT_ID_SUFFIX_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO
    # => [account_id_suffix_hi, account_id_prefix]

    # Validate most significant bit in suffix is zero.
    # ---------------------------------------------------------------------------------------------

    u32shr.31 eq.0
    # => [is_most_significant_bit_zero, account_id_prefix]
    assert.err=ERR_ACCOUNT_ID_SUFFIX_MOST_SIGNIFICANT_BIT_MUST_BE_ZERO
    # => [account_id_prefix]

    drop
    # => []
end

#! Validates an account ID, including that its version is supported.
#!
#! Note that this does not validate anything about the account type, since any 1-bit pattern is a
#! valid account type.
#!
#! Inputs:  [account_id_suffix, account_id_prefix]
#! Outputs: []
#!
#! Where:
#! - account_id_{suffix,prefix} are the suffix and prefix felts of the account ID.
#!
#! Panics if:
#! - account_id_prefix does not contain version one.
#! - account_id_suffix does not have its most significant bit set to zero.
#! - account_id_suffix does not have its lower 8 bits set to zero.
pub proc validate
    # Validate version in prefix. For now only version 1 is supported.
    # ---------------------------------------------------------------------------------------------
    dup.1 exec.id_version
    # => [id_version, account_id_suffix, account_id_prefix]
    eq.VERSION_1
    # => [is_supported_version, account_id_suffix, account_id_prefix]
    assert.err=ERR_ACCOUNT_ID_UNKNOWN_VERSION
    # => [account_id_suffix, account_id_prefix]

    exec.validate_structure
    # => []
end

#! Shapes the suffix so it meets the requirements of the account ID, by setting the lower 8 bits to
#! zero.
#!
#! Inputs:  [seed_digest_suffix]
#! Outputs: [account_id_suffix]
#!
#! Where:
#! - seed_digest_suffix is the suffix of the digest that should be shaped into the suffix
#!   of an account ID.
#! - account_id_suffix is the suffix of an account ID.
pub proc shape_suffix
    u32split
    # => [seed_digest_suffix_lo, seed_digest_suffix_hi]

    # clear lower 8 bits of the lo part
    u32and.0xffffff00 swap
    # => [seed_digest_suffix_hi, seed_digest_suffix_lo']

    # reassemble the suffix by multiplying the hi part with 2^32 and adding the lo part
    mul.0x0100000000 add
    # => [account_id_suffix]
end

# HELPER PROCEDURES
# =================================================================================================

#! Extracts the account ID version from the prefix of an account ID.
#!
#! Inputs:  [account_id_prefix]
#! Outputs: [id_version]
#!
#! Where:
#! - account_id_prefix is the prefix of an account ID.
#! - id_version is the version number of the ID.
proc id_version
    # extract the lower 32 bits
    u32split swap drop
    # => [account_id_prefix_lo]

    # mask out the version
    u32and.ACCOUNT_VERSION_MASK_U32
    # => [id_version]
end

#! Returns a boolean indicating whether assets issued by the account trigger callbacks.
#!
#! Inputs:  [account_id_prefix]
#! Outputs: [has_callbacks]
#!
#! Where:
#! - account_id_prefix is the prefix of an account ID.
#! - has_callbacks is a boolean indicating whether the account's assets trigger callbacks.
pub proc asset_callback_flag
    # extract the lower 32 bits
    u32split swap drop
    # => [account_id_prefix_lo]

    # mask out the asset callback flag bit and reduce it to a boolean
    u32and.ACCOUNT_ASSET_CALLBACK_FLAG_MASK_U32 neq.0
    # => [has_callbacks]
end