# 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