From 1c62f15e86864159f8c7f23d1019027244742c15 Mon Sep 17 00:00:00 2001 From: Andrey Khmuro Date: Tue, 3 Dec 2024 02:54:43 +0300 Subject: [PATCH 01/10] feat: implement utils lib, remove duplicated procedures from miden and kernel libs --- CHANGELOG.md | 1 + Cargo.lock | 84 +++++++++---------- miden-lib/asm/kernels/transaction/api.masm | 4 +- .../asm/kernels/transaction/lib/account.masm | 33 -------- .../asm/kernels/transaction/lib/asset.masm | 18 +--- .../kernels/transaction/lib/asset_vault.masm | 7 +- .../kernels/transaction/lib/constants.masm | 14 ---- .../asm/kernels/transaction/lib/faucet.masm | 7 +- .../asm/kernels/transaction/lib/prologue.masm | 4 +- miden-lib/asm/kernels/transaction/lib/tx.masm | 4 +- miden-lib/asm/miden/account.masm | 57 ------------- miden-lib/asm/miden/asset.masm | 25 ++---- miden-lib/asm/miden/note.masm | 23 ++--- miden-lib/asm/utils/account.masm | 53 ++++++++++++ miden-lib/asm/utils/asset.masm | 12 +++ miden-lib/asm/utils/note.masm | 12 +++ miden-lib/build.rs | 45 ++++++++-- miden-lib/src/lib.rs | 3 + miden-lib/src/transaction/mod.rs | 6 +- .../src/transaction/procedures/kernel_v0.rs | 12 +-- miden-lib/src/utils_lib.rs | 47 +++++++++++ miden-tx/src/executor/mast_store.rs | 8 +- miden-tx/src/testing/executor.rs | 3 +- .../src/tests/kernel_tests/test_account.rs | 14 ++-- 24 files changed, 270 insertions(+), 226 deletions(-) create mode 100644 miden-lib/asm/utils/account.masm create mode 100644 miden-lib/asm/utils/asset.masm create mode 100644 miden-lib/asm/utils/note.masm create mode 100644 miden-lib/src/utils_lib.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f9c94b0fa..cdd1b77ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - [BREAKING] Added `miden::note::get_script_hash` procedure (#995). - [BREAKING] Refactor error messages in `miden-lib` and `miden-tx` and use `thiserror` 2.0 (#1005). - Removed workers list from the proxy configuration file (#1018). +- [BREAKING] Moved the duplicate `masm` procedures to the `utils` module (#1002). ## 0.6.2 (2024-11-20) diff --git a/Cargo.lock b/Cargo.lock index ae5a66c47..6f270966f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,9 +117,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arc-swap" @@ -229,7 +229,7 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -262,7 +262,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", @@ -497,9 +497,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", "clap_derive 4.5.18", @@ -507,9 +507,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstream", "anstyle", @@ -621,7 +621,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.21", + "clap 4.5.22", "criterion-plot", "is-terminal", "itertools 0.10.5", @@ -990,9 +990,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb949699c3e4df3a183b1d2142cb24277057055ed23c68ed58894f76c517223" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" dependencies = [ "cfg-if", "libc", @@ -1066,7 +1066,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http 1.2.0", "indexmap 2.7.0", "slab", "tokio", @@ -1164,9 +1164,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -1191,7 +1191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -1202,7 +1202,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -1253,7 +1253,7 @@ dependencies = [ "futures-channel", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -1299,7 +1299,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "hyper 1.5.1", "pin-project-lite", @@ -1868,7 +1868,7 @@ dependencies = [ "miden-processor", "miden-stdlib", "regex", - "thiserror 2.0.3", + "thiserror 2.0.4", "walkdir", ] @@ -1931,7 +1931,7 @@ dependencies = [ "rand", "rstest", "tempfile", - "thiserror 2.0.3", + "thiserror 2.0.4", "winter-rand-utils", ] @@ -2004,7 +2004,7 @@ dependencies = [ "miden-verifier", "rand", "rand_chacha", - "thiserror 2.0.3", + "thiserror 2.0.4", "winter-maybe-async", ] @@ -2015,7 +2015,7 @@ dependencies = [ "async-trait", "axum", "bytes", - "clap 4.5.21", + "clap 4.5.22", "figment", "getrandom", "miden-lib", @@ -2384,7 +2384,7 @@ checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" dependencies = [ "async-trait", "futures-core", - "http 1.1.0", + "http 1.2.0", "opentelemetry 0.27.1", "opentelemetry-proto", "opentelemetry_sdk 0.27.1", @@ -2628,7 +2628,7 @@ dependencies = [ "blake2", "bytes", "hex", - "http 1.1.0", + "http 1.2.0", "httparse", "httpdate", "indexmap 1.9.3", @@ -2668,7 +2668,7 @@ dependencies = [ "flate2", "futures", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "httparse", "httpdate", "libc", @@ -2714,7 +2714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcb3f62d852da015e76ced56e93e6d52941679a9825281c90f2897841129e59d" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", "httparse", "pingora-error", "pingora-http", @@ -2730,7 +2730,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70202f126056f366549afc804741e12dd9f419cfc79a0063ab15653007a0f4c6" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", "pingora-error", ] @@ -2763,7 +2763,7 @@ dependencies = [ "derivative", "fnv", "futures", - "http 1.1.0", + "http 1.2.0", "log", "pingora-core", "pingora-error", @@ -2812,7 +2812,7 @@ dependencies = [ "clap 3.2.25", "futures", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "log", "once_cell", "pingora-cache", @@ -2996,9 +2996,9 @@ dependencies = [ [[package]] name = "prost-reflect" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7535b02f0e5efe3e1dbfcb428be152226ed0c66cad9541f2274c8ba8d4cd40" +checksum = "20ae544fca2892fd4b7e9ff26cba1090cedf1d4d95c2aded1af15d2f93f270b8" dependencies = [ "logos", "miette", @@ -3850,11 +3850,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.4", ] [[package]] @@ -3870,9 +3870,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" dependencies = [ "proc-macro2", "quote", @@ -4015,9 +4015,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -4072,7 +4072,7 @@ dependencies = [ "base64 0.22.1", "bytes", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -4125,7 +4125,7 @@ checksum = "5299dd20801ad736dccb4a5ea0da7376e59cd98f213bf1c3d478cf53f4834b58" dependencies = [ "base64 0.22.1", "bytes", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "pin-project", @@ -4147,7 +4147,7 @@ dependencies = [ "byteorder", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "httparse", @@ -4206,7 +4206,7 @@ checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "bitflags 2.6.0", "bytes", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "pin-project-lite", diff --git a/miden-lib/asm/kernels/transaction/api.masm b/miden-lib/asm/kernels/transaction/api.masm index 79f4dfdef..af6fba824 100644 --- a/miden-lib/asm/kernels/transaction/api.masm +++ b/miden-lib/asm/kernels/transaction/api.masm @@ -1,6 +1,8 @@ use.std::collections::smt use.std::sys +use.utils::account->account_utils + use.kernel::account use.kernel::asset_vault use.kernel::constants @@ -818,7 +820,7 @@ end #! Invocation: dynexec export.get_fungible_faucet_total_issuance # assert that we are executing a transaction against a fungible faucet (access checks) - exec.account::get_id exec.account::is_fungible_faucet + exec.account::get_id exec.account_utils::is_fungible_faucet assert.err=ERR_ACCOUNT_TOTAL_ISSUANCE_PROC_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_FAUCET # => [pad(16)] diff --git a/miden-lib/asm/kernels/transaction/lib/account.masm b/miden-lib/asm/kernels/transaction/lib/account.masm index e0e29b956..93fb610c0 100644 --- a/miden-lib/asm/kernels/transaction/lib/account.masm +++ b/miden-lib/asm/kernels/transaction/lib/account.masm @@ -81,13 +81,6 @@ const.REGULAR_ACCOUNT_IMMUTABLE_CODE=0 # 0b00000000_00000000_00000000_00000000 # Bit pattern for an account w/ updatable code, after the account type mask has been applied. const.REGULAR_ACCOUNT_UPDATABLE_CODE=268435456 # 0b00010000_00000000_00000000_00000000 -# Bit pattern for a fungible faucet w/ immutable code, after the account type mask has been applied. -const.FUNGIBLE_FAUCET_ACCOUNT=536870912 # 0b00100000_00000000_00000000_00000000 - -# Bit pattern for a non-fungible faucet w/ immutable code, after the account type mask has been -# applied. -const.NON_FUNGIBLE_FAUCET_ACCOUNT=805306368 # 0b00110000_00000000_00000000_00000000 - # Bit pattern for a faucet account, after the account type mask has been applied. const.FAUCET_ACCOUNT=536870912 # 0b00100000_00000000_00000000_00000000 @@ -251,32 +244,6 @@ export.memory::get_acct_nonce->get_nonce #! - INIT_HASH is the initial account hash. export.memory::get_init_acct_hash->get_initial_hash -#! Returns a boolean indicating whether the account is a fungible faucet. -#! -#! Inputs: [acct_id] -#! Outputs: [is_fungible_faucet] -#! -#! Where: -#! - acct_id is the account id. -#! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. -export.is_fungible_faucet - exec.type push.FUNGIBLE_FAUCET_ACCOUNT eq - # => [is_fungible_faucet] -end - -#! Returns a boolean indicating whether the account is a non-fungible faucet. -#! -#! Inputs: [acct_id] -#! Outputs: [is_non_fungible_faucet] -#! -#! Where: -#! - acct_id is the account id. -#! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. -export.is_non_fungible_faucet - exec.type push.NON_FUNGIBLE_FAUCET_ACCOUNT eq - # => [is_non_fungible_faucet] -end - #! Returns a boolean indicating whether the account is a faucet. #! #! Inputs: [acct_id] diff --git a/miden-lib/asm/kernels/transaction/lib/asset.masm b/miden-lib/asm/kernels/transaction/lib/asset.masm index 6c0834b3d..90929e36a 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset.masm @@ -1,3 +1,5 @@ +use.utils::account->account_utils + use.kernel::account # ERRORS @@ -36,18 +38,6 @@ const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 # is used to identify the asset type const.FUNGIBLE_BITMASK_U32=0x20000000 -#! Returns the maximum amount of a fungible asset. -#! -#! Inputs: [] -#! Outputs: [fungible_asset_max_amount] -#! -#! Where: -#! - fungible_asset_max_amount is the maximum amount of a fungible asset. -export.get_fungible_asset_max_amount - push.FUNGIBLE_ASSET_MAX_AMOUNT - # => [fungible_asset_max_amount] -end - # PROCEDURES # ================================================================================================= @@ -75,7 +65,7 @@ export.validate_fungible_asset # => [ASSET] # assert that ASSET[3] is a fungible faucet - dup exec.account::is_fungible_faucet + dup exec.account_utils::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID # => [ASSET] @@ -117,7 +107,7 @@ export.validate_non_fungible_asset # => [ASSET] # assert that ASSET[1] is a fungible faucet - dup.2 exec.account::is_non_fungible_faucet + dup.2 exec.account_utils::is_non_fungible_faucet assert.err=ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_FUNGIBLE_FAUCET_ID # => [ASSET] diff --git a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm index e836b2a63..a40d087c3 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm @@ -1,5 +1,8 @@ use.std::collections::smt +use.utils::asset->asset_utils +use.utils::account->account_utils + use.kernel::account use.kernel::asset use.kernel::memory @@ -48,7 +51,7 @@ const.ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND=0x0002001F #! - the asset is not a fungible asset. export.get_balance # assert that the faucet id is a fungible faucet - dup exec.account::is_fungible_faucet + dup exec.account_utils::is_fungible_faucet assert.err=ERR_VAULT_GET_BALANCE_PROC_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_FAUCET # => [faucet_id, vault_root_ptr] @@ -137,7 +140,7 @@ export.add_fungible_asset # => [amount, amount, cur_amount, faucet_id, 0, 0, VAULT_ROOT, CUR_VAULT_VALUE, vault_root_ptr] # compute max_amount - cur_amount - exec.asset::get_fungible_asset_max_amount dup.3 sub + exec.asset_utils::get_fungible_asset_max_amount dup.3 sub # => [(max_amount - cur_amount), amount, amount, cur_amount, faucet_id, 0, 0, VAULT_ROOT, # CUR_VAULT_VALUE, vault_root_ptr] diff --git a/miden-lib/asm/kernels/transaction/lib/constants.masm b/miden-lib/asm/kernels/transaction/lib/constants.masm index a4fff64b3..88c7a2674 100644 --- a/miden-lib/asm/kernels/transaction/lib/constants.masm +++ b/miden-lib/asm/kernels/transaction/lib/constants.masm @@ -4,9 +4,6 @@ # The number of elements in a Word const.WORD_SIZE=4 -# The maximum number of input values associated with a single note. -const.MAX_INPUTS_PER_NOTE=128 - # The maximum number of assets that can be stored in a single note. const.MAX_ASSETS_PER_NOTE=256 @@ -52,17 +49,6 @@ export.get_word_size push.WORD_SIZE end -#! Returns the max allowed number of input values per note. -#! -#! Inputs: [] -#! Outputs: [max_inputs_per_note] -#! -#! Where: -#! - max_inputs_per_note is the max inputs per note. -export.get_max_inputs_per_note - push.MAX_INPUTS_PER_NOTE -end - #! Returns the max allowed number of assets per note. #! #! Inputs: [] diff --git a/miden-lib/asm/kernels/transaction/lib/faucet.masm b/miden-lib/asm/kernels/transaction/lib/faucet.masm index 364957763..6aa58d257 100644 --- a/miden-lib/asm/kernels/transaction/lib/faucet.masm +++ b/miden-lib/asm/kernels/transaction/lib/faucet.masm @@ -1,5 +1,8 @@ use.std::collections::smt +use.utils::account->account_utils +use.utils::asset->asset_utils + use.kernel::account use.kernel::asset use.kernel::asset_vault @@ -53,7 +56,7 @@ export.mint_fungible_asset # => [TOTAL_ISSUANCE, ASSET] # prepare stack to ensure that minting the asset will not exceed the maximum - dup.7 dup exec.asset::get_fungible_asset_max_amount dup.3 + dup.7 dup exec.asset_utils::get_fungible_asset_max_amount dup.3 # => [total_issuance, max_allowed_issuance, amount, amount, TOTAL_ISSUANCE, ASSET] # compute difference to ensure that the total issuance will not exceed the maximum @@ -191,7 +194,7 @@ end #! transaction via a note or the accounts vault. proc.burn_non_fungible_asset # assert that we are executing a transaction against the non-fungible faucet (access checks) - exec.account::get_id exec.account::is_non_fungible_faucet + exec.account::get_id exec.account_utils::is_non_fungible_faucet assert.err=ERR_FAUCET_BURN_NON_FUNGIBLE_ASSET_CAN_ONLY_BE_CALLED_ON_NON_FUNGIBLE_FAUCET # => [ASSET] diff --git a/miden-lib/asm/kernels/transaction/lib/prologue.masm b/miden-lib/asm/kernels/transaction/lib/prologue.masm index 336db9b17..eee9fc4cc 100644 --- a/miden-lib/asm/kernels/transaction/lib/prologue.masm +++ b/miden-lib/asm/kernels/transaction/lib/prologue.masm @@ -2,6 +2,8 @@ use.std::mem use.std::collections::mmr use.std::crypto::hashes::rpo +use.utils::account->account_utils + use.kernel::account use.kernel::asset_vault use.kernel::constants @@ -346,7 +348,7 @@ proc.validate_new_account # => [FAUCET_RESERVED_SLOT, acct_id] # check if the account is a fungible faucet - movup.4 exec.account::is_fungible_faucet + movup.4 exec.account_utils::is_fungible_faucet # => [is_fungible_faucet, FAUCET_RESERVED_SLOT] if.true diff --git a/miden-lib/asm/kernels/transaction/lib/tx.masm b/miden-lib/asm/kernels/transaction/lib/tx.masm index a71d9ae4f..f6c0017cb 100644 --- a/miden-lib/asm/kernels/transaction/lib/tx.masm +++ b/miden-lib/asm/kernels/transaction/lib/tx.masm @@ -1,3 +1,5 @@ +use.utils::asset->asset_utils + use.kernel::account use.kernel::asset use.kernel::constants @@ -308,7 +310,7 @@ proc.add_fungible_asset_to_note # num_of_assets, note_idx] # check that we don't overflow bc we use lte - dup exec.asset::get_fungible_asset_max_amount lte + dup exec.asset_utils::get_fungible_asset_max_amount lte assert.err=ERR_NOTE_FUNGIBLE_MAX_AMOUNT_EXCEEDED # => [updated_amount, 0, 0, faucet_id, 0, 0, end_asset_ptr, asset_ptr, note_ptr, # num_of_assets, note_idx] diff --git a/miden-lib/asm/miden/account.masm b/miden-lib/asm/miden/account.masm index b87406d89..28bed9e46 100644 --- a/miden-lib/asm/miden/account.masm +++ b/miden-lib/asm/miden/account.masm @@ -437,60 +437,3 @@ export.get_vault_commitment swapdw dropw dropw swapw dropw # => [COM] end - -# PROCEDURES COPIED FROM KERNEL (TODO: get rid of this duplication) -# ================================================================================================= - -# Given the most significant half of an account id, this mask defines the bits used to determine the -# account type. -const.ACCOUNT_TYPE_U32MASK=805306368 # 0b00110000_00000000_00000000_00000000 - -# Bit pattern for a fungible faucet w/ immutable code, after the account type mask has been applied. -const.FUNGIBLE_FAUCET_ACCOUNT=536870912 # 0b00100000_00000000_00000000_00000000 - -# Bit pattern for a non-fungible faucet w/ immutable code, after the account type mask has been -# applied. -const.NON_FUNGIBLE_FAUCET_ACCOUNT=805306368 # 0b00110000_00000000_00000000_00000000 - -#! Returns the most significant half with the account type bits masked out. -#! -#! The account type can be defined by comparing this value with the following constants: -#! -#! - REGULAR_ACCOUNT_UPDATABLE_CODE -#! - REGULAR_ACCOUNT_IMMUTABLE_CODE -#! - FUNGIBLE_FAUCET_ACCOUNT -#! - NON_FUNGIBLE_FAUCET_ACCOUNT -#! -#! Stack: [acct_id] -#! Output: [acct_type] -#! -#! - acct_id is the account id. -#! - acct_type is the account type. -proc.type - u32split swap drop push.ACCOUNT_TYPE_U32MASK u32and - # => [acct_type] -end - -#! Returns a boolean indicating whether the account is a fungible faucet. -#! -#! Stack: [acct_id] -#! Output: [is_fungible_faucet] -#! -#! - acct_id is the account id. -#! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. -export.is_fungible_faucet - exec.type push.FUNGIBLE_FAUCET_ACCOUNT eq - # => [is_fungible_faucet] -end - -#! Returns a boolean indicating whether the account is a non-fungible faucet. -#! -#! Stack: [acct_id] -#! Output: [is_non_fungible_faucet] -#! -#! - acct_id is the account id. -#! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. -export.is_non_fungible_faucet - exec.type push.NON_FUNGIBLE_FAUCET_ACCOUNT eq - # => [is_non_fungible_faucet] -end diff --git a/miden-lib/asm/miden/asset.masm b/miden-lib/asm/miden/asset.masm index 1ba20aade..380b4af28 100644 --- a/miden-lib/asm/miden/asset.masm +++ b/miden-lib/asm/miden/asset.masm @@ -1,3 +1,6 @@ +use.utils::account->account_utils +use.utils::asset->asset_utils + use.miden::account # ERRORS @@ -37,11 +40,11 @@ const.FUNGIBLE_BITMASK_U32=0x20000000 #! Annotation hint: is not used anywhere except this file export.build_fungible_asset # assert the faucet is a fungible faucet - dup exec.account::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID + dup exec.account_utils::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID # => [faucet_id, amount] # assert the amount is valid - dup.1 exec.get_fungible_asset_max_amount lte + dup.1 exec.asset_utils::get_fungible_asset_max_amount lte assert.err=ERR_FUNGIBLE_ASSET_AMOUNT_EXCEEDS_MAX_ALLOWED_AMOUNT # => [faucet_id, amount] @@ -83,7 +86,7 @@ end #! Annotation hint: is not used anywhere except this file export.build_non_fungible_asset # assert the faucet is a non-fungible faucet - dup exec.account::is_non_fungible_faucet + dup exec.account_utils::is_non_fungible_faucet assert.err=ERR_NON_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID # => [faucet_id, DATA_HASH] @@ -115,19 +118,3 @@ export.create_non_fungible_asset exec.build_non_fungible_asset # => [ASSET] end - -# PROCEDURES COPIED FROM KERNEL (TODO: get rid of this duplication) -# ================================================================================================= - -const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 - -#! Returns the maximum amount of a fungible asset. -#! -#! Stack: [] -#! Outputs: [fungible_asset_max_amount] -#! -#! fungible_asset_max_amount is the maximum amount of a fungible asset. -export.get_fungible_asset_max_amount - push.FUNGIBLE_ASSET_MAX_AMOUNT - # => [fungible_asset_max_amount] -end \ No newline at end of file diff --git a/miden-lib/asm/miden/note.masm b/miden-lib/asm/miden/note.masm index 10ff51a13..ba1bdbca8 100644 --- a/miden-lib/asm/miden/note.masm +++ b/miden-lib/asm/miden/note.masm @@ -1,7 +1,10 @@ -use.miden::kernel_proc_offsets use.std::crypto::hashes::rpo use.std::mem +use.utils::note->note_utils + +use.miden::kernel_proc_offsets + # ERRORS # ================================================================================================= @@ -120,7 +123,7 @@ export.get_inputs # => [num_inputs, INPUTS_HASH, dest_ptr] # validate the input length - dup exec.get_max_inputs_per_note lte + dup exec.note_utils::get_max_inputs_per_note lte assert.err=ERR_PROLOGUE_NUMBER_OF_NOTE_INPUTS_EXCEEDED_LIMIT # => [num_inputs, INPUTS_HASH, dest_ptr] @@ -252,19 +255,3 @@ export.get_script_hash swapdw dropw dropw swapw dropw # => [SCRIPT_HASH] end - -# PROCEDURES COPIED FROM KERNEL (TODO: get rid of this duplication) -# ================================================================================================= - -# The maximum number of input values associated with a single note. -const.MAX_INPUTS_PER_NOTE=128 - -#! Returns the max allowed number of input values per note. -#! -#! Stack: [] -#! Output: [max_inputs_per_note] -#! -#! - max_inputs_per_note is the max inputs per note. -export.get_max_inputs_per_note - push.MAX_INPUTS_PER_NOTE -end diff --git a/miden-lib/asm/utils/account.masm b/miden-lib/asm/utils/account.masm new file mode 100644 index 000000000..d5f10cc13 --- /dev/null +++ b/miden-lib/asm/utils/account.masm @@ -0,0 +1,53 @@ +# Given the most significant half of an account id, this mask defines the bits used to determine the +# account type. +const.ACCOUNT_TYPE_U32MASK=805306368 # 0b00110000_00000000_00000000_00000000 + +# Bit pattern for a fungible faucet w/ immutable code, after the account type mask has been applied. +const.FUNGIBLE_FAUCET_ACCOUNT=536870912 # 0b00100000_00000000_00000000_00000000 + +# Bit pattern for a non-fungible faucet w/ immutable code, after the account type mask has been +# applied. +const.NON_FUNGIBLE_FAUCET_ACCOUNT=805306368 # 0b00110000_00000000_00000000_00000000 + +#! Returns the most significant half with the account type bits masked out. +#! +#! The account type can be defined by comparing this value with the following constants: +#! +#! - REGULAR_ACCOUNT_UPDATABLE_CODE +#! - REGULAR_ACCOUNT_IMMUTABLE_CODE +#! - FUNGIBLE_FAUCET_ACCOUNT +#! - NON_FUNGIBLE_FAUCET_ACCOUNT +#! +#! Stack: [acct_id] +#! Output: [acct_type] +#! +#! - acct_id is the account id. +#! - acct_type is the account type. +proc.type + u32split swap drop push.ACCOUNT_TYPE_U32MASK u32and + # => [acct_type] +end + +#! Returns a boolean indicating whether the account is a fungible faucet. +#! +#! Stack: [acct_id] +#! Output: [is_fungible_faucet] +#! +#! - acct_id is the account id. +#! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. +export.is_fungible_faucet + exec.type push.FUNGIBLE_FAUCET_ACCOUNT eq + # => [is_fungible_faucet] +end + +#! Returns a boolean indicating whether the account is a non-fungible faucet. +#! +#! Stack: [acct_id] +#! Output: [is_non_fungible_faucet] +#! +#! - acct_id is the account id. +#! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. +export.is_non_fungible_faucet + exec.type push.NON_FUNGIBLE_FAUCET_ACCOUNT eq + # => [is_non_fungible_faucet] +end diff --git a/miden-lib/asm/utils/asset.masm b/miden-lib/asm/utils/asset.masm new file mode 100644 index 000000000..905a99716 --- /dev/null +++ b/miden-lib/asm/utils/asset.masm @@ -0,0 +1,12 @@ +const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 + +#! Returns the maximum amount of a fungible asset. +#! +#! Stack: [] +#! Outputs: [fungible_asset_max_amount] +#! +#! fungible_asset_max_amount is the maximum amount of a fungible asset. +export.get_fungible_asset_max_amount + push.FUNGIBLE_ASSET_MAX_AMOUNT + # => [fungible_asset_max_amount] +end diff --git a/miden-lib/asm/utils/note.masm b/miden-lib/asm/utils/note.masm new file mode 100644 index 000000000..09308d776 --- /dev/null +++ b/miden-lib/asm/utils/note.masm @@ -0,0 +1,12 @@ +# The maximum number of input values associated with a single note. +const.MAX_INPUTS_PER_NOTE=128 + +#! Returns the max allowed number of input values per note. +#! +#! Stack: [] +#! Output: [max_inputs_per_note] +#! +#! - max_inputs_per_note is the max inputs per note. +export.get_max_inputs_per_note + push.MAX_INPUTS_PER_NOTE +end diff --git a/miden-lib/build.rs b/miden-lib/build.rs index d04b07159..fbf8ac024 100644 --- a/miden-lib/build.rs +++ b/miden-lib/build.rs @@ -29,6 +29,7 @@ const ASM_NOTE_SCRIPTS_DIR: &str = "note_scripts"; const ASM_ACCOUNT_COMPONENTS_DIR: &str = "account_components"; const ASM_TX_KERNEL_DIR: &str = "kernels/transaction"; const KERNEL_V0_RS_FILE: &str = "src/transaction/procedures/kernel_v0.rs"; +const ASM_UTILS_DIR: &str = "utils"; const KERNEL_ERRORS_FILE: &str = "src/errors/tx_kernel_errors.rs"; @@ -56,9 +57,16 @@ fn main() -> Result<()> { // set target directory to {OUT_DIR}/assets let target_dir = Path::new(&build_dir).join(ASSETS_DIR); + + // compile utils dir + let utils_lib = compile_utils_lib(&source_dir, &target_dir)?; + // compile transaction kernel - let mut assembler = - compile_tx_kernel(&source_dir.join(ASM_TX_KERNEL_DIR), &target_dir.join("kernels"))?; + let mut assembler = compile_tx_kernel( + &source_dir.join(ASM_TX_KERNEL_DIR), + &target_dir.join("kernels"), + utils_lib, + )?; // compile miden library let miden_lib = compile_miden_lib(&source_dir, &target_dir, assembler.clone())?; @@ -103,8 +111,12 @@ fn main() -> Result<()> { /// /// When the `testing` feature is enabled, the POW requirements for account ID generation are /// adjusted by modifying the corresponding constants in {source_dir}/lib/constants.masm file. -fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result { - let assembler = build_assembler(None)?; +fn compile_tx_kernel( + source_dir: &Path, + target_dir: &Path, + utils_lib: Library, +) -> Result { + let assembler = build_assembler(None, utils_lib.clone())?; // if this build has the testing flag set, modify the code and reduce the cost of proof-of-work match env::var("CARGO_FEATURE_TESTING") { @@ -144,7 +156,7 @@ fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result let output_file = target_dir.join("tx_kernel").with_extension(Library::LIBRARY_EXTENSION); kernel_lib.write_to_file(output_file).into_diagnostic()?; - let assembler = build_assembler(Some(kernel_lib))?; + let assembler = build_assembler(Some(kernel_lib), utils_lib)?; // assemble the kernel program and write it the "tx_kernel.masb" file let mut main_assembler = assembler.clone(); @@ -280,6 +292,25 @@ fn compile_miden_lib( Ok(miden_lib) } +// COMPILE UTILS LIB +// ================================================================================================ + +/// Reads the MASM files from "{source_dir}/utils" directory, compiles them into a Miden assembly +/// library, saves the library into "{target_dir}/utils.masl", and returns the complied library. +fn compile_utils_lib(source_dir: &Path, target_dir: &Path) -> Result { + let assembler = Assembler::default(); + + let source_dir = source_dir.join(ASM_UTILS_DIR); + + let namespace = "utils".parse::().expect("invalid base namespace"); + let utils_lib = Library::from_dir(source_dir.clone(), namespace.clone(), assembler.clone())?; + + let output_file = target_dir.join("utils").with_extension(Library::LIBRARY_EXTENSION); + utils_lib.write_to_file(output_file).into_diagnostic()?; + + Ok(utils_lib) +} + // COMPILE EXECUTABLE MODULES // ================================================================================================ @@ -350,12 +381,14 @@ fn compile_account_components(target_dir: &Path, assembler: Assembler) -> Result /// Returns a new [Assembler] loaded with miden-stdlib and the specified kernel, if provided. /// /// The returned assembler will be in the `debug` mode if the `with-debug-info` feature is enabled. -fn build_assembler(kernel: Option) -> Result { +fn build_assembler(kernel: Option, utils_lib: Library) -> Result { kernel .map(|kernel| Assembler::with_kernel(Arc::new(DefaultSourceManager::default()), kernel)) .unwrap_or_default() .with_debug_mode(cfg!(feature = "with-debug-info")) .with_library(miden_stdlib::StdLibrary::default()) + .unwrap_or_default() + .with_library(utils_lib) } /// Recursively copies `src` into `dst`. diff --git a/miden-lib/src/lib.rs b/miden-lib/src/lib.rs index 86edb61f9..d81a75904 100644 --- a/miden-lib/src/lib.rs +++ b/miden-lib/src/lib.rs @@ -15,6 +15,9 @@ use miden_objects::{ mod auth; pub use auth::AuthScheme; +mod utils_lib; +pub use utils_lib::UtilsLib; + pub mod accounts; pub mod errors; pub mod notes; diff --git a/miden-lib/src/transaction/mod.rs b/miden-lib/src/transaction/mod.rs index 01d10229c..b07dbd9db 100644 --- a/miden-lib/src/transaction/mod.rs +++ b/miden-lib/src/transaction/mod.rs @@ -14,7 +14,7 @@ use miden_objects::{ use miden_stdlib::StdLibrary; use outputs::EXPIRATION_BLOCK_ELEMENT_IDX; -use super::MidenLib; +use super::{MidenLib, UtilsLib}; pub mod memory; @@ -120,6 +120,8 @@ impl TransactionKernel { .expect("failed to load std-lib") .with_library(MidenLib::default()) .expect("failed to load miden-lib") + .with_library(UtilsLib::default()) + .expect("failed to load utils lib") } // STACK INPUTS / OUTPUTS @@ -355,6 +357,8 @@ impl TransactionKernel { Assembler::with_kernel(source_manager, Self::kernel()) .with_library(StdLibrary::default()) .expect("failed to load std-lib") + .with_library(UtilsLib::default()) + .expect("failed to load utils library") .with_library(MidenLib::default()) .expect("failed to load miden-lib") .with_library(kernel_library) diff --git a/miden-lib/src/transaction/procedures/kernel_v0.rs b/miden-lib/src/transaction/procedures/kernel_v0.rs index ddf75166b..ad5ca1fef 100644 --- a/miden-lib/src/transaction/procedures/kernel_v0.rs +++ b/miden-lib/src/transaction/procedures/kernel_v0.rs @@ -8,9 +8,9 @@ use miden_objects::{digest, Digest}; /// Hashes of all dynamically executed procedures from the kernel 0. pub const KERNEL0_PROCEDURES: [Digest; 33] = [ // account_vault_add_asset - digest!("0xc69b608da541fea9a41322359cc049cac55f816858f530005e333d0b54f2f284"), + digest!("0x5cf407f2af3f6454d8b15e4874d4e86b4dbfb7752adb6e55b6586925869d50bd"), // account_vault_get_balance - digest!("0x37c528cbc741f6c9d81602bcb435185f471eec705a59a36704ef3632960607e8"), + digest!("0x12b9ca5ec182a90b30ad391815eff9c359605e4b65ca58a3f900cb91867675a6"), // account_vault_has_non_fungible_asset digest!("0x7144f9ac1df4c4c90b770891e1665d25a819ea026227a7d143ab89b89991bc14"), // account_vault_remove_asset @@ -38,13 +38,13 @@ pub const KERNEL0_PROCEDURES: [Digest; 33] = [ // set_account_map_item digest!("0x02befd8e777bacc5f4c3b14267b7e5558c9557d82970e74612c5aa6d7febf9c2"), // burn_asset - digest!("0x5b3bcc39db744de02b0111a43191c09c7cafbf138fac5913d959290225f061aa"), + digest!("0xb6199ab60d4537004ac67d09934eea304e552436bc3e3d46d104ba05370f217d"), // get_fungible_faucet_total_issuance - digest!("0x0ba11e1765fac99dd615e32f4035773fad1093f14bd2ed7c98fa5470a60b7e19"), + digest!("0xa88104e2c01847358f697d52d46281a53ac0d9efaa755c7531fad5f8a9c67c29"), // mint_asset - digest!("0xc1e42d63f41e1b5f8b550e01b0ad69de5b264fe7214d036ca09927998eb8e422"), + digest!("0x6bdaab695377806fe6c7c1f3f6b8b34f5a11046697be282eb037d14b21eb7b37"), // add_asset_to_note - digest!("0x9728db11ce1e4aa6420f53bfd8002289d3aa5b18dae9039d3c3ee2b2541ecbeb"), + digest!("0x07e219a8e9c211663fa39b224eccd77b5cb25df0395aa4503556b142cf0cb4b9"), // create_note digest!("0xf3c0b7305783deabeae67fca094df529a04a02332c9a79c1622953f63b08959d"), // get_input_notes_commitment diff --git a/miden-lib/src/utils_lib.rs b/miden-lib/src/utils_lib.rs new file mode 100644 index 000000000..d0efa8be3 --- /dev/null +++ b/miden-lib/src/utils_lib.rs @@ -0,0 +1,47 @@ +use alloc::sync::Arc; + +use miden_objects::{ + assembly::{mast::MastForest, Library}, + utils::{serde::Deserializable, sync::LazyLock}, +}; + +// CONSTANTS +// ================================================================================================ + +const UTILS_LIB_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/assets/utils.masl")); + +// UTILITIES LIBRARY +// ================================================================================================ + +#[derive(Clone)] +pub struct UtilsLib(Library); + +impl UtilsLib { + /// Returns a reference to the [`MastForest`] of the inner [`Library`]. + pub fn mast_forest(&self) -> &Arc { + self.0.mast_forest() + } +} + +impl AsRef for UtilsLib { + fn as_ref(&self) -> &Library { + &self.0 + } +} + +impl From for Library { + fn from(value: UtilsLib) -> Self { + value.0 + } +} + +impl Default for UtilsLib { + fn default() -> Self { + static UTILS_LIB: LazyLock = LazyLock::new(|| { + let contents = + Library::read_from_bytes(UTILS_LIB_BYTES).expect("failed to read miden lib masl!"); + UtilsLib(contents) + }); + UTILS_LIB.clone() + } +} diff --git a/miden-tx/src/executor/mast_store.rs b/miden-tx/src/executor/mast_store.rs index df81d18c4..470e2af4e 100644 --- a/miden-tx/src/executor/mast_store.rs +++ b/miden-tx/src/executor/mast_store.rs @@ -1,6 +1,8 @@ use alloc::{collections::BTreeMap, sync::Arc}; -use miden_lib::{transaction::TransactionKernel, utils::sync::RwLock, MidenLib, StdLibrary}; +use miden_lib::{ + transaction::TransactionKernel, utils::sync::RwLock, MidenLib, StdLibrary, UtilsLib, +}; use miden_objects::{ accounts::AccountCode, assembly::mast::MastForest, @@ -47,6 +49,10 @@ impl TransactionMastStore { let miden_lib_forest = MidenLib::default().mast_forest().clone(); store.insert(miden_lib_forest); + // load utils lib MAST forest + let utils_lib_forest = UtilsLib::default().mast_forest().clone(); + store.insert(utils_lib_forest); + store } diff --git a/miden-tx/src/testing/executor.rs b/miden-tx/src/testing/executor.rs index 47ee41f67..d7a6b322f 100644 --- a/miden-tx/src/testing/executor.rs +++ b/miden-tx/src/testing/executor.rs @@ -1,4 +1,4 @@ -use miden_lib::transaction::TransactionKernel; +use miden_lib::{transaction::TransactionKernel, UtilsLib}; use vm_processor::{ AdviceInputs, AdviceProvider, DefaultHost, ExecutionError, Host, Process, Program, StackInputs, }; @@ -61,6 +61,7 @@ where let test_lib = TransactionKernel::kernel_as_library(); host.load_mast_forest(test_lib.mast_forest().clone()); + host.load_mast_forest(UtilsLib::default().mast_forest().clone()); CodeExecutor::new(host) } diff --git a/miden-tx/src/tests/kernel_tests/test_account.rs b/miden-tx/src/tests/kernel_tests/test_account.rs index 4f9428770..7c2d5a9ea 100644 --- a/miden-tx/src/tests/kernel_tests/test_account.rs +++ b/miden-tx/src/tests/kernel_tests/test_account.rs @@ -112,10 +112,10 @@ pub fn test_set_code_succeeds() { #[test] pub fn test_account_type() { let procedures = vec![ - ("is_fungible_faucet", AccountType::FungibleFaucet), - ("is_non_fungible_faucet", AccountType::NonFungibleFaucet), - ("is_updatable_account", AccountType::RegularAccountUpdatableCode), - ("is_immutable_account", AccountType::RegularAccountImmutableCode), + ("utils", "is_fungible_faucet", AccountType::FungibleFaucet), + ("utils", "is_non_fungible_faucet", AccountType::NonFungibleFaucet), + ("kernel", "is_updatable_account", AccountType::RegularAccountUpdatableCode), + ("kernel", "is_immutable_account", AccountType::RegularAccountImmutableCode), ]; let test_cases = [ @@ -125,7 +125,7 @@ pub fn test_account_type() { ACCOUNT_ID_NON_FUNGIBLE_FAUCET_OFF_CHAIN, ]; - for (procedure, expected_type) in procedures { + for (lib, procedure, expected_type) in procedures { let mut has_type = false; for account_id in test_cases.iter() { @@ -133,13 +133,13 @@ pub fn test_account_type() { let code = format!( " - use.kernel::account + use.{}::account begin exec.account::{} end ", - procedure + lib, procedure ); let process = CodeExecutor::with_advice_provider(MemAdviceProvider::default()) From 7df9a005726bb71b9bd2d0a50f838c7e43b62988 Mon Sep 17 00:00:00 2001 From: Andrey Khmuro Date: Thu, 19 Dec 2024 02:12:43 +0300 Subject: [PATCH 02/10] feat: utils module working state --- miden-lib/asm/kernels/transaction/api.masm | 4 +- .../asm/kernels/transaction/lib/account.masm | 3 ++ .../asm/kernels/transaction/lib/asset.masm | 8 +-- .../kernels/transaction/lib/asset_vault.masm | 7 +-- .../kernels/transaction/lib/constants.masm | 2 + .../asm/kernels/transaction/lib/faucet.masm | 7 +-- .../asm/kernels/transaction/lib/prologue.masm | 4 +- miden-lib/asm/kernels/transaction/lib/tx.masm | 4 +- miden-lib/asm/miden/account.masm | 6 +++ miden-lib/asm/miden/asset.masm | 11 ++-- miden-lib/asm/miden/note.masm | 10 ++-- miden-lib/asm/utils/asset.masm | 12 ----- miden-lib/asm/utils/note.masm | 12 ----- .../asm/utils/{account.masm => utils.masm} | 32 ++++++++++++ miden-lib/build.rs | 50 +++++-------------- miden-lib/src/lib.rs | 3 -- miden-lib/src/transaction/mod.rs | 6 +-- .../src/transaction/procedures/kernel_v0.rs | 12 ++--- miden-tx/src/executor/mast_store.rs | 8 +-- miden-tx/src/testing/executor.rs | 3 +- .../src/tests/kernel_tests/test_account.rs | 14 +++--- 21 files changed, 94 insertions(+), 124 deletions(-) delete mode 100644 miden-lib/asm/utils/asset.masm delete mode 100644 miden-lib/asm/utils/note.masm rename miden-lib/asm/utils/{account.masm => utils.masm} (67%) diff --git a/miden-lib/asm/kernels/transaction/api.masm b/miden-lib/asm/kernels/transaction/api.masm index af6fba824..79f4dfdef 100644 --- a/miden-lib/asm/kernels/transaction/api.masm +++ b/miden-lib/asm/kernels/transaction/api.masm @@ -1,8 +1,6 @@ use.std::collections::smt use.std::sys -use.utils::account->account_utils - use.kernel::account use.kernel::asset_vault use.kernel::constants @@ -820,7 +818,7 @@ end #! Invocation: dynexec export.get_fungible_faucet_total_issuance # assert that we are executing a transaction against a fungible faucet (access checks) - exec.account::get_id exec.account_utils::is_fungible_faucet + exec.account::get_id exec.account::is_fungible_faucet assert.err=ERR_ACCOUNT_TOTAL_ISSUANCE_PROC_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_FAUCET # => [pad(16)] diff --git a/miden-lib/asm/kernels/transaction/lib/account.masm b/miden-lib/asm/kernels/transaction/lib/account.masm index 93fb610c0..7b4db3671 100644 --- a/miden-lib/asm/kernels/transaction/lib/account.masm +++ b/miden-lib/asm/kernels/transaction/lib/account.masm @@ -244,6 +244,9 @@ export.memory::get_acct_nonce->get_nonce #! - INIT_HASH is the initial account hash. export.memory::get_init_acct_hash->get_initial_hash +export.::utils::utils::is_fungible_faucet +export.::utils::utils::is_non_fungible_faucet + #! Returns a boolean indicating whether the account is a faucet. #! #! Inputs: [acct_id] diff --git a/miden-lib/asm/kernels/transaction/lib/asset.masm b/miden-lib/asm/kernels/transaction/lib/asset.masm index 90929e36a..d0dda3e16 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset.masm @@ -1,5 +1,3 @@ -use.utils::account->account_utils - use.kernel::account # ERRORS @@ -38,6 +36,8 @@ const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 # is used to identify the asset type const.FUNGIBLE_BITMASK_U32=0x20000000 +export.::utils::utils::get_fungible_asset_max_amount + # PROCEDURES # ================================================================================================= @@ -65,7 +65,7 @@ export.validate_fungible_asset # => [ASSET] # assert that ASSET[3] is a fungible faucet - dup exec.account_utils::is_fungible_faucet + dup exec.account::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID # => [ASSET] @@ -107,7 +107,7 @@ export.validate_non_fungible_asset # => [ASSET] # assert that ASSET[1] is a fungible faucet - dup.2 exec.account_utils::is_non_fungible_faucet + dup.2 exec.account::is_non_fungible_faucet assert.err=ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_FUNGIBLE_FAUCET_ID # => [ASSET] diff --git a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm index a40d087c3..e836b2a63 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm @@ -1,8 +1,5 @@ use.std::collections::smt -use.utils::asset->asset_utils -use.utils::account->account_utils - use.kernel::account use.kernel::asset use.kernel::memory @@ -51,7 +48,7 @@ const.ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND=0x0002001F #! - the asset is not a fungible asset. export.get_balance # assert that the faucet id is a fungible faucet - dup exec.account_utils::is_fungible_faucet + dup exec.account::is_fungible_faucet assert.err=ERR_VAULT_GET_BALANCE_PROC_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_FAUCET # => [faucet_id, vault_root_ptr] @@ -140,7 +137,7 @@ export.add_fungible_asset # => [amount, amount, cur_amount, faucet_id, 0, 0, VAULT_ROOT, CUR_VAULT_VALUE, vault_root_ptr] # compute max_amount - cur_amount - exec.asset_utils::get_fungible_asset_max_amount dup.3 sub + exec.asset::get_fungible_asset_max_amount dup.3 sub # => [(max_amount - cur_amount), amount, amount, cur_amount, faucet_id, 0, 0, VAULT_ROOT, # CUR_VAULT_VALUE, vault_root_ptr] diff --git a/miden-lib/asm/kernels/transaction/lib/constants.masm b/miden-lib/asm/kernels/transaction/lib/constants.masm index 88c7a2674..861bc9a2d 100644 --- a/miden-lib/asm/kernels/transaction/lib/constants.masm +++ b/miden-lib/asm/kernels/transaction/lib/constants.masm @@ -49,6 +49,8 @@ export.get_word_size push.WORD_SIZE end +export.::utils::utils::get_max_inputs_per_note + #! Returns the max allowed number of assets per note. #! #! Inputs: [] diff --git a/miden-lib/asm/kernels/transaction/lib/faucet.masm b/miden-lib/asm/kernels/transaction/lib/faucet.masm index 6aa58d257..364957763 100644 --- a/miden-lib/asm/kernels/transaction/lib/faucet.masm +++ b/miden-lib/asm/kernels/transaction/lib/faucet.masm @@ -1,8 +1,5 @@ use.std::collections::smt -use.utils::account->account_utils -use.utils::asset->asset_utils - use.kernel::account use.kernel::asset use.kernel::asset_vault @@ -56,7 +53,7 @@ export.mint_fungible_asset # => [TOTAL_ISSUANCE, ASSET] # prepare stack to ensure that minting the asset will not exceed the maximum - dup.7 dup exec.asset_utils::get_fungible_asset_max_amount dup.3 + dup.7 dup exec.asset::get_fungible_asset_max_amount dup.3 # => [total_issuance, max_allowed_issuance, amount, amount, TOTAL_ISSUANCE, ASSET] # compute difference to ensure that the total issuance will not exceed the maximum @@ -194,7 +191,7 @@ end #! transaction via a note or the accounts vault. proc.burn_non_fungible_asset # assert that we are executing a transaction against the non-fungible faucet (access checks) - exec.account::get_id exec.account_utils::is_non_fungible_faucet + exec.account::get_id exec.account::is_non_fungible_faucet assert.err=ERR_FAUCET_BURN_NON_FUNGIBLE_ASSET_CAN_ONLY_BE_CALLED_ON_NON_FUNGIBLE_FAUCET # => [ASSET] diff --git a/miden-lib/asm/kernels/transaction/lib/prologue.masm b/miden-lib/asm/kernels/transaction/lib/prologue.masm index eee9fc4cc..336db9b17 100644 --- a/miden-lib/asm/kernels/transaction/lib/prologue.masm +++ b/miden-lib/asm/kernels/transaction/lib/prologue.masm @@ -2,8 +2,6 @@ use.std::mem use.std::collections::mmr use.std::crypto::hashes::rpo -use.utils::account->account_utils - use.kernel::account use.kernel::asset_vault use.kernel::constants @@ -348,7 +346,7 @@ proc.validate_new_account # => [FAUCET_RESERVED_SLOT, acct_id] # check if the account is a fungible faucet - movup.4 exec.account_utils::is_fungible_faucet + movup.4 exec.account::is_fungible_faucet # => [is_fungible_faucet, FAUCET_RESERVED_SLOT] if.true diff --git a/miden-lib/asm/kernels/transaction/lib/tx.masm b/miden-lib/asm/kernels/transaction/lib/tx.masm index f6c0017cb..a71d9ae4f 100644 --- a/miden-lib/asm/kernels/transaction/lib/tx.masm +++ b/miden-lib/asm/kernels/transaction/lib/tx.masm @@ -1,5 +1,3 @@ -use.utils::asset->asset_utils - use.kernel::account use.kernel::asset use.kernel::constants @@ -310,7 +308,7 @@ proc.add_fungible_asset_to_note # num_of_assets, note_idx] # check that we don't overflow bc we use lte - dup exec.asset_utils::get_fungible_asset_max_amount lte + dup exec.asset::get_fungible_asset_max_amount lte assert.err=ERR_NOTE_FUNGIBLE_MAX_AMOUNT_EXCEEDED # => [updated_amount, 0, 0, faucet_id, 0, 0, end_asset_ptr, asset_ptr, note_ptr, # num_of_assets, note_idx] diff --git a/miden-lib/asm/miden/account.masm b/miden-lib/asm/miden/account.masm index 28bed9e46..0a5405b46 100644 --- a/miden-lib/asm/miden/account.masm +++ b/miden-lib/asm/miden/account.masm @@ -1,5 +1,11 @@ use.miden::kernel_proc_offsets +# REEXPORTED PROCEDURES +# ================================================================================================= + +export.::utils::utils::is_fungible_faucet +export.::utils::utils::is_non_fungible_faucet + # NATIVE ACCOUNT PROCEDURES # ================================================================================================= diff --git a/miden-lib/asm/miden/asset.masm b/miden-lib/asm/miden/asset.masm index 380b4af28..60ba13082 100644 --- a/miden-lib/asm/miden/asset.masm +++ b/miden-lib/asm/miden/asset.masm @@ -1,6 +1,3 @@ -use.utils::account->account_utils -use.utils::asset->asset_utils - use.miden::account # ERRORS @@ -27,6 +24,8 @@ const.FUNGIBLE_BITMASK_U32=0x20000000 # PROCEDURES # ================================================================================================= +export.::utils::utils::get_fungible_asset_max_amount + #! Builds a fungible asset for the specified fungible faucet and amount. #! #! Inputs: [faucet_id, amount] @@ -40,11 +39,11 @@ const.FUNGIBLE_BITMASK_U32=0x20000000 #! Annotation hint: is not used anywhere except this file export.build_fungible_asset # assert the faucet is a fungible faucet - dup exec.account_utils::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID + dup exec.account::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID # => [faucet_id, amount] # assert the amount is valid - dup.1 exec.asset_utils::get_fungible_asset_max_amount lte + dup.1 exec.get_fungible_asset_max_amount lte assert.err=ERR_FUNGIBLE_ASSET_AMOUNT_EXCEEDS_MAX_ALLOWED_AMOUNT # => [faucet_id, amount] @@ -86,7 +85,7 @@ end #! Annotation hint: is not used anywhere except this file export.build_non_fungible_asset # assert the faucet is a non-fungible faucet - dup exec.account_utils::is_non_fungible_faucet + dup exec.account::is_non_fungible_faucet assert.err=ERR_NON_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID # => [faucet_id, DATA_HASH] diff --git a/miden-lib/asm/miden/note.masm b/miden-lib/asm/miden/note.masm index ba1bdbca8..0ae844041 100644 --- a/miden-lib/asm/miden/note.masm +++ b/miden-lib/asm/miden/note.masm @@ -1,8 +1,6 @@ use.std::crypto::hashes::rpo use.std::mem -use.utils::note->note_utils - use.miden::kernel_proc_offsets # ERRORS @@ -14,6 +12,12 @@ const.ERR_NOTE_DATA_DOES_NOT_MATCH_COMMITMENT=0x0002004E # Number of note inputs exceeded the maximum limit of 128 const.ERR_PROLOGUE_NUMBER_OF_NOTE_INPUTS_EXCEEDED_LIMIT=0x0002004F + +# PROCEDURES +# ================================================================================================= + +export.::utils::utils::get_max_inputs_per_note + #! Writes the data currently on the advice stack into the memory at the specified location and #! verifies that the hash of the written data is equal to the provided hash. #! @@ -123,7 +127,7 @@ export.get_inputs # => [num_inputs, INPUTS_HASH, dest_ptr] # validate the input length - dup exec.note_utils::get_max_inputs_per_note lte + dup exec.get_max_inputs_per_note lte assert.err=ERR_PROLOGUE_NUMBER_OF_NOTE_INPUTS_EXCEEDED_LIMIT # => [num_inputs, INPUTS_HASH, dest_ptr] diff --git a/miden-lib/asm/utils/asset.masm b/miden-lib/asm/utils/asset.masm deleted file mode 100644 index 905a99716..000000000 --- a/miden-lib/asm/utils/asset.masm +++ /dev/null @@ -1,12 +0,0 @@ -const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 - -#! Returns the maximum amount of a fungible asset. -#! -#! Stack: [] -#! Outputs: [fungible_asset_max_amount] -#! -#! fungible_asset_max_amount is the maximum amount of a fungible asset. -export.get_fungible_asset_max_amount - push.FUNGIBLE_ASSET_MAX_AMOUNT - # => [fungible_asset_max_amount] -end diff --git a/miden-lib/asm/utils/note.masm b/miden-lib/asm/utils/note.masm deleted file mode 100644 index 09308d776..000000000 --- a/miden-lib/asm/utils/note.masm +++ /dev/null @@ -1,12 +0,0 @@ -# The maximum number of input values associated with a single note. -const.MAX_INPUTS_PER_NOTE=128 - -#! Returns the max allowed number of input values per note. -#! -#! Stack: [] -#! Output: [max_inputs_per_note] -#! -#! - max_inputs_per_note is the max inputs per note. -export.get_max_inputs_per_note - push.MAX_INPUTS_PER_NOTE -end diff --git a/miden-lib/asm/utils/account.masm b/miden-lib/asm/utils/utils.masm similarity index 67% rename from miden-lib/asm/utils/account.masm rename to miden-lib/asm/utils/utils.masm index d5f10cc13..5a4c22f5a 100644 --- a/miden-lib/asm/utils/account.masm +++ b/miden-lib/asm/utils/utils.masm @@ -1,3 +1,5 @@ +### ACCOUNT ######################################################### + # Given the most significant half of an account id, this mask defines the bits used to determine the # account type. const.ACCOUNT_TYPE_U32MASK=805306368 # 0b00110000_00000000_00000000_00000000 @@ -51,3 +53,33 @@ export.is_non_fungible_faucet exec.type push.NON_FUNGIBLE_FAUCET_ACCOUNT eq # => [is_non_fungible_faucet] end + +### ASSET ########################################################### + +const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 + +#! Returns the maximum amount of a fungible asset. +#! +#! Stack: [] +#! Outputs: [fungible_asset_max_amount] +#! +#! fungible_asset_max_amount is the maximum amount of a fungible asset. +export.get_fungible_asset_max_amount + push.FUNGIBLE_ASSET_MAX_AMOUNT + # => [fungible_asset_max_amount] +end + +### NOTE ############################################################ + +# The maximum number of input values associated with a single note. +const.MAX_INPUTS_PER_NOTE=128 + +#! Returns the max allowed number of input values per note. +#! +#! Stack: [] +#! Output: [max_inputs_per_note] +#! +#! - max_inputs_per_note is the max inputs per note. +export.get_max_inputs_per_note + push.MAX_INPUTS_PER_NOTE +end diff --git a/miden-lib/build.rs b/miden-lib/build.rs index fbf8ac024..9420fb339 100644 --- a/miden-lib/build.rs +++ b/miden-lib/build.rs @@ -29,7 +29,7 @@ const ASM_NOTE_SCRIPTS_DIR: &str = "note_scripts"; const ASM_ACCOUNT_COMPONENTS_DIR: &str = "account_components"; const ASM_TX_KERNEL_DIR: &str = "kernels/transaction"; const KERNEL_V0_RS_FILE: &str = "src/transaction/procedures/kernel_v0.rs"; -const ASM_UTILS_DIR: &str = "utils"; +const UTILS_DIR: &str = "utils"; const KERNEL_ERRORS_FILE: &str = "src/errors/tx_kernel_errors.rs"; @@ -58,15 +58,9 @@ fn main() -> Result<()> { // set target directory to {OUT_DIR}/assets let target_dir = Path::new(&build_dir).join(ASSETS_DIR); - // compile utils dir - let utils_lib = compile_utils_lib(&source_dir, &target_dir)?; - // compile transaction kernel - let mut assembler = compile_tx_kernel( - &source_dir.join(ASM_TX_KERNEL_DIR), - &target_dir.join("kernels"), - utils_lib, - )?; + let mut assembler = + compile_tx_kernel(&source_dir.join(ASM_TX_KERNEL_DIR), &target_dir.join("kernels"))?; // compile miden library let miden_lib = compile_miden_lib(&source_dir, &target_dir, assembler.clone())?; @@ -111,12 +105,12 @@ fn main() -> Result<()> { /// /// When the `testing` feature is enabled, the POW requirements for account ID generation are /// adjusted by modifying the corresponding constants in {source_dir}/lib/constants.masm file. -fn compile_tx_kernel( - source_dir: &Path, - target_dir: &Path, - utils_lib: Library, -) -> Result { - let assembler = build_assembler(None, utils_lib.clone())?; +fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result { + let utils_namespace = LibraryNamespace::new("utils").expect("invalid namespace"); + let utils_path = Path::new(ASM_DIR).join(UTILS_DIR); + + let mut assembler = build_assembler(None)?; + assembler.add_modules_from_dir(utils_namespace.clone(), &utils_path)?; // if this build has the testing flag set, modify the code and reduce the cost of proof-of-work match env::var("CARGO_FEATURE_TESTING") { @@ -156,7 +150,8 @@ fn compile_tx_kernel( let output_file = target_dir.join("tx_kernel").with_extension(Library::LIBRARY_EXTENSION); kernel_lib.write_to_file(output_file).into_diagnostic()?; - let assembler = build_assembler(Some(kernel_lib), utils_lib)?; + let mut assembler = build_assembler(Some(kernel_lib))?; + assembler.add_modules_from_dir(utils_namespace, &utils_path)?; // assemble the kernel program and write it the "tx_kernel.masb" file let mut main_assembler = assembler.clone(); @@ -292,25 +287,6 @@ fn compile_miden_lib( Ok(miden_lib) } -// COMPILE UTILS LIB -// ================================================================================================ - -/// Reads the MASM files from "{source_dir}/utils" directory, compiles them into a Miden assembly -/// library, saves the library into "{target_dir}/utils.masl", and returns the complied library. -fn compile_utils_lib(source_dir: &Path, target_dir: &Path) -> Result { - let assembler = Assembler::default(); - - let source_dir = source_dir.join(ASM_UTILS_DIR); - - let namespace = "utils".parse::().expect("invalid base namespace"); - let utils_lib = Library::from_dir(source_dir.clone(), namespace.clone(), assembler.clone())?; - - let output_file = target_dir.join("utils").with_extension(Library::LIBRARY_EXTENSION); - utils_lib.write_to_file(output_file).into_diagnostic()?; - - Ok(utils_lib) -} - // COMPILE EXECUTABLE MODULES // ================================================================================================ @@ -381,14 +357,12 @@ fn compile_account_components(target_dir: &Path, assembler: Assembler) -> Result /// Returns a new [Assembler] loaded with miden-stdlib and the specified kernel, if provided. /// /// The returned assembler will be in the `debug` mode if the `with-debug-info` feature is enabled. -fn build_assembler(kernel: Option, utils_lib: Library) -> Result { +fn build_assembler(kernel: Option) -> Result { kernel .map(|kernel| Assembler::with_kernel(Arc::new(DefaultSourceManager::default()), kernel)) .unwrap_or_default() .with_debug_mode(cfg!(feature = "with-debug-info")) .with_library(miden_stdlib::StdLibrary::default()) - .unwrap_or_default() - .with_library(utils_lib) } /// Recursively copies `src` into `dst`. diff --git a/miden-lib/src/lib.rs b/miden-lib/src/lib.rs index d81a75904..86edb61f9 100644 --- a/miden-lib/src/lib.rs +++ b/miden-lib/src/lib.rs @@ -15,9 +15,6 @@ use miden_objects::{ mod auth; pub use auth::AuthScheme; -mod utils_lib; -pub use utils_lib::UtilsLib; - pub mod accounts; pub mod errors; pub mod notes; diff --git a/miden-lib/src/transaction/mod.rs b/miden-lib/src/transaction/mod.rs index b07dbd9db..01d10229c 100644 --- a/miden-lib/src/transaction/mod.rs +++ b/miden-lib/src/transaction/mod.rs @@ -14,7 +14,7 @@ use miden_objects::{ use miden_stdlib::StdLibrary; use outputs::EXPIRATION_BLOCK_ELEMENT_IDX; -use super::{MidenLib, UtilsLib}; +use super::MidenLib; pub mod memory; @@ -120,8 +120,6 @@ impl TransactionKernel { .expect("failed to load std-lib") .with_library(MidenLib::default()) .expect("failed to load miden-lib") - .with_library(UtilsLib::default()) - .expect("failed to load utils lib") } // STACK INPUTS / OUTPUTS @@ -357,8 +355,6 @@ impl TransactionKernel { Assembler::with_kernel(source_manager, Self::kernel()) .with_library(StdLibrary::default()) .expect("failed to load std-lib") - .with_library(UtilsLib::default()) - .expect("failed to load utils library") .with_library(MidenLib::default()) .expect("failed to load miden-lib") .with_library(kernel_library) diff --git a/miden-lib/src/transaction/procedures/kernel_v0.rs b/miden-lib/src/transaction/procedures/kernel_v0.rs index ad5ca1fef..ddf75166b 100644 --- a/miden-lib/src/transaction/procedures/kernel_v0.rs +++ b/miden-lib/src/transaction/procedures/kernel_v0.rs @@ -8,9 +8,9 @@ use miden_objects::{digest, Digest}; /// Hashes of all dynamically executed procedures from the kernel 0. pub const KERNEL0_PROCEDURES: [Digest; 33] = [ // account_vault_add_asset - digest!("0x5cf407f2af3f6454d8b15e4874d4e86b4dbfb7752adb6e55b6586925869d50bd"), + digest!("0xc69b608da541fea9a41322359cc049cac55f816858f530005e333d0b54f2f284"), // account_vault_get_balance - digest!("0x12b9ca5ec182a90b30ad391815eff9c359605e4b65ca58a3f900cb91867675a6"), + digest!("0x37c528cbc741f6c9d81602bcb435185f471eec705a59a36704ef3632960607e8"), // account_vault_has_non_fungible_asset digest!("0x7144f9ac1df4c4c90b770891e1665d25a819ea026227a7d143ab89b89991bc14"), // account_vault_remove_asset @@ -38,13 +38,13 @@ pub const KERNEL0_PROCEDURES: [Digest; 33] = [ // set_account_map_item digest!("0x02befd8e777bacc5f4c3b14267b7e5558c9557d82970e74612c5aa6d7febf9c2"), // burn_asset - digest!("0xb6199ab60d4537004ac67d09934eea304e552436bc3e3d46d104ba05370f217d"), + digest!("0x5b3bcc39db744de02b0111a43191c09c7cafbf138fac5913d959290225f061aa"), // get_fungible_faucet_total_issuance - digest!("0xa88104e2c01847358f697d52d46281a53ac0d9efaa755c7531fad5f8a9c67c29"), + digest!("0x0ba11e1765fac99dd615e32f4035773fad1093f14bd2ed7c98fa5470a60b7e19"), // mint_asset - digest!("0x6bdaab695377806fe6c7c1f3f6b8b34f5a11046697be282eb037d14b21eb7b37"), + digest!("0xc1e42d63f41e1b5f8b550e01b0ad69de5b264fe7214d036ca09927998eb8e422"), // add_asset_to_note - digest!("0x07e219a8e9c211663fa39b224eccd77b5cb25df0395aa4503556b142cf0cb4b9"), + digest!("0x9728db11ce1e4aa6420f53bfd8002289d3aa5b18dae9039d3c3ee2b2541ecbeb"), // create_note digest!("0xf3c0b7305783deabeae67fca094df529a04a02332c9a79c1622953f63b08959d"), // get_input_notes_commitment diff --git a/miden-tx/src/executor/mast_store.rs b/miden-tx/src/executor/mast_store.rs index 470e2af4e..df81d18c4 100644 --- a/miden-tx/src/executor/mast_store.rs +++ b/miden-tx/src/executor/mast_store.rs @@ -1,8 +1,6 @@ use alloc::{collections::BTreeMap, sync::Arc}; -use miden_lib::{ - transaction::TransactionKernel, utils::sync::RwLock, MidenLib, StdLibrary, UtilsLib, -}; +use miden_lib::{transaction::TransactionKernel, utils::sync::RwLock, MidenLib, StdLibrary}; use miden_objects::{ accounts::AccountCode, assembly::mast::MastForest, @@ -49,10 +47,6 @@ impl TransactionMastStore { let miden_lib_forest = MidenLib::default().mast_forest().clone(); store.insert(miden_lib_forest); - // load utils lib MAST forest - let utils_lib_forest = UtilsLib::default().mast_forest().clone(); - store.insert(utils_lib_forest); - store } diff --git a/miden-tx/src/testing/executor.rs b/miden-tx/src/testing/executor.rs index d7a6b322f..47ee41f67 100644 --- a/miden-tx/src/testing/executor.rs +++ b/miden-tx/src/testing/executor.rs @@ -1,4 +1,4 @@ -use miden_lib::{transaction::TransactionKernel, UtilsLib}; +use miden_lib::transaction::TransactionKernel; use vm_processor::{ AdviceInputs, AdviceProvider, DefaultHost, ExecutionError, Host, Process, Program, StackInputs, }; @@ -61,7 +61,6 @@ where let test_lib = TransactionKernel::kernel_as_library(); host.load_mast_forest(test_lib.mast_forest().clone()); - host.load_mast_forest(UtilsLib::default().mast_forest().clone()); CodeExecutor::new(host) } diff --git a/miden-tx/src/tests/kernel_tests/test_account.rs b/miden-tx/src/tests/kernel_tests/test_account.rs index 7c2d5a9ea..4f9428770 100644 --- a/miden-tx/src/tests/kernel_tests/test_account.rs +++ b/miden-tx/src/tests/kernel_tests/test_account.rs @@ -112,10 +112,10 @@ pub fn test_set_code_succeeds() { #[test] pub fn test_account_type() { let procedures = vec![ - ("utils", "is_fungible_faucet", AccountType::FungibleFaucet), - ("utils", "is_non_fungible_faucet", AccountType::NonFungibleFaucet), - ("kernel", "is_updatable_account", AccountType::RegularAccountUpdatableCode), - ("kernel", "is_immutable_account", AccountType::RegularAccountImmutableCode), + ("is_fungible_faucet", AccountType::FungibleFaucet), + ("is_non_fungible_faucet", AccountType::NonFungibleFaucet), + ("is_updatable_account", AccountType::RegularAccountUpdatableCode), + ("is_immutable_account", AccountType::RegularAccountImmutableCode), ]; let test_cases = [ @@ -125,7 +125,7 @@ pub fn test_account_type() { ACCOUNT_ID_NON_FUNGIBLE_FAUCET_OFF_CHAIN, ]; - for (lib, procedure, expected_type) in procedures { + for (procedure, expected_type) in procedures { let mut has_type = false; for account_id in test_cases.iter() { @@ -133,13 +133,13 @@ pub fn test_account_type() { let code = format!( " - use.{}::account + use.kernel::account begin exec.account::{} end ", - lib, procedure + procedure ); let process = CodeExecutor::with_advice_provider(MemAdviceProvider::default()) From 73fa206766a7eda18d7f021f55b35d158f30f60a Mon Sep 17 00:00:00 2001 From: Andrey Khmuro Date: Fri, 20 Dec 2024 03:52:36 +0300 Subject: [PATCH 03/10] refactor: optimize utils module path in masm --- .../asm/kernels/transaction/lib/account.masm | 19 +++++++- .../asm/kernels/transaction/lib/asset.masm | 10 +++- .../kernels/transaction/lib/constants.masm | 8 +++- miden-lib/asm/miden/account.masm | 22 +++++++-- miden-lib/asm/miden/asset.masm | 8 +++- miden-lib/asm/miden/note.masm | 9 +++- miden-lib/asm/{utils => }/utils.masm | 0 miden-lib/build.rs | 23 +++++---- miden-lib/src/utils_lib.rs | 47 ------------------- 9 files changed, 77 insertions(+), 69 deletions(-) rename miden-lib/asm/{utils => }/utils.masm (100%) delete mode 100644 miden-lib/src/utils_lib.rs diff --git a/miden-lib/asm/kernels/transaction/lib/account.masm b/miden-lib/asm/kernels/transaction/lib/account.masm index 7b4db3671..743aa5a8c 100644 --- a/miden-lib/asm/kernels/transaction/lib/account.masm +++ b/miden-lib/asm/kernels/transaction/lib/account.masm @@ -244,8 +244,23 @@ export.memory::get_acct_nonce->get_nonce #! - INIT_HASH is the initial account hash. export.memory::get_init_acct_hash->get_initial_hash -export.::utils::utils::is_fungible_faucet -export.::utils::utils::is_non_fungible_faucet +#! Returns a boolean indicating whether the account is a fungible faucet. +#! +#! Stack: [acct_id] +#! Output: [is_fungible_faucet] +#! +#! - acct_id is the account id. +#! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. +export.::utils::is_fungible_faucet + +#! Returns a boolean indicating whether the account is a non-fungible faucet. +#! +#! Stack: [acct_id] +#! Output: [is_non_fungible_faucet] +#! +#! - acct_id is the account id. +#! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. +export.::utils::is_non_fungible_faucet #! Returns a boolean indicating whether the account is a faucet. #! diff --git a/miden-lib/asm/kernels/transaction/lib/asset.masm b/miden-lib/asm/kernels/transaction/lib/asset.masm index d0dda3e16..86fb9bcc8 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset.masm @@ -36,11 +36,17 @@ const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 # is used to identify the asset type const.FUNGIBLE_BITMASK_U32=0x20000000 -export.::utils::utils::get_fungible_asset_max_amount - # PROCEDURES # ================================================================================================= +#! Returns the maximum amount of a fungible asset. +#! +#! Stack: [] +#! Outputs: [fungible_asset_max_amount] +#! +#! fungible_asset_max_amount is the maximum amount of a fungible asset. +export.::utils::get_fungible_asset_max_amount + #! Validates that a fungible asset is well formed. #! #! Inputs: [ASSET] diff --git a/miden-lib/asm/kernels/transaction/lib/constants.masm b/miden-lib/asm/kernels/transaction/lib/constants.masm index 861bc9a2d..e35c9b75a 100644 --- a/miden-lib/asm/kernels/transaction/lib/constants.masm +++ b/miden-lib/asm/kernels/transaction/lib/constants.masm @@ -49,7 +49,13 @@ export.get_word_size push.WORD_SIZE end -export.::utils::utils::get_max_inputs_per_note +#! Returns the max allowed number of input values per note. +#! +#! Stack: [] +#! Output: [max_inputs_per_note] +#! +#! - max_inputs_per_note is the max inputs per note. +export.::utils::get_max_inputs_per_note #! Returns the max allowed number of assets per note. #! diff --git a/miden-lib/asm/miden/account.masm b/miden-lib/asm/miden/account.masm index 0a5405b46..e1bcf8f9f 100644 --- a/miden-lib/asm/miden/account.masm +++ b/miden-lib/asm/miden/account.masm @@ -1,13 +1,25 @@ use.miden::kernel_proc_offsets -# REEXPORTED PROCEDURES +# NATIVE ACCOUNT PROCEDURES # ================================================================================================= -export.::utils::utils::is_fungible_faucet -export.::utils::utils::is_non_fungible_faucet +#! Returns a boolean indicating whether the account is a fungible faucet. +#! +#! Stack: [acct_id] +#! Output: [is_fungible_faucet] +#! +#! - acct_id is the account id. +#! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. +export.::utils::is_fungible_faucet -# NATIVE ACCOUNT PROCEDURES -# ================================================================================================= +#! Returns a boolean indicating whether the account is a non-fungible faucet. +#! +#! Stack: [acct_id] +#! Output: [is_non_fungible_faucet] +#! +#! - acct_id is the account id. +#! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. +export.::utils::is_non_fungible_faucet #! Returns the account id. #! diff --git a/miden-lib/asm/miden/asset.masm b/miden-lib/asm/miden/asset.masm index 60ba13082..c729caa2a 100644 --- a/miden-lib/asm/miden/asset.masm +++ b/miden-lib/asm/miden/asset.masm @@ -24,7 +24,13 @@ const.FUNGIBLE_BITMASK_U32=0x20000000 # PROCEDURES # ================================================================================================= -export.::utils::utils::get_fungible_asset_max_amount +#! Returns the maximum amount of a fungible asset. +#! +#! Stack: [] +#! Outputs: [fungible_asset_max_amount] +#! +#! fungible_asset_max_amount is the maximum amount of a fungible asset. +export.::utils::get_fungible_asset_max_amount #! Builds a fungible asset for the specified fungible faucet and amount. #! diff --git a/miden-lib/asm/miden/note.masm b/miden-lib/asm/miden/note.masm index 0ae844041..65dbe070f 100644 --- a/miden-lib/asm/miden/note.masm +++ b/miden-lib/asm/miden/note.masm @@ -12,11 +12,16 @@ const.ERR_NOTE_DATA_DOES_NOT_MATCH_COMMITMENT=0x0002004E # Number of note inputs exceeded the maximum limit of 128 const.ERR_PROLOGUE_NUMBER_OF_NOTE_INPUTS_EXCEEDED_LIMIT=0x0002004F - # PROCEDURES # ================================================================================================= -export.::utils::utils::get_max_inputs_per_note +#! Returns the max allowed number of input values per note. +#! +#! Stack: [] +#! Output: [max_inputs_per_note] +#! +#! - max_inputs_per_note is the max inputs per note. +export.::utils::get_max_inputs_per_note #! Writes the data currently on the advice stack into the memory at the specified location and #! verifies that the hash of the written data is equal to the provided hash. diff --git a/miden-lib/asm/utils/utils.masm b/miden-lib/asm/utils.masm similarity index 100% rename from miden-lib/asm/utils/utils.masm rename to miden-lib/asm/utils.masm diff --git a/miden-lib/build.rs b/miden-lib/build.rs index 9420fb339..52cfc60ea 100644 --- a/miden-lib/build.rs +++ b/miden-lib/build.rs @@ -11,7 +11,8 @@ use std::{ use assembly::{ diagnostics::{IntoDiagnostic, Result}, utils::Serializable, - Assembler, DefaultSourceManager, KernelLibrary, Library, LibraryNamespace, Report, + Assembler, CompileOptions, DefaultSourceManager, KernelLibrary, Library, LibraryNamespace, + LibraryPath, Report, }; use regex::Regex; use walkdir::WalkDir; @@ -29,8 +30,6 @@ const ASM_NOTE_SCRIPTS_DIR: &str = "note_scripts"; const ASM_ACCOUNT_COMPONENTS_DIR: &str = "account_components"; const ASM_TX_KERNEL_DIR: &str = "kernels/transaction"; const KERNEL_V0_RS_FILE: &str = "src/transaction/procedures/kernel_v0.rs"; -const UTILS_DIR: &str = "utils"; - const KERNEL_ERRORS_FILE: &str = "src/errors/tx_kernel_errors.rs"; // PRE-PROCESSING @@ -106,11 +105,16 @@ fn main() -> Result<()> { /// When the `testing` feature is enabled, the POW requirements for account ID generation are /// adjusted by modifying the corresponding constants in {source_dir}/lib/constants.masm file. fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result { - let utils_namespace = LibraryNamespace::new("utils").expect("invalid namespace"); - let utils_path = Path::new(ASM_DIR).join(UTILS_DIR); + let utils_path = Path::new(ASM_DIR).join("utils.masm"); + let utils_compile_options = CompileOptions { + path: Some(LibraryPath::new("utils").expect("library path for utils module is incorrect")), + ..CompileOptions::for_library() + }; - let mut assembler = build_assembler(None)?; - assembler.add_modules_from_dir(utils_namespace.clone(), &utils_path)?; + // add the utils module to the kernel lib by providing it to the assembler + let assembler = build_assembler(None)? + .with_module_and_options(utils_path.clone(), utils_compile_options.clone()) + .expect("provided utils module is not a library module"); // if this build has the testing flag set, modify the code and reduce the cost of proof-of-work match env::var("CARGO_FEATURE_TESTING") { @@ -150,8 +154,9 @@ fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result let output_file = target_dir.join("tx_kernel").with_extension(Library::LIBRARY_EXTENSION); kernel_lib.write_to_file(output_file).into_diagnostic()?; - let mut assembler = build_assembler(Some(kernel_lib))?; - assembler.add_modules_from_dir(utils_namespace, &utils_path)?; + let assembler = build_assembler(Some(kernel_lib))? + .with_module_and_options(utils_path, utils_compile_options) + .expect("provided utils module is not a library module"); // assemble the kernel program and write it the "tx_kernel.masb" file let mut main_assembler = assembler.clone(); diff --git a/miden-lib/src/utils_lib.rs b/miden-lib/src/utils_lib.rs deleted file mode 100644 index d0efa8be3..000000000 --- a/miden-lib/src/utils_lib.rs +++ /dev/null @@ -1,47 +0,0 @@ -use alloc::sync::Arc; - -use miden_objects::{ - assembly::{mast::MastForest, Library}, - utils::{serde::Deserializable, sync::LazyLock}, -}; - -// CONSTANTS -// ================================================================================================ - -const UTILS_LIB_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/assets/utils.masl")); - -// UTILITIES LIBRARY -// ================================================================================================ - -#[derive(Clone)] -pub struct UtilsLib(Library); - -impl UtilsLib { - /// Returns a reference to the [`MastForest`] of the inner [`Library`]. - pub fn mast_forest(&self) -> &Arc { - self.0.mast_forest() - } -} - -impl AsRef for UtilsLib { - fn as_ref(&self) -> &Library { - &self.0 - } -} - -impl From for Library { - fn from(value: UtilsLib) -> Self { - value.0 - } -} - -impl Default for UtilsLib { - fn default() -> Self { - static UTILS_LIB: LazyLock = LazyLock::new(|| { - let contents = - Library::read_from_bytes(UTILS_LIB_BYTES).expect("failed to read miden lib masl!"); - UtilsLib(contents) - }); - UTILS_LIB.clone() - } -} From 38e3fdabd68ff75576a878d577bfa9d6c212dce9 Mon Sep 17 00:00:00 2001 From: Andrey Khmuro Date: Fri, 10 Jan 2025 00:36:43 +0300 Subject: [PATCH 04/10] refactor: move pure utils functions out of account --- miden-lib/asm/kernels/transaction/api.masm | 15 +- .../asm/kernels/transaction/lib/account.masm | 345 +----------------- .../transaction/lib/account_utils.masm | 338 +++++++++++++++++ .../asm/kernels/transaction/lib/asset.masm | 11 +- .../kernels/transaction/lib/asset_vault.masm | 3 +- .../asm/kernels/transaction/lib/faucet.masm | 21 +- .../asm/kernels/transaction/lib/prologue.masm | 15 +- 7 files changed, 384 insertions(+), 364 deletions(-) create mode 100644 miden-lib/asm/kernels/transaction/lib/account_utils.masm diff --git a/miden-lib/asm/kernels/transaction/api.masm b/miden-lib/asm/kernels/transaction/api.masm index 48ada8128..bcd6ecff3 100644 --- a/miden-lib/asm/kernels/transaction/api.masm +++ b/miden-lib/asm/kernels/transaction/api.masm @@ -2,6 +2,7 @@ use.std::collections::smt use.std::sys use.kernel::account +use.kernel::account_utils use.kernel::asset_vault use.kernel::constants use.kernel::faucet @@ -193,7 +194,7 @@ export.get_account_item # => [storage_offset, storage_size, index, pad(15)] # apply offset to storage slot index - exec.account::apply_storage_offset + exec.account_utils::apply_storage_offset # => [index_with_offset, pad(15)] # fetch the account storage item @@ -228,8 +229,8 @@ export.set_account_item # if the transaction is being executed against a faucet account then assert # index != FAUCET_STORAGE_DATA_SLOT (reserved slot) - dup exec.account::get_faucet_storage_data_slot eq - exec.account::get_id swap drop exec.account::is_faucet + dup exec.account_utils::get_faucet_storage_data_slot eq + exec.account::get_id swap drop exec.account_utils::is_faucet and assertz.err=ERR_FAUCET_STORAGE_DATA_SLOT_IS_RESERVED # => [index, V', pad(11)] @@ -238,7 +239,7 @@ export.set_account_item # => [storage_offset, storage_size, index, V', pad(11)] # apply offset to storage slot index - exec.account::apply_storage_offset + exec.account_utils::apply_storage_offset # => [index_with_offset, V', pad(11)] # set the account storage item @@ -279,7 +280,7 @@ export.get_account_map_item # => [storage_offset, storage_size, index, KEY, pad(11)] # apply offset to storage slot index - exec.account::apply_storage_offset + exec.account_utils::apply_storage_offset # => [index_with_offset, KEY, pad(11)] # fetch the account storage item, which is ROOT of the map @@ -325,7 +326,7 @@ export.set_account_map_item.1 # => [storage_offset, storage_size, index, KEY, NEW_VALUE, pad(7)] # apply offset to storage slot index - exec.account::apply_storage_offset + exec.account_utils::apply_storage_offset # => [index_with_offset, KEY, NEW_VALUE, pad(7)] # store index for later @@ -820,7 +821,7 @@ end #! Invocation: dynexec export.get_fungible_faucet_total_issuance # assert that we are executing a transaction against a fungible faucet (access checks) - exec.account::get_id swap drop exec.account::is_fungible_faucet + exec.account::get_id swap drop exec.account_utils::is_fungible_faucet assert.err=ERR_ACCOUNT_TOTAL_ISSUANCE_PROC_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_FAUCET # => [pad(16)] diff --git a/miden-lib/asm/kernels/transaction/lib/account.masm b/miden-lib/asm/kernels/transaction/lib/account.masm index 0f597d349..bb59fd07b 100644 --- a/miden-lib/asm/kernels/transaction/lib/account.masm +++ b/miden-lib/asm/kernels/transaction/lib/account.masm @@ -3,6 +3,7 @@ use.std::collections::smt use.std::crypto::hashes::rpo use.std::mem +use.kernel::account_utils use.kernel::constants use.kernel::memory @@ -12,9 +13,6 @@ use.kernel::memory # Account nonce cannot be increased by a greater than u32 value const.ERR_ACCOUNT_NONCE_INCREASE_MUST_BE_U32=0x00020004 -# Least significant byte of second felt of the account id must be zero. -const.ERR_ACCOUNT_ID_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO=0x00020005 - # Account code must be updatable for it to be possible to set new code const.ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE=0x00020006 @@ -69,46 +67,9 @@ const.ERR_FOREIGN_ACCOUNT_ID_EQUALS_NATIVE_ACCT_ID=0x00020016 # State of the current foreign account is invalid. const.ERR_FOREIGN_ACCOUNT_INVALID=0x00020017 -# Unknown version in account id. -const.ERR_ACCOUNT_ID_UNKNOWN_VERSION=0x00020057 - -# Epoch must be less than u16::MAX (0xffff). -const.ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX=0x00020058 - # CONSTANTS # ================================================================================================= -# Given the least significant 32 bits of an account id's first felt, 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 first felt, this mask defines the bits used -# to determine the account type. -const.ACCOUNT_ID_TYPE_MASK_U32=0x30 # 0b11_0000 - -# Bit pattern for an account w/ immutable code, after the account type mask has been applied. -const.REGULAR_ACCOUNT_IMMUTABLE_CODE=0 # 0b00_0000 - -# Bit pattern for an account w/ updatable code, after the account type mask has been applied. -const.REGULAR_ACCOUNT_UPDATABLE_CODE=0x10 # 0b01_0000 - -# Bit pattern for a faucet account, after the account type mask has been applied. -const.FAUCET_ACCOUNT=0x20 # 0b10_0000 - -# The maximum number of account interface procedures. -const.MAX_NUM_PROCEDURES=256 - -# The account storage slot at which faucet data is stored. -# Fungible faucet: The faucet data consists of [0, 0, 0, total_issuance] -# Non-fungible faucet: The faucet data consists of SMT root containing minted non-fungible assets. -const.FAUCET_STORAGE_DATA_SLOT=0 - -# The maximum storage slot index -const.MAX_STORAGE_SLOT_INDEX=254 - -# The maximum number of account storage slots. -const.MAX_NUM_STORAGE_SLOTS=MAX_STORAGE_SLOT_INDEX+1 - # Depth of the account database tree. const.ACCOUNT_TREE_DEPTH=64 @@ -140,44 +101,6 @@ const.ACCOUNT_AFTER_INCREMENT_NONCE_EVENT=131081 # the advice stack. const.ACCOUNT_PUSH_PROCEDURE_INDEX_EVENT=131082 -# CONSTANT ACCESSORS -# ================================================================================================= - -#! Returns the account storage slot at which faucet data is stored. -#! Fungible faucet: The faucet data consists of [0, 0, 0, total_issuance] -#! Non-fungible faucet: The faucet data consists of SMT root containing minted non-fungible assets. -#! -#! Inputs: [] -#! Outputs: [faucet_storage_data_slot] -#! -#! Where: -#! - faucet_storage_data_slot is the account storage slot at which faucet data is stored. -export.get_faucet_storage_data_slot - push.FAUCET_STORAGE_DATA_SLOT -end - -#! Returns the maximum number of account storage slots. -#! -#! Inputs: [] -#! Outputs: [max_num_storage_slots] -#! -#! Where: -#! - max_num_storage_slots is the maximum number of account storage slots. -export.get_max_num_storage_slots - push.MAX_NUM_STORAGE_SLOTS -end - -#! Returns the maximum number of account interface procedures. -#! -#! Inputs: [] -#! Outputs: [max_num_procedures] -#! -#! Where: -#! - max_num_procedures is the maximum number of account interface procedures. -export.get_max_num_procedures - push.MAX_NUM_PROCEDURES -end - # PROCEDURES # ================================================================================================= @@ -252,116 +175,6 @@ export.memory::get_acct_nonce->get_nonce #! - INIT_HASH is the initial account hash. export.memory::get_init_acct_hash->get_initial_hash -#! Returns a boolean indicating whether the account is a fungible faucet. -#! -#! Inputs: [acct_id_hi] -#! Outputs: [is_fungible_faucet] -#! -#! Where: -#! - acct_id_hi is the first felt of the account id. -#! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. -export.::utils::is_fungible_faucet - -#! Returns a boolean indicating whether the account is a non-fungible faucet. -#! -#! Inputs: [acct_id_hi] -#! Outputs: [is_non_fungible_faucet] -#! -#! Where: -#! - acct_id_hi is the first felt of the account id. -#! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. -export.::utils::is_non_fungible_faucet - -#! Returns a boolean indicating whether the given account_ids are equal. -#! -#! Inputs: [acct_id_hi, acct_id_lo, other_acct_id_hi, other_acct_id_lo] -#! Outputs: [is_id_equal] -#! -#! Where: -#! - acct_id_{hi,lo} are the first and second felt of an account id. -#! - other_acct_id_{hi,lo} are the first and second felt of the other account id to compare against. -#! - is_id_equal is a boolean indicating whether the account ids are equal. -export.::utils::is_id_eq - -#! Returns a boolean indicating whether the account is a faucet. -#! -#! Inputs: [acct_id_hi] -#! Outputs: [is_faucet] -#! -#! Where: -#! - acct_id_hi is the first felt of the account id. -#! - is_faucet is a boolean indicating whether the account is a faucet. -export.is_faucet - u32split drop push.FAUCET_ACCOUNT u32and eq.0 not - # => [is_faucet] -end - -#! Returns a boolean indicating whether the account is a regular updatable account. -#! -#! Inputs: [acct_id_hi] -#! Outputs: [is_updatable_account] -#! -#! Where: -#! - acct_id_hi is the first felt of the account id. -#! - is_updatable_account is a boolean indicating whether the account is a regular updatable -#! account. -export.is_updatable_account - exec.type push.REGULAR_ACCOUNT_UPDATABLE_CODE eq - # => [is_updatable_account] -end - -#! Returns a boolean indicating whether the account is a regular immutable account. -#! -#! Inputs: [acct_id_hi] -#! Outputs: [is_immutable_account] -#! -#! Where: -#! - acct_id_hi is the first felt of the account id. -#! - is_immutable_account is a boolean indicating whether the account is a regular immutable -#! account. -export.is_immutable_account - exec.type push.REGULAR_ACCOUNT_IMMUTABLE_CODE eq - # => [is_immutable_account] -end - -#! Validates an account id. -#! -#! Inputs: [account_id_hi, account_id_lo] -#! Outputs: [] -#! -#! Where: -#! - account_id_{hi,lo} are the first and second felt of the account id. -#! -#! Panics if: -#! - account_id_hi does not contain version zero. -#! - account_id_lo contains an anchor epoch that is greater or equal to 2^16. -#! - account_id_lo does not have its lower 8 bits set to zero. -export.validate_id - # Validate version in first felt. For now only version 0 is supported. - # --------------------------------------------------------------------------------------------- - - exec.id_version - # => [id_version, account_id_lo] - assertz.err=ERR_ACCOUNT_ID_UNKNOWN_VERSION - # => [account_id_lo] - - # Validate anchor epoch is less than u16::MAX (0xffff) in second felt. - # --------------------------------------------------------------------------------------------- - - dup exec.id_anchor_epoch - # => [anchor_epoch, account_id_lo] - lt.0xffff assert.err=ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX - # => [account_id_lo] - - # Validate lower 8 bits of second felt are zero. - # --------------------------------------------------------------------------------------------- - - u32split drop u32and.0xff eq.0 - # => [is_least_significant_byte_zero] - assert.err=ERR_ACCOUNT_ID_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO - # => [] -end - #! Sets the code of the account the transaction is being executed against. #! #! Inputs: [CODE_COMMITMENT] @@ -378,7 +191,7 @@ export.set_code # => [acct_id_hi, CODE_COMMITMENT] # assert the account is an updatable regular account - exec.is_updatable_account assert.err=ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE + exec.account_utils::is_updatable_account assert.err=ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE # => [CODE_COMMITMENT] # set the code commitment @@ -386,29 +199,6 @@ export.set_code # => [] end -#! Applies storage offset to provided storage slot index for storage access. -#! -#! Inputs: [storage_offset, storage_size, slot_index] -#! Outputs: [offset_slot_index] -#! -#! Where: -#! - storage_offset is the offset of the storage for this account component. -#! - storage_size is the number of storage slots accessible from this account component. -#! - slot_index is the index of the storage slot to be accessed. -#! - offset_slot_index is the final index of the storage slot with the storage offset applied to it. -#! -#! Panics if: -#! - the computed index is out of bounds -export.apply_storage_offset - # offset index - dup movup.3 add - # => [offset_slot_index, storage_offset, storage_size] - - # verify that slot_index is in bounds - movdn.2 add dup.1 gt assert.err=ERR_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS - # => [offset_slot_index] -end - #! Validates all account procedures storage metadata by checking that: #! - All storage offsets and sizes are in bounds. #! - All procedures not accessing storage have offset and size set to 0. @@ -427,7 +217,7 @@ export.validate_procedure_metadata # => [start_loop, index, num_storage_slots, num_account_procedures] # check if the account is a faucet - exec.get_id swap drop exec.is_faucet + exec.get_id swap drop exec.account_utils::is_faucet # => [is_faucet, start_loop, index, num_storage_slots, num_account_procedures] # we do not check if num_account_procedures == 0 here because a valid @@ -734,7 +524,7 @@ export.validate_seed # => [0, 0, account_id_hi, account_id_lo] # get the anchor block's number - dup.3 exec.id_anchor_block_num + dup.3 exec.account_utils::id_anchor_block_num # => [anchor_block_num, 0, 0, account_id_hi, account_id_lo] exec.memory::get_chain_mmr_ptr swap @@ -798,112 +588,18 @@ export.validate_seed # => [account_id_lo, hashed_account_id_hi, hashed_account_id_lo, account_id_hi] # extract anchor epoch from ID of the new account - dup movdn.4 exec.id_anchor_epoch + dup movdn.4 exec.account_utils::id_anchor_epoch # => [anchor_epoch, hashed_account_id_hi, hashed_account_id_lo, account_id_hi, account_id_lo] # shape second felt of hashed id, adding the anchor epoch and setting the lower 8 bits to zero - movup.2 exec.shape_second_felt swap + movup.2 exec.account_utils::shape_second_felt swap # => [hashed_account_id_hi, hashed_account_id_lo, account_id_hi, account_id_lo] # assert the account id matches the account id of the new account - exec.is_id_eq assert.err=ERR_ACCOUNT_SEED_ANCHOR_BLOCK_HASH_DIGEST_MISMATCH + exec.account_utils::is_id_eq assert.err=ERR_ACCOUNT_SEED_ANCHOR_BLOCK_HASH_DIGEST_MISMATCH # => [] end -#! Shapes the second felt so it meets the requirements of the account ID, by overwriting the -#! upper 16 bits with the anchor epoch and setting the lower 8 bits to zero. -#! -#! Inputs: [seed_digest_lo, anchor_epoch] -#! Outputs: [account_id_lo] -#! -#! Where: -#! - seed_digest_lo is the second felt of the digest that should be shaped into the second felt -#! of an account ID. -#! - account_id_lo is the second felt of an account ID. -#! - anchor_epoch is the epoch number to which this account ID is anchored. -proc.shape_second_felt - u32split - # => [seed_digest_lo_hi, seed_digest_lo_lo, anchor_epoch] - - # clear epoch bits in hi part so we can set them later - u32and.0x0000ffff swap - # => [seed_digest_lo_lo, seed_digest_lo_hi', anchor_epoch] - - # clear lower 8 bits of the lo part - u32and.0xffffff00 swap.2 - # => [anchor_epoch, seed_digest_lo_hi', seed_digest_lo_lo'] - - # assert epoch is not 2^16 - # this is technically optional as we will compare this id with the provided one for which - # this property was already checked, but since this check is cheap we include it anyway - dup eq.0xffff assertz.err=ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX - # => [anchor_epoch, seed_digest_lo_hi', seed_digest_lo_lo'] - - # shift epoch left by 16 bits and set epoch bits on hi part - u32shl.16 u32or - # => [seed_digest_lo_hi'', seed_digest_lo_lo'] - - # reassemble the second felt by multiplying the hi part with 2^32 and adding the lo part - mul.0x0100000000 add - # => [account_id_lo] -end - -#! Extracts the block number of the anchor block from the second felt of an account ID. -#! -#! Inputs: [account_id_lo] -#! Outputs: [anchor_block_num] -#! -#! Where: -#! - account_id_lo is the second felt of an account ID. -#! - anchor_block_num is the number of the block to which this account ID is anchored. -proc.id_anchor_block_num - # extract the upper 32 bits - u32split swap drop - # => [account_id_lo_hi] - - # to get the epoch's block number we would have to multiply the epoch in the account id by 2^16 - # since the epoch is already in the upper 16 bits of the u32, we can simply zero out the - # lower 16 bits to achieve the same result. - u32and.0xffff0000 - # => [anchor_block_num] -end - -#! Extracts the epoch from the second felt of an account ID. -#! -#! Inputs: [account_id_lo] -#! Outputs: [anchor_epoch] -#! -#! Where: -#! - account_id_lo is the second felt of an account ID. -#! - anchor_epoch is the epoch number to which this account ID is anchored. -proc.id_anchor_epoch - # extract the upper 32 bits - u32split swap drop - # => [account_id_lo_hi] - - # shift the upper 16 bits to the right to produce the epoch - u32shr.16 - # => [anchor_epoch] -end - -#! Extracts the account ID version from the first felt of an account ID. -#! -#! Inputs: [account_id_hi] -#! Outputs: [id_version] -#! -#! Where: -#! - account_id_hi is the first felt of an account ID. -#! - id_version is the version number of the ID. -proc.id_version - # extract the lower 32 bits - u32split drop - # => [account_id_hi_lo] - - # mask out the version - u32and.ACCOUNT_VERSION_MASK_U32 - # => [id_version] -end - # DATA LOADERS # ================================================================================================= @@ -939,7 +635,7 @@ export.save_account_storage_data # AS => [[STORAGE_SLOT_DATA]] # assert that account does not exceed allowed maximum number of storage slots - dup exec.get_max_num_storage_slots lte assert.err=ERR_ACCOUNT_TOO_MANY_STORAGE_SLOTS + dup exec.account_utils::get_max_num_storage_slots lte assert.err=ERR_ACCOUNT_TOO_MANY_STORAGE_SLOTS # OS => [num_storage_slots, STORAGE_COMMITMENT] # AS => [[STORAGE_SLOT_DATA]] @@ -1008,7 +704,7 @@ export.save_account_procedure_data # AS => [[ACCOUNT_PROCEDURE_DATA]] # assert that account does not exceed allowed maximum number of procedures - dup exec.get_max_num_procedures lte assert.err=ERR_ACCOUNT_TOO_MANY_PROCEDURES + dup exec.account_utils::get_max_num_procedures lte assert.err=ERR_ACCOUNT_TOO_MANY_PROCEDURES # OS => [num_procs, CODE_COMMITMENT] # AS => [[ACCOUNT_PROCEDURE_DATA]] @@ -1048,25 +744,6 @@ end # HELPER PROCEDURES # ================================================================================================= -#! Returns the most significant half with the account type bits masked out. -#! -#! The account type can be defined by comparing this value with the following constants: -#! - REGULAR_ACCOUNT_UPDATABLE_CODE -#! - REGULAR_ACCOUNT_IMMUTABLE_CODE -#! - FUNGIBLE_FAUCET_ACCOUNT -#! - NON_FUNGIBLE_FAUCET_ACCOUNT -#! -#! Inputs: [acct_id_hi] -#! Outputs: [acct_type] -#! -#! Where: -#! - acct_id_hi is the first felt of the account id. -#! - acct_type is the account type. -proc.type - u32split drop push.ACCOUNT_ID_TYPE_MASK_U32 u32and - # => [acct_type] -end - #! Sets an item in the account storage. Doesn't emit any events. #! #! Inputs: [index, NEW_VALUE] @@ -1142,7 +819,7 @@ export.get_foreign_account_ptr # => [foreign_account_id_hi, foreign_account_id_lo] # check that foreign account id is not equal to the native account id - dup.1 dup.1 exec.memory::get_native_account_id exec.is_id_eq not + dup.1 dup.1 exec.memory::get_native_account_id exec.account_utils::is_id_eq not assert.err=ERR_FOREIGN_ACCOUNT_ID_EQUALS_NATIVE_ACCT_ID # get the initial account data pointer @@ -1172,7 +849,7 @@ export.get_foreign_account_ptr # => [is_empty_block, maybe_account_id_hi, maybe_account_id_lo, curr_account_ptr', foreign_account_id_hi, foreign_account_id_lo] # check whether the current id matches the foreign id - movdn.2 dup.5 dup.5 exec.is_id_eq + movdn.2 dup.5 dup.5 exec.account_utils::is_id_eq # => [is_equal_id, is_empty_word, curr_account_ptr', foreign_account_id_hi, foreign_account_id_lo] # get the loop flag diff --git a/miden-lib/asm/kernels/transaction/lib/account_utils.masm b/miden-lib/asm/kernels/transaction/lib/account_utils.masm new file mode 100644 index 000000000..9536464d1 --- /dev/null +++ b/miden-lib/asm/kernels/transaction/lib/account_utils.masm @@ -0,0 +1,338 @@ +# ERRORS +# ================================================================================================= + +# Unknown version in account id. +const.ERR_ACCOUNT_ID_UNKNOWN_VERSION=0x00020057 + +# Epoch must be less than u16::MAX (0xffff). +const.ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX=0x00020058 + +# Least significant byte of second felt of the account id must be zero. +const.ERR_ACCOUNT_ID_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO=0x00020005 + +# Provided storage slot index is out of bounds +const.ERR_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS=0x0002000D + +# CONSTANTS +# ================================================================================================= + +# The account storage slot at which faucet data is stored. +# Fungible faucet: The faucet data consists of [0, 0, 0, total_issuance] +# Non-fungible faucet: The faucet data consists of SMT root containing minted non-fungible assets. +const.FAUCET_STORAGE_DATA_SLOT=0 + +# The maximum storage slot index +const.MAX_STORAGE_SLOT_INDEX=254 + +# The maximum number of account storage slots. +const.MAX_NUM_STORAGE_SLOTS=MAX_STORAGE_SLOT_INDEX+1 + +# The maximum number of account interface procedures. +const.MAX_NUM_PROCEDURES=256 + +# Bit pattern for a faucet account, after the account type mask has been applied. +const.FAUCET_ACCOUNT=0x20 # 0b10_0000 + +# Bit pattern for an account w/ updatable code, after the account type mask has been applied. +const.REGULAR_ACCOUNT_UPDATABLE_CODE=0x10 # 0b01_0000 + +# Bit pattern for an account w/ immutable code, after the account type mask has been applied. +const.REGULAR_ACCOUNT_IMMUTABLE_CODE=0 # 0b00_0000 + +# Given the least significant 32 bits of an account id's first felt, this mask defines the bits used +# to determine the account type. +const.ACCOUNT_ID_TYPE_MASK_U32=0x30 # 0b11_0000 + +# Given the least significant 32 bits of an account id's first felt, this mask defines the bits used +# to determine the account version. +const.ACCOUNT_VERSION_MASK_U32=0x0f # 0b1111 + +# CONSTANT ACCESSORS +# ================================================================================================= + +#! Returns the account storage slot at which faucet data is stored. +#! Fungible faucet: The faucet data consists of [0, 0, 0, total_issuance] +#! Non-fungible faucet: The faucet data consists of SMT root containing minted non-fungible assets. +#! +#! Inputs: [] +#! Outputs: [faucet_storage_data_slot] +#! +#! Where: +#! - faucet_storage_data_slot is the account storage slot at which faucet data is stored. +export.get_faucet_storage_data_slot + push.FAUCET_STORAGE_DATA_SLOT +end + +#! Returns the maximum number of account storage slots. +#! +#! Inputs: [] +#! Outputs: [max_num_storage_slots] +#! +#! Where: +#! - max_num_storage_slots is the maximum number of account storage slots. +export.get_max_num_storage_slots + push.MAX_NUM_STORAGE_SLOTS +end + +#! Returns the maximum number of account interface procedures. +#! +#! Inputs: [] +#! Outputs: [max_num_procedures] +#! +#! Where: +#! - max_num_procedures is the maximum number of account interface procedures. +export.get_max_num_procedures + push.MAX_NUM_PROCEDURES +end + +# PROCEDURES +# ================================================================================================= + +#! Returns a boolean indicating whether the account is a fungible faucet. +#! +#! Inputs: [acct_id_hi] +#! Outputs: [is_fungible_faucet] +#! +#! Where: +#! - acct_id_hi is the first felt of the account id. +#! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. +export.::utils::is_fungible_faucet + +#! Returns a boolean indicating whether the account is a non-fungible faucet. +#! +#! Inputs: [acct_id_hi] +#! Outputs: [is_non_fungible_faucet] +#! +#! Where: +#! - acct_id_hi is the first felt of the account id. +#! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. +export.::utils::is_non_fungible_faucet + +#! Returns a boolean indicating whether the given account_ids are equal. +#! +#! Inputs: [acct_id_hi, acct_id_lo, other_acct_id_hi, other_acct_id_lo] +#! Outputs: [is_id_equal] +#! +#! Where: +#! - acct_id_{hi,lo} are the first and second felt of an account id. +#! - other_acct_id_{hi,lo} are the first and second felt of the other account id to compare against. +#! - is_id_equal is a boolean indicating whether the account ids are equal. +export.::utils::is_id_eq + +#! Returns a boolean indicating whether the account is a faucet. +#! +#! Inputs: [acct_id_hi] +#! Outputs: [is_faucet] +#! +#! Where: +#! - acct_id_hi is the first felt of the account id. +#! - is_faucet is a boolean indicating whether the account is a faucet. +export.is_faucet + u32split drop push.FAUCET_ACCOUNT u32and eq.0 not + # => [is_faucet] +end + +#! Returns a boolean indicating whether the account is a regular updatable account. +#! +#! Inputs: [acct_id_hi] +#! Outputs: [is_updatable_account] +#! +#! Where: +#! - acct_id_hi is the first felt of the account id. +#! - is_updatable_account is a boolean indicating whether the account is a regular updatable +#! account. +export.is_updatable_account + exec.type push.REGULAR_ACCOUNT_UPDATABLE_CODE eq + # => [is_updatable_account] +end + +#! Returns a boolean indicating whether the account is a regular immutable account. +#! +#! Inputs: [acct_id_hi] +#! Outputs: [is_immutable_account] +#! +#! Where: +#! - acct_id_hi is the first felt of the account id. +#! - is_immutable_account is a boolean indicating whether the account is a regular immutable +#! account. +export.is_immutable_account + exec.type push.REGULAR_ACCOUNT_IMMUTABLE_CODE eq + # => [is_immutable_account] +end + +#! Validates an account id. +#! +#! Inputs: [account_id_hi, account_id_lo] +#! Outputs: [] +#! +#! Where: +#! - account_id_{hi,lo} are the first and second felt of the account id. +#! +#! Panics if: +#! - account_id_hi does not contain version zero. +#! - account_id_lo contains an anchor epoch that is greater or equal to 2^16. +#! - account_id_lo does not have its lower 8 bits set to zero. +export.validate_id + # Validate version in first felt. For now only version 0 is supported. + # --------------------------------------------------------------------------------------------- + + exec.id_version + # => [id_version, account_id_lo] + assertz.err=ERR_ACCOUNT_ID_UNKNOWN_VERSION + # => [account_id_lo] + + # Validate anchor epoch is less than u16::MAX (0xffff) in second felt. + # --------------------------------------------------------------------------------------------- + + dup exec.id_anchor_epoch + # => [anchor_epoch, account_id_lo] + lt.0xffff assert.err=ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX + # => [account_id_lo] + + # Validate lower 8 bits of second felt are zero. + # --------------------------------------------------------------------------------------------- + + u32split drop u32and.0xff eq.0 + # => [is_least_significant_byte_zero] + assert.err=ERR_ACCOUNT_ID_LEAST_SIGNIFICANT_BYTE_MUST_BE_ZERO + # => [] +end + +#! Applies storage offset to provided storage slot index for storage access. +#! +#! Inputs: [storage_offset, storage_size, slot_index] +#! Outputs: [offset_slot_index] +#! +#! Where: +#! - storage_offset is the offset of the storage for this account component. +#! - storage_size is the number of storage slots accessible from this account component. +#! - slot_index is the index of the storage slot to be accessed. +#! - offset_slot_index is the final index of the storage slot with the storage offset applied to it. +#! +#! Panics if: +#! - the computed index is out of bounds +export.apply_storage_offset + # offset index + dup movup.3 add + # => [offset_slot_index, storage_offset, storage_size] + + # verify that slot_index is in bounds + movdn.2 add dup.1 gt assert.err=ERR_STORAGE_SLOT_INDEX_OUT_OF_BOUNDS + # => [offset_slot_index] +end + +#! Shapes the second felt so it meets the requirements of the account ID, by overwriting the +#! upper 16 bits with the anchor epoch and setting the lower 8 bits to zero. +#! +#! Inputs: [seed_digest_lo, anchor_epoch] +#! Outputs: [account_id_lo] +#! +#! Where: +#! - seed_digest_lo is the second felt of the digest that should be shaped into the second felt +#! of an account ID. +#! - account_id_lo is the second felt of an account ID. +#! - anchor_epoch is the epoch number to which this account ID is anchored. +proc.shape_second_felt + u32split + # => [seed_digest_lo_hi, seed_digest_lo_lo, anchor_epoch] + + # clear epoch bits in hi part so we can set them later + u32and.0x0000ffff swap + # => [seed_digest_lo_lo, seed_digest_lo_hi', anchor_epoch] + + # clear lower 8 bits of the lo part + u32and.0xffffff00 swap.2 + # => [anchor_epoch, seed_digest_lo_hi', seed_digest_lo_lo'] + + # assert epoch is not 2^16 + # this is technically optional as we will compare this id with the provided one for which + # this property was already checked, but since this check is cheap we include it anyway + dup eq.0xffff assertz.err=ERR_ACCOUNT_ID_EPOCH_MUST_BE_LESS_THAN_U16_MAX + # => [anchor_epoch, seed_digest_lo_hi', seed_digest_lo_lo'] + + # shift epoch left by 16 bits and set epoch bits on hi part + u32shl.16 u32or + # => [seed_digest_lo_hi'', seed_digest_lo_lo'] + + # reassemble the second felt by multiplying the hi part with 2^32 and adding the lo part + mul.0x0100000000 add + # => [account_id_lo] +end + +#! Extracts the block number of the anchor block from the second felt of an account ID. +#! +#! Inputs: [account_id_lo] +#! Outputs: [anchor_block_num] +#! +#! Where: +#! - account_id_lo is the second felt of an account ID. +#! - anchor_block_num is the number of the block to which this account ID is anchored. +proc.id_anchor_block_num + # extract the upper 32 bits + u32split swap drop + # => [account_id_lo_hi] + + # to get the epoch's block number we would have to multiply the epoch in the account id by 2^16 + # since the epoch is already in the upper 16 bits of the u32, we can simply zero out the + # lower 16 bits to achieve the same result. + u32and.0xffff0000 + # => [anchor_block_num] +end + +#! Extracts the epoch from the second felt of an account ID. +#! +#! Inputs: [account_id_lo] +#! Outputs: [anchor_epoch] +#! +#! Where: +#! - account_id_lo is the second felt of an account ID. +#! - anchor_epoch is the epoch number to which this account ID is anchored. +proc.id_anchor_epoch + # extract the upper 32 bits + u32split swap drop + # => [account_id_lo_hi] + + # shift the upper 16 bits to the right to produce the epoch + u32shr.16 + # => [anchor_epoch] +end + +#! Extracts the account ID version from the first felt of an account ID. +#! +#! Inputs: [account_id_hi] +#! Outputs: [id_version] +#! +#! Where: +#! - account_id_hi is the first felt of an account ID. +#! - id_version is the version number of the ID. +proc.id_version + # extract the lower 32 bits + u32split drop + # => [account_id_hi_lo] + + # mask out the version + u32and.ACCOUNT_VERSION_MASK_U32 + # => [id_version] +end + +# HELPER PROCEDURES +# ================================================================================================= + +#! Returns the most significant half with the account type bits masked out. +#! +#! The account type can be defined by comparing this value with the following constants: +#! - REGULAR_ACCOUNT_UPDATABLE_CODE +#! - REGULAR_ACCOUNT_IMMUTABLE_CODE +#! - FUNGIBLE_FAUCET_ACCOUNT +#! - NON_FUNGIBLE_FAUCET_ACCOUNT +#! +#! Inputs: [acct_id_hi] +#! Outputs: [acct_type] +#! +#! Where: +#! - acct_id_hi is the first felt of the account id. +#! - acct_type is the account type. +proc.type + u32split drop push.ACCOUNT_ID_TYPE_MASK_U32 u32and + # => [acct_type] +end \ No newline at end of file diff --git a/miden-lib/asm/kernels/transaction/lib/asset.masm b/miden-lib/asm/kernels/transaction/lib/asset.masm index d4c08fe60..2de8240ba 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset.masm @@ -1,4 +1,5 @@ use.kernel::account +use.kernel::account_utils # ERRORS # ================================================================================================= @@ -56,11 +57,11 @@ export.validate_fungible_asset # => [ASSET] # assert that the tuple (ASSET[3], ASSET[2]) forms a valid account id - dup.1 dup.1 exec.account::validate_id + dup.1 dup.1 exec.account_utils::validate_id # => [ASSET] # assert that the first felt (ASSET[3]) of the account id is of type fungible faucet - dup exec.account::is_fungible_faucet + dup exec.account_utils::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID # => [ASSET] @@ -99,11 +100,11 @@ end export.validate_non_fungible_asset # assert that ASSET[3] is a valid account id prefix # hack: because we only have the first felt we add a 0 as the second felt which is always valid - push.0 dup.1 exec.account::validate_id + push.0 dup.1 exec.account_utils::validate_id # => [ASSET] # assert that the account ID prefix ASSET[3] is of type non fungible faucet - dup exec.account::is_non_fungible_faucet + dup exec.account_utils::is_non_fungible_faucet assert.err=ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID # => [ASSET] end @@ -162,7 +163,7 @@ export.validate_fungible_asset_origin dup.3 dup.3 # => [asset_id_hi, asset_id_lo, faucet_id_hi, faucet_id_lo, ASSET] - exec.account::is_id_eq assert.err=ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN + exec.account_utils::is_id_eq assert.err=ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN # => [ASSET] # assert the fungible asset is valid diff --git a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm index cbba6e040..c902c9e69 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm @@ -1,6 +1,7 @@ use.std::collections::smt use.kernel::account +use.kernel::account_utils use.kernel::asset use.kernel::memory @@ -54,7 +55,7 @@ const.INVERSE_FUNGIBLE_BITMASK_U32=0xffffffdf # last byte: 0b1101_1111 #! - the asset is not a fungible asset. export.get_balance # assert that the faucet id is a fungible faucet - dup exec.account::is_fungible_faucet + dup exec.account_utils::is_fungible_faucet assert.err=ERR_VAULT_GET_BALANCE_PROC_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_FAUCET # => [faucet_id_hi, faucet_id_lo, vault_root_ptr] diff --git a/miden-lib/asm/kernels/transaction/lib/faucet.masm b/miden-lib/asm/kernels/transaction/lib/faucet.masm index f5fcb6817..af6d8621c 100644 --- a/miden-lib/asm/kernels/transaction/lib/faucet.masm +++ b/miden-lib/asm/kernels/transaction/lib/faucet.masm @@ -1,6 +1,7 @@ use.std::collections::smt use.kernel::account +use.kernel::account_utils use.kernel::asset use.kernel::asset_vault use.kernel::memory @@ -49,7 +50,7 @@ export.mint_fungible_asset # => [ASSET] # get the current total issuance - exec.account::get_faucet_storage_data_slot exec.account::get_item + exec.account_utils::get_faucet_storage_data_slot exec.account::get_item # => [TOTAL_ISSUANCE, ASSET] # prepare stack to ensure that minting the asset will not exceed the maximum @@ -61,7 +62,7 @@ export.mint_fungible_asset # => [amount, TOTAL_ISSUANCE, ASSET] # update the total issuance - add exec.account::get_faucet_storage_data_slot exec.account::set_item dropw + add exec.account_utils::get_faucet_storage_data_slot exec.account::set_item dropw # => [ASSET] # add the asset to the input vault for asset preservation checks @@ -91,7 +92,7 @@ proc.burn_fungible_asset # => [ASSET] # fetch TOTAL_ISSUANCE such that we can compute the new total issuance - exec.account::get_faucet_storage_data_slot exec.account::get_item + exec.account_utils::get_faucet_storage_data_slot exec.account::get_item # => [TOTAL_ISSUANCE, ASSET] # assert that the asset amount being burned is less or equal to the total issuance @@ -99,7 +100,7 @@ proc.burn_fungible_asset # => [amount, TOTAL_ISSUANCE, ASSET] # compute new total issuance - sub exec.account::get_faucet_storage_data_slot exec.account::set_item dropw + sub exec.account_utils::get_faucet_storage_data_slot exec.account::set_item dropw # => [ASSET] # remove the asset from the input vault @@ -117,7 +118,7 @@ end #! against. export.get_total_issuance # fetch the TOTAL_ISSUANCE from storage - exec.account::get_faucet_storage_data_slot exec.account::get_item + exec.account_utils::get_faucet_storage_data_slot exec.account::get_item # => [TOTAL_ISSUANCE] # extract the total_issuance and purge the padding @@ -150,7 +151,7 @@ proc.mint_non_fungible_asset # => [ASSET] # fetch the root of the SMT containing the non-fungible assets - dupw exec.account::get_faucet_storage_data_slot exec.account::get_item + dupw exec.account_utils::get_faucet_storage_data_slot exec.account::get_item # => [SMT_ROOT, ASSET, ASSET] # prepare stack for insert of non-fungible asset into tracking SMT @@ -167,7 +168,7 @@ proc.mint_non_fungible_asset # => [SMT_ROOT', ASSET] # update the root of the SMT containing the non-fungible assets - exec.account::get_faucet_storage_data_slot exec.account::set_item dropw + exec.account_utils::get_faucet_storage_data_slot exec.account::set_item dropw # => [ASSET] # add the non-fungible asset to the input vault for asset preservation checks @@ -192,7 +193,7 @@ end #! transaction via a note or the accounts vault. proc.burn_non_fungible_asset # assert that we are executing a transaction against the non-fungible faucet (access checks) - exec.account::get_id exec.account::is_non_fungible_faucet + exec.account::get_id exec.account_utils::is_non_fungible_faucet assert.err=ERR_FAUCET_BURN_NON_FUNGIBLE_ASSET_CAN_ONLY_BE_CALLED_ON_NON_FUNGIBLE_FAUCET # => [ASSET] @@ -201,7 +202,7 @@ proc.burn_non_fungible_asset # => [ASSET, ASSET] # fetch the root of the SMT containing the non-fungible assets - exec.account::get_faucet_storage_data_slot exec.account::get_item + exec.account_utils::get_faucet_storage_data_slot exec.account::get_item # => [SMT_ROOT, ASSET, ASSET] # prepare stack for removal of non-fungible asset from tracking SMT @@ -218,7 +219,7 @@ proc.burn_non_fungible_asset # => [SMT_ROOT', ASSET] # update the root of the SMT containing the non-fungible assets - exec.account::get_faucet_storage_data_slot exec.account::set_item dropw + exec.account_utils::get_faucet_storage_data_slot exec.account::set_item dropw # => [ASSET] # remove the non-fungible asset from the input vault for asset preservation checks diff --git a/miden-lib/asm/kernels/transaction/lib/prologue.masm b/miden-lib/asm/kernels/transaction/lib/prologue.masm index f72943eef..2fff3ee08 100644 --- a/miden-lib/asm/kernels/transaction/lib/prologue.masm +++ b/miden-lib/asm/kernels/transaction/lib/prologue.masm @@ -3,6 +3,7 @@ use.std::collections::mmr use.std::crypto::hashes::rpo use.kernel::account +use.kernel::account_utils use.kernel::asset_vault use.kernel::constants use.kernel::memory @@ -317,7 +318,7 @@ end #! Outputs: [] proc.validate_new_account # Assert the account id of the account is valid - exec.memory::get_account_id exec.account::validate_id + exec.memory::get_account_id exec.account_utils::validate_id # => [] # Assert the account nonce is 0 @@ -340,17 +341,17 @@ proc.validate_new_account # Assert faucet reserved slot is correctly initialized # --------------------------------------------------------------------------------------------- # check if the account is a faucet - exec.account::get_id swap drop dup exec.account::is_faucet + exec.account::get_id swap drop dup exec.account_utils::is_faucet # => [is_faucet, acct_id_hi] # process conditional logic depending on whether the account is a faucet if.true # get the faucet reserved slot - exec.account::get_faucet_storage_data_slot exec.account::get_item + exec.account_utils::get_faucet_storage_data_slot exec.account::get_item # => [FAUCET_RESERVED_SLOT, acct_id_hi] # check if the account is a fungible faucet - movup.4 exec.account::is_fungible_faucet + movup.4 exec.account_utils::is_fungible_faucet # => [is_fungible_faucet, FAUCET_RESERVED_SLOT] if.true @@ -361,7 +362,7 @@ proc.validate_new_account # => [] # get the faucet reserved storage data slot type - exec.account::get_faucet_storage_data_slot exec.account::get_storage_slot_type + exec.account_utils::get_faucet_storage_data_slot exec.account::get_storage_slot_type # => [slot_type] # assert the fungible faucet reserved slot type == value @@ -377,7 +378,7 @@ proc.validate_new_account push.1001 drop # TODO: remove line, see miden-vm/#1122 # get the faucet reserved storage data slot type - exec.account::get_faucet_storage_data_slot exec.account::get_storage_slot_type + exec.account_utils::get_faucet_storage_data_slot exec.account::get_storage_slot_type # => [slot_type] # assert the non-fungible faucet reserved slot type == map @@ -469,7 +470,7 @@ proc.process_account_data # assert the account id matches the account id in global inputs exec.memory::get_global_acct_id exec.memory::get_account_id - exec.account::is_id_eq assert.err=ERR_PROLOGUE_MISMATCH_OF_ACCOUNT_IDS_FROM_GLOBAL_INPUTS_AND_ADVICE_PROVIDER + exec.account_utils::is_id_eq assert.err=ERR_PROLOGUE_MISMATCH_OF_ACCOUNT_IDS_FROM_GLOBAL_INPUTS_AND_ADVICE_PROVIDER # => [ACCT_HASH] # store a copy of the initial nonce in global inputs From 21f1671f33669857fbcad6db7994c11836d7e808 Mon Sep 17 00:00:00 2001 From: Andrey Khmuro Date: Tue, 14 Jan 2025 14:13:48 +0300 Subject: [PATCH 05/10] refactor: move pure account procs to account_util --- miden-lib/asm/kernels/transaction/api.masm | 3 +- .../asm/kernels/transaction/lib/account.masm | 3 +- .../asm/kernels/transaction/lib/asset.masm | 5 +- .../kernels/transaction/lib/asset_vault.masm | 3 +- .../kernels/transaction/lib/constants.masm | 2 +- .../asm/kernels/transaction/lib/faucet.masm | 3 +- .../asm/kernels/transaction/lib/prologue.masm | 3 +- miden-lib/asm/miden/account.masm | 6 +- miden-lib/asm/miden/asset.masm | 2 +- miden-lib/asm/miden/note.masm | 2 +- miden-lib/asm/utils.masm | 107 ------------------ .../lib => utils}/account_utils.masm | 19 +++- miden-lib/asm/utils/utils.masm | 33 ++++++ miden-lib/build.rs | 21 ++-- 14 files changed, 76 insertions(+), 136 deletions(-) delete mode 100644 miden-lib/asm/utils.masm rename miden-lib/asm/{kernels/transaction/lib => utils}/account_utils.masm (97%) create mode 100644 miden-lib/asm/utils/utils.masm diff --git a/miden-lib/asm/kernels/transaction/api.masm b/miden-lib/asm/kernels/transaction/api.masm index ed41cdd78..407c2ce61 100644 --- a/miden-lib/asm/kernels/transaction/api.masm +++ b/miden-lib/asm/kernels/transaction/api.masm @@ -1,8 +1,9 @@ use.std::collections::smt use.std::sys +use.utils::account_utils + use.kernel::account -use.kernel::account_utils use.kernel::asset_vault use.kernel::constants use.kernel::faucet diff --git a/miden-lib/asm/kernels/transaction/lib/account.masm b/miden-lib/asm/kernels/transaction/lib/account.masm index 9d65ee61f..7ccc94560 100644 --- a/miden-lib/asm/kernels/transaction/lib/account.masm +++ b/miden-lib/asm/kernels/transaction/lib/account.masm @@ -3,7 +3,8 @@ use.std::collections::smt use.std::crypto::hashes::rpo use.std::mem -use.kernel::account_utils +use.utils::account_utils + use.kernel::constants use.kernel::memory diff --git a/miden-lib/asm/kernels/transaction/lib/asset.masm b/miden-lib/asm/kernels/transaction/lib/asset.masm index f6eb01041..85ae4a7a4 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset.masm @@ -1,5 +1,6 @@ +use.utils::account_utils + use.kernel::account -use.kernel::account_utils # ERRORS # ================================================================================================= @@ -39,7 +40,7 @@ const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 #! Outputs: [fungible_asset_max_amount] #! #! fungible_asset_max_amount is the maximum amount of a fungible asset. -export.::utils::get_fungible_asset_max_amount +export.::utils::utils::get_fungible_asset_max_amount #! Validates that a fungible asset is well formed. #! diff --git a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm index 2363e32fe..7395f6a62 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm @@ -1,7 +1,8 @@ use.std::collections::smt +use.utils::account_utils + use.kernel::account -use.kernel::account_utils use.kernel::asset use.kernel::memory diff --git a/miden-lib/asm/kernels/transaction/lib/constants.masm b/miden-lib/asm/kernels/transaction/lib/constants.masm index 42e5fb7d0..fc446cdb3 100644 --- a/miden-lib/asm/kernels/transaction/lib/constants.masm +++ b/miden-lib/asm/kernels/transaction/lib/constants.masm @@ -47,7 +47,7 @@ end #! Output: [max_inputs_per_note] #! #! - max_inputs_per_note is the max inputs per note. -export.::utils::get_max_inputs_per_note +export.::utils::utils::get_max_inputs_per_note #! Returns the max allowed number of assets per note. #! diff --git a/miden-lib/asm/kernels/transaction/lib/faucet.masm b/miden-lib/asm/kernels/transaction/lib/faucet.masm index af6d8621c..0ecd3577b 100644 --- a/miden-lib/asm/kernels/transaction/lib/faucet.masm +++ b/miden-lib/asm/kernels/transaction/lib/faucet.masm @@ -1,7 +1,8 @@ use.std::collections::smt +use.utils::account_utils + use.kernel::account -use.kernel::account_utils use.kernel::asset use.kernel::asset_vault use.kernel::memory diff --git a/miden-lib/asm/kernels/transaction/lib/prologue.masm b/miden-lib/asm/kernels/transaction/lib/prologue.masm index 62aab2570..297f49971 100644 --- a/miden-lib/asm/kernels/transaction/lib/prologue.masm +++ b/miden-lib/asm/kernels/transaction/lib/prologue.masm @@ -2,8 +2,9 @@ use.std::mem use.std::collections::mmr use.std::crypto::hashes::rpo +use.utils::account_utils + use.kernel::account -use.kernel::account_utils use.kernel::asset_vault use.kernel::constants use.kernel::memory diff --git a/miden-lib/asm/miden/account.masm b/miden-lib/asm/miden/account.masm index c4a2e67c2..63cbe7bea 100644 --- a/miden-lib/asm/miden/account.masm +++ b/miden-lib/asm/miden/account.masm @@ -11,7 +11,7 @@ use.miden::kernel_proc_offsets #! Where: #! - acct_id_prefix is the prefix of the account ID. #! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. -export.::utils::is_fungible_faucet +export.::utils::account_utils::is_fungible_faucet #! Returns a boolean indicating whether the account is a non-fungible faucet. #! @@ -21,7 +21,7 @@ export.::utils::is_fungible_faucet #! Where: #! - acct_id_prefix is the prefix of the account ID. #! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. -export.::utils::is_non_fungible_faucet +export.::utils::account_utils::is_non_fungible_faucet #! Returns a boolean indicating whether the given account_ids are equal. #! @@ -32,7 +32,7 @@ export.::utils::is_non_fungible_faucet #! - acct_id_{prefix,suffix} are the prefix and suffix felts of an account ID. #! - other_acct_id_{prefix,suffix} are the prefix and suffix felts of the other account ID to compare against. #! - is_id_equal is a boolean indicating whether the account IDs are equal. -export.::utils::is_id_eq +export.::utils::account_utils::is_id_eq #! Returns the account id. #! diff --git a/miden-lib/asm/miden/asset.masm b/miden-lib/asm/miden/asset.masm index 421904ae7..123951402 100644 --- a/miden-lib/asm/miden/asset.masm +++ b/miden-lib/asm/miden/asset.masm @@ -21,7 +21,7 @@ const.ERR_NON_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID=0x0002004D #! Outputs: [fungible_asset_max_amount] #! #! fungible_asset_max_amount is the maximum amount of a fungible asset. -export.::utils::get_fungible_asset_max_amount +export.::utils::utils::get_fungible_asset_max_amount #! Builds a fungible asset for the specified fungible faucet and amount. #! diff --git a/miden-lib/asm/miden/note.masm b/miden-lib/asm/miden/note.masm index d1729c937..a8765d0c4 100644 --- a/miden-lib/asm/miden/note.masm +++ b/miden-lib/asm/miden/note.masm @@ -21,7 +21,7 @@ const.ERR_PROLOGUE_NUMBER_OF_NOTE_INPUTS_EXCEEDED_LIMIT=0x0002004F #! Output: [max_inputs_per_note] #! #! - max_inputs_per_note is the max inputs per note. -export.::utils::get_max_inputs_per_note +export.::utils::utils::get_max_inputs_per_note #! Writes the data currently on the advice stack into the memory at the specified location and #! verifies that the hash of the written data is equal to the provided hash. diff --git a/miden-lib/asm/utils.masm b/miden-lib/asm/utils.masm deleted file mode 100644 index f5ef4197d..000000000 --- a/miden-lib/asm/utils.masm +++ /dev/null @@ -1,107 +0,0 @@ -### ACCOUNT ######################################################### - -# Given the least significant 32 bits of an account id's first felt, this mask defines the bits used -# to determine the account type. -const.ACCOUNT_ID_TYPE_MASK_U32=0x30 # 0b11_0000 - -# Bit pattern for a fungible faucet w/ immutable code, after the account type mask has been applied. -const.FUNGIBLE_FAUCET_ACCOUNT=0x20 # 0b10_0000 - -# Bit pattern for a non-fungible faucet w/ immutable code, after the account type mask has been -# applied. -const.NON_FUNGIBLE_FAUCET_ACCOUNT=0x30 # 0b11_0000 - -#! Returns the most significant half with the account type bits masked out. -#! -#! The account type can be defined by comparing this value with the following constants: -#! - REGULAR_ACCOUNT_UPDATABLE_CODE -#! - REGULAR_ACCOUNT_IMMUTABLE_CODE -#! - FUNGIBLE_FAUCET_ACCOUNT -#! - NON_FUNGIBLE_FAUCET_ACCOUNT -#! -#! Inputs: [acct_id_hi] -#! Outputs: [acct_type] -#! -#! Where: -#! - acct_id_hi is the first felt of the account id. -#! - acct_type is the account type. -proc.type - u32split drop push.ACCOUNT_ID_TYPE_MASK_U32 u32and - # => [acct_type] -end - -#! Returns a boolean indicating whether the account is a fungible faucet. -#! -#! Inputs: [acct_id_prefix] -#! Outputs: [is_fungible_faucet] -#! -#! Where: -#! - acct_id_prefix is the prefix of the account ID. -#! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. -export.is_fungible_faucet - exec.type push.FUNGIBLE_FAUCET_ACCOUNT eq - # => [is_fungible_faucet] -end - -#! Returns a boolean indicating whether the account is a non-fungible faucet. -#! -#! Inputs: [acct_id_prefix] -#! Outputs: [is_non_fungible_faucet] -#! -#! Where: -#! - acct_id_prefix is the prefix of the account ID. -#! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. -export.is_non_fungible_faucet - exec.type push.NON_FUNGIBLE_FAUCET_ACCOUNT eq - # => [is_non_fungible_faucet] -end - -#! Returns a boolean indicating whether the given account_ids are equal. -#! -#! Inputs: [acct_id_prefix, acct_id_suffix, other_acct_id_prefix, other_acct_id_suffix] -#! Outputs: [is_id_equal] -#! -#! Where: -#! - acct_id_{prefix,suffix} are the prefix and suffix felts of an account ID. -#! - other_acct_id_{prefix,suffix} are the prefix and suffix felts of the other account ID to compare against. -#! - is_id_equal is a boolean indicating whether the account IDs are equal. -export.is_id_eq - movup.2 eq - # => [is_prefix_equal, acct_id_suffix, other_acct_id_suffix] - movdn.2 eq - # => [is_suffix_equal, is_prefix_equal] - and - # => [is_id_equal] -end - -### ASSET ########################################################### - -const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 - -#! Returns the maximum amount of a fungible asset. -#! -#! Inputs: [] -#! Outputs: [fungible_asset_max_amount] -#! -#! Where: -#! - fungible_asset_max_amount is the maximum amount of a fungible asset. -export.get_fungible_asset_max_amount - push.FUNGIBLE_ASSET_MAX_AMOUNT - # => [fungible_asset_max_amount] -end - -### NOTE ############################################################ - -# The maximum number of input values associated with a single note. -const.MAX_INPUTS_PER_NOTE=128 - -#! Returns the max allowed number of input values per note. -#! -#! Inputs: [] -#! Outputs: [max_inputs_per_note] -#! -#! Where: -#! - max_inputs_per_note is the max inputs per note. -export.get_max_inputs_per_note - push.MAX_INPUTS_PER_NOTE -end diff --git a/miden-lib/asm/kernels/transaction/lib/account_utils.masm b/miden-lib/asm/utils/account_utils.masm similarity index 97% rename from miden-lib/asm/kernels/transaction/lib/account_utils.masm rename to miden-lib/asm/utils/account_utils.masm index 6ad757188..8c4b0830c 100644 --- a/miden-lib/asm/kernels/transaction/lib/account_utils.masm +++ b/miden-lib/asm/utils/account_utils.masm @@ -118,7 +118,10 @@ end #! Where: #! - acct_id_prefix is the prefix of the account ID. #! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. -export.::utils::is_fungible_faucet +export.is_fungible_faucet + exec.type push.FUNGIBLE_FAUCET_ACCOUNT eq + # => [is_fungible_faucet] +end #! Returns a boolean indicating whether the account is a non-fungible faucet. #! @@ -128,7 +131,10 @@ export.::utils::is_fungible_faucet #! Where: #! - acct_id_prefix is the prefix of the account ID. #! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. -export.::utils::is_non_fungible_faucet +export.is_non_fungible_faucet + exec.type push.NON_FUNGIBLE_FAUCET_ACCOUNT eq + # => [is_non_fungible_faucet] +end #! Returns a boolean indicating whether the given account_ids are equal. #! @@ -139,7 +145,14 @@ export.::utils::is_non_fungible_faucet #! - acct_id_{prefix,suffix} are the prefix and suffix felts of an account ID. #! - other_acct_id_{prefix,suffix} are the prefix and suffix felts of the other account ID to compare against. #! - is_id_equal is a boolean indicating whether the account IDs are equal. -export.::utils::is_id_eq +export.is_id_eq + movup.2 eq + # => [is_prefix_equal, acct_id_suffix, other_acct_id_suffix] + movdn.2 eq + # => [is_suffix_equal, is_prefix_equal] + and + # => [is_id_equal] +end #! Returns a boolean indicating whether the account is a faucet. #! diff --git a/miden-lib/asm/utils/utils.masm b/miden-lib/asm/utils/utils.masm new file mode 100644 index 000000000..ce93a0263 --- /dev/null +++ b/miden-lib/asm/utils/utils.masm @@ -0,0 +1,33 @@ +# TODO: move these procedures to the dedicated `*_uitls` masm file + +### ASSET ########################################################### + +const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 + +#! Returns the maximum amount of a fungible asset. +#! +#! Inputs: [] +#! Outputs: [fungible_asset_max_amount] +#! +#! Where: +#! - fungible_asset_max_amount is the maximum amount of a fungible asset. +export.get_fungible_asset_max_amount + push.FUNGIBLE_ASSET_MAX_AMOUNT + # => [fungible_asset_max_amount] +end + +### NOTE ############################################################ + +# The maximum number of input values associated with a single note. +const.MAX_INPUTS_PER_NOTE=128 + +#! Returns the max allowed number of input values per note. +#! +#! Inputs: [] +#! Outputs: [max_inputs_per_note] +#! +#! Where: +#! - max_inputs_per_note is the max inputs per note. +export.get_max_inputs_per_note + push.MAX_INPUTS_PER_NOTE +end diff --git a/miden-lib/build.rs b/miden-lib/build.rs index 5dde028be..7fa4168e8 100644 --- a/miden-lib/build.rs +++ b/miden-lib/build.rs @@ -11,8 +11,7 @@ use std::{ use assembly::{ diagnostics::{IntoDiagnostic, Result}, utils::Serializable, - Assembler, CompileOptions, DefaultSourceManager, KernelLibrary, Library, LibraryNamespace, - LibraryPath, Report, + Assembler, DefaultSourceManager, KernelLibrary, Library, LibraryNamespace, Report, }; use regex::Regex; use walkdir::WalkDir; @@ -28,6 +27,7 @@ const ASM_DIR: &str = "asm"; const ASM_MIDEN_DIR: &str = "miden"; const ASM_NOTE_SCRIPTS_DIR: &str = "note_scripts"; const ASM_ACCOUNT_COMPONENTS_DIR: &str = "account_components"; +const UTILS_DIR: &str = "utils"; const ASM_TX_KERNEL_DIR: &str = "kernels/transaction"; const KERNEL_V0_RS_FILE: &str = "src/transaction/procedures/kernel_v0.rs"; const KERNEL_ERRORS_FILE: &str = "src/errors/tx_kernel_errors.rs"; @@ -102,16 +102,12 @@ fn main() -> Result<()> { /// - {target_dir}/tx_kernel.masb -> contains the executable compiled from main.masm. /// - src/transaction/procedures/kernel_v0.rs -> contains the kernel procedures table. fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result { - let utils_path = Path::new(ASM_DIR).join("utils.masm"); - let utils_compile_options = CompileOptions { - path: Some(LibraryPath::new("utils").expect("library path for utils module is incorrect")), - ..CompileOptions::for_library() - }; + let utils_namespace = LibraryNamespace::new("utils").expect("invalid namespace"); + let utils_path = Path::new(ASM_DIR).join(UTILS_DIR); // add the utils module to the kernel lib by providing it to the assembler - let assembler = build_assembler(None)? - .with_module_and_options(utils_path.clone(), utils_compile_options.clone()) - .expect("provided utils module is not a library module"); + let mut assembler = build_assembler(None)?; + assembler.add_modules_from_dir(utils_namespace.clone(), &utils_path)?; // assemble the kernel library and write it to the "tx_kernel.masl" file let kernel_lib = KernelLibrary::from_dir( @@ -126,9 +122,8 @@ fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result let output_file = target_dir.join("tx_kernel").with_extension(Library::LIBRARY_EXTENSION); kernel_lib.write_to_file(output_file).into_diagnostic()?; - let assembler = build_assembler(Some(kernel_lib))? - .with_module_and_options(utils_path, utils_compile_options) - .expect("provided utils module is not a library module"); + let mut assembler = build_assembler(Some(kernel_lib))?; + assembler.add_modules_from_dir(utils_namespace, &utils_path)?; // assemble the kernel program and write it the "tx_kernel.masb" file let mut main_assembler = assembler.clone(); From 60d15eabeb7fa79de28cc836c2518c711623a157 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 14 Jan 2025 13:56:49 +0100 Subject: [PATCH 06/10] feat: Move asset vault and asset util procs to utils --- .../asm/kernels/transaction/lib/asset.masm | 117 +---------- .../kernels/transaction/lib/asset_vault.masm | 44 +--- miden-lib/asm/miden/asset.masm | 2 +- miden-lib/asm/utils/asset_utils.masm | 193 ++++++++++++++++++ miden-lib/asm/utils/asset_vault_utils.masm | 36 ++++ miden-lib/asm/utils/utils.masm | 16 -- miden-lib/src/transaction/mod.rs | 18 +- miden-tx/src/testing/executor.rs | 2 + .../src/tests/kernel_tests/test_account.rs | 12 +- 9 files changed, 265 insertions(+), 175 deletions(-) create mode 100644 miden-lib/asm/utils/asset_utils.masm create mode 100644 miden-lib/asm/utils/asset_vault_utils.masm diff --git a/miden-lib/asm/kernels/transaction/lib/asset.masm b/miden-lib/asm/kernels/transaction/lib/asset.masm index 85ae4a7a4..28768d238 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset.masm @@ -2,35 +2,6 @@ use.utils::account_utils use.kernel::account -# ERRORS -# ================================================================================================= - -# Malformed fungible asset: ASSET[1] must be 0 -const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_ZERO=0x00020020 - -# Malformed fungible asset: ASSET[2] and ASSET[3] must be a valid fungible faucet id -const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID=0x00020022 - -# Malformed fungible asset: ASSET[0] exceeds the maximum allowed amount -const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ZERO_MUST_BE_WITHIN_LIMITS=0x00020023 - -# Malformed non-fungible asset: ASSET[3] is not a valid non-fungible faucet id -const.ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID=0x00020024 - -# Malformed non-fungible asset: the most significant bit must be 0 -const.ERR_NON_FUNGIBLE_ASSET_FORMAT_MOST_SIGNIFICANT_BIT_MUST_BE_ZERO=0x00020025 - -# The origin of the fungible asset is not this faucet -const.ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020026 - -# The origin of the non-fungible asset is not this faucet -const.ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020027 - -# CONSTANTS -# ================================================================================================= - -const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 - # PROCEDURES # ================================================================================================= @@ -40,7 +11,7 @@ const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 #! Outputs: [fungible_asset_max_amount] #! #! fungible_asset_max_amount is the maximum amount of a fungible asset. -export.::utils::utils::get_fungible_asset_max_amount +export.::utils::asset_utils::get_fungible_asset_max_amount #! Validates that a fungible asset is well formed. #! @@ -52,25 +23,7 @@ export.::utils::utils::get_fungible_asset_max_amount #! #! Panics if: #! - the asset is not well formed. -export.validate_fungible_asset - # assert that ASSET[1] == ZERO - dup.2 not assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_ZERO - # => [ASSET] - - # assert that the tuple (ASSET[3], ASSET[2]) forms a valid account ID - dup.1 dup.1 exec.account_utils::validate_id - # => [ASSET] - - # assert that the prefix (ASSET[3]) of the account ID is of type fungible faucet - dup exec.account_utils::is_fungible_faucet - assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID - # => [ASSET] - - # assert that the max amount (ASSET[0]) of a fungible asset is not exceeded - dup.3 push.FUNGIBLE_ASSET_MAX_AMOUNT lte - assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ZERO_MUST_BE_WITHIN_LIMITS - # => [ASSET] -end +export.::utils::asset_utils::validate_fungible_asset #! Returns a boolean indicating whether the asset is fungible. #! @@ -80,13 +33,7 @@ end #! Where: #! - ASSET is the asset to check. #! - is_fungible_asset is a boolean indicating whether the asset is fungible. -export.is_fungible_asset - # check the first element, it will be: - # - zero for a fungible asset - # - non zero for a non-fungible asset - dup.2 eq.0 - # => [is_fungible_asset, ASSET] -end +export.::utils::asset_utils::is_fungible_asset #! Validates that a non fungible asset is well formed. #! @@ -98,17 +45,7 @@ end #! #! Panics if: #! - the asset is not well formed. -export.validate_non_fungible_asset - # assert that ASSET[3] is a valid account ID prefix - # hack: because we only have the prefix we add a 0 as the suffix which is always valid - push.0 dup.1 exec.account_utils::validate_id - # => [ASSET] - - # assert that the account ID prefix ASSET[3] is of type non fungible faucet - dup exec.account_utils::is_non_fungible_faucet - assert.err=ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID - # => [ASSET] -end +export.::utils::asset_utils::validate_non_fungible_asset #! Returns a boolean indicating whether the asset is non-fungible. #! @@ -118,13 +55,7 @@ end #! Where: #! - ASSET is the asset to check. #! - is_non_fungible_asset is a boolean indicating whether the asset is non-fungible. -export.is_non_fungible_asset - # check the first element, it will be: - # - zero for a fungible asset - # - non zero for a non-fungible asset - exec.is_fungible_asset not - # => [is_non_fungible_asset, ASSET] -end +export.::utils::asset_utils::is_non_fungible_asset #! Validates that an asset is well formed. #! @@ -136,20 +67,7 @@ end #! #! Panics if: #! - the asset is not well formed. -export.validate_asset - # check if the asset is fungible - exec.is_fungible_asset - # => [is_fungible_asset, ASSET] - - # if the asset is fungible, validate the fungible asset - if.true - exec.validate_fungible_asset - else - # if the asset is non fungible, validate the non fungible asset - exec.validate_non_fungible_asset - end - # => [ASSET] -end +export.::utils::asset_utils::validate_asset #! Validates that a fungible asset is associated with the provided faucet_id. #! @@ -159,18 +77,7 @@ end #! Where: #! - faucet_id_prefix is the prefix of the faucet's account ID. #! - ASSET is the asset to validate. -export.validate_fungible_asset_origin - # assert the origin of the asset is the faucet_id provided via the stack - dup.3 dup.3 - # => [asset_id_prefix, asset_id_suffix, faucet_id_prefix, faucet_id_suffix, ASSET] - - exec.account_utils::is_id_eq assert.err=ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN - # => [ASSET] - - # assert the fungible asset is valid - exec.validate_fungible_asset - # => [ASSET] -end +export.::utils::asset_utils::validate_fungible_asset_origin #! Validates that a non-fungible asset is associated with the provided faucet_id. #! @@ -180,12 +87,4 @@ end #! Where: #! - faucet_id_prefix is the prefix of the faucet's account ID. #! - ASSET is the asset to validate. -export.validate_non_fungible_asset_origin - # assert the origin of the asset is the faucet_id prefix provided via the stack - dup.1 assert_eq.err=ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN - # => [ASSET] - - # assert the non-fungible asset is valid - exec.validate_non_fungible_asset - # => [ASSET] -end +export.::utils::asset_utils::validate_non_fungible_asset_origin diff --git a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm index 7395f6a62..9da892a85 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm @@ -1,6 +1,7 @@ use.std::collections::smt use.utils::account_utils +use.utils::asset_vault_utils use.kernel::account use.kernel::asset @@ -33,12 +34,6 @@ const.ERR_VAULT_REMOVE_FUNGIBLE_ASSET_FAILED_INITIAL_VALUE_INVALID=0x0002001E # Failed to remove non-existent non-fungible asset from the vault const.ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND=0x0002001F -# CONSTANTS -# ================================================================================================= - -# The bitmask that when applied will set the fungible bit to zero. -const.INVERSE_FUNGIBLE_BITMASK_U32=0xffffffdf # last byte: 0b1101_1111 - # ACCESSORS # ================================================================================================= @@ -96,7 +91,7 @@ export.has_non_fungible_asset # => [ASSET, vault_root_ptr] # build the asset key from the non-fungible asset - exec.build_non_fungible_asset_vault_key + exec.asset_vault_utils::build_non_fungible_asset_vault_key # => [ASSET_KEY, vault_root_ptr] # prepare the stack to read non-fungible asset from vault @@ -226,7 +221,7 @@ export.add_non_fungible_asset # Build the asset key from the non-fungible asset. # --------------------------------------------------------------------------------------------- - dupw exec.build_non_fungible_asset_vault_key + dupw exec.asset_vault_utils::build_non_fungible_asset_vault_key # => [ASSET_KEY, ASSET, vault_root_ptr] # Load VAULT_ROOT and insert asset. @@ -369,7 +364,7 @@ end #! - the non-fungible asset is not found in the vault. export.remove_non_fungible_asset # build non-fungible asset key - dupw exec.build_non_fungible_asset_vault_key padw + dupw exec.asset_vault_utils::build_non_fungible_asset_vault_key padw # => [pad(4), ASSET_KEY, ASSET, vault_root_ptr] # load vault root @@ -420,34 +415,3 @@ export.remove_asset # => [ASSET] end end - -# HELPER PROCEDURES -# ================================================================================================= - -#! Builds the vault key of a non fungible asset. The asset is NOT validated and therefore must -#! be a valid non-fungible asset. -#! -#! Inputs: [ASSET] -#! Outputs: [ASSET_KEY] -#! -#! Where: -#! - ASSET is the non-fungible asset for which the vault key is built. -#! - ASSET_KEY is the vault key of the non-fungible asset. -proc.build_non_fungible_asset_vault_key - # create the asset key from the non-fungible asset by swapping hash0 with the faucet id - # => [faucet_id_prefix, hash2, hash1, hash0] - swap.3 - # => [hash0, hash2, hash1 faucet_id_prefix] - - # disassemble hash0 into u32 limbs - u32split swap - # => [hash0_lo, hash0_hi, hash2, hash1 faucet_id_prefix] - - # set the fungible bit to 0 - u32and.INVERSE_FUNGIBLE_BITMASK_U32 - # => [hash0_lo', hash0_hi, hash2, hash1 faucet_id_prefix] - - # reassemble hash0 felt by multiplying the high part with 2^32 and adding the lo part - swap push.0x0100000000 mul add - # => [ASSET_KEY] -end \ No newline at end of file diff --git a/miden-lib/asm/miden/asset.masm b/miden-lib/asm/miden/asset.masm index 123951402..346a85004 100644 --- a/miden-lib/asm/miden/asset.masm +++ b/miden-lib/asm/miden/asset.masm @@ -21,7 +21,7 @@ const.ERR_NON_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID=0x0002004D #! Outputs: [fungible_asset_max_amount] #! #! fungible_asset_max_amount is the maximum amount of a fungible asset. -export.::utils::utils::get_fungible_asset_max_amount +export.::utils::asset_utils::get_fungible_asset_max_amount #! Builds a fungible asset for the specified fungible faucet and amount. #! diff --git a/miden-lib/asm/utils/asset_utils.masm b/miden-lib/asm/utils/asset_utils.masm new file mode 100644 index 000000000..e1fef1a3f --- /dev/null +++ b/miden-lib/asm/utils/asset_utils.masm @@ -0,0 +1,193 @@ +use.utils::account_utils + +# ERRORS +# ================================================================================================= + +# Malformed fungible asset: ASSET[1] must be 0 +const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_ZERO=0x00020020 + +# Malformed fungible asset: ASSET[2] and ASSET[3] must be a valid fungible faucet id +const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID=0x00020022 + +# Malformed fungible asset: ASSET[0] exceeds the maximum allowed amount +const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ZERO_MUST_BE_WITHIN_LIMITS=0x00020023 + +# Malformed non-fungible asset: ASSET[3] is not a valid non-fungible faucet id +const.ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID=0x00020024 + +# Malformed non-fungible asset: the most significant bit must be 0 +const.ERR_NON_FUNGIBLE_ASSET_FORMAT_MOST_SIGNIFICANT_BIT_MUST_BE_ZERO=0x00020025 + +# The origin of the fungible asset is not this faucet +const.ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020026 + +# The origin of the non-fungible asset is not this faucet +const.ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020027 + +# CONSTANTS +# ================================================================================================= + +const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 + +# PROCEDURES +# ================================================================================================= + +#! Returns the maximum amount of a fungible asset. +#! +#! Inputs: [] +#! Outputs: [fungible_asset_max_amount] +#! +#! Where: +#! - fungible_asset_max_amount is the maximum amount of a fungible asset. +export.get_fungible_asset_max_amount + push.FUNGIBLE_ASSET_MAX_AMOUNT + # => [fungible_asset_max_amount] +end + +#! Validates that a fungible asset is well formed. +#! +#! Inputs: [ASSET] +#! Outputs: [ASSET] +#! +#! Where: +#! - ASSET is the asset to validate. +#! +#! Panics if: +#! - the asset is not well formed. +export.validate_fungible_asset + # assert that ASSET[1] == ZERO + dup.2 not assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_ZERO + # => [ASSET] + + # assert that the tuple (ASSET[3], ASSET[2]) forms a valid account ID + dup.1 dup.1 exec.account_utils::validate_id + # => [ASSET] + + # assert that the prefix (ASSET[3]) of the account ID is of type fungible faucet + dup exec.account_utils::is_fungible_faucet + assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID + # => [ASSET] + + # assert that the max amount (ASSET[0]) of a fungible asset is not exceeded + dup.3 push.FUNGIBLE_ASSET_MAX_AMOUNT lte + assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ZERO_MUST_BE_WITHIN_LIMITS + # => [ASSET] +end + +#! Returns a boolean indicating whether the asset is fungible. +#! +#! Inputs: [ASSET] +#! Outputs: [is_fungible_asset, ASSET] +#! +#! Where: +#! - ASSET is the asset to check. +#! - is_fungible_asset is a boolean indicating whether the asset is fungible. +export.is_fungible_asset + # check the first element, it will be: + # - zero for a fungible asset + # - non zero for a non-fungible asset + dup.2 eq.0 + # => [is_fungible_asset, ASSET] +end + +#! Validates that a non fungible asset is well formed. +#! +#! Inputs: [ASSET] +#! Outputs: [ASSET] +#! +#! Where: +#! - ASSET is the asset to validate. +#! +#! Panics if: +#! - the asset is not well formed. +export.validate_non_fungible_asset + # assert that ASSET[3] is a valid account ID prefix + # hack: because we only have the prefix we add a 0 as the suffix which is always valid + push.0 dup.1 exec.account_utils::validate_id + # => [ASSET] + + # assert that the account ID prefix ASSET[3] is of type non fungible faucet + dup exec.account_utils::is_non_fungible_faucet + assert.err=ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID + # => [ASSET] +end + +#! Returns a boolean indicating whether the asset is non-fungible. +#! +#! Inputs: [ASSET] +#! Outputs: [is_non_fungible_asset, ASSET] +#! +#! Where: +#! - ASSET is the asset to check. +#! - is_non_fungible_asset is a boolean indicating whether the asset is non-fungible. +export.is_non_fungible_asset + # check the first element, it will be: + # - zero for a fungible asset + # - non zero for a non-fungible asset + exec.is_fungible_asset not + # => [is_non_fungible_asset, ASSET] +end + +#! Validates that an asset is well formed. +#! +#! Inputs: [ASSET] +#! Outputs: [ASSET] +#! +#! Where: +#! - ASSET is the asset to validate. +#! +#! Panics if: +#! - the asset is not well formed. +export.validate_asset + # check if the asset is fungible + exec.is_fungible_asset + # => [is_fungible_asset, ASSET] + + # if the asset is fungible, validate the fungible asset + if.true + exec.validate_fungible_asset + else + # if the asset is non fungible, validate the non fungible asset + exec.validate_non_fungible_asset + end + # => [ASSET] +end + +#! Validates that a fungible asset is associated with the provided faucet_id. +#! +#! Inputs: [faucet_id_prefix, faucet_id_suffix, ASSET] +#! Outputs: [ASSET] +#! +#! Where: +#! - faucet_id_prefix is the prefix of the faucet's account ID. +#! - ASSET is the asset to validate. +export.validate_fungible_asset_origin + # assert the origin of the asset is the faucet_id provided via the stack + dup.3 dup.3 + # => [asset_id_prefix, asset_id_suffix, faucet_id_prefix, faucet_id_suffix, ASSET] + + exec.account_utils::is_id_eq assert.err=ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN + # => [ASSET] + + # assert the fungible asset is valid + exec.validate_fungible_asset + # => [ASSET] +end + +#! Validates that a non-fungible asset is associated with the provided faucet_id. +#! +#! Inputs: [faucet_id_prefix, ASSET] +#! Outputs: [ASSET] +#! +#! Where: +#! - faucet_id_prefix is the prefix of the faucet's account ID. +#! - ASSET is the asset to validate. +export.validate_non_fungible_asset_origin + # assert the origin of the asset is the faucet_id prefix provided via the stack + dup.1 assert_eq.err=ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN + # => [ASSET] + + # assert the non-fungible asset is valid + exec.validate_non_fungible_asset + # => [ASSET] +end diff --git a/miden-lib/asm/utils/asset_vault_utils.masm b/miden-lib/asm/utils/asset_vault_utils.masm new file mode 100644 index 000000000..33dc98d6d --- /dev/null +++ b/miden-lib/asm/utils/asset_vault_utils.masm @@ -0,0 +1,36 @@ +# CONSTANTS +# ================================================================================================= + +# The bitmask that when applied will set the fungible bit to zero. +const.INVERSE_FUNGIBLE_BITMASK_U32=0xffffffdf # last byte: 0b1101_1111 + +# PROCEDURES +# ================================================================================================= + +#! Builds the vault key of a non fungible asset. The asset is NOT validated and therefore must +#! be a valid non-fungible asset. +#! +#! Inputs: [ASSET] +#! Outputs: [ASSET_KEY] +#! +#! Where: +#! - ASSET is the non-fungible asset for which the vault key is built. +#! - ASSET_KEY is the vault key of the non-fungible asset. +proc.build_non_fungible_asset_vault_key + # create the asset key from the non-fungible asset by swapping hash0 with the faucet id + # => [faucet_id_prefix, hash2, hash1, hash0] + swap.3 + # => [hash0, hash2, hash1 faucet_id_prefix] + + # disassemble hash0 into u32 limbs + u32split swap + # => [hash0_lo, hash0_hi, hash2, hash1 faucet_id_prefix] + + # set the fungible bit to 0 + u32and.INVERSE_FUNGIBLE_BITMASK_U32 + # => [hash0_lo', hash0_hi, hash2, hash1 faucet_id_prefix] + + # reassemble hash0 felt by multiplying the high part with 2^32 and adding the lo part + swap push.0x0100000000 mul add + # => [ASSET_KEY] +end \ No newline at end of file diff --git a/miden-lib/asm/utils/utils.masm b/miden-lib/asm/utils/utils.masm index ce93a0263..80bacff88 100644 --- a/miden-lib/asm/utils/utils.masm +++ b/miden-lib/asm/utils/utils.masm @@ -1,21 +1,5 @@ # TODO: move these procedures to the dedicated `*_uitls` masm file -### ASSET ########################################################### - -const.FUNGIBLE_ASSET_MAX_AMOUNT=9223372036854775807 - -#! Returns the maximum amount of a fungible asset. -#! -#! Inputs: [] -#! Outputs: [fungible_asset_max_amount] -#! -#! Where: -#! - fungible_asset_max_amount is the maximum amount of a fungible asset. -export.get_fungible_asset_max_amount - push.FUNGIBLE_ASSET_MAX_AMOUNT - # => [fungible_asset_max_amount] -end - ### NOTE ############################################################ # The maximum number of input values associated with a single note. diff --git a/miden-lib/src/transaction/mod.rs b/miden-lib/src/transaction/mod.rs index aa8789894..db45db0b4 100644 --- a/miden-lib/src/transaction/mod.rs +++ b/miden-lib/src/transaction/mod.rs @@ -2,7 +2,7 @@ use alloc::{string::ToString, sync::Arc, vec::Vec}; use miden_objects::{ accounts::{AccountCode, AccountHeader, AccountId, AccountStorageHeader}, - assembly::{Assembler, DefaultSourceManager, KernelLibrary}, + assembly::{Assembler, DefaultSourceManager, KernelLibrary, LibraryNamespace}, crypto::merkle::{MerkleError, MerklePath}, transaction::{ OutputNote, OutputNotes, TransactionArgs, TransactionInputs, TransactionOutputs, @@ -352,17 +352,29 @@ impl TransactionKernel { /// The `kernel` library is added separately because even though the library (`api.masm`) and /// the kernel binary (`main.masm`) include this code, it is not exposed explicitly. By adding /// it separately, we can expose procedures from `/lib` and test them individually. + /// + /// This assembler also includes the `utils` namespace which contains the modules defined + /// in the utils directory. pub fn testing_assembler() -> Assembler { let source_manager = Arc::new(DefaultSourceManager::default()); let kernel_library = Self::kernel_as_library(); - Assembler::with_kernel(source_manager, Self::kernel()) + let mut assembler = Assembler::with_kernel(source_manager, Self::kernel()) .with_library(StdLibrary::default()) .expect("failed to load std-lib") .with_library(MidenLib::default()) .expect("failed to load miden-lib") .with_library(kernel_library) - .expect("failed to load kernel library (/lib)") + .expect("failed to load kernel library (/lib)"); + + // Add the utils modules under the utils namespace. + let utils_namespace = LibraryNamespace::new("utils").expect("invalid namespace"); + let utils_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("asm").join("utils"); + assembler + .add_modules_from_dir(utils_namespace, &utils_path) + .expect("util library should exist and assemble successfully"); + + assembler } /// Returns the testing assembler, and additionally contains the library for diff --git a/miden-tx/src/testing/executor.rs b/miden-tx/src/testing/executor.rs index 47ee41f67..3e9c2d0b6 100644 --- a/miden-tx/src/testing/executor.rs +++ b/miden-tx/src/testing/executor.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use miden_lib::transaction::TransactionKernel; use vm_processor::{ AdviceInputs, AdviceProvider, DefaultHost, ExecutionError, Host, Process, Program, StackInputs, diff --git a/miden-tx/src/tests/kernel_tests/test_account.rs b/miden-tx/src/tests/kernel_tests/test_account.rs index afbcf5055..3b189fb12 100644 --- a/miden-tx/src/tests/kernel_tests/test_account.rs +++ b/miden-tx/src/tests/kernel_tests/test_account.rs @@ -139,10 +139,10 @@ pub fn test_account_type() { let code = format!( " - use.kernel::account + use.utils::account_utils begin - exec.account::{} + exec.account_utils::{} end ", procedure @@ -209,10 +209,10 @@ pub fn test_account_validate_id() -> anyhow::Result<()> { let suffix = Felt::try_from((account_id % (1u128 << 64)) as u64).unwrap(); let code = " - use.kernel::account + use.utils::account_utils begin - exec.account::validate_id + exec.account_utils::validate_id end "; @@ -260,11 +260,11 @@ fn test_is_faucet_procedure() { let code = format!( " - use.kernel::account + use.utils::account_utils begin push.{prefix} - exec.account::is_faucet + exec.account_utils::is_faucet # => [is_faucet, account_id_prefix] # truncate the stack From dcf53b955001feb71190cf36c4de548b89c81e07 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 14 Jan 2025 14:24:10 +0100 Subject: [PATCH 07/10] feat: Move pure procedures to note_utils --- .../kernels/transaction/lib/constants.masm | 2 +- miden-lib/asm/kernels/transaction/lib/tx.masm | 12 +++--- miden-lib/asm/miden/note.masm | 2 +- miden-lib/asm/miden/tx.masm | 11 +---- miden-lib/asm/utils/note_utils.masm | 42 +++++++++++++++++++ miden-lib/asm/utils/utils.masm | 17 -------- miden-tx/src/testing/executor.rs | 2 - 7 files changed, 52 insertions(+), 36 deletions(-) create mode 100644 miden-lib/asm/utils/note_utils.masm delete mode 100644 miden-lib/asm/utils/utils.masm diff --git a/miden-lib/asm/kernels/transaction/lib/constants.masm b/miden-lib/asm/kernels/transaction/lib/constants.masm index fc446cdb3..8ba83288e 100644 --- a/miden-lib/asm/kernels/transaction/lib/constants.masm +++ b/miden-lib/asm/kernels/transaction/lib/constants.masm @@ -47,7 +47,7 @@ end #! Output: [max_inputs_per_note] #! #! - max_inputs_per_note is the max inputs per note. -export.::utils::utils::get_max_inputs_per_note +export.::utils::note_utils::get_max_inputs_per_note #! Returns the max allowed number of assets per note. #! diff --git a/miden-lib/asm/kernels/transaction/lib/tx.masm b/miden-lib/asm/kernels/transaction/lib/tx.masm index dbaa41b09..8ad454d5e 100644 --- a/miden-lib/asm/kernels/transaction/lib/tx.masm +++ b/miden-lib/asm/kernels/transaction/lib/tx.masm @@ -12,9 +12,6 @@ const.PUBLIC_NOTE=1 # 0b01 const.PRIVATE_NOTE=2 # 0b10 const.ENCRYPTED_NOTE=3 # 0b11 -# Two raised to the power of 38 (2^38), used for shifting the note type value -const.TWO_POW_38=274877906944 - # Max value for U16, used as the upper limit for expiration block delta const.EXPIRY_UPPER_LIMIT=0xFFFF+1 @@ -352,8 +349,13 @@ proc.add_fungible_asset_to_note # => [note_ptr, note_idx] end -#! Builds the stack into the NOTE_METADATA word, encoding the note type and execution hint into a -#! single element. +#! Builds the inputs on the stack into the NOTE_METADATA word with the following layout: +#! +#! 1st felt: [sender_id_prefix (64 bits)] +#! 2nd felt: [sender_id_suffix (56 bits) | note_type (2 bits) | execution_hint_tag (6 bits)] +#! 3rd felt: [execution_hint_payload (32 bits) | tag (32 bits)] +#! 4th felt: [aux (64 bits)] +#! #! Note that this procedure is only exported so it can be tested. It should not be called from #! non-test code. #! diff --git a/miden-lib/asm/miden/note.masm b/miden-lib/asm/miden/note.masm index a8765d0c4..9d796f23f 100644 --- a/miden-lib/asm/miden/note.masm +++ b/miden-lib/asm/miden/note.masm @@ -21,7 +21,7 @@ const.ERR_PROLOGUE_NUMBER_OF_NOTE_INPUTS_EXCEEDED_LIMIT=0x0002004F #! Output: [max_inputs_per_note] #! #! - max_inputs_per_note is the max inputs per note. -export.::utils::utils::get_max_inputs_per_note +export.::utils::note_utils::get_max_inputs_per_note #! Writes the data currently on the advice stack into the memory at the specified location and #! verifies that the hash of the written data is equal to the provided hash. diff --git a/miden-lib/asm/miden/tx.masm b/miden-lib/asm/miden/tx.masm index f4d5f6e5e..43a997fca 100644 --- a/miden-lib/asm/miden/tx.masm +++ b/miden-lib/asm/miden/tx.masm @@ -173,16 +173,7 @@ end #! - RECIPIENT is the recipient of the note. #! #! Invocation: exec -export.build_recipient_hash - padw hmerge - # => [SERIAL_NUM_HASH, SCRIPT_HASH, INPUT_HASH] - - swapw hmerge - # => [MERGE_SCRIPT, INPUT_HASH] - - swapw hmerge - # [RECIPIENT] -end +export.::utils::note_utils::build_recipient_hash #! Executes the provided procedure against the foreign account. #! diff --git a/miden-lib/asm/utils/note_utils.masm b/miden-lib/asm/utils/note_utils.masm new file mode 100644 index 000000000..4d35574a7 --- /dev/null +++ b/miden-lib/asm/utils/note_utils.masm @@ -0,0 +1,42 @@ +# CONSTANTS +# ================================================================================================= + +# The maximum number of input values associated with a single note. +const.MAX_INPUTS_PER_NOTE=128 + +# PROCEDURES +# ================================================================================================= + +#! Returns the max allowed number of input values per note. +#! +#! Inputs: [] +#! Outputs: [max_inputs_per_note] +#! +#! Where: +#! - max_inputs_per_note is the max inputs per note. +export.get_max_inputs_per_note + push.MAX_INPUTS_PER_NOTE +end + +#! Returns the RECIPIENT for a specified SERIAL_NUM, SCRIPT_HASH, and inputs hash +#! +#! Inputs: [SERIAL_NUM, SCRIPT_HASH, INPUT_HASH] +#! Outputs: [RECIPIENT] +#! +#! Where: +#! - SERIAL_NUM is the serial number of the recipient. +#! - SCRIPT_HASH is the commitment of the note script. +#! - INPUT_HASH is the commitment of the note inputs. +#! - RECIPIENT is the recipient of the note. +#! +#! Invocation: exec +export.build_recipient_hash + padw hmerge + # => [SERIAL_NUM_HASH, SCRIPT_HASH, INPUT_HASH] + + swapw hmerge + # => [MERGE_SCRIPT, INPUT_HASH] + + swapw hmerge + # [RECIPIENT] +end \ No newline at end of file diff --git a/miden-lib/asm/utils/utils.masm b/miden-lib/asm/utils/utils.masm deleted file mode 100644 index 80bacff88..000000000 --- a/miden-lib/asm/utils/utils.masm +++ /dev/null @@ -1,17 +0,0 @@ -# TODO: move these procedures to the dedicated `*_uitls` masm file - -### NOTE ############################################################ - -# The maximum number of input values associated with a single note. -const.MAX_INPUTS_PER_NOTE=128 - -#! Returns the max allowed number of input values per note. -#! -#! Inputs: [] -#! Outputs: [max_inputs_per_note] -#! -#! Where: -#! - max_inputs_per_note is the max inputs per note. -export.get_max_inputs_per_note - push.MAX_INPUTS_PER_NOTE -end diff --git a/miden-tx/src/testing/executor.rs b/miden-tx/src/testing/executor.rs index 3e9c2d0b6..47ee41f67 100644 --- a/miden-tx/src/testing/executor.rs +++ b/miden-tx/src/testing/executor.rs @@ -1,5 +1,3 @@ -use std::path::Path; - use miden_lib::transaction::TransactionKernel; use vm_processor::{ AdviceInputs, AdviceProvider, DefaultHost, ExecutionError, Host, Process, Program, StackInputs, From fb441e09f15c7884e858416bd4f1cf46e4da1ad5 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 14 Jan 2025 14:43:23 +0100 Subject: [PATCH 08/10] feat: Add utils library to testing_assembler --- miden-lib/asm/utils/account_utils.masm | 2 +- miden-lib/src/transaction/mod.rs | 27 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/miden-lib/asm/utils/account_utils.masm b/miden-lib/asm/utils/account_utils.masm index 8c4b0830c..9b7b66467 100644 --- a/miden-lib/asm/utils/account_utils.masm +++ b/miden-lib/asm/utils/account_utils.masm @@ -1,7 +1,7 @@ # ERRORS # ================================================================================================= -# Unknown version in account id. +# Unknown version in account ID. const.ERR_ACCOUNT_ID_UNKNOWN_VERSION=0x00020057 # Epoch must be less than u16::MAX (0xffff). diff --git a/miden-lib/src/transaction/mod.rs b/miden-lib/src/transaction/mod.rs index db45db0b4..5eb16970b 100644 --- a/miden-lib/src/transaction/mod.rs +++ b/miden-lib/src/transaction/mod.rs @@ -2,7 +2,7 @@ use alloc::{string::ToString, sync::Arc, vec::Vec}; use miden_objects::{ accounts::{AccountCode, AccountHeader, AccountId, AccountStorageHeader}, - assembly::{Assembler, DefaultSourceManager, KernelLibrary, LibraryNamespace}, + assembly::{Assembler, DefaultSourceManager, KernelLibrary}, crypto::merkle::{MerkleError, MerklePath}, transaction::{ OutputNote, OutputNotes, TransactionArgs, TransactionInputs, TransactionOutputs, @@ -354,12 +354,12 @@ impl TransactionKernel { /// it separately, we can expose procedures from `/lib` and test them individually. /// /// This assembler also includes the `utils` namespace which contains the modules defined - /// in the utils directory. + /// in the utils directory (only under feature `std`). pub fn testing_assembler() -> Assembler { let source_manager = Arc::new(DefaultSourceManager::default()); let kernel_library = Self::kernel_as_library(); - let mut assembler = Assembler::with_kernel(source_manager, Self::kernel()) + let assembler = Assembler::with_kernel(source_manager, Self::kernel()) .with_library(StdLibrary::default()) .expect("failed to load std-lib") .with_library(MidenLib::default()) @@ -367,12 +367,21 @@ impl TransactionKernel { .with_library(kernel_library) .expect("failed to load kernel library (/lib)"); - // Add the utils modules under the utils namespace. - let utils_namespace = LibraryNamespace::new("utils").expect("invalid namespace"); - let utils_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("asm").join("utils"); - assembler - .add_modules_from_dir(utils_namespace, &utils_path) - .expect("util library should exist and assemble successfully"); + #[cfg(feature = "std")] + let mut assembler = assembler; + // We don't build the utils modules as a library in build.rs so we have to load it here + // instead. This means it won't be included in no_std environments. + #[cfg(feature = "std")] + { + // Add the utils modules under the utils namespace. + let utils_namespace = + miden_objects::assembly::LibraryNamespace::new("utils").expect("invalid namespace"); + let utils_path = + std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("asm").join("utils"); + assembler + .add_modules_from_dir(utils_namespace, &utils_path) + .expect("util library should exist and assemble successfully"); + } assembler } From 1177f89749df77241d4aced74c69d83f7ad8f773 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 15 Jan 2025 10:23:09 +0100 Subject: [PATCH 09/10] chore: Move non-shared procedures back to kernel --- .../asm/kernels/transaction/lib/asset.masm | 95 +++++++++++- .../kernels/transaction/lib/asset_vault.masm | 44 +++++- miden-lib/asm/miden/tx.masm | 11 +- miden-lib/asm/utils/asset_utils.masm | 139 ------------------ miden-lib/asm/utils/asset_vault_utils.masm | 36 ----- miden-lib/asm/utils/note_utils.masm | 23 --- 6 files changed, 139 insertions(+), 209 deletions(-) delete mode 100644 miden-lib/asm/utils/asset_vault_utils.masm diff --git a/miden-lib/asm/kernels/transaction/lib/asset.masm b/miden-lib/asm/kernels/transaction/lib/asset.masm index 28768d238..35d5a720f 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset.masm @@ -1,6 +1,29 @@ +use.kernel::account use.utils::account_utils -use.kernel::account +# ERRORS +# ================================================================================================= + +# Malformed fungible asset: ASSET[1] must be 0 +const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_ZERO=0x00020020 + +# Malformed fungible asset: ASSET[2] and ASSET[3] must be a valid fungible faucet id +const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID=0x00020022 + +# Malformed fungible asset: ASSET[0] exceeds the maximum allowed amount +const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ZERO_MUST_BE_WITHIN_LIMITS=0x00020023 + +# Malformed non-fungible asset: ASSET[3] is not a valid non-fungible faucet id +const.ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID=0x00020024 + +# Malformed non-fungible asset: the most significant bit must be 0 +const.ERR_NON_FUNGIBLE_ASSET_FORMAT_MOST_SIGNIFICANT_BIT_MUST_BE_ZERO=0x00020025 + +# The origin of the fungible asset is not this faucet +const.ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020026 + +# The origin of the non-fungible asset is not this faucet +const.ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020027 # PROCEDURES # ================================================================================================= @@ -23,7 +46,25 @@ export.::utils::asset_utils::get_fungible_asset_max_amount #! #! Panics if: #! - the asset is not well formed. -export.::utils::asset_utils::validate_fungible_asset +export.validate_fungible_asset + # assert that ASSET[1] == ZERO + dup.2 not assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_ZERO + # => [ASSET] + + # assert that the tuple (ASSET[3], ASSET[2]) forms a valid account ID + dup.1 dup.1 exec.account_utils::validate_id + # => [ASSET] + + # assert that the prefix (ASSET[3]) of the account ID is of type fungible faucet + dup exec.account_utils::is_fungible_faucet + assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID + # => [ASSET] + + # assert that the max amount (ASSET[0]) of a fungible asset is not exceeded + dup.3 exec.get_fungible_asset_max_amount lte + assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ZERO_MUST_BE_WITHIN_LIMITS + # => [ASSET] +end #! Returns a boolean indicating whether the asset is fungible. #! @@ -45,7 +86,17 @@ export.::utils::asset_utils::is_fungible_asset #! #! Panics if: #! - the asset is not well formed. -export.::utils::asset_utils::validate_non_fungible_asset +export.validate_non_fungible_asset + # assert that ASSET[3] is a valid account ID prefix + # hack: because we only have the prefix we add a 0 as the suffix which is always valid + push.0 dup.1 exec.account_utils::validate_id + # => [ASSET] + + # assert that the account ID prefix ASSET[3] is of type non fungible faucet + dup exec.account_utils::is_non_fungible_faucet + assert.err=ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID + # => [ASSET] +end #! Returns a boolean indicating whether the asset is non-fungible. #! @@ -67,7 +118,20 @@ export.::utils::asset_utils::is_non_fungible_asset #! #! Panics if: #! - the asset is not well formed. -export.::utils::asset_utils::validate_asset +export.validate_asset + # check if the asset is fungible + exec.is_fungible_asset + # => [is_fungible_asset, ASSET] + + # if the asset is fungible, validate the fungible asset + if.true + exec.validate_fungible_asset + else + # if the asset is non fungible, validate the non fungible asset + exec.validate_non_fungible_asset + end + # => [ASSET] +end #! Validates that a fungible asset is associated with the provided faucet_id. #! @@ -77,7 +141,18 @@ export.::utils::asset_utils::validate_asset #! Where: #! - faucet_id_prefix is the prefix of the faucet's account ID. #! - ASSET is the asset to validate. -export.::utils::asset_utils::validate_fungible_asset_origin +export.validate_fungible_asset_origin + # assert the origin of the asset is the faucet_id provided via the stack + dup.3 dup.3 + # => [asset_id_prefix, asset_id_suffix, faucet_id_prefix, faucet_id_suffix, ASSET] + + exec.account_utils::is_id_eq assert.err=ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN + # => [ASSET] + + # assert the fungible asset is valid + exec.validate_fungible_asset + # => [ASSET] +end #! Validates that a non-fungible asset is associated with the provided faucet_id. #! @@ -87,4 +162,12 @@ export.::utils::asset_utils::validate_fungible_asset_origin #! Where: #! - faucet_id_prefix is the prefix of the faucet's account ID. #! - ASSET is the asset to validate. -export.::utils::asset_utils::validate_non_fungible_asset_origin +export.validate_non_fungible_asset_origin + # assert the origin of the asset is the faucet_id prefix provided via the stack + dup.1 assert_eq.err=ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN + # => [ASSET] + + # assert the non-fungible asset is valid + exec.validate_non_fungible_asset + # => [ASSET] +end diff --git a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm index 9da892a85..39a3f5b93 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm @@ -1,7 +1,6 @@ use.std::collections::smt use.utils::account_utils -use.utils::asset_vault_utils use.kernel::account use.kernel::asset @@ -34,6 +33,12 @@ const.ERR_VAULT_REMOVE_FUNGIBLE_ASSET_FAILED_INITIAL_VALUE_INVALID=0x0002001E # Failed to remove non-existent non-fungible asset from the vault const.ERR_VAULT_NON_FUNGIBLE_ASSET_TO_REMOVE_NOT_FOUND=0x0002001F +# CONSTANTS +# ================================================================================================= + +# The bitmask that when applied will set the fungible bit to zero. +const.INVERSE_FUNGIBLE_BITMASK_U32=0xffffffdf # last byte: 0b1101_1111 + # ACCESSORS # ================================================================================================= @@ -91,7 +96,7 @@ export.has_non_fungible_asset # => [ASSET, vault_root_ptr] # build the asset key from the non-fungible asset - exec.asset_vault_utils::build_non_fungible_asset_vault_key + exec.build_non_fungible_asset_vault_key # => [ASSET_KEY, vault_root_ptr] # prepare the stack to read non-fungible asset from vault @@ -221,7 +226,7 @@ export.add_non_fungible_asset # Build the asset key from the non-fungible asset. # --------------------------------------------------------------------------------------------- - dupw exec.asset_vault_utils::build_non_fungible_asset_vault_key + dupw exec.build_non_fungible_asset_vault_key # => [ASSET_KEY, ASSET, vault_root_ptr] # Load VAULT_ROOT and insert asset. @@ -364,7 +369,7 @@ end #! - the non-fungible asset is not found in the vault. export.remove_non_fungible_asset # build non-fungible asset key - dupw exec.asset_vault_utils::build_non_fungible_asset_vault_key padw + dupw exec.build_non_fungible_asset_vault_key padw # => [pad(4), ASSET_KEY, ASSET, vault_root_ptr] # load vault root @@ -415,3 +420,34 @@ export.remove_asset # => [ASSET] end end + +# PROCEDURES +# ================================================================================================= + +#! Builds the vault key of a non fungible asset. The asset is NOT validated and therefore must +#! be a valid non-fungible asset. +#! +#! Inputs: [ASSET] +#! Outputs: [ASSET_KEY] +#! +#! Where: +#! - ASSET is the non-fungible asset for which the vault key is built. +#! - ASSET_KEY is the vault key of the non-fungible asset. +proc.build_non_fungible_asset_vault_key + # create the asset key from the non-fungible asset by swapping hash0 with the faucet id + # => [faucet_id_prefix, hash2, hash1, hash0] + swap.3 + # => [hash0, hash2, hash1 faucet_id_prefix] + + # disassemble hash0 into u32 limbs + u32split swap + # => [hash0_lo, hash0_hi, hash2, hash1 faucet_id_prefix] + + # set the fungible bit to 0 + u32and.INVERSE_FUNGIBLE_BITMASK_U32 + # => [hash0_lo', hash0_hi, hash2, hash1 faucet_id_prefix] + + # reassemble hash0 felt by multiplying the high part with 2^32 and adding the lo part + swap push.0x0100000000 mul add + # => [ASSET_KEY] +end \ No newline at end of file diff --git a/miden-lib/asm/miden/tx.masm b/miden-lib/asm/miden/tx.masm index 43a997fca..f4d5f6e5e 100644 --- a/miden-lib/asm/miden/tx.masm +++ b/miden-lib/asm/miden/tx.masm @@ -173,7 +173,16 @@ end #! - RECIPIENT is the recipient of the note. #! #! Invocation: exec -export.::utils::note_utils::build_recipient_hash +export.build_recipient_hash + padw hmerge + # => [SERIAL_NUM_HASH, SCRIPT_HASH, INPUT_HASH] + + swapw hmerge + # => [MERGE_SCRIPT, INPUT_HASH] + + swapw hmerge + # [RECIPIENT] +end #! Executes the provided procedure against the foreign account. #! diff --git a/miden-lib/asm/utils/asset_utils.masm b/miden-lib/asm/utils/asset_utils.masm index e1fef1a3f..7218582f3 100644 --- a/miden-lib/asm/utils/asset_utils.masm +++ b/miden-lib/asm/utils/asset_utils.masm @@ -1,29 +1,5 @@ use.utils::account_utils -# ERRORS -# ================================================================================================= - -# Malformed fungible asset: ASSET[1] must be 0 -const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_ZERO=0x00020020 - -# Malformed fungible asset: ASSET[2] and ASSET[3] must be a valid fungible faucet id -const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID=0x00020022 - -# Malformed fungible asset: ASSET[0] exceeds the maximum allowed amount -const.ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ZERO_MUST_BE_WITHIN_LIMITS=0x00020023 - -# Malformed non-fungible asset: ASSET[3] is not a valid non-fungible faucet id -const.ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID=0x00020024 - -# Malformed non-fungible asset: the most significant bit must be 0 -const.ERR_NON_FUNGIBLE_ASSET_FORMAT_MOST_SIGNIFICANT_BIT_MUST_BE_ZERO=0x00020025 - -# The origin of the fungible asset is not this faucet -const.ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020026 - -# The origin of the non-fungible asset is not this faucet -const.ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020027 - # CONSTANTS # ================================================================================================= @@ -44,36 +20,6 @@ export.get_fungible_asset_max_amount # => [fungible_asset_max_amount] end -#! Validates that a fungible asset is well formed. -#! -#! Inputs: [ASSET] -#! Outputs: [ASSET] -#! -#! Where: -#! - ASSET is the asset to validate. -#! -#! Panics if: -#! - the asset is not well formed. -export.validate_fungible_asset - # assert that ASSET[1] == ZERO - dup.2 not assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ONE_MUST_BE_ZERO - # => [ASSET] - - # assert that the tuple (ASSET[3], ASSET[2]) forms a valid account ID - dup.1 dup.1 exec.account_utils::validate_id - # => [ASSET] - - # assert that the prefix (ASSET[3]) of the account ID is of type fungible faucet - dup exec.account_utils::is_fungible_faucet - assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID - # => [ASSET] - - # assert that the max amount (ASSET[0]) of a fungible asset is not exceeded - dup.3 push.FUNGIBLE_ASSET_MAX_AMOUNT lte - assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_ZERO_MUST_BE_WITHIN_LIMITS - # => [ASSET] -end - #! Returns a boolean indicating whether the asset is fungible. #! #! Inputs: [ASSET] @@ -90,28 +36,6 @@ export.is_fungible_asset # => [is_fungible_asset, ASSET] end -#! Validates that a non fungible asset is well formed. -#! -#! Inputs: [ASSET] -#! Outputs: [ASSET] -#! -#! Where: -#! - ASSET is the asset to validate. -#! -#! Panics if: -#! - the asset is not well formed. -export.validate_non_fungible_asset - # assert that ASSET[3] is a valid account ID prefix - # hack: because we only have the prefix we add a 0 as the suffix which is always valid - push.0 dup.1 exec.account_utils::validate_id - # => [ASSET] - - # assert that the account ID prefix ASSET[3] is of type non fungible faucet - dup exec.account_utils::is_non_fungible_faucet - assert.err=ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID - # => [ASSET] -end - #! Returns a boolean indicating whether the asset is non-fungible. #! #! Inputs: [ASSET] @@ -128,66 +52,3 @@ export.is_non_fungible_asset # => [is_non_fungible_asset, ASSET] end -#! Validates that an asset is well formed. -#! -#! Inputs: [ASSET] -#! Outputs: [ASSET] -#! -#! Where: -#! - ASSET is the asset to validate. -#! -#! Panics if: -#! - the asset is not well formed. -export.validate_asset - # check if the asset is fungible - exec.is_fungible_asset - # => [is_fungible_asset, ASSET] - - # if the asset is fungible, validate the fungible asset - if.true - exec.validate_fungible_asset - else - # if the asset is non fungible, validate the non fungible asset - exec.validate_non_fungible_asset - end - # => [ASSET] -end - -#! Validates that a fungible asset is associated with the provided faucet_id. -#! -#! Inputs: [faucet_id_prefix, faucet_id_suffix, ASSET] -#! Outputs: [ASSET] -#! -#! Where: -#! - faucet_id_prefix is the prefix of the faucet's account ID. -#! - ASSET is the asset to validate. -export.validate_fungible_asset_origin - # assert the origin of the asset is the faucet_id provided via the stack - dup.3 dup.3 - # => [asset_id_prefix, asset_id_suffix, faucet_id_prefix, faucet_id_suffix, ASSET] - - exec.account_utils::is_id_eq assert.err=ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN - # => [ASSET] - - # assert the fungible asset is valid - exec.validate_fungible_asset - # => [ASSET] -end - -#! Validates that a non-fungible asset is associated with the provided faucet_id. -#! -#! Inputs: [faucet_id_prefix, ASSET] -#! Outputs: [ASSET] -#! -#! Where: -#! - faucet_id_prefix is the prefix of the faucet's account ID. -#! - ASSET is the asset to validate. -export.validate_non_fungible_asset_origin - # assert the origin of the asset is the faucet_id prefix provided via the stack - dup.1 assert_eq.err=ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN - # => [ASSET] - - # assert the non-fungible asset is valid - exec.validate_non_fungible_asset - # => [ASSET] -end diff --git a/miden-lib/asm/utils/asset_vault_utils.masm b/miden-lib/asm/utils/asset_vault_utils.masm deleted file mode 100644 index 33dc98d6d..000000000 --- a/miden-lib/asm/utils/asset_vault_utils.masm +++ /dev/null @@ -1,36 +0,0 @@ -# CONSTANTS -# ================================================================================================= - -# The bitmask that when applied will set the fungible bit to zero. -const.INVERSE_FUNGIBLE_BITMASK_U32=0xffffffdf # last byte: 0b1101_1111 - -# PROCEDURES -# ================================================================================================= - -#! Builds the vault key of a non fungible asset. The asset is NOT validated and therefore must -#! be a valid non-fungible asset. -#! -#! Inputs: [ASSET] -#! Outputs: [ASSET_KEY] -#! -#! Where: -#! - ASSET is the non-fungible asset for which the vault key is built. -#! - ASSET_KEY is the vault key of the non-fungible asset. -proc.build_non_fungible_asset_vault_key - # create the asset key from the non-fungible asset by swapping hash0 with the faucet id - # => [faucet_id_prefix, hash2, hash1, hash0] - swap.3 - # => [hash0, hash2, hash1 faucet_id_prefix] - - # disassemble hash0 into u32 limbs - u32split swap - # => [hash0_lo, hash0_hi, hash2, hash1 faucet_id_prefix] - - # set the fungible bit to 0 - u32and.INVERSE_FUNGIBLE_BITMASK_U32 - # => [hash0_lo', hash0_hi, hash2, hash1 faucet_id_prefix] - - # reassemble hash0 felt by multiplying the high part with 2^32 and adding the lo part - swap push.0x0100000000 mul add - # => [ASSET_KEY] -end \ No newline at end of file diff --git a/miden-lib/asm/utils/note_utils.masm b/miden-lib/asm/utils/note_utils.masm index 4d35574a7..dc1bc2185 100644 --- a/miden-lib/asm/utils/note_utils.masm +++ b/miden-lib/asm/utils/note_utils.masm @@ -17,26 +17,3 @@ const.MAX_INPUTS_PER_NOTE=128 export.get_max_inputs_per_note push.MAX_INPUTS_PER_NOTE end - -#! Returns the RECIPIENT for a specified SERIAL_NUM, SCRIPT_HASH, and inputs hash -#! -#! Inputs: [SERIAL_NUM, SCRIPT_HASH, INPUT_HASH] -#! Outputs: [RECIPIENT] -#! -#! Where: -#! - SERIAL_NUM is the serial number of the recipient. -#! - SCRIPT_HASH is the commitment of the note script. -#! - INPUT_HASH is the commitment of the note inputs. -#! - RECIPIENT is the recipient of the note. -#! -#! Invocation: exec -export.build_recipient_hash - padw hmerge - # => [SERIAL_NUM_HASH, SCRIPT_HASH, INPUT_HASH] - - swapw hmerge - # => [MERGE_SCRIPT, INPUT_HASH] - - swapw hmerge - # [RECIPIENT] -end \ No newline at end of file From ee3c662252752d65ad8ada9b29df8cb7e6355d64 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 16 Jan 2025 09:36:21 +0100 Subject: [PATCH 10/10] feat: Implement shared modules under different namespaces --- miden-lib/asm/kernels/transaction/api.masm | 17 ++++---- .../asm/kernels/transaction/lib/account.masm | 23 ++++++----- .../asm/kernels/transaction/lib/asset.masm | 19 +++++---- .../kernels/transaction/lib/asset_vault.masm | 6 +-- .../kernels/transaction/lib/constants.masm | 2 +- .../asm/kernels/transaction/lib/faucet.masm | 23 ++++++----- .../asm/kernels/transaction/lib/memory.masm | 1 - .../asm/kernels/transaction/lib/prologue.masm | 17 ++++---- miden-lib/asm/miden/account.masm | 6 +-- miden-lib/asm/miden/asset.masm | 7 ++-- miden-lib/asm/miden/note.masm | 2 +- .../util/account_id.masm} | 4 +- .../util/asset.masm} | 2 - .../note_utils.masm => shared/util/note.masm} | 0 miden-lib/build.rs | 39 ++++++++++++------- 15 files changed, 85 insertions(+), 83 deletions(-) rename miden-lib/asm/{utils/account_utils.masm => shared/util/account_id.masm} (99%) rename miden-lib/asm/{utils/asset_utils.masm => shared/util/asset.masm} (98%) rename miden-lib/asm/{utils/note_utils.masm => shared/util/note.masm} (100%) diff --git a/miden-lib/asm/kernels/transaction/api.masm b/miden-lib/asm/kernels/transaction/api.masm index 407c2ce61..28466f427 100644 --- a/miden-lib/asm/kernels/transaction/api.masm +++ b/miden-lib/asm/kernels/transaction/api.masm @@ -1,8 +1,7 @@ use.std::collections::smt use.std::sys -use.utils::account_utils - +use.kernel::util::account_id use.kernel::account use.kernel::asset_vault use.kernel::constants @@ -195,7 +194,7 @@ export.get_account_item # => [storage_offset, storage_size, index, pad(15)] # apply offset to storage slot index - exec.account_utils::apply_storage_offset + exec.account_id::apply_storage_offset # => [index_with_offset, pad(15)] # fetch the account storage item @@ -230,8 +229,8 @@ export.set_account_item # if the transaction is being executed against a faucet account then assert # index != FAUCET_STORAGE_DATA_SLOT (reserved slot) - dup exec.account_utils::get_faucet_storage_data_slot eq - exec.account::get_id swap drop exec.account_utils::is_faucet + dup exec.account_id::get_faucet_storage_data_slot eq + exec.account::get_id swap drop exec.account_id::is_faucet and assertz.err=ERR_FAUCET_STORAGE_DATA_SLOT_IS_RESERVED # => [index, V', pad(11)] @@ -240,7 +239,7 @@ export.set_account_item # => [storage_offset, storage_size, index, V', pad(11)] # apply offset to storage slot index - exec.account_utils::apply_storage_offset + exec.account_id::apply_storage_offset # => [index_with_offset, V', pad(11)] # set the account storage item @@ -281,7 +280,7 @@ export.get_account_map_item # => [storage_offset, storage_size, index, KEY, pad(11)] # apply offset to storage slot index - exec.account_utils::apply_storage_offset + exec.account_id::apply_storage_offset # => [index_with_offset, KEY, pad(11)] # fetch the account storage item, which is ROOT of the map @@ -327,7 +326,7 @@ export.set_account_map_item.1 # => [storage_offset, storage_size, index, KEY, NEW_VALUE, pad(7)] # apply offset to storage slot index - exec.account_utils::apply_storage_offset + exec.account_id::apply_storage_offset # => [index_with_offset, KEY, NEW_VALUE, pad(7)] # store index for later @@ -822,7 +821,7 @@ end #! Invocation: dynexec export.get_fungible_faucet_total_issuance # assert that we are executing a transaction against a fungible faucet (access checks) - exec.account::get_id swap drop exec.account_utils::is_fungible_faucet + exec.account::get_id swap drop exec.account_id::is_fungible_faucet assert.err=ERR_ACCOUNT_TOTAL_ISSUANCE_PROC_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_FAUCET # => [pad(16)] diff --git a/miden-lib/asm/kernels/transaction/lib/account.masm b/miden-lib/asm/kernels/transaction/lib/account.masm index 7ccc94560..f0295bcfd 100644 --- a/miden-lib/asm/kernels/transaction/lib/account.masm +++ b/miden-lib/asm/kernels/transaction/lib/account.masm @@ -3,8 +3,7 @@ use.std::collections::smt use.std::crypto::hashes::rpo use.std::mem -use.utils::account_utils - +use.kernel::util::account_id use.kernel::constants use.kernel::memory @@ -192,7 +191,7 @@ export.set_code # => [acct_id_prefix, CODE_COMMITMENT] # assert the account is an updatable regular account - exec.account_utils::is_updatable_account assert.err=ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE + exec.account_id::is_updatable_account assert.err=ERR_ACCOUNT_CODE_IS_NOT_UPDATABLE # => [CODE_COMMITMENT] # set the code commitment @@ -218,7 +217,7 @@ export.validate_procedure_metadata # => [start_loop, index, num_storage_slots, num_account_procedures] # check if the account is a faucet - exec.get_id swap drop exec.account_utils::is_faucet + exec.get_id swap drop exec.account_id::is_faucet # => [is_faucet, start_loop, index, num_storage_slots, num_account_procedures] # we do not check if num_account_procedures == 0 here because a valid @@ -525,7 +524,7 @@ export.validate_seed # => [0, 0, account_id_prefix, account_id_suffix] # get the anchor block's number - dup.3 exec.account_utils::id_anchor_block_num + dup.3 exec.account_id::id_anchor_block_num # => [anchor_block_num, 0, 0, account_id_prefix, account_id_suffix] exec.memory::get_chain_mmr_ptr swap @@ -589,15 +588,15 @@ export.validate_seed # => [account_id_suffix, hashed_account_id_prefix, hashed_account_id_suffix, account_id_prefix] # extract anchor epoch from ID of the new account - dup movdn.4 exec.account_utils::id_anchor_epoch + dup movdn.4 exec.account_id::id_anchor_epoch # => [anchor_epoch, hashed_account_id_prefix, hashed_account_id_suffix, account_id_prefix, account_id_suffix] # shape suffix of hashed id, adding the anchor epoch and setting the lower 8 bits to zero - movup.2 exec.account_utils::shape_suffix swap + movup.2 exec.account_id::shape_suffix swap # => [hashed_account_id_prefix, hashed_account_id_suffix, account_id_prefix, account_id_suffix] # assert the account ID matches the account ID of the new account - exec.account_utils::is_id_eq assert.err=ERR_ACCOUNT_SEED_ANCHOR_BLOCK_HASH_DIGEST_MISMATCH + exec.account_id::is_id_eq assert.err=ERR_ACCOUNT_SEED_ANCHOR_BLOCK_HASH_DIGEST_MISMATCH # => [] end @@ -636,7 +635,7 @@ export.save_account_storage_data # AS => [[STORAGE_SLOT_DATA]] # assert that account does not exceed allowed maximum number of storage slots - dup exec.account_utils::get_max_num_storage_slots lte assert.err=ERR_ACCOUNT_TOO_MANY_STORAGE_SLOTS + dup exec.account_id::get_max_num_storage_slots lte assert.err=ERR_ACCOUNT_TOO_MANY_STORAGE_SLOTS # OS => [num_storage_slots, STORAGE_COMMITMENT] # AS => [[STORAGE_SLOT_DATA]] @@ -705,7 +704,7 @@ export.save_account_procedure_data # AS => [[ACCOUNT_PROCEDURE_DATA]] # assert that account does not exceed allowed maximum number of procedures - dup exec.account_utils::get_max_num_procedures lte assert.err=ERR_ACCOUNT_TOO_MANY_PROCEDURES + dup exec.account_id::get_max_num_procedures lte assert.err=ERR_ACCOUNT_TOO_MANY_PROCEDURES # OS => [num_procs, CODE_COMMITMENT] # AS => [[ACCOUNT_PROCEDURE_DATA]] @@ -820,7 +819,7 @@ export.get_foreign_account_ptr # => [foreign_account_id_prefix, foreign_account_id_suffix] # check that foreign account ID is not equal to the native account ID - dup.1 dup.1 exec.memory::get_native_account_id exec.account_utils::is_id_eq not + dup.1 dup.1 exec.memory::get_native_account_id exec.account_id::is_id_eq not assert.err=ERR_FOREIGN_ACCOUNT_ID_EQUALS_NATIVE_ACCT_ID # get the initial account data pointer @@ -850,7 +849,7 @@ export.get_foreign_account_ptr # => [is_empty_block, maybe_account_id_prefix, maybe_account_id_suffix, curr_account_ptr', foreign_account_id_prefix, foreign_account_id_suffix] # check whether the current id matches the foreign id - movdn.2 dup.5 dup.5 exec.account_utils::is_id_eq + movdn.2 dup.5 dup.5 exec.account_id::is_id_eq # => [is_equal_id, is_empty_word, curr_account_ptr', foreign_account_id_prefix, foreign_account_id_suffix] # get the loop flag diff --git a/miden-lib/asm/kernels/transaction/lib/asset.masm b/miden-lib/asm/kernels/transaction/lib/asset.masm index 35d5a720f..d683080a0 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset.masm @@ -1,5 +1,4 @@ -use.kernel::account -use.utils::account_utils +use.kernel::util::account_id # ERRORS # ================================================================================================= @@ -34,7 +33,7 @@ const.ERR_NON_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN=0x00020027 #! Outputs: [fungible_asset_max_amount] #! #! fungible_asset_max_amount is the maximum amount of a fungible asset. -export.::utils::asset_utils::get_fungible_asset_max_amount +export.::kernel::util::asset::get_fungible_asset_max_amount #! Validates that a fungible asset is well formed. #! @@ -52,11 +51,11 @@ export.validate_fungible_asset # => [ASSET] # assert that the tuple (ASSET[3], ASSET[2]) forms a valid account ID - dup.1 dup.1 exec.account_utils::validate_id + dup.1 dup.1 exec.account_id::validate_id # => [ASSET] # assert that the prefix (ASSET[3]) of the account ID is of type fungible faucet - dup exec.account_utils::is_fungible_faucet + dup exec.account_id::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_FORMAT_ELEMENT_TWO_AND_THREE_MUST_BE_FUNGIBLE_FAUCET_ID # => [ASSET] @@ -74,7 +73,7 @@ end #! Where: #! - ASSET is the asset to check. #! - is_fungible_asset is a boolean indicating whether the asset is fungible. -export.::utils::asset_utils::is_fungible_asset +export.::kernel::util::asset::is_fungible_asset #! Validates that a non fungible asset is well formed. #! @@ -89,11 +88,11 @@ export.::utils::asset_utils::is_fungible_asset export.validate_non_fungible_asset # assert that ASSET[3] is a valid account ID prefix # hack: because we only have the prefix we add a 0 as the suffix which is always valid - push.0 dup.1 exec.account_utils::validate_id + push.0 dup.1 exec.account_id::validate_id # => [ASSET] # assert that the account ID prefix ASSET[3] is of type non fungible faucet - dup exec.account_utils::is_non_fungible_faucet + dup exec.account_id::is_non_fungible_faucet assert.err=ERR_NON_FUNGIBLE_ASSET_FORMAT_ELEMENT_THREE_MUST_BE_FUNGIBLE_FAUCET_ID # => [ASSET] end @@ -106,7 +105,7 @@ end #! Where: #! - ASSET is the asset to check. #! - is_non_fungible_asset is a boolean indicating whether the asset is non-fungible. -export.::utils::asset_utils::is_non_fungible_asset +export.::kernel::util::asset::is_non_fungible_asset #! Validates that an asset is well formed. #! @@ -146,7 +145,7 @@ export.validate_fungible_asset_origin dup.3 dup.3 # => [asset_id_prefix, asset_id_suffix, faucet_id_prefix, faucet_id_suffix, ASSET] - exec.account_utils::is_id_eq assert.err=ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN + exec.account_id::is_id_eq assert.err=ERR_FUNGIBLE_ASSET_FAUCET_IS_NOT_ORIGIN # => [ASSET] # assert the fungible asset is valid diff --git a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm index 39a3f5b93..4d298f2e4 100644 --- a/miden-lib/asm/kernels/transaction/lib/asset_vault.masm +++ b/miden-lib/asm/kernels/transaction/lib/asset_vault.masm @@ -1,8 +1,6 @@ use.std::collections::smt -use.utils::account_utils - -use.kernel::account +use.kernel::util::account_id use.kernel::asset use.kernel::memory @@ -56,7 +54,7 @@ const.INVERSE_FUNGIBLE_BITMASK_U32=0xffffffdf # last byte: 0b1101_1111 #! - the asset is not a fungible asset. export.get_balance # assert that the faucet id is a fungible faucet - dup exec.account_utils::is_fungible_faucet + dup exec.account_id::is_fungible_faucet assert.err=ERR_VAULT_GET_BALANCE_PROC_CAN_ONLY_BE_CALLED_ON_FUNGIBLE_FAUCET # => [faucet_id_prefix, faucet_id_suffix, vault_root_ptr] diff --git a/miden-lib/asm/kernels/transaction/lib/constants.masm b/miden-lib/asm/kernels/transaction/lib/constants.masm index 8ba83288e..e00f1a2a8 100644 --- a/miden-lib/asm/kernels/transaction/lib/constants.masm +++ b/miden-lib/asm/kernels/transaction/lib/constants.masm @@ -47,7 +47,7 @@ end #! Output: [max_inputs_per_note] #! #! - max_inputs_per_note is the max inputs per note. -export.::utils::note_utils::get_max_inputs_per_note +export.::kernel::util::note::get_max_inputs_per_note #! Returns the max allowed number of assets per note. #! diff --git a/miden-lib/asm/kernels/transaction/lib/faucet.masm b/miden-lib/asm/kernels/transaction/lib/faucet.masm index 0ecd3577b..9d76334ae 100644 --- a/miden-lib/asm/kernels/transaction/lib/faucet.masm +++ b/miden-lib/asm/kernels/transaction/lib/faucet.masm @@ -1,7 +1,6 @@ use.std::collections::smt -use.utils::account_utils - +use.kernel::util::account_id use.kernel::account use.kernel::asset use.kernel::asset_vault @@ -51,7 +50,7 @@ export.mint_fungible_asset # => [ASSET] # get the current total issuance - exec.account_utils::get_faucet_storage_data_slot exec.account::get_item + exec.account_id::get_faucet_storage_data_slot exec.account::get_item # => [TOTAL_ISSUANCE, ASSET] # prepare stack to ensure that minting the asset will not exceed the maximum @@ -63,7 +62,7 @@ export.mint_fungible_asset # => [amount, TOTAL_ISSUANCE, ASSET] # update the total issuance - add exec.account_utils::get_faucet_storage_data_slot exec.account::set_item dropw + add exec.account_id::get_faucet_storage_data_slot exec.account::set_item dropw # => [ASSET] # add the asset to the input vault for asset preservation checks @@ -93,7 +92,7 @@ proc.burn_fungible_asset # => [ASSET] # fetch TOTAL_ISSUANCE such that we can compute the new total issuance - exec.account_utils::get_faucet_storage_data_slot exec.account::get_item + exec.account_id::get_faucet_storage_data_slot exec.account::get_item # => [TOTAL_ISSUANCE, ASSET] # assert that the asset amount being burned is less or equal to the total issuance @@ -101,7 +100,7 @@ proc.burn_fungible_asset # => [amount, TOTAL_ISSUANCE, ASSET] # compute new total issuance - sub exec.account_utils::get_faucet_storage_data_slot exec.account::set_item dropw + sub exec.account_id::get_faucet_storage_data_slot exec.account::set_item dropw # => [ASSET] # remove the asset from the input vault @@ -119,7 +118,7 @@ end #! against. export.get_total_issuance # fetch the TOTAL_ISSUANCE from storage - exec.account_utils::get_faucet_storage_data_slot exec.account::get_item + exec.account_id::get_faucet_storage_data_slot exec.account::get_item # => [TOTAL_ISSUANCE] # extract the total_issuance and purge the padding @@ -152,7 +151,7 @@ proc.mint_non_fungible_asset # => [ASSET] # fetch the root of the SMT containing the non-fungible assets - dupw exec.account_utils::get_faucet_storage_data_slot exec.account::get_item + dupw exec.account_id::get_faucet_storage_data_slot exec.account::get_item # => [SMT_ROOT, ASSET, ASSET] # prepare stack for insert of non-fungible asset into tracking SMT @@ -169,7 +168,7 @@ proc.mint_non_fungible_asset # => [SMT_ROOT', ASSET] # update the root of the SMT containing the non-fungible assets - exec.account_utils::get_faucet_storage_data_slot exec.account::set_item dropw + exec.account_id::get_faucet_storage_data_slot exec.account::set_item dropw # => [ASSET] # add the non-fungible asset to the input vault for asset preservation checks @@ -194,7 +193,7 @@ end #! transaction via a note or the accounts vault. proc.burn_non_fungible_asset # assert that we are executing a transaction against the non-fungible faucet (access checks) - exec.account::get_id exec.account_utils::is_non_fungible_faucet + exec.account::get_id exec.account_id::is_non_fungible_faucet assert.err=ERR_FAUCET_BURN_NON_FUNGIBLE_ASSET_CAN_ONLY_BE_CALLED_ON_NON_FUNGIBLE_FAUCET # => [ASSET] @@ -203,7 +202,7 @@ proc.burn_non_fungible_asset # => [ASSET, ASSET] # fetch the root of the SMT containing the non-fungible assets - exec.account_utils::get_faucet_storage_data_slot exec.account::get_item + exec.account_id::get_faucet_storage_data_slot exec.account::get_item # => [SMT_ROOT, ASSET, ASSET] # prepare stack for removal of non-fungible asset from tracking SMT @@ -220,7 +219,7 @@ proc.burn_non_fungible_asset # => [SMT_ROOT', ASSET] # update the root of the SMT containing the non-fungible assets - exec.account_utils::get_faucet_storage_data_slot exec.account::set_item dropw + exec.account_id::get_faucet_storage_data_slot exec.account::set_item dropw # => [ASSET] # remove the non-fungible asset from the input vault for asset preservation checks diff --git a/miden-lib/asm/kernels/transaction/lib/memory.masm b/miden-lib/asm/kernels/transaction/lib/memory.masm index e7804eb40..8729fe848 100644 --- a/miden-lib/asm/kernels/transaction/lib/memory.masm +++ b/miden-lib/asm/kernels/transaction/lib/memory.masm @@ -1,4 +1,3 @@ -use.kernel::account use.kernel::constants # ERRORS diff --git a/miden-lib/asm/kernels/transaction/lib/prologue.masm b/miden-lib/asm/kernels/transaction/lib/prologue.masm index 297f49971..8f5f6dfaa 100644 --- a/miden-lib/asm/kernels/transaction/lib/prologue.masm +++ b/miden-lib/asm/kernels/transaction/lib/prologue.masm @@ -2,8 +2,7 @@ use.std::mem use.std::collections::mmr use.std::crypto::hashes::rpo -use.utils::account_utils - +use.kernel::util::account_id use.kernel::account use.kernel::asset_vault use.kernel::constants @@ -319,7 +318,7 @@ end #! Outputs: [] proc.validate_new_account # Assert the account ID of the account is valid - exec.memory::get_account_id exec.account_utils::validate_id + exec.memory::get_account_id exec.account_id::validate_id # => [] # Assert the account nonce is 0 @@ -342,17 +341,17 @@ proc.validate_new_account # Assert faucet reserved slot is correctly initialized # --------------------------------------------------------------------------------------------- # check if the account is a faucet - exec.account::get_id swap drop dup exec.account_utils::is_faucet + exec.account::get_id swap drop dup exec.account_id::is_faucet # => [is_faucet, acct_id_prefix] # process conditional logic depending on whether the account is a faucet if.true # get the faucet reserved slot - exec.account_utils::get_faucet_storage_data_slot exec.account::get_item + exec.account_id::get_faucet_storage_data_slot exec.account::get_item # => [FAUCET_RESERVED_SLOT, acct_id_prefix] # check if the account is a fungible faucet - movup.4 exec.account_utils::is_fungible_faucet + movup.4 exec.account_id::is_fungible_faucet # => [is_fungible_faucet, FAUCET_RESERVED_SLOT] if.true @@ -363,7 +362,7 @@ proc.validate_new_account # => [] # get the faucet reserved storage data slot type - exec.account_utils::get_faucet_storage_data_slot exec.account::get_storage_slot_type + exec.account_id::get_faucet_storage_data_slot exec.account::get_storage_slot_type # => [slot_type] # assert the fungible faucet reserved slot type == value @@ -379,7 +378,7 @@ proc.validate_new_account push.1001 drop # TODO: remove line, see miden-vm/#1122 # get the faucet reserved storage data slot type - exec.account_utils::get_faucet_storage_data_slot exec.account::get_storage_slot_type + exec.account_id::get_faucet_storage_data_slot exec.account::get_storage_slot_type # => [slot_type] # assert the non-fungible faucet reserved slot type == map @@ -471,7 +470,7 @@ proc.process_account_data # assert the account ID matches the account ID in global inputs exec.memory::get_global_acct_id exec.memory::get_account_id - exec.account_utils::is_id_eq assert.err=ERR_PROLOGUE_MISMATCH_OF_ACCOUNT_IDS_FROM_GLOBAL_INPUTS_AND_ADVICE_PROVIDER + exec.account_id::is_id_eq assert.err=ERR_PROLOGUE_MISMATCH_OF_ACCOUNT_IDS_FROM_GLOBAL_INPUTS_AND_ADVICE_PROVIDER # => [ACCT_HASH] # store a copy of the initial nonce in global inputs diff --git a/miden-lib/asm/miden/account.masm b/miden-lib/asm/miden/account.masm index 63cbe7bea..82f948acb 100644 --- a/miden-lib/asm/miden/account.masm +++ b/miden-lib/asm/miden/account.masm @@ -11,7 +11,7 @@ use.miden::kernel_proc_offsets #! Where: #! - acct_id_prefix is the prefix of the account ID. #! - is_fungible_faucet is a boolean indicating whether the account is a fungible faucet. -export.::utils::account_utils::is_fungible_faucet +export.::miden::util::account_id::is_fungible_faucet #! Returns a boolean indicating whether the account is a non-fungible faucet. #! @@ -21,7 +21,7 @@ export.::utils::account_utils::is_fungible_faucet #! Where: #! - acct_id_prefix is the prefix of the account ID. #! - is_non_fungible_faucet is a boolean indicating whether the account is a non-fungible faucet. -export.::utils::account_utils::is_non_fungible_faucet +export.::miden::util::account_id::is_non_fungible_faucet #! Returns a boolean indicating whether the given account_ids are equal. #! @@ -32,7 +32,7 @@ export.::utils::account_utils::is_non_fungible_faucet #! - acct_id_{prefix,suffix} are the prefix and suffix felts of an account ID. #! - other_acct_id_{prefix,suffix} are the prefix and suffix felts of the other account ID to compare against. #! - is_id_equal is a boolean indicating whether the account IDs are equal. -export.::utils::account_utils::is_id_eq +export.::miden::util::account_id::is_id_eq #! Returns the account id. #! diff --git a/miden-lib/asm/miden/asset.masm b/miden-lib/asm/miden/asset.masm index 346a85004..164e51f74 100644 --- a/miden-lib/asm/miden/asset.masm +++ b/miden-lib/asm/miden/asset.masm @@ -1,3 +1,4 @@ +use.miden::util::account_id use.miden::account # ERRORS @@ -21,7 +22,7 @@ const.ERR_NON_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID=0x0002004D #! Outputs: [fungible_asset_max_amount] #! #! fungible_asset_max_amount is the maximum amount of a fungible asset. -export.::utils::asset_utils::get_fungible_asset_max_amount +export.::miden::util::asset::get_fungible_asset_max_amount #! Builds a fungible asset for the specified fungible faucet and amount. #! @@ -36,7 +37,7 @@ export.::utils::asset_utils::get_fungible_asset_max_amount #! Annotation hint: is not used anywhere except this file export.build_fungible_asset # assert the faucet is a fungible faucet - dup exec.account::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID + dup exec.account_id::is_fungible_faucet assert.err=ERR_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID # => [faucet_id_prefix, faucet_id_suffix, amount] # assert the amount is valid @@ -82,7 +83,7 @@ end #! Annotation hint: is not used anywhere except this file export.build_non_fungible_asset # assert the faucet is a non-fungible faucet - dup exec.account::is_non_fungible_faucet + dup exec.account_id::is_non_fungible_faucet assert.err=ERR_NON_FUNGIBLE_ASSET_PROVIDED_FAUCET_ID_IS_INVALID # => [faucet_id_prefix, hash3, hash2, hash1, hash0] diff --git a/miden-lib/asm/miden/note.masm b/miden-lib/asm/miden/note.masm index 9d796f23f..65b2a3f12 100644 --- a/miden-lib/asm/miden/note.masm +++ b/miden-lib/asm/miden/note.masm @@ -21,7 +21,7 @@ const.ERR_PROLOGUE_NUMBER_OF_NOTE_INPUTS_EXCEEDED_LIMIT=0x0002004F #! Output: [max_inputs_per_note] #! #! - max_inputs_per_note is the max inputs per note. -export.::utils::note_utils::get_max_inputs_per_note +export.::miden::util::note::get_max_inputs_per_note #! Writes the data currently on the advice stack into the memory at the specified location and #! verifies that the hash of the written data is equal to the provided hash. diff --git a/miden-lib/asm/utils/account_utils.masm b/miden-lib/asm/shared/util/account_id.masm similarity index 99% rename from miden-lib/asm/utils/account_utils.masm rename to miden-lib/asm/shared/util/account_id.masm index 9b7b66467..1cf961e87 100644 --- a/miden-lib/asm/utils/account_utils.masm +++ b/miden-lib/asm/shared/util/account_id.masm @@ -45,7 +45,7 @@ const.REGULAR_ACCOUNT_IMMUTABLE_CODE=0 # 0b00_0000 # Bit pattern for a fungible faucet w/ immutable code, after the account type mask has been applied. const.FUNGIBLE_FAUCET_ACCOUNT=0x20 # 0b10_0000 -# Bit pattern for a non-fungible faucet w/ immutable code, after the account type mask has been +# Bit pattern for a non-fungible faucet w/ immutable code, after the account type mask has been # applied. const.NON_FUNGIBLE_FAUCET_ACCOUNT=0x30 # 0b11_0000 @@ -384,4 +384,4 @@ end proc.type u32split drop push.ACCOUNT_ID_TYPE_MASK_U32 u32and # => [acct_type] -end \ No newline at end of file +end diff --git a/miden-lib/asm/utils/asset_utils.masm b/miden-lib/asm/shared/util/asset.masm similarity index 98% rename from miden-lib/asm/utils/asset_utils.masm rename to miden-lib/asm/shared/util/asset.masm index 7218582f3..7ff213c74 100644 --- a/miden-lib/asm/utils/asset_utils.masm +++ b/miden-lib/asm/shared/util/asset.masm @@ -1,5 +1,3 @@ -use.utils::account_utils - # CONSTANTS # ================================================================================================= diff --git a/miden-lib/asm/utils/note_utils.masm b/miden-lib/asm/shared/util/note.masm similarity index 100% rename from miden-lib/asm/utils/note_utils.masm rename to miden-lib/asm/shared/util/note.masm diff --git a/miden-lib/build.rs b/miden-lib/build.rs index 7fa4168e8..3239008d9 100644 --- a/miden-lib/build.rs +++ b/miden-lib/build.rs @@ -27,7 +27,7 @@ const ASM_DIR: &str = "asm"; const ASM_MIDEN_DIR: &str = "miden"; const ASM_NOTE_SCRIPTS_DIR: &str = "note_scripts"; const ASM_ACCOUNT_COMPONENTS_DIR: &str = "account_components"; -const UTILS_DIR: &str = "utils"; +const SHARED_DIR: &str = "shared"; const ASM_TX_KERNEL_DIR: &str = "kernels/transaction"; const KERNEL_V0_RS_FILE: &str = "src/transaction/procedures/kernel_v0.rs"; const KERNEL_ERRORS_FILE: &str = "src/errors/tx_kernel_errors.rs"; @@ -102,12 +102,12 @@ fn main() -> Result<()> { /// - {target_dir}/tx_kernel.masb -> contains the executable compiled from main.masm. /// - src/transaction/procedures/kernel_v0.rs -> contains the kernel procedures table. fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result { - let utils_namespace = LibraryNamespace::new("utils").expect("invalid namespace"); - let utils_path = Path::new(ASM_DIR).join(UTILS_DIR); + let shared_path = Path::new(ASM_DIR).join(SHARED_DIR); + let kernel_namespace = LibraryNamespace::new("kernel").expect("namespace should be valid"); - // add the utils module to the kernel lib by providing it to the assembler let mut assembler = build_assembler(None)?; - assembler.add_modules_from_dir(utils_namespace.clone(), &utils_path)?; + // add the shared modules to the kernel lib under the kernel::util namespace + assembler.add_modules_from_dir(kernel_namespace.clone(), &shared_path)?; // assemble the kernel library and write it to the "tx_kernel.masl" file let kernel_lib = KernelLibrary::from_dir( @@ -122,13 +122,13 @@ fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result let output_file = target_dir.join("tx_kernel").with_extension(Library::LIBRARY_EXTENSION); kernel_lib.write_to_file(output_file).into_diagnostic()?; - let mut assembler = build_assembler(Some(kernel_lib))?; - assembler.add_modules_from_dir(utils_namespace, &utils_path)?; + let assembler = build_assembler(Some(kernel_lib))?; // assemble the kernel program and write it the "tx_kernel.masb" file let mut main_assembler = assembler.clone(); - let namespace = LibraryNamespace::new("kernel").expect("invalid namespace"); - main_assembler.add_modules_from_dir(namespace, &source_dir.join("lib"))?; + main_assembler.add_modules_from_dir(kernel_namespace.clone(), &source_dir.join("lib"))?; + // add the shared modules to the kernel lib under the kernel::util namespace + main_assembler.add_modules_from_dir(kernel_namespace, &shared_path)?; let main_file_path = source_dir.join("main.masm").clone(); let kernel_main = main_assembler.assemble_program(main_file_path)?; @@ -138,12 +138,19 @@ fn compile_tx_kernel(source_dir: &Path, target_dir: &Path) -> Result #[cfg(any(feature = "testing", test))] { + let mut kernel_lib_assembler = assembler.clone(); // Build kernel as a library and save it to file. // This is needed in test assemblers to access individual procedures which would otherwise // be hidden when using KernelLibrary (api.masm) - let namespace = "kernel".parse::().expect("invalid base namespace"); + let kernel_namespace = + "kernel".parse::().expect("invalid base namespace"); + + // add the shared modules to the kernel lib under the kernel::util namespace + kernel_lib_assembler.add_modules_from_dir(kernel_namespace.clone(), &shared_path)?; + let test_lib = - Library::from_dir(source_dir.join("lib"), namespace, assembler.clone()).unwrap(); + Library::from_dir(source_dir.join("lib"), kernel_namespace, kernel_lib_assembler) + .unwrap(); let masb_file_path = target_dir.join("kernel_library").with_extension(Library::LIBRARY_EXTENSION); @@ -232,12 +239,16 @@ fn parse_proc_offsets(filename: impl AsRef) -> Result Result { let source_dir = source_dir.join(ASM_MIDEN_DIR); + let shared_path = Path::new(ASM_DIR).join(SHARED_DIR); + + let miden_namespace = "miden".parse::().expect("invalid base namespace"); + // add the shared modules to the kernel lib under the miden::util namespace + assembler.add_modules_from_dir(miden_namespace.clone(), &shared_path)?; - let namespace = "miden".parse::().expect("invalid base namespace"); - let miden_lib = Library::from_dir(source_dir, namespace, assembler)?; + let miden_lib = Library::from_dir(source_dir, miden_namespace, assembler)?; let output_file = target_dir.join("miden").with_extension(Library::LIBRARY_EXTENSION); miden_lib.write_to_file(output_file).into_diagnostic()?;