From bd75f2888dee1fa1059b69b03d98b22d49983465 Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 23 Mar 2026 12:24:15 -0300 Subject: [PATCH 1/7] chore: rename from PSM to Guardian --- CHANGELOG.md | 1 + ...ltisig_psm.masm => multisig_guardian.masm} | 14 +- .../asm/standards/auth/guardian.masm | 157 ++++++++++ .../asm/standards/auth/multisig.masm | 2 +- .../asm/standards/auth/psm.masm | 158 ---------- .../miden-standards/src/account/auth/mod.rs | 4 +- .../src/account/auth/multisig.rs | 19 +- .../{multisig_psm.rs => multisig_guardian.rs} | 278 ++++++++++-------- .../src/account/components/mod.rs | 24 +- .../src/account/interface/component.rs | 18 +- .../src/account/interface/extension.rs | 20 +- crates/miden-testing/src/mock_chain/auth.rs | 37 ++- crates/miden-testing/tests/auth/mod.rs | 2 +- .../{multisig_psm.rs => multisig_guardian.rs} | 216 +++++++------- 14 files changed, 484 insertions(+), 466 deletions(-) rename crates/miden-standards/asm/account_components/auth/{multisig_psm.masm => multisig_guardian.masm} (70%) create mode 100644 crates/miden-standards/asm/standards/auth/guardian.masm delete mode 100644 crates/miden-standards/asm/standards/auth/psm.masm rename crates/miden-standards/src/account/auth/{multisig_psm.rs => multisig_guardian.rs} (64%) rename crates/miden-testing/tests/auth/{multisig_psm.rs => multisig_guardian.rs} (67%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60259dc228..3c421a7dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ ### Changes +- [BREAKING] Renamed the multisig PSM auth component, procedures, storage paths, and related APIs from `psm` to `guardian`. - [BREAKING] Renamed `AccountComponent::get_procedures()` to `procedures()`, returning `impl Iterator` ([#2597](https://github.com/0xMiden/protocol/pull/2597)). - [BREAKING] Removed `NoteAssets::add_asset`; `OutputNoteBuilder` now accumulates assets in a `Vec` and computes the commitment only when `build()` is called, avoiding rehashing on every asset addition. ([#2577](https://github.com/0xMiden/protocol/pull/2577)) - [BREAKING] Made `supported_types` a required parameter of `AccountComponentMetadata::new()`; removed `with_supported_type`, `with_supported_types`, `with_supports_all_types`, and `with_supports_regular_types` builder methods; added `AccountType::all()` and `AccountType::regular()` helpers ([#2554](https://github.com/0xMiden/protocol/pull/2554)). diff --git a/crates/miden-standards/asm/account_components/auth/multisig_psm.masm b/crates/miden-standards/asm/account_components/auth/multisig_guardian.masm similarity index 70% rename from crates/miden-standards/asm/account_components/auth/multisig_psm.masm rename to crates/miden-standards/asm/account_components/auth/multisig_guardian.masm index 591ba376ab..6b7e3231c3 100644 --- a/crates/miden-standards/asm/account_components/auth/multisig_psm.masm +++ b/crates/miden-standards/asm/account_components/auth/multisig_guardian.masm @@ -1,9 +1,9 @@ -# The MASM code of the Multi-Signature Authentication Component with Private State Manager. +# The MASM code of the Multi-Signature Authentication Component with Guardian. # -# See the `AuthMultisigPsm` Rust type's documentation for more details. +# See the `AuthMultisigGuardian` Rust type's documentation for more details. use miden::standards::auth::multisig -use miden::standards::auth::psm +use miden::standards::auth::guardian pub use multisig::update_signers_and_threshold pub use multisig::get_threshold_and_num_approvers @@ -11,9 +11,9 @@ pub use multisig::set_procedure_threshold pub use multisig::get_signer_at pub use multisig::is_signer -pub use psm::update_psm_public_key +pub use guardian::update_guardian_public_key -#! Authenticate a transaction with multi-signature support and optional PSM verification. +#! Authenticate a transaction with multi-signature support and optional guardian verification. #! #! Inputs: #! Operand stack: [SALT] @@ -22,14 +22,14 @@ pub use psm::update_psm_public_key #! #! Invocation: call @auth_script -pub proc auth_tx_multisig_psm(salt: word) +pub proc auth_tx_multisig_guardian(salt: word) exec.multisig::auth_tx # => [TX_SUMMARY_COMMITMENT] dupw # => [TX_SUMMARY_COMMITMENT, TX_SUMMARY_COMMITMENT] - exec.psm::verify_signature + exec.guardian::verify_signature # => [TX_SUMMARY_COMMITMENT] exec.multisig::assert_new_tx diff --git a/crates/miden-standards/asm/standards/auth/guardian.masm b/crates/miden-standards/asm/standards/auth/guardian.masm new file mode 100644 index 0000000000..7b3bee2f1b --- /dev/null +++ b/crates/miden-standards/asm/standards/auth/guardian.masm @@ -0,0 +1,157 @@ +# Guardian account component. +# This component is composed into account auth flows especially for multisig and adds +# an extra signature check by a dedicated guardian signer. +# +# A guardian can help coordinate state availability for private accounts. + +use miden::protocol::auth::AUTH_UNAUTHORIZED_EVENT +use miden::protocol::native_account +use miden::standards::auth::tx_policy +use miden::standards::auth::signature + +# IMPORTANT SECURITY NOTES +# -------------------------------------------------------------------------------- +# - By default, exactly one valid guardian signature is required. +# - If `update_guardian_public_key` is the only non-auth account procedure called in the current +# transaction, `verify_signature` skips the guardian signature check so key rotation can proceed +# without the old guardian signer. +# - `update_guardian_public_key` rotates the guardian public key and corresponding scheme id using the fixed +# map key `GUARDIAN_MAP_KEY`. + + +# CONSTANTS +# ================================================================================================= + +# Storage Slots +# +# This authentication component uses named storage slots. +# - GUARDIAN_PUBLIC_KEYS_SLOT (map): +# GUARDIAN_MAP_KEY => GUARDIAN_PUBLIC_KEY +# where: GUARDIAN_MAP_KEY = [0, 0, 0, 0] +# +# - GUARDIAN_SCHEME_ID_SLOT (map): +# GUARDIAN_MAP_KEY => [scheme_id, 0, 0, 0] +# where: GUARDIAN_MAP_KEY = [0, 0, 0, 0] + +# The slot in this component's storage layout where the guardian public key map is stored. +# Map entries: [GUARDIAN_MAP_KEY] => [GUARDIAN_PUBLIC_KEY] +const GUARDIAN_PUBLIC_KEYS_SLOT = word("miden::standards::auth::guardian::pub_key") + +# The slot in this component's storage layout where the scheme id for the corresponding guardian public key map is stored. +# Map entries: [GUARDIAN_MAP_KEY] => [scheme_id, 0, 0, 0] +const GUARDIAN_SCHEME_ID_SLOT = word("miden::standards::auth::guardian::scheme") + +# Single-entry storage map key where guardian signer data is stored. +const GUARDIAN_MAP_KEY = [0, 0, 0, 0] + +# ERRORS +# ------------------------------------------------------------------------------------------------- +const ERR_INVALID_GUARDIAN_SIGNATURE = "invalid guardian signature" + +# PUBLIC INTERFACE +# ================================================================================================ + +#! Updates the guardian public key. +#! +#! Inputs: [new_guardian_scheme_id, NEW_GUARDIAN_PUBLIC_KEY] +#! Outputs: [] +#! +#! Notes: +#! - This procedure only updates the guardian public key and corresponding scheme id. +#! - `verify_signature` skips guardian verification only when this is the only non-auth account +#! procedure called in the transaction. +#! +#! Invocation: call +@locals(1) +pub proc update_guardian_public_key(new_guardian_scheme_id: felt, new_guardian_public_key: word) + # Validate supported signature scheme before committing it to storage. + dup exec.signature::assert_supported_scheme + # => [new_guardian_scheme_id, NEW_GUARDIAN_PUBLIC_KEY] + + loc_store.0 + # => [NEW_GUARDIAN_PUBLIC_KEY] + + push.GUARDIAN_MAP_KEY + # => [GUARDIAN_MAP_KEY, NEW_GUARDIAN_PUBLIC_KEY] + + push.GUARDIAN_PUBLIC_KEYS_SLOT[0..2] + # => [guardian_pubkeys_slot_prefix, guardian_pubkeys_slot_suffix, GUARDIAN_MAP_KEY, NEW_GUARDIAN_PUBLIC_KEY] + + exec.native_account::set_map_item + # => [OLD_GUARDIAN_PUBLIC_KEY] + + dropw + # => [] + + # Store new scheme id as [scheme_id, 0, 0, 0] in the single-entry map. + loc_load.0 + # => [scheme_id] + + push.0.0.0 movup.3 + # => [NEW_GUARDIAN_SCHEME_ID_WORD] + + push.GUARDIAN_MAP_KEY + # => [GUARDIAN_MAP_KEY, NEW_GUARDIAN_SCHEME_ID_WORD] + + push.GUARDIAN_SCHEME_ID_SLOT[0..2] + # => [guardian_scheme_slot_prefix, guardian_scheme_slot_suffix, GUARDIAN_MAP_KEY, NEW_GUARDIAN_SCHEME_ID_WORD] + + exec.native_account::set_map_item + # => [OLD_GUARDIAN_SCHEME_ID_WORD] + + dropw + # => [] +end + +#! Conditionally verifies a guardian signature. +#! +#! Inputs: [MSG] +#! Outputs: [] +#! +#! Panics if: +#! - `update_guardian_public_key` is called together with another non-auth account procedure. +#! - `update_guardian_public_key` was not called and a valid guardian signature is missing or invalid. +#! +#! Invocation: exec +pub proc verify_signature(msg: word) + procref.update_guardian_public_key + # => [UPDATE_GUARDIAN_PUBLIC_KEY_ROOT, MSG] + + exec.native_account::was_procedure_called + # => [was_update_guardian_public_key_called, MSG] + + if.true + exec.tx_policy::assert_only_one_non_auth_procedure_called + # => [MSG] + + exec.tx_policy::assert_no_input_or_output_notes + # => [MSG] + + dropw + # => [] + else + push.1 + # => [1, MSG] + + push.GUARDIAN_PUBLIC_KEYS_SLOT[0..2] + # => [guardian_pubkeys_slot_prefix, guardian_pubkeys_slot_suffix, 1, MSG] + + push.GUARDIAN_SCHEME_ID_SLOT[0..2] + # => [guardian_scheme_slot_prefix, guardian_scheme_slot_suffix, guardian_pubkeys_slot_prefix, guardian_pubkeys_slot_suffix, 1, MSG] + + exec.signature::verify_signatures + # => [num_verified_signatures, MSG] + + neq.1 + # => [is_not_exactly_one, MSG] + + if.true + emit.AUTH_UNAUTHORIZED_EVENT + push.0 assert.err=ERR_INVALID_GUARDIAN_SIGNATURE + end + # => [MSG] + + dropw + # => [] + end +end diff --git a/crates/miden-standards/asm/standards/auth/multisig.masm b/crates/miden-standards/asm/standards/auth/multisig.masm index ed20ff2325..b8d43b4dc5 100644 --- a/crates/miden-standards/asm/standards/auth/multisig.masm +++ b/crates/miden-standards/asm/standards/auth/multisig.masm @@ -727,6 +727,6 @@ pub proc auth_tx(salt: word) end # TX_SUMMARY_COMMITMENT is returned so wrappers can run optional checks - # (e.g. PSM) before replay-protection finalization. + # (e.g. guardian verification) before replay-protection finalization. # => [TX_SUMMARY_COMMITMENT] end diff --git a/crates/miden-standards/asm/standards/auth/psm.masm b/crates/miden-standards/asm/standards/auth/psm.masm deleted file mode 100644 index d778cafb14..0000000000 --- a/crates/miden-standards/asm/standards/auth/psm.masm +++ /dev/null @@ -1,158 +0,0 @@ -# Private State Manager (PSM) account component. -# This component is composed into account auth flows especially for multisig and adds -# an extra signature check by a dedicated private state manager signer. -# -# Private State Manager (PSM) is a cloud backup and synchronization layer for Miden private accounts -# See: https://github.com/OpenZeppelin/private-state-manager - -use miden::protocol::auth::AUTH_UNAUTHORIZED_EVENT -use miden::protocol::native_account -use miden::standards::auth::tx_policy -use miden::standards::auth::signature - -# IMPORTANT SECURITY NOTES -# -------------------------------------------------------------------------------- -# - By default, exactly one valid PSM signature is required. -# - If `update_psm_public_key` is the only non-auth account procedure called in the current -# transaction, `verify_signature` skips the PSM signature check so key rotation can proceed -# without the old PSM signer. -# - `update_psm_public_key` rotates the PSM public key and corresponding scheme id using the fixed -# map key `PSM_MAP_KEY`. - - -# CONSTANTS -# ================================================================================================= - -# Storage Slots -# -# This authentication component uses named storage slots. -# - PSM_PUBLIC_KEYS_SLOT (map): -# PSM_MAP_KEY => PSM_PUBLIC_KEY -# where: PSM_MAP_KEY = [0, 0, 0, 0] -# -# - PSM_SCHEME_ID_SLOT (map): -# PSM_MAP_KEY => [scheme_id, 0, 0, 0] -# where: PSM_MAP_KEY = [0, 0, 0, 0] - -# The slot in this component's storage layout where the PSM public key map is stored. -# Map entries: [PSM_MAP_KEY] => [PSM_PUBLIC_KEY] -const PSM_PUBLIC_KEYS_SLOT = word("miden::standards::auth::psm::pub_key") - -# The slot in this component's storage layout where the scheme id for the corresponding PSM public key map is stored. -# Map entries: [PSM_MAP_KEY] => [scheme_id, 0, 0, 0] -const PSM_SCHEME_ID_SLOT = word("miden::standards::auth::psm::scheme") - -# Single-entry storage map key where private state manager signer data is stored. -const PSM_MAP_KEY = [0, 0, 0, 0] - -# ERRORS -# ------------------------------------------------------------------------------------------------- -const ERR_INVALID_PSM_SIGNATURE = "invalid private state manager signature" - -# PUBLIC INTERFACE -# ================================================================================================ - -#! Updates the private state manager public key. -#! -#! Inputs: [new_psm_scheme_id, NEW_PSM_PUBLIC_KEY] -#! Outputs: [] -#! -#! Notes: -#! - This procedure only updates the PSM public key and corresponding scheme id. -#! - `verify_signature` skips PSM verification only when this is the only non-auth account -#! procedure called in the transaction. -#! -#! Invocation: call -@locals(1) -pub proc update_psm_public_key(new_psm_scheme_id: felt, new_psm_public_key: word) - # Validate supported signature scheme before committing it to storage. - dup exec.signature::assert_supported_scheme - # => [new_psm_scheme_id, NEW_PSM_PUBLIC_KEY] - - loc_store.0 - # => [NEW_PSM_PUBLIC_KEY] - - push.PSM_MAP_KEY - # => [PSM_MAP_KEY, NEW_PSM_PUBLIC_KEY] - - push.PSM_PUBLIC_KEYS_SLOT[0..2] - # => [psm_pubkeys_slot_prefix, psm_pubkeys_slot_suffix, PSM_MAP_KEY, NEW_PSM_PUBLIC_KEY] - - exec.native_account::set_map_item - # => [OLD_PSM_PUBLIC_KEY] - - dropw - # => [] - - # Store new scheme id as [scheme_id, 0, 0, 0] in the single-entry map. - loc_load.0 - # => [scheme_id] - - push.0.0.0 movup.3 - # => [NEW_PSM_SCHEME_ID_WORD] - - push.PSM_MAP_KEY - # => [PSM_MAP_KEY, NEW_PSM_SCHEME_ID_WORD] - - push.PSM_SCHEME_ID_SLOT[0..2] - # => [psm_scheme_slot_prefix, psm_scheme_slot_suffix, PSM_MAP_KEY, NEW_PSM_SCHEME_ID_WORD] - - exec.native_account::set_map_item - # => [OLD_PSM_SCHEME_ID_WORD] - - dropw - # => [] -end - -#! Conditionally verifies a private state manager signature. -#! -#! Inputs: [MSG] -#! Outputs: [] -#! -#! Panics if: -#! - `update_psm_public_key` is called together with another non-auth account procedure. -#! - `update_psm_public_key` was not called and a valid PSM signature is missing or invalid. -#! -#! Invocation: exec -pub proc verify_signature(msg: word) - procref.update_psm_public_key - # => [UPDATE_PSM_PUBLIC_KEY_ROOT, MSG] - - exec.native_account::was_procedure_called - # => [was_update_psm_public_key_called, MSG] - - if.true - exec.tx_policy::assert_only_one_non_auth_procedure_called - # => [MSG] - - exec.tx_policy::assert_no_input_or_output_notes - # => [MSG] - - dropw - # => [] - else - push.1 - # => [1, MSG] - - push.PSM_PUBLIC_KEYS_SLOT[0..2] - # => [psm_pubkeys_slot_prefix, psm_pubkeys_slot_suffix, 1, MSG] - - push.PSM_SCHEME_ID_SLOT[0..2] - # => [psm_scheme_slot_prefix, psm_scheme_slot_suffix, psm_pubkeys_slot_prefix, psm_pubkeys_slot_suffix, 1, MSG] - - exec.signature::verify_signatures - # => [num_verified_signatures, MSG] - - neq.1 - # => [is_not_exactly_one, MSG] - - if.true - emit.AUTH_UNAUTHORIZED_EVENT - push.0 assert.err=ERR_INVALID_PSM_SIGNATURE - end - # => [MSG] - - dropw - # => [] - end -end diff --git a/crates/miden-standards/src/account/auth/mod.rs b/crates/miden-standards/src/account/auth/mod.rs index e999fab153..597d099c76 100644 --- a/crates/miden-standards/src/account/auth/mod.rs +++ b/crates/miden-standards/src/account/auth/mod.rs @@ -10,5 +10,5 @@ pub use singlesig_acl::{AuthSingleSigAcl, AuthSingleSigAclConfig}; mod multisig; pub use multisig::{AuthMultisig, AuthMultisigConfig}; -mod multisig_psm; -pub use multisig_psm::{AuthMultisigPsm, AuthMultisigPsmConfig, PsmConfig}; +mod multisig_guardian; +pub use multisig_guardian::{AuthMultisigGuardian, AuthMultisigGuardianConfig, GuardianConfig}; diff --git a/crates/miden-standards/src/account/auth/multisig.rs b/crates/miden-standards/src/account/auth/multisig.rs index 196bb3de0c..d0437f1a58 100644 --- a/crates/miden-standards/src/account/auth/multisig.rs +++ b/crates/miden-standards/src/account/auth/multisig.rs @@ -4,19 +4,10 @@ use alloc::vec::Vec; use miden_protocol::Word; use miden_protocol::account::auth::{AuthScheme, PublicKeyCommitment}; use miden_protocol::account::component::{ - AccountComponentMetadata, - FeltSchema, - SchemaType, - StorageSchema, - StorageSlotSchema, + AccountComponentMetadata, FeltSchema, SchemaType, StorageSchema, StorageSlotSchema, }; use miden_protocol::account::{ - AccountComponent, - AccountType, - StorageMap, - StorageMapKey, - StorageSlot, - StorageSlotName, + AccountComponent, AccountType, StorageMap, StorageMapKey, StorageSlot, StorageSlotName, }; use miden_protocol::errors::AccountError; use miden_protocol::utils::sync::LazyLock; @@ -130,9 +121,9 @@ impl AuthMultisigConfig { /// /// It enforces a threshold of approver signatures for every transaction, with optional /// per-procedure threshold overrides. Non-uniform thresholds (especially a threshold of one) -/// should be used with caution for private multisig accounts, without Private State Manager (PSM), -/// a single approver may advance state and withhold updates from other approvers, effectively -/// locking them out. +/// should be used with caution for private multisig accounts; without a guardian, a single +/// approver may advance state and withhold updates from other approvers, effectively locking +/// them out. /// /// This component supports all account types. #[derive(Debug)] diff --git a/crates/miden-standards/src/account/auth/multisig_psm.rs b/crates/miden-standards/src/account/auth/multisig_guardian.rs similarity index 64% rename from crates/miden-standards/src/account/auth/multisig_psm.rs rename to crates/miden-standards/src/account/auth/multisig_guardian.rs index 1e9ecc34b2..f9e5199744 100644 --- a/crates/miden-standards/src/account/auth/multisig_psm.rs +++ b/crates/miden-standards/src/account/auth/multisig_guardian.rs @@ -3,56 +3,48 @@ use alloc::vec::Vec; use miden_protocol::Word; use miden_protocol::account::auth::{AuthScheme, PublicKeyCommitment}; use miden_protocol::account::component::{ - AccountComponentMetadata, - SchemaType, - StorageSchema, - StorageSlotSchema, + AccountComponentMetadata, SchemaType, StorageSchema, StorageSlotSchema, }; use miden_protocol::account::{ - AccountComponent, - AccountType, - StorageMap, - StorageMapKey, - StorageSlot, - StorageSlotName, + AccountComponent, AccountType, StorageMap, StorageMapKey, StorageSlot, StorageSlotName, }; use miden_protocol::errors::AccountError; use miden_protocol::utils::sync::LazyLock; use super::multisig::{AuthMultisig, AuthMultisigConfig}; -use crate::account::components::multisig_psm_library; +use crate::account::components::multisig_guardian_library; // CONSTANTS // ================================================================================================ -static PSM_PUBKEY_SLOT_NAME: LazyLock = LazyLock::new(|| { - StorageSlotName::new("miden::standards::auth::psm::pub_key") +static GUARDIAN_PUBKEY_SLOT_NAME: LazyLock = LazyLock::new(|| { + StorageSlotName::new("miden::standards::auth::guardian::pub_key") .expect("storage slot name should be valid") }); -static PSM_SCHEME_ID_SLOT_NAME: LazyLock = LazyLock::new(|| { - StorageSlotName::new("miden::standards::auth::psm::scheme") +static GUARDIAN_SCHEME_ID_SLOT_NAME: LazyLock = LazyLock::new(|| { + StorageSlotName::new("miden::standards::auth::guardian::scheme") .expect("storage slot name should be valid") }); // MULTISIG AUTHENTICATION COMPONENT // ================================================================================================ -/// Configuration for [`AuthMultisigPsm`] component. +/// Configuration for [`AuthMultisigGuardian`] component. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct AuthMultisigPsmConfig { +pub struct AuthMultisigGuardianConfig { multisig: AuthMultisigConfig, - psm_config: PsmConfig, + guardian_config: GuardianConfig, } -/// Public configuration for the private state manager signer. +/// Public configuration for the guardian signer. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct PsmConfig { +pub struct GuardianConfig { pub_key: PublicKeyCommitment, auth_scheme: AuthScheme, } -impl PsmConfig { +impl GuardianConfig { pub fn new(pub_key: PublicKeyCommitment, auth_scheme: AuthScheme) -> Self { Self { pub_key, auth_scheme } } @@ -66,18 +58,18 @@ impl PsmConfig { } fn public_key_slot() -> &'static StorageSlotName { - &PSM_PUBKEY_SLOT_NAME + &GUARDIAN_PUBKEY_SLOT_NAME } fn scheme_id_slot() -> &'static StorageSlotName { - &PSM_SCHEME_ID_SLOT_NAME + &GUARDIAN_SCHEME_ID_SLOT_NAME } fn public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) { ( Self::public_key_slot().clone(), StorageSlotSchema::map( - "Private state manager public keys", + "Guardian public keys", SchemaType::u32(), SchemaType::pub_key(), ), @@ -88,7 +80,7 @@ impl PsmConfig { ( Self::scheme_id_slot().clone(), StorageSlotSchema::map( - "Private state manager scheme IDs", + "Guardian scheme IDs", SchemaType::u32(), SchemaType::auth_scheme(), ), @@ -98,22 +90,22 @@ impl PsmConfig { fn into_component_parts(self) -> (Vec, Vec<(StorageSlotName, StorageSlotSchema)>) { let mut storage_slots = Vec::with_capacity(2); - // Private state manager public key slot (map: [0, 0, 0, 0] -> pubkey) - let psm_public_key_entries = + // Guardian public key slot (map: [0, 0, 0, 0] -> pubkey) + let guardian_public_key_entries = [(StorageMapKey::from_raw(Word::from([0u32, 0, 0, 0])), Word::from(self.pub_key))]; storage_slots.push(StorageSlot::with_map( Self::public_key_slot().clone(), - StorageMap::with_entries(psm_public_key_entries).unwrap(), + StorageMap::with_entries(guardian_public_key_entries).unwrap(), )); - // Private state manager scheme IDs slot (map: [0, 0, 0, 0] -> [scheme_id, 0, 0, 0]) - let psm_scheme_id_entries = [( + // Guardian scheme IDs slot (map: [0, 0, 0, 0] -> [scheme_id, 0, 0, 0]) + let guardian_scheme_id_entries = [( StorageMapKey::from_raw(Word::from([0u32, 0, 0, 0])), Word::from([self.auth_scheme as u32, 0, 0, 0]), )]; storage_slots.push(StorageSlot::with_map( Self::scheme_id_slot().clone(), - StorageMap::with_entries(psm_scheme_id_entries).unwrap(), + StorageMap::with_entries(guardian_scheme_id_entries).unwrap(), )); let slot_metadata = vec![Self::public_key_slot_schema(), Self::auth_scheme_slot_schema()]; @@ -122,28 +114,28 @@ impl PsmConfig { } } -impl AuthMultisigPsmConfig { - /// Creates a new configuration with the given approvers, default threshold and PSM signer. +impl AuthMultisigGuardianConfig { + /// Creates a new configuration with the given approvers, default threshold and guardian signer. /// /// The `default_threshold` must be at least 1 and at most the number of approvers. - /// The private state manager public key must be different from all approver public keys. + /// The guardian public key must be different from all approver public keys. pub fn new( approvers: Vec<(PublicKeyCommitment, AuthScheme)>, default_threshold: u32, - psm_config: PsmConfig, + guardian_config: GuardianConfig, ) -> Result { let multisig = AuthMultisigConfig::new(approvers, default_threshold)?; if multisig .approvers() .iter() - .any(|(approver, _)| *approver == psm_config.pub_key()) + .any(|(approver, _)| *approver == guardian_config.pub_key()) { return Err(AccountError::other( - "private state manager public key must be different from approvers", + "guardian public key must be different from approvers", )); } - Ok(Self { multisig, psm_config }) + Ok(Self { multisig, guardian_config }) } /// Attaches a per-procedure threshold map. Each procedure threshold must be at least 1 and @@ -168,41 +160,40 @@ impl AuthMultisigPsmConfig { self.multisig.proc_thresholds() } - pub fn psm_config(&self) -> PsmConfig { - self.psm_config + pub fn guardian_config(&self) -> GuardianConfig { + self.guardian_config } - fn into_parts(self) -> (AuthMultisigConfig, PsmConfig) { - (self.multisig, self.psm_config) + fn into_parts(self) -> (AuthMultisigConfig, GuardianConfig) { + (self.multisig, self.guardian_config) } } -/// An [`AccountComponent`] implementing a multisig authentication with a private state manager. +/// An [`AccountComponent`] implementing a multisig authentication with a guardian. /// /// It enforces a threshold of approver signatures for every transaction, with optional -/// per-procedure threshold overrides. With Private State Manager (PSM) is configured, -/// multisig authorization is combined with PSM authorization, so operations require both -/// multisig approval and a valid PSM signature. This substantially mitigates low-threshold -/// state-withholding scenarios since the PSM is expected to forward state updates to other -/// approvers. +/// per-procedure threshold overrides. When a guardian is configured, multisig authorization is +/// combined with guardian authorization, so operations require both multisig approval and a valid +/// guardian signature. This substantially mitigates low-threshold state-withholding scenarios +/// since the guardian is expected to forward state updates to other approvers. /// /// This component supports all account types. #[derive(Debug)] -pub struct AuthMultisigPsm { +pub struct AuthMultisigGuardian { multisig: AuthMultisig, - psm_config: PsmConfig, + guardian_config: GuardianConfig, } -impl AuthMultisigPsm { +impl AuthMultisigGuardian { /// The name of the component. - pub const NAME: &'static str = "miden::standards::components::auth::multisig_psm"; + pub const NAME: &'static str = "miden::standards::components::auth::multisig_guardian"; - /// Creates a new [`AuthMultisigPsm`] component from the provided configuration. - pub fn new(config: AuthMultisigPsmConfig) -> Result { - let (multisig_config, psm_config) = config.into_parts(); + /// Creates a new [`AuthMultisigGuardian`] component from the provided configuration. + pub fn new(config: AuthMultisigGuardianConfig) -> Result { + let (multisig_config, guardian_config) = config.into_parts(); Ok(Self { multisig: AuthMultisig::new(multisig_config)?, - psm_config, + guardian_config, }) } @@ -231,14 +222,14 @@ impl AuthMultisigPsm { AuthMultisig::procedure_thresholds_slot() } - /// Returns the [`StorageSlotName`] where the private state manager public key is stored. - pub fn psm_public_key_slot() -> &'static StorageSlotName { - PsmConfig::public_key_slot() + /// Returns the [`StorageSlotName`] where the guardian public key is stored. + pub fn guardian_public_key_slot() -> &'static StorageSlotName { + GuardianConfig::public_key_slot() } - /// Returns the [`StorageSlotName`] where the private state manager scheme IDs are stored. - pub fn psm_scheme_id_slot() -> &'static StorageSlotName { - PsmConfig::scheme_id_slot() + /// Returns the [`StorageSlotName`] where the guardian scheme IDs are stored. + pub fn guardian_scheme_id_slot() -> &'static StorageSlotName { + GuardianConfig::scheme_id_slot() } /// Returns the storage slot schema for the threshold configuration slot. @@ -266,14 +257,14 @@ impl AuthMultisigPsm { AuthMultisig::procedure_thresholds_slot_schema() } - /// Returns the storage slot schema for the private state manager public key slot. - pub fn psm_public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - PsmConfig::public_key_slot_schema() + /// Returns the storage slot schema for the guardian public key slot. + pub fn guardian_public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) { + GuardianConfig::public_key_slot_schema() } - /// Returns the storage slot schema for the private state manager scheme IDs slot. - pub fn psm_auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) { - PsmConfig::auth_scheme_slot_schema() + /// Returns the storage slot schema for the guardian scheme IDs slot. + pub fn guardian_auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) { + GuardianConfig::auth_scheme_slot_schema() } /// Returns the [`AccountComponentMetadata`] for this component. @@ -284,48 +275,48 @@ impl AuthMultisigPsm { Self::approver_auth_scheme_slot_schema(), Self::executed_transactions_slot_schema(), Self::procedure_thresholds_slot_schema(), - Self::psm_public_key_slot_schema(), - Self::psm_auth_scheme_slot_schema(), + Self::guardian_public_key_slot_schema(), + Self::guardian_auth_scheme_slot_schema(), ]) .expect("storage schema should be valid"); AccountComponentMetadata::new(Self::NAME, AccountType::all()) .with_description( - "Multisig authentication component with private state manager \ + "Multisig authentication component with guardian \ using hybrid signature schemes", ) .with_storage_schema(storage_schema) } } -impl From for AccountComponent { - fn from(multisig: AuthMultisigPsm) -> Self { - let AuthMultisigPsm { multisig, psm_config } = multisig; +impl From for AccountComponent { + fn from(multisig: AuthMultisigGuardian) -> Self { + let AuthMultisigGuardian { multisig, guardian_config } = multisig; let multisig_component = AccountComponent::from(multisig); - let (psm_slots, psm_slot_metadata) = psm_config.into_component_parts(); + let (guardian_slots, guardian_slot_metadata) = guardian_config.into_component_parts(); let mut storage_slots = multisig_component.storage_slots().to_vec(); - storage_slots.extend(psm_slots); + storage_slots.extend(guardian_slots); let mut slot_schemas: Vec<(StorageSlotName, StorageSlotSchema)> = multisig_component .storage_schema() .iter() .map(|(slot_name, slot_schema)| (slot_name.clone(), slot_schema.clone())) .collect(); - slot_schemas.extend(psm_slot_metadata); + slot_schemas.extend(guardian_slot_metadata); let storage_schema = StorageSchema::new(slot_schemas).expect("storage schema should be valid"); let metadata = AccountComponentMetadata::new( - AuthMultisigPsm::NAME, + AuthMultisigGuardian::NAME, multisig_component.supported_types().clone(), ) .with_description(multisig_component.metadata().description()) .with_version(multisig_component.metadata().version().clone()) .with_storage_schema(storage_schema); - AccountComponent::new(multisig_psm_library(), storage_slots, metadata).expect( + AccountComponent::new(multisig_guardian_library(), storage_slots, metadata).expect( "Multisig auth component should satisfy the requirements of a valid account component", ) } @@ -352,7 +343,7 @@ mod tests { let sec_key_1 = AuthSecretKey::new_falcon512_poseidon2(); let sec_key_2 = AuthSecretKey::new_falcon512_poseidon2(); let sec_key_3 = AuthSecretKey::new_falcon512_poseidon2(); - let psm_key = AuthSecretKey::new_ecdsa_k256_keccak(); + let guardian_key = AuthSecretKey::new_ecdsa_k256_keccak(); // Create approvers list for multisig config let approvers = vec![ @@ -364,11 +355,14 @@ mod tests { let threshold = 2u32; // Create multisig component - let multisig_component = AuthMultisigPsm::new( - AuthMultisigPsmConfig::new( + let multisig_component = AuthMultisigGuardian::new( + AuthMultisigGuardianConfig::new( approvers.clone(), threshold, - PsmConfig::new(psm_key.public_key().to_commitment(), psm_key.auth_scheme()), + GuardianConfig::new( + guardian_key.public_key().to_commitment(), + guardian_key.auth_scheme(), + ), ) .expect("invalid multisig config"), ) @@ -384,7 +378,7 @@ mod tests { // Verify config slot: [threshold, num_approvers, 0, 0] let config_slot = account .storage() - .get_item(AuthMultisigPsm::threshold_config_slot()) + .get_item(AuthMultisigGuardian::threshold_config_slot()) .expect("config storage slot access failed"); assert_eq!(config_slot, Word::from([threshold, approvers.len() as u32, 0, 0])); @@ -393,7 +387,7 @@ mod tests { let stored_pub_key = account .storage() .get_map_item( - AuthMultisigPsm::approver_public_keys_slot(), + AuthMultisigGuardian::approver_public_keys_slot(), Word::from([i as u32, 0, 0, 0]), ) .expect("approver public key storage map access failed"); @@ -405,40 +399,49 @@ mod tests { let stored_scheme_id = account .storage() .get_map_item( - AuthMultisigPsm::approver_scheme_ids_slot(), + AuthMultisigGuardian::approver_scheme_ids_slot(), Word::from([i as u32, 0, 0, 0]), ) .expect("approver scheme ID storage map access failed"); assert_eq!(stored_scheme_id, Word::from([*expected_auth_scheme as u32, 0, 0, 0])); } - // Verify private state manager signer is configured. - let psm_public_key = account + // Verify guardian signer is configured. + let guardian_public_key = account .storage() - .get_map_item(AuthMultisigPsm::psm_public_key_slot(), Word::from([0u32, 0, 0, 0])) - .expect("private state manager public key storage map access failed"); - assert_eq!(psm_public_key, Word::from(psm_key.public_key().to_commitment())); + .get_map_item( + AuthMultisigGuardian::guardian_public_key_slot(), + Word::from([0u32, 0, 0, 0]), + ) + .expect("guardian public key storage map access failed"); + assert_eq!(guardian_public_key, Word::from(guardian_key.public_key().to_commitment())); - let psm_scheme_id = account + let guardian_scheme_id = account .storage() - .get_map_item(AuthMultisigPsm::psm_scheme_id_slot(), Word::from([0u32, 0, 0, 0])) - .expect("private state manager scheme ID storage map access failed"); - assert_eq!(psm_scheme_id, Word::from([psm_key.auth_scheme() as u32, 0, 0, 0])); + .get_map_item( + AuthMultisigGuardian::guardian_scheme_id_slot(), + Word::from([0u32, 0, 0, 0]), + ) + .expect("guardian scheme ID storage map access failed"); + assert_eq!(guardian_scheme_id, Word::from([guardian_key.auth_scheme() as u32, 0, 0, 0])); } /// Test multisig component with minimum threshold (1 of 1) #[test] fn test_multisig_component_minimum_threshold() { let pub_key = AuthSecretKey::new_ecdsa_k256_keccak().public_key().to_commitment(); - let psm_key = AuthSecretKey::new_falcon512_poseidon2(); + let guardian_key = AuthSecretKey::new_falcon512_poseidon2(); let approvers = vec![(pub_key, AuthScheme::EcdsaK256Keccak)]; let threshold = 1u32; - let multisig_component = AuthMultisigPsm::new( - AuthMultisigPsmConfig::new( + let multisig_component = AuthMultisigGuardian::new( + AuthMultisigGuardianConfig::new( approvers.clone(), threshold, - PsmConfig::new(psm_key.public_key().to_commitment(), psm_key.auth_scheme()), + GuardianConfig::new( + guardian_key.public_key().to_commitment(), + guardian_key.auth_scheme(), + ), ) .expect("invalid multisig config"), ) @@ -453,40 +456,49 @@ mod tests { // Verify storage layout let config_slot = account .storage() - .get_item(AuthMultisigPsm::threshold_config_slot()) + .get_item(AuthMultisigGuardian::threshold_config_slot()) .expect("config storage slot access failed"); assert_eq!(config_slot, Word::from([threshold, approvers.len() as u32, 0, 0])); let stored_pub_key = account .storage() - .get_map_item(AuthMultisigPsm::approver_public_keys_slot(), Word::from([0u32, 0, 0, 0])) + .get_map_item( + AuthMultisigGuardian::approver_public_keys_slot(), + Word::from([0u32, 0, 0, 0]), + ) .expect("approver pub keys storage map access failed"); assert_eq!(stored_pub_key, Word::from(pub_key)); let stored_scheme_id = account .storage() - .get_map_item(AuthMultisigPsm::approver_scheme_ids_slot(), Word::from([0u32, 0, 0, 0])) + .get_map_item( + AuthMultisigGuardian::approver_scheme_ids_slot(), + Word::from([0u32, 0, 0, 0]), + ) .expect("approver scheme IDs storage map access failed"); assert_eq!(stored_scheme_id, Word::from([AuthScheme::EcdsaK256Keccak as u32, 0, 0, 0])); } - /// Test multisig component setup with a private state manager. + /// Test multisig component setup with a guardian. #[test] - fn test_multisig_component_with_psm() { + fn test_multisig_component_with_guardian() { let sec_key_1 = AuthSecretKey::new_falcon512_poseidon2(); let sec_key_2 = AuthSecretKey::new_falcon512_poseidon2(); - let psm_key = AuthSecretKey::new_ecdsa_k256_keccak(); + let guardian_key = AuthSecretKey::new_ecdsa_k256_keccak(); let approvers = vec![ (sec_key_1.public_key().to_commitment(), sec_key_1.auth_scheme()), (sec_key_2.public_key().to_commitment(), sec_key_2.auth_scheme()), ]; - let multisig_component = AuthMultisigPsm::new( - AuthMultisigPsmConfig::new( + let multisig_component = AuthMultisigGuardian::new( + AuthMultisigGuardianConfig::new( approvers, 2, - PsmConfig::new(psm_key.public_key().to_commitment(), psm_key.auth_scheme()), + GuardianConfig::new( + guardian_key.public_key().to_commitment(), + guardian_key.auth_scheme(), + ), ) .expect("invalid multisig config"), ) @@ -498,31 +510,40 @@ mod tests { .build() .expect("account building failed"); - let psm_public_key = account + let guardian_public_key = account .storage() - .get_map_item(AuthMultisigPsm::psm_public_key_slot(), Word::from([0u32, 0, 0, 0])) - .expect("private state manager public key storage map access failed"); - assert_eq!(psm_public_key, Word::from(psm_key.public_key().to_commitment())); + .get_map_item( + AuthMultisigGuardian::guardian_public_key_slot(), + Word::from([0u32, 0, 0, 0]), + ) + .expect("guardian public key storage map access failed"); + assert_eq!(guardian_public_key, Word::from(guardian_key.public_key().to_commitment())); - let psm_scheme_id = account + let guardian_scheme_id = account .storage() - .get_map_item(AuthMultisigPsm::psm_scheme_id_slot(), Word::from([0u32, 0, 0, 0])) - .expect("private state manager scheme ID storage map access failed"); - assert_eq!(psm_scheme_id, Word::from([psm_key.auth_scheme() as u32, 0, 0, 0])); + .get_map_item( + AuthMultisigGuardian::guardian_scheme_id_slot(), + Word::from([0u32, 0, 0, 0]), + ) + .expect("guardian scheme ID storage map access failed"); + assert_eq!(guardian_scheme_id, Word::from([guardian_key.auth_scheme() as u32, 0, 0, 0])); } /// Test multisig component error cases #[test] fn test_multisig_component_error_cases() { let pub_key = AuthSecretKey::new_ecdsa_k256_keccak().public_key().to_commitment(); - let psm_key = AuthSecretKey::new_falcon512_poseidon2(); + let guardian_key = AuthSecretKey::new_falcon512_poseidon2(); let approvers = vec![(pub_key, AuthScheme::EcdsaK256Keccak)]; // Test threshold > number of approvers (should fail) - let result = AuthMultisigPsmConfig::new( + let result = AuthMultisigGuardianConfig::new( approvers, 2, - PsmConfig::new(psm_key.public_key().to_commitment(), psm_key.auth_scheme()), + GuardianConfig::new( + guardian_key.public_key().to_commitment(), + guardian_key.auth_scheme(), + ), ); assert!( @@ -539,7 +560,7 @@ mod tests { // Create secret keys for approvers let sec_key_1 = AuthSecretKey::new_ecdsa_k256_keccak(); let sec_key_2 = AuthSecretKey::new_ecdsa_k256_keccak(); - let psm_key = AuthSecretKey::new_falcon512_poseidon2(); + let guardian_key = AuthSecretKey::new_falcon512_poseidon2(); // Create approvers list with duplicate public keys let approvers = vec![ @@ -548,10 +569,13 @@ mod tests { (sec_key_2.public_key().to_commitment(), sec_key_2.auth_scheme()), ]; - let result = AuthMultisigPsmConfig::new( + let result = AuthMultisigGuardianConfig::new( approvers, 2, - PsmConfig::new(psm_key.public_key().to_commitment(), psm_key.auth_scheme()), + GuardianConfig::new( + guardian_key.public_key().to_commitment(), + guardian_key.auth_scheme(), + ), ); assert!( result @@ -561,9 +585,9 @@ mod tests { ); } - /// Test multisig component rejects a private state manager key which is already an approver. + /// Test multisig component rejects a guardian key which is already an approver. #[test] - fn test_multisig_component_psm_not_approver() { + fn test_multisig_component_guardian_not_approver() { let sec_key_1 = AuthSecretKey::new_ecdsa_k256_keccak(); let sec_key_2 = AuthSecretKey::new_ecdsa_k256_keccak(); @@ -572,17 +596,17 @@ mod tests { (sec_key_2.public_key().to_commitment(), sec_key_2.auth_scheme()), ]; - let result = AuthMultisigPsmConfig::new( + let result = AuthMultisigGuardianConfig::new( approvers, 2, - PsmConfig::new(sec_key_1.public_key().to_commitment(), sec_key_1.auth_scheme()), + GuardianConfig::new(sec_key_1.public_key().to_commitment(), sec_key_1.auth_scheme()), ); assert!( result .unwrap_err() .to_string() - .contains("private state manager public key must be different from approvers") + .contains("guardian public key must be different from approvers") ); } } diff --git a/crates/miden-standards/src/account/components/mod.rs b/crates/miden-standards/src/account/components/mod.rs index a14d3ce523..28a933396c 100644 --- a/crates/miden-standards/src/account/components/mod.rs +++ b/crates/miden-standards/src/account/components/mod.rs @@ -60,13 +60,13 @@ static MULTISIG_LIBRARY: LazyLock = LazyLock::new(|| { Library::read_from_bytes(bytes).expect("Shipped Multisig library is well-formed") }); -/// Initialize the Multisig PSM library only once. -static MULTISIG_PSM_LIBRARY: LazyLock = LazyLock::new(|| { +/// Initialize the Multisig Guardian library only once. +static MULTISIG_GUARDIAN_LIBRARY: LazyLock = LazyLock::new(|| { let bytes = include_bytes!(concat!( env!("OUT_DIR"), - "/assets/account_components/auth/multisig_psm.masl" + "/assets/account_components/auth/multisig_guardian.masl" )); - Library::read_from_bytes(bytes).expect("Shipped Multisig PSM library is well-formed") + Library::read_from_bytes(bytes).expect("Shipped Multisig Guardian library is well-formed") }); // Initialize the NoAuth library only once. @@ -165,9 +165,9 @@ pub fn multisig_library() -> Library { MULTISIG_LIBRARY.clone() } -/// Returns the Multisig PSM Library. -pub fn multisig_psm_library() -> Library { - MULTISIG_PSM_LIBRARY.clone() +/// Returns the Multisig Guardian Library. +pub fn multisig_guardian_library() -> Library { + MULTISIG_GUARDIAN_LIBRARY.clone() } /// Returns the NoAuth Library. @@ -187,7 +187,7 @@ pub enum StandardAccountComponent { AuthSingleSig, AuthSingleSigAcl, AuthMultisig, - AuthMultisigPsm, + AuthMultisigGuardian, AuthNoAuth, } @@ -201,7 +201,7 @@ impl StandardAccountComponent { Self::AuthSingleSig => SINGLESIG_LIBRARY.as_ref(), Self::AuthSingleSigAcl => SINGLESIG_ACL_LIBRARY.as_ref(), Self::AuthMultisig => MULTISIG_LIBRARY.as_ref(), - Self::AuthMultisigPsm => MULTISIG_PSM_LIBRARY.as_ref(), + Self::AuthMultisigGuardian => MULTISIG_GUARDIAN_LIBRARY.as_ref(), Self::AuthNoAuth => NO_AUTH_LIBRARY.as_ref(), }; @@ -254,8 +254,8 @@ impl StandardAccountComponent { Self::AuthMultisig => { component_interface_vec.push(AccountComponentInterface::AuthMultisig) }, - Self::AuthMultisigPsm => { - component_interface_vec.push(AccountComponentInterface::AuthMultisigPsm) + Self::AuthMultisigGuardian => { + component_interface_vec.push(AccountComponentInterface::AuthMultisigGuardian) }, Self::AuthNoAuth => { component_interface_vec.push(AccountComponentInterface::AuthNoAuth) @@ -275,7 +275,7 @@ impl StandardAccountComponent { Self::NetworkFungibleFaucet.extract_component(procedures_set, component_interface_vec); Self::AuthSingleSig.extract_component(procedures_set, component_interface_vec); Self::AuthSingleSigAcl.extract_component(procedures_set, component_interface_vec); - Self::AuthMultisigPsm.extract_component(procedures_set, component_interface_vec); + Self::AuthMultisigGuardian.extract_component(procedures_set, component_interface_vec); Self::AuthMultisig.extract_component(procedures_set, component_interface_vec); Self::AuthNoAuth.extract_component(procedures_set, component_interface_vec); } diff --git a/crates/miden-standards/src/account/interface/component.rs b/crates/miden-standards/src/account/interface/component.rs index 6527767f3f..271d23ee00 100644 --- a/crates/miden-standards/src/account/interface/component.rs +++ b/crates/miden-standards/src/account/interface/component.rs @@ -7,7 +7,7 @@ use miden_protocol::note::PartialNote; use miden_protocol::{Felt, Word}; use crate::AuthMethod; -use crate::account::auth::{AuthMultisig, AuthMultisigPsm, AuthSingleSig, AuthSingleSigAcl}; +use crate::account::auth::{AuthMultisig, AuthMultisigGuardian, AuthSingleSig, AuthSingleSigAcl}; use crate::account::interface::AccountInterfaceError; // ACCOUNT COMPONENT INTERFACE @@ -34,8 +34,8 @@ pub enum AccountComponentInterface { /// [`AuthMultisig`][crate::account::auth::AuthMultisig] module. AuthMultisig, /// Exposes procedures from the - /// [`AuthMultisigPsm`][crate::account::auth::AuthMultisigPsm] module. - AuthMultisigPsm, + /// [`AuthMultisigGuardian`][crate::account::auth::AuthMultisigGuardian] module. + AuthMultisigGuardian, /// Exposes procedures from the [`NoAuth`][crate::account::auth::NoAuth] module. /// /// This authentication scheme provides no cryptographic authentication and only increments @@ -64,7 +64,7 @@ impl AccountComponentInterface { AccountComponentInterface::AuthSingleSig => "SingleSig".to_string(), AccountComponentInterface::AuthSingleSigAcl => "SingleSig ACL".to_string(), AccountComponentInterface::AuthMultisig => "Multisig".to_string(), - AccountComponentInterface::AuthMultisigPsm => "Multisig PSM".to_string(), + AccountComponentInterface::AuthMultisigGuardian => "Multisig Guardian".to_string(), AccountComponentInterface::AuthNoAuth => "No Auth".to_string(), AccountComponentInterface::Custom(proc_root_vec) => { let result = proc_root_vec @@ -86,7 +86,7 @@ impl AccountComponentInterface { AccountComponentInterface::AuthSingleSig | AccountComponentInterface::AuthSingleSigAcl | AccountComponentInterface::AuthMultisig - | AccountComponentInterface::AuthMultisigPsm + | AccountComponentInterface::AuthMultisigGuardian | AccountComponentInterface::AuthNoAuth ) } @@ -112,12 +112,12 @@ impl AccountComponentInterface { AuthMultisig::approver_scheme_ids_slot(), )] }, - AccountComponentInterface::AuthMultisigPsm => { + AccountComponentInterface::AuthMultisigGuardian => { vec![extract_multisig_auth_method( storage, - AuthMultisigPsm::threshold_config_slot(), - AuthMultisigPsm::approver_public_keys_slot(), - AuthMultisigPsm::approver_scheme_ids_slot(), + AuthMultisigGuardian::threshold_config_slot(), + AuthMultisigGuardian::approver_public_keys_slot(), + AuthMultisigGuardian::approver_scheme_ids_slot(), )] }, AccountComponentInterface::AuthNoAuth => vec![AuthMethod::NoAuth], diff --git a/crates/miden-standards/src/account/interface/extension.rs b/crates/miden-standards/src/account/interface/extension.rs index f23b1414a7..340bcba485 100644 --- a/crates/miden-standards/src/account/interface/extension.rs +++ b/crates/miden-standards/src/account/interface/extension.rs @@ -10,20 +10,12 @@ use miden_protocol::note::{Note, NoteScript}; use crate::AuthMethod; use crate::account::components::{ - StandardAccountComponent, - basic_fungible_faucet_library, - basic_wallet_library, - multisig_library, - multisig_psm_library, - network_fungible_faucet_library, - no_auth_library, - singlesig_acl_library, - singlesig_library, + StandardAccountComponent, basic_fungible_faucet_library, basic_wallet_library, + multisig_guardian_library, multisig_library, network_fungible_faucet_library, no_auth_library, + singlesig_acl_library, singlesig_library, }; use crate::account::interface::{ - AccountComponentInterface, - AccountInterface, - NoteAccountCompatibility, + AccountComponentInterface, AccountInterface, NoteAccountCompatibility, }; use crate::note::StandardNote; @@ -113,9 +105,9 @@ impl AccountInterfaceExt for AccountInterface { component_proc_digests .extend(multisig_library().mast_forest().procedure_digests()); }, - AccountComponentInterface::AuthMultisigPsm => { + AccountComponentInterface::AuthMultisigGuardian => { component_proc_digests - .extend(multisig_psm_library().mast_forest().procedure_digests()); + .extend(multisig_guardian_library().mast_forest().procedure_digests()); }, AccountComponentInterface::AuthNoAuth => { component_proc_digests diff --git a/crates/miden-testing/src/mock_chain/auth.rs b/crates/miden-testing/src/mock_chain/auth.rs index 5b7f06b06a..2036beb784 100644 --- a/crates/miden-testing/src/mock_chain/auth.rs +++ b/crates/miden-testing/src/mock_chain/auth.rs @@ -7,18 +7,11 @@ use miden_protocol::account::AccountComponent; use miden_protocol::account::auth::{AuthScheme, AuthSecretKey, PublicKeyCommitment}; use miden_protocol::testing::noop_auth_component::NoopAuthComponent; use miden_standards::account::auth::{ - AuthMultisig, - AuthMultisigConfig, - AuthMultisigPsm, - AuthMultisigPsmConfig, - AuthSingleSig, - AuthSingleSigAcl, - AuthSingleSigAclConfig, - PsmConfig, + AuthMultisig, AuthMultisigConfig, AuthMultisigGuardian, AuthMultisigGuardianConfig, + AuthSingleSig, AuthSingleSigAcl, AuthSingleSigAclConfig, GuardianConfig, }; use miden_standards::testing::account_component::{ - ConditionalAuthComponent, - IncrNonceAuthComponent, + ConditionalAuthComponent, IncrNonceAuthComponent, }; use miden_tx::auth::BasicAuthenticator; use rand::SeedableRng; @@ -38,11 +31,11 @@ pub enum Auth { proc_threshold_map: Vec<(Word, u32)>, }, - /// Multisig with a private state manager. - MultisigPsm { + /// Multisig with a guardian. + MultisigGuardian { threshold: u32, approvers: Vec<(PublicKeyCommitment, AuthScheme)>, - psm_config: PsmConfig, + guardian_config: GuardianConfig, proc_threshold_map: Vec<(Word, u32)>, }, @@ -96,17 +89,21 @@ impl Auth { (component, None) }, - Auth::MultisigPsm { + Auth::MultisigGuardian { threshold, approvers, - psm_config, + guardian_config, proc_threshold_map, } => { - let config = AuthMultisigPsmConfig::new(approvers.clone(), *threshold, *psm_config) - .and_then(|cfg| cfg.with_proc_thresholds(proc_threshold_map.clone())) - .expect("invalid multisig psm config"); - let component = AuthMultisigPsm::new(config) - .expect("multisig psm component creation failed") + let config = AuthMultisigGuardianConfig::new( + approvers.clone(), + *threshold, + *guardian_config, + ) + .and_then(|cfg| cfg.with_proc_thresholds(proc_threshold_map.clone())) + .expect("invalid multisig guardian config"); + let component = AuthMultisigGuardian::new(config) + .expect("multisig guardian component creation failed") .into(); (component, None) diff --git a/crates/miden-testing/tests/auth/mod.rs b/crates/miden-testing/tests/auth/mod.rs index 33d6f35bde..c03d07fecb 100644 --- a/crates/miden-testing/tests/auth/mod.rs +++ b/crates/miden-testing/tests/auth/mod.rs @@ -4,4 +4,4 @@ mod multisig; mod hybrid_multisig; -mod multisig_psm; +mod multisig_guardian; diff --git a/crates/miden-testing/tests/auth/multisig_psm.rs b/crates/miden-testing/tests/auth/multisig_guardian.rs similarity index 67% rename from crates/miden-testing/tests/auth/multisig_psm.rs rename to crates/miden-testing/tests/auth/multisig_guardian.rs index 31d090d460..9e1608f67b 100644 --- a/crates/miden-testing/tests/auth/multisig_psm.rs +++ b/crates/miden-testing/tests/auth/multisig_guardian.rs @@ -1,21 +1,18 @@ use miden_protocol::account::auth::{AuthScheme, AuthSecretKey, PublicKey}; use miden_protocol::account::{ - Account, - AccountBuilder, - AccountId, - AccountStorageMode, - AccountType, + Account, AccountBuilder, AccountId, AccountStorageMode, AccountType, }; use miden_protocol::asset::FungibleAsset; use miden_protocol::note::{Note, NoteAssets, NoteMetadata, NoteRecipient, NoteStorage, NoteType}; use miden_protocol::testing::account_id::{ - ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, - ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, + ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, }; use miden_protocol::transaction::RawOutputNote; use miden_protocol::{Felt, Word}; -use miden_standards::account::auth::{AuthMultisigPsm, AuthMultisigPsmConfig, PsmConfig}; -use miden_standards::account::components::multisig_psm_library; +use miden_standards::account::auth::{ + AuthMultisigGuardian, AuthMultisigGuardianConfig, GuardianConfig, +}; +use miden_standards::account::components::multisig_guardian_library; use miden_standards::account::wallets::BasicWallet; use miden_standards::code_builder::CodeBuilder; use miden_standards::errors::standards::{ @@ -74,11 +71,11 @@ fn setup_keys_and_authenticators_with_scheme( Ok((secret_keys, auth_schemes, public_keys, authenticators)) } -/// Creates a multisig account configured with a private state manager signer. -fn create_multisig_account_with_psm( +/// Creates a multisig account configured with a guardian signer. +fn create_multisig_account_with_guardian( threshold: u32, approvers: &[(PublicKey, AuthScheme)], - psm: PsmConfig, + guardian: GuardianConfig, asset_amount: u64, proc_threshold_map: Vec<(Word, u32)>, ) -> anyhow::Result { @@ -87,11 +84,11 @@ fn create_multisig_account_with_psm( .map(|(pub_key, auth_scheme)| (pub_key.to_commitment(), *auth_scheme)) .collect(); - let config = AuthMultisigPsmConfig::new(approvers, threshold, psm)? + let config = AuthMultisigGuardianConfig::new(approvers, threshold, guardian)? .with_proc_thresholds(proc_threshold_map)?; let multisig_account = AccountBuilder::new([0; 32]) - .with_auth_component(AuthMultisigPsm::new(config)?) + .with_auth_component(AuthMultisigGuardian::new(config)?) .with_component(BasicWallet) .account_type(AccountType::RegularAccountUpdatableCode) .storage_mode(AccountStorageMode::Public) @@ -105,13 +102,13 @@ fn create_multisig_account_with_psm( // TESTS // ================================================================================================ -/// Tests that multisig authentication requires an additional PSM signature when +/// Tests that multisig authentication requires an additional guardian signature when /// configured. #[rstest] #[case::ecdsa(AuthScheme::EcdsaK256Keccak)] #[case::falcon(AuthScheme::Falcon512Poseidon2)] #[tokio::test] -async fn test_multisig_psm_signature_required( +async fn test_multisig_guardian_signature_required( #[case] auth_scheme: AuthScheme, ) -> anyhow::Result<()> { let (_secret_keys, auth_schemes, public_keys, authenticators) = @@ -122,14 +119,15 @@ async fn test_multisig_psm_signature_required( .map(|(pk, scheme)| (pk.clone(), *scheme)) .collect::>(); - let psm_secret_key = AuthSecretKey::new_ecdsa_k256_keccak(); - let psm_public_key = psm_secret_key.public_key(); - let psm_authenticator = BasicAuthenticator::new(core::slice::from_ref(&psm_secret_key)); + let guardian_secret_key = AuthSecretKey::new_ecdsa_k256_keccak(); + let guardian_public_key = guardian_secret_key.public_key(); + let guardian_authenticator = + BasicAuthenticator::new(core::slice::from_ref(&guardian_secret_key)); - let mut multisig_account = create_multisig_account_with_psm( + let mut multisig_account = create_multisig_account_with_guardian( 2, &approvers, - PsmConfig::new(psm_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), + GuardianConfig::new(guardian_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), 10, vec![], )?; @@ -168,8 +166,8 @@ async fn test_multisig_psm_signature_required( .get_signature(public_keys[1].to_commitment(), &tx_summary_signing) .await?; - // Missing PSM signature must fail. - let without_psm_result = mock_chain + // Missing guardian signature must fail. + let without_guardian_result = mock_chain .build_tx_context(multisig_account.id(), &[input_note.id()], &[])? .extend_expected_output_notes(vec![RawOutputNote::Full(output_note.clone())]) .add_signature(public_keys[0].to_commitment(), msg, sig_1.clone()) @@ -178,19 +176,22 @@ async fn test_multisig_psm_signature_required( .build()? .execute() .await; - assert!(matches!(without_psm_result, Err(TransactionExecutorError::Unauthorized(_)))); + assert!(matches!( + without_guardian_result, + Err(TransactionExecutorError::Unauthorized(_)) + )); - let psm_signature = psm_authenticator - .get_signature(psm_public_key.to_commitment(), &tx_summary_signing) + let guardian_signature = guardian_authenticator + .get_signature(guardian_public_key.to_commitment(), &tx_summary_signing) .await?; - // With PSM signature the transaction should succeed. + // With guardian signature the transaction should succeed. let tx_context_execute = mock_chain .build_tx_context(multisig_account.id(), &[input_note.id()], &[])? .extend_expected_output_notes(vec![RawOutputNote::Full(output_note)]) .add_signature(public_keys[0].to_commitment(), msg, sig_1) .add_signature(public_keys[1].to_commitment(), msg, sig_2) - .add_signature(psm_public_key.to_commitment(), msg, psm_signature) + .add_signature(guardian_public_key.to_commitment(), msg, guardian_signature) .auth_args(salt) .build()? .execute() @@ -211,12 +212,12 @@ async fn test_multisig_psm_signature_required( Ok(()) } -/// Tests that the PSM public key can be updated and then enforced. +/// Tests that the guardian public key can be updated and then enforced. #[rstest] #[case::ecdsa(AuthScheme::EcdsaK256Keccak)] #[case::falcon(AuthScheme::Falcon512Poseidon2)] #[tokio::test] -async fn test_multisig_update_psm_public_key( +async fn test_multisig_update_guardian_public_key( #[case] auth_scheme: AuthScheme, ) -> anyhow::Result<()> { let (_secret_keys, auth_schemes, public_keys, authenticators) = @@ -227,19 +228,21 @@ async fn test_multisig_update_psm_public_key( .map(|(pk, scheme)| (pk.clone(), *scheme)) .collect::>(); - let old_psm_secret_key = AuthSecretKey::new_ecdsa_k256_keccak(); - let old_psm_public_key = old_psm_secret_key.public_key(); - let old_psm_authenticator = BasicAuthenticator::new(core::slice::from_ref(&old_psm_secret_key)); + let old_guardian_secret_key = AuthSecretKey::new_ecdsa_k256_keccak(); + let old_guardian_public_key = old_guardian_secret_key.public_key(); + let old_guardian_authenticator = + BasicAuthenticator::new(core::slice::from_ref(&old_guardian_secret_key)); - let new_psm_secret_key = AuthSecretKey::new_falcon512_poseidon2(); - let new_psm_public_key = new_psm_secret_key.public_key(); - let new_psm_auth_scheme = new_psm_secret_key.auth_scheme(); - let new_psm_authenticator = BasicAuthenticator::new(core::slice::from_ref(&new_psm_secret_key)); + let new_guardian_secret_key = AuthSecretKey::new_falcon512_poseidon2(); + let new_guardian_public_key = new_guardian_secret_key.public_key(); + let new_guardian_auth_scheme = new_guardian_secret_key.auth_scheme(); + let new_guardian_authenticator = + BasicAuthenticator::new(core::slice::from_ref(&new_guardian_secret_key)); - let multisig_account = create_multisig_account_with_psm( + let multisig_account = create_multisig_account_with_guardian( 2, &approvers, - PsmConfig::new(old_psm_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), + GuardianConfig::new(old_guardian_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), 10, vec![], )?; @@ -249,18 +252,18 @@ async fn test_multisig_update_psm_public_key( .build() .unwrap(); - let new_psm_key_word: Word = new_psm_public_key.to_commitment().into(); - let new_psm_scheme_id = new_psm_auth_scheme as u32; - let update_psm_script = CodeBuilder::new() - .with_dynamically_linked_library(multisig_psm_library())? + let new_guardian_key_word: Word = new_guardian_public_key.to_commitment().into(); + let new_guardian_scheme_id = new_guardian_auth_scheme as u32; + let update_guardian_script = CodeBuilder::new() + .with_dynamically_linked_library(multisig_guardian_library())? .compile_tx_script(format!( - "begin\n push.{new_psm_key_word}\n push.{new_psm_scheme_id}\n call.::miden::standards::components::auth::multisig_psm::update_psm_public_key\n drop\n dropw\nend" + "begin\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::multisig_guardian::update_guardian_public_key\n drop\n dropw\nend" ))?; let update_salt = Word::from([Felt::new(991); 4]); let tx_context_init = mock_chain .build_tx_context(multisig_account.id(), &[], &[])? - .tx_script(update_psm_script.clone()) + .tx_script(update_guardian_script.clone()) .auth_args(update_salt) .build()?; @@ -278,10 +281,10 @@ async fn test_multisig_update_psm_public_key( .get_signature(public_keys[1].to_commitment(), &tx_summary_signing) .await?; - // PSM key rotation intentionally skips PSM signature for this update tx. - let update_psm_tx = mock_chain + // Guardian key rotation intentionally skips guardian signature for this update tx. + let update_guardian_tx = mock_chain .build_tx_context(multisig_account.id(), &[], &[])? - .tx_script(update_psm_script) + .tx_script(update_guardian_script) .add_signature(public_keys[0].to_commitment(), update_msg, sig_1) .add_signature(public_keys[1].to_commitment(), update_msg, sig_2) .auth_args(update_salt) @@ -290,23 +293,24 @@ async fn test_multisig_update_psm_public_key( .await?; let mut updated_multisig_account = multisig_account.clone(); - updated_multisig_account.apply_delta(update_psm_tx.account_delta())?; - let updated_psm_public_key = updated_multisig_account - .storage() - .get_map_item(AuthMultisigPsm::psm_public_key_slot(), Word::empty())?; - assert_eq!(updated_psm_public_key, Word::from(new_psm_public_key.to_commitment())); - let updated_psm_scheme_id = updated_multisig_account + updated_multisig_account.apply_delta(update_guardian_tx.account_delta())?; + let updated_guardian_public_key = updated_multisig_account .storage() - .get_map_item(AuthMultisigPsm::psm_scheme_id_slot(), Word::from([0u32, 0, 0, 0]))?; + .get_map_item(AuthMultisigGuardian::guardian_public_key_slot(), Word::empty())?; + assert_eq!(updated_guardian_public_key, Word::from(new_guardian_public_key.to_commitment())); + let updated_guardian_scheme_id = updated_multisig_account.storage().get_map_item( + AuthMultisigGuardian::guardian_scheme_id_slot(), + Word::from([0u32, 0, 0, 0]), + )?; assert_eq!( - updated_psm_scheme_id, - Word::from([new_psm_auth_scheme as u32, 0u32, 0u32, 0u32]) + updated_guardian_scheme_id, + Word::from([new_guardian_auth_scheme as u32, 0u32, 0u32, 0u32]) ); - mock_chain.add_pending_executed_transaction(&update_psm_tx)?; + mock_chain.add_pending_executed_transaction(&update_guardian_tx)?; mock_chain.prove_next_block()?; - // Build one tx summary after key update. Old PSM must fail and new PSM must pass on this same + // Build one tx summary after key update. Old GUARDIAN must fail and new GUARDIAN must pass on this same // transaction. let next_salt = Word::from([Felt::new(992); 4]); let tx_context_init_next = mock_chain @@ -327,31 +331,34 @@ async fn test_multisig_update_psm_public_key( let next_sig_2 = authenticators[1] .get_signature(public_keys[1].to_commitment(), &tx_summary_next_signing) .await?; - let old_psm_sig_next = old_psm_authenticator - .get_signature(old_psm_public_key.to_commitment(), &tx_summary_next_signing) + let old_guardian_sig_next = old_guardian_authenticator + .get_signature(old_guardian_public_key.to_commitment(), &tx_summary_next_signing) .await?; - let new_psm_sig_next = new_psm_authenticator - .get_signature(new_psm_public_key.to_commitment(), &tx_summary_next_signing) + let new_guardian_sig_next = new_guardian_authenticator + .get_signature(new_guardian_public_key.to_commitment(), &tx_summary_next_signing) .await?; - // Old PSM signature must fail after key update. - let with_old_psm_result = mock_chain + // Old guardian signature must fail after key update. + let with_old_guardian_result = mock_chain .build_tx_context(updated_multisig_account.id(), &[], &[])? .add_signature(public_keys[0].to_commitment(), next_msg, next_sig_1.clone()) .add_signature(public_keys[1].to_commitment(), next_msg, next_sig_2.clone()) - .add_signature(old_psm_public_key.to_commitment(), next_msg, old_psm_sig_next) + .add_signature(old_guardian_public_key.to_commitment(), next_msg, old_guardian_sig_next) .auth_args(next_salt) .build()? .execute() .await; - assert!(matches!(with_old_psm_result, Err(TransactionExecutorError::Unauthorized(_)))); + assert!(matches!( + with_old_guardian_result, + Err(TransactionExecutorError::Unauthorized(_)) + )); - // New PSM signature must pass. + // New guardian signature must pass. mock_chain .build_tx_context(updated_multisig_account.id(), &[], &[])? .add_signature(public_keys[0].to_commitment(), next_msg, next_sig_1) .add_signature(public_keys[1].to_commitment(), next_msg, next_sig_2) - .add_signature(new_psm_public_key.to_commitment(), next_msg, new_psm_sig_next) + .add_signature(new_guardian_public_key.to_commitment(), next_msg, new_guardian_sig_next) .auth_args(next_salt) .build()? .execute() @@ -360,12 +367,12 @@ async fn test_multisig_update_psm_public_key( Ok(()) } -/// Tests that `update_psm_public_key` must be the only account action in the transaction. +/// Tests that `update_guardian_public_key` must be the only account action in the transaction. #[rstest] #[case::ecdsa(AuthScheme::EcdsaK256Keccak)] #[case::falcon(AuthScheme::Falcon512Poseidon2)] #[tokio::test] -async fn test_multisig_update_psm_public_key_must_be_called_alone( +async fn test_multisig_update_guardian_public_key_must_be_called_alone( #[case] auth_scheme: AuthScheme, ) -> anyhow::Result<()> { let (_secret_keys, auth_schemes, public_keys, authenticators) = @@ -376,28 +383,29 @@ async fn test_multisig_update_psm_public_key_must_be_called_alone( .map(|(pk, scheme)| (pk.clone(), *scheme)) .collect::>(); - let old_psm_secret_key = AuthSecretKey::new_ecdsa_k256_keccak(); - let old_psm_public_key = old_psm_secret_key.public_key(); - let old_psm_authenticator = BasicAuthenticator::new(core::slice::from_ref(&old_psm_secret_key)); + let old_guardian_secret_key = AuthSecretKey::new_ecdsa_k256_keccak(); + let old_guardian_public_key = old_guardian_secret_key.public_key(); + let old_guardian_authenticator = + BasicAuthenticator::new(core::slice::from_ref(&old_guardian_secret_key)); - let new_psm_secret_key = AuthSecretKey::new_falcon512_poseidon2(); - let new_psm_public_key = new_psm_secret_key.public_key(); - let new_psm_auth_scheme = new_psm_secret_key.auth_scheme(); + let new_guardian_secret_key = AuthSecretKey::new_falcon512_poseidon2(); + let new_guardian_public_key = new_guardian_secret_key.public_key(); + let new_guardian_auth_scheme = new_guardian_secret_key.auth_scheme(); - let multisig_account = create_multisig_account_with_psm( + let multisig_account = create_multisig_account_with_guardian( 2, &approvers, - PsmConfig::new(old_psm_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), + GuardianConfig::new(old_guardian_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), 10, vec![], )?; - let new_psm_key_word: Word = new_psm_public_key.to_commitment().into(); - let new_psm_scheme_id = new_psm_auth_scheme as u32; - let update_psm_script = CodeBuilder::new() - .with_dynamically_linked_library(multisig_psm_library())? + let new_guardian_key_word: Word = new_guardian_public_key.to_commitment().into(); + let new_guardian_scheme_id = new_guardian_auth_scheme as u32; + let update_guardian_script = CodeBuilder::new() + .with_dynamically_linked_library(multisig_guardian_library())? .compile_tx_script(format!( - "begin\n push.{new_psm_key_word}\n push.{new_psm_scheme_id}\n call.::miden::standards::components::auth::multisig_psm::update_psm_public_key\n drop\n dropw\nend" + "begin\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::multisig_guardian::update_guardian_public_key\n drop\n dropw\nend" ))?; let mut mock_chain_builder = @@ -413,7 +421,7 @@ async fn test_multisig_update_psm_public_key_must_be_called_alone( let salt = Word::from([Felt::new(993); 4]); let tx_context_init = mock_chain .build_tx_context(multisig_account.id(), &[receive_asset_note.id()], &[])? - .tx_script(update_psm_script.clone()) + .tx_script(update_guardian_script.clone()) .auth_args(salt) .build()?; @@ -431,33 +439,39 @@ async fn test_multisig_update_psm_public_key_must_be_called_alone( .get_signature(public_keys[1].to_commitment(), &tx_summary_signing) .await?; - let without_psm_result = mock_chain + let without_guardian_result = mock_chain .build_tx_context(multisig_account.id(), &[receive_asset_note.id()], &[])? - .tx_script(update_psm_script.clone()) + .tx_script(update_guardian_script.clone()) .add_signature(public_keys[0].to_commitment(), msg, sig_1.clone()) .add_signature(public_keys[1].to_commitment(), msg, sig_2.clone()) .auth_args(salt) .build()? .execute() .await; - assert_transaction_executor_error!(without_psm_result, ERR_AUTH_PROCEDURE_MUST_BE_CALLED_ALONE); + assert_transaction_executor_error!( + without_guardian_result, + ERR_AUTH_PROCEDURE_MUST_BE_CALLED_ALONE + ); - let old_psm_signature = old_psm_authenticator - .get_signature(old_psm_public_key.to_commitment(), &tx_summary_signing) + let old_guardian_signature = old_guardian_authenticator + .get_signature(old_guardian_public_key.to_commitment(), &tx_summary_signing) .await?; - let with_psm_result = mock_chain + let with_guardian_result = mock_chain .build_tx_context(multisig_account.id(), &[receive_asset_note.id()], &[])? - .tx_script(update_psm_script) + .tx_script(update_guardian_script) .add_signature(public_keys[0].to_commitment(), msg, sig_1) .add_signature(public_keys[1].to_commitment(), msg, sig_2) - .add_signature(old_psm_public_key.to_commitment(), msg, old_psm_signature) + .add_signature(old_guardian_public_key.to_commitment(), msg, old_guardian_signature) .auth_args(salt) .build()? .execute() .await; - assert_transaction_executor_error!(with_psm_result, ERR_AUTH_PROCEDURE_MUST_BE_CALLED_ALONE); + assert_transaction_executor_error!( + with_guardian_result, + ERR_AUTH_PROCEDURE_MUST_BE_CALLED_ALONE + ); // Also reject rotation transactions that touch notes even when no other account procedure is // called. @@ -471,12 +485,12 @@ async fn test_multisig_update_psm_public_key_must_be_called_alone( note_recipient, ); - let new_psm_key_word: Word = new_psm_public_key.to_commitment().into(); - let new_psm_scheme_id = new_psm_auth_scheme as u32; - let update_psm_with_output_script = CodeBuilder::new() - .with_dynamically_linked_library(multisig_psm_library())? + let new_guardian_key_word: Word = new_guardian_public_key.to_commitment().into(); + let new_guardian_scheme_id = new_guardian_auth_scheme as u32; + let update_guardian_with_output_script = CodeBuilder::new() + .with_dynamically_linked_library(multisig_guardian_library())? .compile_tx_script(format!( - "use miden::protocol::output_note\nbegin\n push.{recipient}\n push.{note_type}\n push.{tag}\n exec.output_note::create\n swapdw\n dropw\n dropw\n push.{new_psm_key_word}\n push.{new_psm_scheme_id}\n call.::miden::standards::components::auth::multisig_psm::update_psm_public_key\n drop\n dropw\nend", + "use miden::protocol::output_note\nbegin\n push.{recipient}\n push.{note_type}\n push.{tag}\n exec.output_note::create\n swapdw\n dropw\n dropw\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::multisig_guardian::update_guardian_public_key\n drop\n dropw\nend", recipient = output_note.recipient().digest(), note_type = NoteType::Public as u8, tag = Felt::from(output_note.metadata().tag()), @@ -490,7 +504,7 @@ async fn test_multisig_update_psm_public_key_must_be_called_alone( let salt = Word::from([Felt::new(994); 4]); let tx_context_init = mock_chain .build_tx_context(multisig_account.id(), &[], &[])? - .tx_script(update_psm_with_output_script.clone()) + .tx_script(update_guardian_with_output_script.clone()) .add_note_script(note_script.clone()) .extend_expected_output_notes(vec![RawOutputNote::Full(output_note.clone())]) .auth_args(salt) @@ -512,7 +526,7 @@ async fn test_multisig_update_psm_public_key_must_be_called_alone( let result = mock_chain .build_tx_context(multisig_account.id(), &[], &[])? - .tx_script(update_psm_with_output_script) + .tx_script(update_guardian_with_output_script) .add_note_script(note_script) .extend_expected_output_notes(vec![RawOutputNote::Full(output_note)]) .add_signature(public_keys[0].to_commitment(), msg, sig_1) From 73401f0bb9d20ce3eb245d53a8e77c9a23545e62 Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 25 Mar 2026 17:46:14 -0300 Subject: [PATCH 2/7] fix: prefer state guardian in comments --- .../asm/account_components/auth/multisig_guardian.masm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/miden-standards/asm/account_components/auth/multisig_guardian.masm b/crates/miden-standards/asm/account_components/auth/multisig_guardian.masm index 6b7e3231c3..3f7146261a 100644 --- a/crates/miden-standards/asm/account_components/auth/multisig_guardian.masm +++ b/crates/miden-standards/asm/account_components/auth/multisig_guardian.masm @@ -1,4 +1,4 @@ -# The MASM code of the Multi-Signature Authentication Component with Guardian. +# The MASM code of the Multi-Signature Authentication component integrated with a state guardian. # # See the `AuthMultisigGuardian` Rust type's documentation for more details. From 1b268fc487168a90f828ab829fa3f6c6ffb1aa1b Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 25 Mar 2026 17:58:23 -0300 Subject: [PATCH 3/7] fix: rename guardian multisig to guarded multisig --- ...ig_guardian.masm => guarded_multisig.masm} | 4 +- ...ltisig_guardian.rs => guarded_multisig.rs} | 109 +++++++++--------- .../miden-standards/src/account/auth/mod.rs | 4 +- .../src/account/components/mod.rs | 24 ++-- .../src/account/interface/component.rs | 18 +-- .../src/account/interface/extension.rs | 6 +- crates/miden-testing/src/mock_chain/auth.rs | 23 ++-- ...ltisig_guardian.rs => guarded_multisig.rs} | 44 +++---- crates/miden-testing/tests/auth/mod.rs | 2 +- 9 files changed, 116 insertions(+), 118 deletions(-) rename crates/miden-standards/asm/account_components/auth/{multisig_guardian.masm => guarded_multisig.masm} (87%) rename crates/miden-standards/src/account/auth/{multisig_guardian.rs => guarded_multisig.rs} (85%) rename crates/miden-testing/tests/auth/{multisig_guardian.rs => guarded_multisig.rs} (93%) diff --git a/crates/miden-standards/asm/account_components/auth/multisig_guardian.masm b/crates/miden-standards/asm/account_components/auth/guarded_multisig.masm similarity index 87% rename from crates/miden-standards/asm/account_components/auth/multisig_guardian.masm rename to crates/miden-standards/asm/account_components/auth/guarded_multisig.masm index 3f7146261a..29ffded0e5 100644 --- a/crates/miden-standards/asm/account_components/auth/multisig_guardian.masm +++ b/crates/miden-standards/asm/account_components/auth/guarded_multisig.masm @@ -1,6 +1,6 @@ # The MASM code of the Multi-Signature Authentication component integrated with a state guardian. # -# See the `AuthMultisigGuardian` Rust type's documentation for more details. +# See the `AuthGuardedMultisig` Rust type's documentation for more details. use miden::standards::auth::multisig use miden::standards::auth::guardian @@ -22,7 +22,7 @@ pub use guardian::update_guardian_public_key #! #! Invocation: call @auth_script -pub proc auth_tx_multisig_guardian(salt: word) +pub proc auth_tx_guarded_multisig(salt: word) exec.multisig::auth_tx # => [TX_SUMMARY_COMMITMENT] diff --git a/crates/miden-standards/src/account/auth/multisig_guardian.rs b/crates/miden-standards/src/account/auth/guarded_multisig.rs similarity index 85% rename from crates/miden-standards/src/account/auth/multisig_guardian.rs rename to crates/miden-standards/src/account/auth/guarded_multisig.rs index f9e5199744..952c3667ea 100644 --- a/crates/miden-standards/src/account/auth/multisig_guardian.rs +++ b/crates/miden-standards/src/account/auth/guarded_multisig.rs @@ -12,7 +12,7 @@ use miden_protocol::errors::AccountError; use miden_protocol::utils::sync::LazyLock; use super::multisig::{AuthMultisig, AuthMultisigConfig}; -use crate::account::components::multisig_guardian_library; +use crate::account::components::guarded_multisig_library; // CONSTANTS // ================================================================================================ @@ -30,9 +30,9 @@ static GUARDIAN_SCHEME_ID_SLOT_NAME: LazyLock = LazyLock::new(| // MULTISIG AUTHENTICATION COMPONENT // ================================================================================================ -/// Configuration for [`AuthMultisigGuardian`] component. +/// Configuration for [`AuthGuardedMultisig`] component. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct AuthMultisigGuardianConfig { +pub struct AuthGuardedMultisigConfig { multisig: AuthMultisigConfig, guardian_config: GuardianConfig, } @@ -114,7 +114,7 @@ impl GuardianConfig { } } -impl AuthMultisigGuardianConfig { +impl AuthGuardedMultisigConfig { /// Creates a new configuration with the given approvers, default threshold and guardian signer. /// /// The `default_threshold` must be at least 1 and at most the number of approvers. @@ -169,7 +169,7 @@ impl AuthMultisigGuardianConfig { } } -/// An [`AccountComponent`] implementing a multisig authentication with a guardian. +/// An [`AccountComponent`] implementing guarded multisig authentication with a guardian. /// /// It enforces a threshold of approver signatures for every transaction, with optional /// per-procedure threshold overrides. When a guardian is configured, multisig authorization is @@ -179,17 +179,17 @@ impl AuthMultisigGuardianConfig { /// /// This component supports all account types. #[derive(Debug)] -pub struct AuthMultisigGuardian { +pub struct AuthGuardedMultisig { multisig: AuthMultisig, guardian_config: GuardianConfig, } -impl AuthMultisigGuardian { +impl AuthGuardedMultisig { /// The name of the component. - pub const NAME: &'static str = "miden::standards::components::auth::multisig_guardian"; + pub const NAME: &'static str = "miden::standards::components::auth::guarded_multisig"; - /// Creates a new [`AuthMultisigGuardian`] component from the provided configuration. - pub fn new(config: AuthMultisigGuardianConfig) -> Result { + /// Creates a new [`AuthGuardedMultisig`] component from the provided configuration. + pub fn new(config: AuthGuardedMultisigConfig) -> Result { let (multisig_config, guardian_config) = config.into_parts(); Ok(Self { multisig: AuthMultisig::new(multisig_config)?, @@ -282,16 +282,16 @@ impl AuthMultisigGuardian { AccountComponentMetadata::new(Self::NAME, AccountType::all()) .with_description( - "Multisig authentication component with guardian \ - using hybrid signature schemes", + "Guarded multisig authentication component integrated \ + with a state guardian using hybrid signature schemes", ) .with_storage_schema(storage_schema) } } -impl From for AccountComponent { - fn from(multisig: AuthMultisigGuardian) -> Self { - let AuthMultisigGuardian { multisig, guardian_config } = multisig; +impl From for AccountComponent { + fn from(multisig: AuthGuardedMultisig) -> Self { + let AuthGuardedMultisig { multisig, guardian_config } = multisig; let multisig_component = AccountComponent::from(multisig); let (guardian_slots, guardian_slot_metadata) = guardian_config.into_component_parts(); @@ -309,15 +309,16 @@ impl From for AccountComponent { StorageSchema::new(slot_schemas).expect("storage schema should be valid"); let metadata = AccountComponentMetadata::new( - AuthMultisigGuardian::NAME, + AuthGuardedMultisig::NAME, multisig_component.supported_types().clone(), ) .with_description(multisig_component.metadata().description()) .with_version(multisig_component.metadata().version().clone()) .with_storage_schema(storage_schema); - AccountComponent::new(multisig_guardian_library(), storage_slots, metadata).expect( - "Multisig auth component should satisfy the requirements of a valid account component", + AccountComponent::new(guarded_multisig_library(), storage_slots, metadata).expect( + "Guarded multisig auth component should satisfy the requirements of a valid account \ + component", ) } } @@ -336,9 +337,9 @@ mod tests { use super::*; use crate::account::wallets::BasicWallet; - /// Test multisig component setup with various configurations + /// Test guarded multisig component setup with various configurations. #[test] - fn test_multisig_component_setup() { + fn test_guarded_multisig_component_setup() { // Create test secret keys let sec_key_1 = AuthSecretKey::new_falcon512_poseidon2(); let sec_key_2 = AuthSecretKey::new_falcon512_poseidon2(); @@ -354,9 +355,9 @@ mod tests { let threshold = 2u32; - // Create multisig component - let multisig_component = AuthMultisigGuardian::new( - AuthMultisigGuardianConfig::new( + // Create guarded multisig component. + let multisig_component = AuthGuardedMultisig::new( + AuthGuardedMultisigConfig::new( approvers.clone(), threshold, GuardianConfig::new( @@ -366,9 +367,9 @@ mod tests { ) .expect("invalid multisig config"), ) - .expect("multisig component creation failed"); + .expect("guarded multisig component creation failed"); - // Build account with multisig component + // Build account with guarded multisig component. let account = AccountBuilder::new([0; 32]) .with_auth_component(multisig_component) .with_component(BasicWallet) @@ -378,7 +379,7 @@ mod tests { // Verify config slot: [threshold, num_approvers, 0, 0] let config_slot = account .storage() - .get_item(AuthMultisigGuardian::threshold_config_slot()) + .get_item(AuthGuardedMultisig::threshold_config_slot()) .expect("config storage slot access failed"); assert_eq!(config_slot, Word::from([threshold, approvers.len() as u32, 0, 0])); @@ -387,7 +388,7 @@ mod tests { let stored_pub_key = account .storage() .get_map_item( - AuthMultisigGuardian::approver_public_keys_slot(), + AuthGuardedMultisig::approver_public_keys_slot(), Word::from([i as u32, 0, 0, 0]), ) .expect("approver public key storage map access failed"); @@ -399,7 +400,7 @@ mod tests { let stored_scheme_id = account .storage() .get_map_item( - AuthMultisigGuardian::approver_scheme_ids_slot(), + AuthGuardedMultisig::approver_scheme_ids_slot(), Word::from([i as u32, 0, 0, 0]), ) .expect("approver scheme ID storage map access failed"); @@ -410,7 +411,7 @@ mod tests { let guardian_public_key = account .storage() .get_map_item( - AuthMultisigGuardian::guardian_public_key_slot(), + AuthGuardedMultisig::guardian_public_key_slot(), Word::from([0u32, 0, 0, 0]), ) .expect("guardian public key storage map access failed"); @@ -419,23 +420,23 @@ mod tests { let guardian_scheme_id = account .storage() .get_map_item( - AuthMultisigGuardian::guardian_scheme_id_slot(), + AuthGuardedMultisig::guardian_scheme_id_slot(), Word::from([0u32, 0, 0, 0]), ) .expect("guardian scheme ID storage map access failed"); assert_eq!(guardian_scheme_id, Word::from([guardian_key.auth_scheme() as u32, 0, 0, 0])); } - /// Test multisig component with minimum threshold (1 of 1) + /// Test guarded multisig component with minimum threshold (1 of 1). #[test] - fn test_multisig_component_minimum_threshold() { + fn test_guarded_multisig_component_minimum_threshold() { let pub_key = AuthSecretKey::new_ecdsa_k256_keccak().public_key().to_commitment(); let guardian_key = AuthSecretKey::new_falcon512_poseidon2(); let approvers = vec![(pub_key, AuthScheme::EcdsaK256Keccak)]; let threshold = 1u32; - let multisig_component = AuthMultisigGuardian::new( - AuthMultisigGuardianConfig::new( + let multisig_component = AuthGuardedMultisig::new( + AuthGuardedMultisigConfig::new( approvers.clone(), threshold, GuardianConfig::new( @@ -445,7 +446,7 @@ mod tests { ) .expect("invalid multisig config"), ) - .expect("multisig component creation failed"); + .expect("guarded multisig component creation failed"); let account = AccountBuilder::new([0; 32]) .with_auth_component(multisig_component) @@ -456,14 +457,14 @@ mod tests { // Verify storage layout let config_slot = account .storage() - .get_item(AuthMultisigGuardian::threshold_config_slot()) + .get_item(AuthGuardedMultisig::threshold_config_slot()) .expect("config storage slot access failed"); assert_eq!(config_slot, Word::from([threshold, approvers.len() as u32, 0, 0])); let stored_pub_key = account .storage() .get_map_item( - AuthMultisigGuardian::approver_public_keys_slot(), + AuthGuardedMultisig::approver_public_keys_slot(), Word::from([0u32, 0, 0, 0]), ) .expect("approver pub keys storage map access failed"); @@ -472,16 +473,16 @@ mod tests { let stored_scheme_id = account .storage() .get_map_item( - AuthMultisigGuardian::approver_scheme_ids_slot(), + AuthGuardedMultisig::approver_scheme_ids_slot(), Word::from([0u32, 0, 0, 0]), ) .expect("approver scheme IDs storage map access failed"); assert_eq!(stored_scheme_id, Word::from([AuthScheme::EcdsaK256Keccak as u32, 0, 0, 0])); } - /// Test multisig component setup with a guardian. + /// Test guarded multisig component setup with a guardian. #[test] - fn test_multisig_component_with_guardian() { + fn test_guarded_multisig_component_with_guardian() { let sec_key_1 = AuthSecretKey::new_falcon512_poseidon2(); let sec_key_2 = AuthSecretKey::new_falcon512_poseidon2(); let guardian_key = AuthSecretKey::new_ecdsa_k256_keccak(); @@ -491,8 +492,8 @@ mod tests { (sec_key_2.public_key().to_commitment(), sec_key_2.auth_scheme()), ]; - let multisig_component = AuthMultisigGuardian::new( - AuthMultisigGuardianConfig::new( + let multisig_component = AuthGuardedMultisig::new( + AuthGuardedMultisigConfig::new( approvers, 2, GuardianConfig::new( @@ -502,7 +503,7 @@ mod tests { ) .expect("invalid multisig config"), ) - .expect("multisig component creation failed"); + .expect("guarded multisig component creation failed"); let account = AccountBuilder::new([0; 32]) .with_auth_component(multisig_component) @@ -513,7 +514,7 @@ mod tests { let guardian_public_key = account .storage() .get_map_item( - AuthMultisigGuardian::guardian_public_key_slot(), + AuthGuardedMultisig::guardian_public_key_slot(), Word::from([0u32, 0, 0, 0]), ) .expect("guardian public key storage map access failed"); @@ -522,22 +523,22 @@ mod tests { let guardian_scheme_id = account .storage() .get_map_item( - AuthMultisigGuardian::guardian_scheme_id_slot(), + AuthGuardedMultisig::guardian_scheme_id_slot(), Word::from([0u32, 0, 0, 0]), ) .expect("guardian scheme ID storage map access failed"); assert_eq!(guardian_scheme_id, Word::from([guardian_key.auth_scheme() as u32, 0, 0, 0])); } - /// Test multisig component error cases + /// Test guarded multisig component error cases. #[test] - fn test_multisig_component_error_cases() { + fn test_guarded_multisig_component_error_cases() { let pub_key = AuthSecretKey::new_ecdsa_k256_keccak().public_key().to_commitment(); let guardian_key = AuthSecretKey::new_falcon512_poseidon2(); let approvers = vec![(pub_key, AuthScheme::EcdsaK256Keccak)]; // Test threshold > number of approvers (should fail) - let result = AuthMultisigGuardianConfig::new( + let result = AuthGuardedMultisigConfig::new( approvers, 2, GuardianConfig::new( @@ -554,9 +555,9 @@ mod tests { ); } - /// Test multisig component with duplicate approvers (should fail) + /// Test guarded multisig component with duplicate approvers (should fail). #[test] - fn test_multisig_component_duplicate_approvers() { + fn test_guarded_multisig_component_duplicate_approvers() { // Create secret keys for approvers let sec_key_1 = AuthSecretKey::new_ecdsa_k256_keccak(); let sec_key_2 = AuthSecretKey::new_ecdsa_k256_keccak(); @@ -569,7 +570,7 @@ mod tests { (sec_key_2.public_key().to_commitment(), sec_key_2.auth_scheme()), ]; - let result = AuthMultisigGuardianConfig::new( + let result = AuthGuardedMultisigConfig::new( approvers, 2, GuardianConfig::new( @@ -585,9 +586,9 @@ mod tests { ); } - /// Test multisig component rejects a guardian key which is already an approver. + /// Test guarded multisig component rejects a guardian key which is already an approver. #[test] - fn test_multisig_component_guardian_not_approver() { + fn test_guarded_multisig_component_guardian_not_approver() { let sec_key_1 = AuthSecretKey::new_ecdsa_k256_keccak(); let sec_key_2 = AuthSecretKey::new_ecdsa_k256_keccak(); @@ -596,7 +597,7 @@ mod tests { (sec_key_2.public_key().to_commitment(), sec_key_2.auth_scheme()), ]; - let result = AuthMultisigGuardianConfig::new( + let result = AuthGuardedMultisigConfig::new( approvers, 2, GuardianConfig::new(sec_key_1.public_key().to_commitment(), sec_key_1.auth_scheme()), diff --git a/crates/miden-standards/src/account/auth/mod.rs b/crates/miden-standards/src/account/auth/mod.rs index 597d099c76..4a526bb77d 100644 --- a/crates/miden-standards/src/account/auth/mod.rs +++ b/crates/miden-standards/src/account/auth/mod.rs @@ -10,5 +10,5 @@ pub use singlesig_acl::{AuthSingleSigAcl, AuthSingleSigAclConfig}; mod multisig; pub use multisig::{AuthMultisig, AuthMultisigConfig}; -mod multisig_guardian; -pub use multisig_guardian::{AuthMultisigGuardian, AuthMultisigGuardianConfig, GuardianConfig}; +mod guarded_multisig; +pub use guarded_multisig::{AuthGuardedMultisig, AuthGuardedMultisigConfig, GuardianConfig}; diff --git a/crates/miden-standards/src/account/components/mod.rs b/crates/miden-standards/src/account/components/mod.rs index 28a933396c..723cbf5d14 100644 --- a/crates/miden-standards/src/account/components/mod.rs +++ b/crates/miden-standards/src/account/components/mod.rs @@ -60,13 +60,13 @@ static MULTISIG_LIBRARY: LazyLock = LazyLock::new(|| { Library::read_from_bytes(bytes).expect("Shipped Multisig library is well-formed") }); -/// Initialize the Multisig Guardian library only once. -static MULTISIG_GUARDIAN_LIBRARY: LazyLock = LazyLock::new(|| { +/// Initialize the Guarded Multisig library only once. +static GUARDED_MULTISIG_LIBRARY: LazyLock = LazyLock::new(|| { let bytes = include_bytes!(concat!( env!("OUT_DIR"), - "/assets/account_components/auth/multisig_guardian.masl" + "/assets/account_components/auth/guarded_multisig.masl" )); - Library::read_from_bytes(bytes).expect("Shipped Multisig Guardian library is well-formed") + Library::read_from_bytes(bytes).expect("Shipped Guarded Multisig library is well-formed") }); // Initialize the NoAuth library only once. @@ -165,9 +165,9 @@ pub fn multisig_library() -> Library { MULTISIG_LIBRARY.clone() } -/// Returns the Multisig Guardian Library. -pub fn multisig_guardian_library() -> Library { - MULTISIG_GUARDIAN_LIBRARY.clone() +/// Returns the Guarded Multisig Library. +pub fn guarded_multisig_library() -> Library { + GUARDED_MULTISIG_LIBRARY.clone() } /// Returns the NoAuth Library. @@ -187,7 +187,7 @@ pub enum StandardAccountComponent { AuthSingleSig, AuthSingleSigAcl, AuthMultisig, - AuthMultisigGuardian, + AuthGuardedMultisig, AuthNoAuth, } @@ -201,7 +201,7 @@ impl StandardAccountComponent { Self::AuthSingleSig => SINGLESIG_LIBRARY.as_ref(), Self::AuthSingleSigAcl => SINGLESIG_ACL_LIBRARY.as_ref(), Self::AuthMultisig => MULTISIG_LIBRARY.as_ref(), - Self::AuthMultisigGuardian => MULTISIG_GUARDIAN_LIBRARY.as_ref(), + Self::AuthGuardedMultisig => GUARDED_MULTISIG_LIBRARY.as_ref(), Self::AuthNoAuth => NO_AUTH_LIBRARY.as_ref(), }; @@ -254,8 +254,8 @@ impl StandardAccountComponent { Self::AuthMultisig => { component_interface_vec.push(AccountComponentInterface::AuthMultisig) }, - Self::AuthMultisigGuardian => { - component_interface_vec.push(AccountComponentInterface::AuthMultisigGuardian) + Self::AuthGuardedMultisig => { + component_interface_vec.push(AccountComponentInterface::AuthGuardedMultisig) }, Self::AuthNoAuth => { component_interface_vec.push(AccountComponentInterface::AuthNoAuth) @@ -275,7 +275,7 @@ impl StandardAccountComponent { Self::NetworkFungibleFaucet.extract_component(procedures_set, component_interface_vec); Self::AuthSingleSig.extract_component(procedures_set, component_interface_vec); Self::AuthSingleSigAcl.extract_component(procedures_set, component_interface_vec); - Self::AuthMultisigGuardian.extract_component(procedures_set, component_interface_vec); + Self::AuthGuardedMultisig.extract_component(procedures_set, component_interface_vec); Self::AuthMultisig.extract_component(procedures_set, component_interface_vec); Self::AuthNoAuth.extract_component(procedures_set, component_interface_vec); } diff --git a/crates/miden-standards/src/account/interface/component.rs b/crates/miden-standards/src/account/interface/component.rs index 271d23ee00..6ce052af26 100644 --- a/crates/miden-standards/src/account/interface/component.rs +++ b/crates/miden-standards/src/account/interface/component.rs @@ -7,7 +7,7 @@ use miden_protocol::note::PartialNote; use miden_protocol::{Felt, Word}; use crate::AuthMethod; -use crate::account::auth::{AuthMultisig, AuthMultisigGuardian, AuthSingleSig, AuthSingleSigAcl}; +use crate::account::auth::{AuthGuardedMultisig, AuthMultisig, AuthSingleSig, AuthSingleSigAcl}; use crate::account::interface::AccountInterfaceError; // ACCOUNT COMPONENT INTERFACE @@ -34,8 +34,8 @@ pub enum AccountComponentInterface { /// [`AuthMultisig`][crate::account::auth::AuthMultisig] module. AuthMultisig, /// Exposes procedures from the - /// [`AuthMultisigGuardian`][crate::account::auth::AuthMultisigGuardian] module. - AuthMultisigGuardian, + /// [`AuthGuardedMultisig`][crate::account::auth::AuthGuardedMultisig] module. + AuthGuardedMultisig, /// Exposes procedures from the [`NoAuth`][crate::account::auth::NoAuth] module. /// /// This authentication scheme provides no cryptographic authentication and only increments @@ -64,7 +64,7 @@ impl AccountComponentInterface { AccountComponentInterface::AuthSingleSig => "SingleSig".to_string(), AccountComponentInterface::AuthSingleSigAcl => "SingleSig ACL".to_string(), AccountComponentInterface::AuthMultisig => "Multisig".to_string(), - AccountComponentInterface::AuthMultisigGuardian => "Multisig Guardian".to_string(), + AccountComponentInterface::AuthGuardedMultisig => "Guarded Multisig".to_string(), AccountComponentInterface::AuthNoAuth => "No Auth".to_string(), AccountComponentInterface::Custom(proc_root_vec) => { let result = proc_root_vec @@ -86,7 +86,7 @@ impl AccountComponentInterface { AccountComponentInterface::AuthSingleSig | AccountComponentInterface::AuthSingleSigAcl | AccountComponentInterface::AuthMultisig - | AccountComponentInterface::AuthMultisigGuardian + | AccountComponentInterface::AuthGuardedMultisig | AccountComponentInterface::AuthNoAuth ) } @@ -112,12 +112,12 @@ impl AccountComponentInterface { AuthMultisig::approver_scheme_ids_slot(), )] }, - AccountComponentInterface::AuthMultisigGuardian => { + AccountComponentInterface::AuthGuardedMultisig => { vec![extract_multisig_auth_method( storage, - AuthMultisigGuardian::threshold_config_slot(), - AuthMultisigGuardian::approver_public_keys_slot(), - AuthMultisigGuardian::approver_scheme_ids_slot(), + AuthGuardedMultisig::threshold_config_slot(), + AuthGuardedMultisig::approver_public_keys_slot(), + AuthGuardedMultisig::approver_scheme_ids_slot(), )] }, AccountComponentInterface::AuthNoAuth => vec![AuthMethod::NoAuth], diff --git a/crates/miden-standards/src/account/interface/extension.rs b/crates/miden-standards/src/account/interface/extension.rs index 340bcba485..d842f6947c 100644 --- a/crates/miden-standards/src/account/interface/extension.rs +++ b/crates/miden-standards/src/account/interface/extension.rs @@ -11,7 +11,7 @@ use miden_protocol::note::{Note, NoteScript}; use crate::AuthMethod; use crate::account::components::{ StandardAccountComponent, basic_fungible_faucet_library, basic_wallet_library, - multisig_guardian_library, multisig_library, network_fungible_faucet_library, no_auth_library, + guarded_multisig_library, multisig_library, network_fungible_faucet_library, no_auth_library, singlesig_acl_library, singlesig_library, }; use crate::account::interface::{ @@ -105,9 +105,9 @@ impl AccountInterfaceExt for AccountInterface { component_proc_digests .extend(multisig_library().mast_forest().procedure_digests()); }, - AccountComponentInterface::AuthMultisigGuardian => { + AccountComponentInterface::AuthGuardedMultisig => { component_proc_digests - .extend(multisig_guardian_library().mast_forest().procedure_digests()); + .extend(guarded_multisig_library().mast_forest().procedure_digests()); }, AccountComponentInterface::AuthNoAuth => { component_proc_digests diff --git a/crates/miden-testing/src/mock_chain/auth.rs b/crates/miden-testing/src/mock_chain/auth.rs index 2036beb784..98cf632d6e 100644 --- a/crates/miden-testing/src/mock_chain/auth.rs +++ b/crates/miden-testing/src/mock_chain/auth.rs @@ -7,7 +7,7 @@ use miden_protocol::account::AccountComponent; use miden_protocol::account::auth::{AuthScheme, AuthSecretKey, PublicKeyCommitment}; use miden_protocol::testing::noop_auth_component::NoopAuthComponent; use miden_standards::account::auth::{ - AuthMultisig, AuthMultisigConfig, AuthMultisigGuardian, AuthMultisigGuardianConfig, + AuthGuardedMultisig, AuthGuardedMultisigConfig, AuthMultisig, AuthMultisigConfig, AuthSingleSig, AuthSingleSigAcl, AuthSingleSigAclConfig, GuardianConfig, }; use miden_standards::testing::account_component::{ @@ -31,8 +31,8 @@ pub enum Auth { proc_threshold_map: Vec<(Word, u32)>, }, - /// Multisig with a guardian. - MultisigGuardian { + /// Guarded multisig. + GuardedMultisig { threshold: u32, approvers: Vec<(PublicKeyCommitment, AuthScheme)>, guardian_config: GuardianConfig, @@ -89,21 +89,18 @@ impl Auth { (component, None) }, - Auth::MultisigGuardian { + Auth::GuardedMultisig { threshold, approvers, guardian_config, proc_threshold_map, } => { - let config = AuthMultisigGuardianConfig::new( - approvers.clone(), - *threshold, - *guardian_config, - ) - .and_then(|cfg| cfg.with_proc_thresholds(proc_threshold_map.clone())) - .expect("invalid multisig guardian config"); - let component = AuthMultisigGuardian::new(config) - .expect("multisig guardian component creation failed") + let config = + AuthGuardedMultisigConfig::new(approvers.clone(), *threshold, *guardian_config) + .and_then(|cfg| cfg.with_proc_thresholds(proc_threshold_map.clone())) + .expect("invalid guarded multisig config"); + let component = AuthGuardedMultisig::new(config) + .expect("guarded multisig component creation failed") .into(); (component, None) diff --git a/crates/miden-testing/tests/auth/multisig_guardian.rs b/crates/miden-testing/tests/auth/guarded_multisig.rs similarity index 93% rename from crates/miden-testing/tests/auth/multisig_guardian.rs rename to crates/miden-testing/tests/auth/guarded_multisig.rs index 9e1608f67b..d56b03936c 100644 --- a/crates/miden-testing/tests/auth/multisig_guardian.rs +++ b/crates/miden-testing/tests/auth/guarded_multisig.rs @@ -10,9 +10,9 @@ use miden_protocol::testing::account_id::{ use miden_protocol::transaction::RawOutputNote; use miden_protocol::{Felt, Word}; use miden_standards::account::auth::{ - AuthMultisigGuardian, AuthMultisigGuardianConfig, GuardianConfig, + AuthGuardedMultisig, AuthGuardedMultisigConfig, GuardianConfig, }; -use miden_standards::account::components::multisig_guardian_library; +use miden_standards::account::components::guarded_multisig_library; use miden_standards::account::wallets::BasicWallet; use miden_standards::code_builder::CodeBuilder; use miden_standards::errors::standards::{ @@ -71,8 +71,8 @@ fn setup_keys_and_authenticators_with_scheme( Ok((secret_keys, auth_schemes, public_keys, authenticators)) } -/// Creates a multisig account configured with a guardian signer. -fn create_multisig_account_with_guardian( +/// Creates a guarded multisig account configured with a guardian signer. +fn create_guarded_multisig_account( threshold: u32, approvers: &[(PublicKey, AuthScheme)], guardian: GuardianConfig, @@ -84,11 +84,11 @@ fn create_multisig_account_with_guardian( .map(|(pub_key, auth_scheme)| (pub_key.to_commitment(), *auth_scheme)) .collect(); - let config = AuthMultisigGuardianConfig::new(approvers, threshold, guardian)? + let config = AuthGuardedMultisigConfig::new(approvers, threshold, guardian)? .with_proc_thresholds(proc_threshold_map)?; let multisig_account = AccountBuilder::new([0; 32]) - .with_auth_component(AuthMultisigGuardian::new(config)?) + .with_auth_component(AuthGuardedMultisig::new(config)?) .with_component(BasicWallet) .account_type(AccountType::RegularAccountUpdatableCode) .storage_mode(AccountStorageMode::Public) @@ -102,13 +102,13 @@ fn create_multisig_account_with_guardian( // TESTS // ================================================================================================ -/// Tests that multisig authentication requires an additional guardian signature when +/// Tests that guarded multisig authentication requires an additional guardian signature when /// configured. #[rstest] #[case::ecdsa(AuthScheme::EcdsaK256Keccak)] #[case::falcon(AuthScheme::Falcon512Poseidon2)] #[tokio::test] -async fn test_multisig_guardian_signature_required( +async fn test_guarded_multisig_signature_required( #[case] auth_scheme: AuthScheme, ) -> anyhow::Result<()> { let (_secret_keys, auth_schemes, public_keys, authenticators) = @@ -124,7 +124,7 @@ async fn test_multisig_guardian_signature_required( let guardian_authenticator = BasicAuthenticator::new(core::slice::from_ref(&guardian_secret_key)); - let mut multisig_account = create_multisig_account_with_guardian( + let mut multisig_account = create_guarded_multisig_account( 2, &approvers, GuardianConfig::new(guardian_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), @@ -212,12 +212,12 @@ async fn test_multisig_guardian_signature_required( Ok(()) } -/// Tests that the guardian public key can be updated and then enforced. +/// Tests that the guardian public key can be updated and then enforced for guarded multisig. #[rstest] #[case::ecdsa(AuthScheme::EcdsaK256Keccak)] #[case::falcon(AuthScheme::Falcon512Poseidon2)] #[tokio::test] -async fn test_multisig_update_guardian_public_key( +async fn test_guarded_multisig_update_guardian_public_key( #[case] auth_scheme: AuthScheme, ) -> anyhow::Result<()> { let (_secret_keys, auth_schemes, public_keys, authenticators) = @@ -239,7 +239,7 @@ async fn test_multisig_update_guardian_public_key( let new_guardian_authenticator = BasicAuthenticator::new(core::slice::from_ref(&new_guardian_secret_key)); - let multisig_account = create_multisig_account_with_guardian( + let multisig_account = create_guarded_multisig_account( 2, &approvers, GuardianConfig::new(old_guardian_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), @@ -255,9 +255,9 @@ async fn test_multisig_update_guardian_public_key( let new_guardian_key_word: Word = new_guardian_public_key.to_commitment().into(); let new_guardian_scheme_id = new_guardian_auth_scheme as u32; let update_guardian_script = CodeBuilder::new() - .with_dynamically_linked_library(multisig_guardian_library())? + .with_dynamically_linked_library(guarded_multisig_library())? .compile_tx_script(format!( - "begin\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::multisig_guardian::update_guardian_public_key\n drop\n dropw\nend" + "begin\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::guarded_multisig::update_guardian_public_key\n drop\n dropw\nend" ))?; let update_salt = Word::from([Felt::new(991); 4]); @@ -296,10 +296,10 @@ async fn test_multisig_update_guardian_public_key( updated_multisig_account.apply_delta(update_guardian_tx.account_delta())?; let updated_guardian_public_key = updated_multisig_account .storage() - .get_map_item(AuthMultisigGuardian::guardian_public_key_slot(), Word::empty())?; + .get_map_item(AuthGuardedMultisig::guardian_public_key_slot(), Word::empty())?; assert_eq!(updated_guardian_public_key, Word::from(new_guardian_public_key.to_commitment())); let updated_guardian_scheme_id = updated_multisig_account.storage().get_map_item( - AuthMultisigGuardian::guardian_scheme_id_slot(), + AuthGuardedMultisig::guardian_scheme_id_slot(), Word::from([0u32, 0, 0, 0]), )?; assert_eq!( @@ -372,7 +372,7 @@ async fn test_multisig_update_guardian_public_key( #[case::ecdsa(AuthScheme::EcdsaK256Keccak)] #[case::falcon(AuthScheme::Falcon512Poseidon2)] #[tokio::test] -async fn test_multisig_update_guardian_public_key_must_be_called_alone( +async fn test_guarded_multisig_update_guardian_public_key_must_be_called_alone( #[case] auth_scheme: AuthScheme, ) -> anyhow::Result<()> { let (_secret_keys, auth_schemes, public_keys, authenticators) = @@ -392,7 +392,7 @@ async fn test_multisig_update_guardian_public_key_must_be_called_alone( let new_guardian_public_key = new_guardian_secret_key.public_key(); let new_guardian_auth_scheme = new_guardian_secret_key.auth_scheme(); - let multisig_account = create_multisig_account_with_guardian( + let multisig_account = create_guarded_multisig_account( 2, &approvers, GuardianConfig::new(old_guardian_public_key.to_commitment(), AuthScheme::EcdsaK256Keccak), @@ -403,9 +403,9 @@ async fn test_multisig_update_guardian_public_key_must_be_called_alone( let new_guardian_key_word: Word = new_guardian_public_key.to_commitment().into(); let new_guardian_scheme_id = new_guardian_auth_scheme as u32; let update_guardian_script = CodeBuilder::new() - .with_dynamically_linked_library(multisig_guardian_library())? + .with_dynamically_linked_library(guarded_multisig_library())? .compile_tx_script(format!( - "begin\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::multisig_guardian::update_guardian_public_key\n drop\n dropw\nend" + "begin\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::guarded_multisig::update_guardian_public_key\n drop\n dropw\nend" ))?; let mut mock_chain_builder = @@ -488,9 +488,9 @@ async fn test_multisig_update_guardian_public_key_must_be_called_alone( let new_guardian_key_word: Word = new_guardian_public_key.to_commitment().into(); let new_guardian_scheme_id = new_guardian_auth_scheme as u32; let update_guardian_with_output_script = CodeBuilder::new() - .with_dynamically_linked_library(multisig_guardian_library())? + .with_dynamically_linked_library(guarded_multisig_library())? .compile_tx_script(format!( - "use miden::protocol::output_note\nbegin\n push.{recipient}\n push.{note_type}\n push.{tag}\n exec.output_note::create\n swapdw\n dropw\n dropw\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::multisig_guardian::update_guardian_public_key\n drop\n dropw\nend", + "use miden::protocol::output_note\nbegin\n push.{recipient}\n push.{note_type}\n push.{tag}\n exec.output_note::create\n swapdw\n dropw\n dropw\n push.{new_guardian_key_word}\n push.{new_guardian_scheme_id}\n call.::miden::standards::components::auth::guarded_multisig::update_guardian_public_key\n drop\n dropw\nend", recipient = output_note.recipient().digest(), note_type = NoteType::Public as u8, tag = Felt::from(output_note.metadata().tag()), diff --git a/crates/miden-testing/tests/auth/mod.rs b/crates/miden-testing/tests/auth/mod.rs index c03d07fecb..752dfd9700 100644 --- a/crates/miden-testing/tests/auth/mod.rs +++ b/crates/miden-testing/tests/auth/mod.rs @@ -4,4 +4,4 @@ mod multisig; mod hybrid_multisig; -mod multisig_guardian; +mod guarded_multisig; From 3a8285461d1a4fdd999a693fe140df270d30ba72 Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 25 Mar 2026 18:03:43 -0300 Subject: [PATCH 4/7] fix: restore changelog note and apply nightly formatting --- CHANGELOG.md | 1 + .../src/account/auth/guarded_multisig.rs | 12 ++++++++++-- .../src/account/auth/multisig.rs | 13 +++++++++++-- .../src/account/interface/extension.rs | 16 ++++++++++++---- crates/miden-testing/src/mock_chain/auth.rs | 13 ++++++++++--- .../tests/auth/guarded_multisig.rs | 17 ++++++++++++----- 6 files changed, 56 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aad75832a3..fab43db6ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ ### Changes - [BREAKING] Renamed the multisig PSM auth component, procedures, storage paths, and related APIs from `psm` to `guardian`. +- [BREAKING] Renamed the guarded multisig component-facing APIs from `multisig_guardian` / `AuthMultisigGuardian` to `guarded_multisig` / `AuthGuardedMultisig`, while retaining the `guardian` auth namespace and guardian-specific procedures. - Migrated to miden-vm v0.22 and miden-crypto v0.23 ([#2644](https://github.com/0xMiden/protocol/pull/2644)). - [BREAKING] Renamed `AccountComponent::get_procedures()` to `procedures()`, returning `impl Iterator` ([#2597](https://github.com/0xMiden/protocol/pull/2597)). - [BREAKING] Removed `NoteAssets::add_asset`; `OutputNoteBuilder` now accumulates assets in a `Vec` and computes the commitment only when `build()` is called, avoiding rehashing on every asset addition. ([#2577](https://github.com/0xMiden/protocol/pull/2577)) diff --git a/crates/miden-standards/src/account/auth/guarded_multisig.rs b/crates/miden-standards/src/account/auth/guarded_multisig.rs index 952c3667ea..179ef4f7a0 100644 --- a/crates/miden-standards/src/account/auth/guarded_multisig.rs +++ b/crates/miden-standards/src/account/auth/guarded_multisig.rs @@ -3,10 +3,18 @@ use alloc::vec::Vec; use miden_protocol::Word; use miden_protocol::account::auth::{AuthScheme, PublicKeyCommitment}; use miden_protocol::account::component::{ - AccountComponentMetadata, SchemaType, StorageSchema, StorageSlotSchema, + AccountComponentMetadata, + SchemaType, + StorageSchema, + StorageSlotSchema, }; use miden_protocol::account::{ - AccountComponent, AccountType, StorageMap, StorageMapKey, StorageSlot, StorageSlotName, + AccountComponent, + AccountType, + StorageMap, + StorageMapKey, + StorageSlot, + StorageSlotName, }; use miden_protocol::errors::AccountError; use miden_protocol::utils::sync::LazyLock; diff --git a/crates/miden-standards/src/account/auth/multisig.rs b/crates/miden-standards/src/account/auth/multisig.rs index d0437f1a58..edcddf5709 100644 --- a/crates/miden-standards/src/account/auth/multisig.rs +++ b/crates/miden-standards/src/account/auth/multisig.rs @@ -4,10 +4,19 @@ use alloc::vec::Vec; use miden_protocol::Word; use miden_protocol::account::auth::{AuthScheme, PublicKeyCommitment}; use miden_protocol::account::component::{ - AccountComponentMetadata, FeltSchema, SchemaType, StorageSchema, StorageSlotSchema, + AccountComponentMetadata, + FeltSchema, + SchemaType, + StorageSchema, + StorageSlotSchema, }; use miden_protocol::account::{ - AccountComponent, AccountType, StorageMap, StorageMapKey, StorageSlot, StorageSlotName, + AccountComponent, + AccountType, + StorageMap, + StorageMapKey, + StorageSlot, + StorageSlotName, }; use miden_protocol::errors::AccountError; use miden_protocol::utils::sync::LazyLock; diff --git a/crates/miden-standards/src/account/interface/extension.rs b/crates/miden-standards/src/account/interface/extension.rs index d842f6947c..ebeac7355e 100644 --- a/crates/miden-standards/src/account/interface/extension.rs +++ b/crates/miden-standards/src/account/interface/extension.rs @@ -10,12 +10,20 @@ use miden_protocol::note::{Note, NoteScript}; use crate::AuthMethod; use crate::account::components::{ - StandardAccountComponent, basic_fungible_faucet_library, basic_wallet_library, - guarded_multisig_library, multisig_library, network_fungible_faucet_library, no_auth_library, - singlesig_acl_library, singlesig_library, + StandardAccountComponent, + basic_fungible_faucet_library, + basic_wallet_library, + guarded_multisig_library, + multisig_library, + network_fungible_faucet_library, + no_auth_library, + singlesig_acl_library, + singlesig_library, }; use crate::account::interface::{ - AccountComponentInterface, AccountInterface, NoteAccountCompatibility, + AccountComponentInterface, + AccountInterface, + NoteAccountCompatibility, }; use crate::note::StandardNote; diff --git a/crates/miden-testing/src/mock_chain/auth.rs b/crates/miden-testing/src/mock_chain/auth.rs index 98cf632d6e..566d0904c9 100644 --- a/crates/miden-testing/src/mock_chain/auth.rs +++ b/crates/miden-testing/src/mock_chain/auth.rs @@ -7,11 +7,18 @@ use miden_protocol::account::AccountComponent; use miden_protocol::account::auth::{AuthScheme, AuthSecretKey, PublicKeyCommitment}; use miden_protocol::testing::noop_auth_component::NoopAuthComponent; use miden_standards::account::auth::{ - AuthGuardedMultisig, AuthGuardedMultisigConfig, AuthMultisig, AuthMultisigConfig, - AuthSingleSig, AuthSingleSigAcl, AuthSingleSigAclConfig, GuardianConfig, + AuthGuardedMultisig, + AuthGuardedMultisigConfig, + AuthMultisig, + AuthMultisigConfig, + AuthSingleSig, + AuthSingleSigAcl, + AuthSingleSigAclConfig, + GuardianConfig, }; use miden_standards::testing::account_component::{ - ConditionalAuthComponent, IncrNonceAuthComponent, + ConditionalAuthComponent, + IncrNonceAuthComponent, }; use miden_tx::auth::BasicAuthenticator; use rand::SeedableRng; diff --git a/crates/miden-testing/tests/auth/guarded_multisig.rs b/crates/miden-testing/tests/auth/guarded_multisig.rs index d56b03936c..13bb9ae2aa 100644 --- a/crates/miden-testing/tests/auth/guarded_multisig.rs +++ b/crates/miden-testing/tests/auth/guarded_multisig.rs @@ -1,16 +1,23 @@ use miden_protocol::account::auth::{AuthScheme, AuthSecretKey, PublicKey}; use miden_protocol::account::{ - Account, AccountBuilder, AccountId, AccountStorageMode, AccountType, + Account, + AccountBuilder, + AccountId, + AccountStorageMode, + AccountType, }; use miden_protocol::asset::FungibleAsset; use miden_protocol::note::{Note, NoteAssets, NoteMetadata, NoteRecipient, NoteStorage, NoteType}; use miden_protocol::testing::account_id::{ - ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, + ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, + ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, }; use miden_protocol::transaction::RawOutputNote; use miden_protocol::{Felt, Word}; use miden_standards::account::auth::{ - AuthGuardedMultisig, AuthGuardedMultisigConfig, GuardianConfig, + AuthGuardedMultisig, + AuthGuardedMultisigConfig, + GuardianConfig, }; use miden_standards::account::components::guarded_multisig_library; use miden_standards::account::wallets::BasicWallet; @@ -310,8 +317,8 @@ async fn test_guarded_multisig_update_guardian_public_key( mock_chain.add_pending_executed_transaction(&update_guardian_tx)?; mock_chain.prove_next_block()?; - // Build one tx summary after key update. Old GUARDIAN must fail and new GUARDIAN must pass on this same - // transaction. + // Build one tx summary after key update. Old GUARDIAN must fail and new GUARDIAN must pass on + // this same transaction. let next_salt = Word::from([Felt::new(992); 4]); let tx_context_init_next = mock_chain .build_tx_context(updated_multisig_account.id(), &[], &[])? From 8e9e966917fa1c9b2462e37d1f946e4127c6aa38 Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 26 Mar 2026 16:46:42 -0300 Subject: [PATCH 5/7] fix: move guardian rename changelog notes to v0.15 --- CHANGELOG.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fab43db6ad..3afa96a79b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Changes - [BREAKING] Renamed `ProvenBatch::new` to `new_unchecked` ([#2687](https://github.com/0xMiden/miden-base/issues/2687)). +- [BREAKING] Renamed the multisig PSM auth component, procedures, storage paths, and related APIs from `psm` to `guardian`. +- [BREAKING] Renamed the guarded multisig component-facing APIs from `multisig_guardian` / `AuthMultisigGuardian` to `guarded_multisig` / `AuthGuardedMultisig`, while retaining the `guardian` auth namespace and guardian-specific procedures. ## 0.14.0 (2026-03-23) @@ -49,16 +51,6 @@ ### Changes -- [BREAKING] Renamed the multisig PSM auth component, procedures, storage paths, and related APIs from `psm` to `guardian`. -- [BREAKING] Renamed the guarded multisig component-facing APIs from `multisig_guardian` / `AuthMultisigGuardian` to `guarded_multisig` / `AuthGuardedMultisig`, while retaining the `guardian` auth namespace and guardian-specific procedures. -- Migrated to miden-vm v0.22 and miden-crypto v0.23 ([#2644](https://github.com/0xMiden/protocol/pull/2644)). -- [BREAKING] Renamed `AccountComponent::get_procedures()` to `procedures()`, returning `impl Iterator` ([#2597](https://github.com/0xMiden/protocol/pull/2597)). -- [BREAKING] Removed `NoteAssets::add_asset`; `OutputNoteBuilder` now accumulates assets in a `Vec` and computes the commitment only when `build()` is called, avoiding rehashing on every asset addition. ([#2577](https://github.com/0xMiden/protocol/pull/2577)) -- [BREAKING] Made `supported_types` a required parameter of `AccountComponentMetadata::new()`; removed `with_supported_type`, `with_supported_types`, `with_supports_all_types`, and `with_supports_regular_types` builder methods; added `AccountType::all()` and `AccountType::regular()` helpers ([#2554](https://github.com/0xMiden/protocol/pull/2554)). -- [BREAKING] Migrated to miden-vm 0.21 and miden-crypto 0.22 ([#2508](https://github.com/0xMiden/miden-base/pull/2508)). -- [BREAKING] The stack orientation changed from big-endian to little-endian - see PR description ([#2508](https://github.com/0xMiden/miden-base/pull/2508)). -- [BREAKING] The native hash function changed from RPO256 to Poseidon2 - see PR description ([#2508](https://github.com/0xMiden/miden-base/pull/2508)). -- Introduced `StorageMapKey` and `StorageMapKeyHash` Word wrappers for type-safe storage map key handling ([#2431](https://github.com/0xMiden/miden-base/pull/2431)). - [BREAKING] Renamed `NoteInputs` to `NoteStorage` to better reflect that values are stored data associated with a note rather than inputs ([#1662](https://github.com/0xMiden/miden-base/issues/1662), [#2316](https://github.com/0xMiden/miden-base/issues/2316)). - Introduced NOTE_MAX_SIZE (256 KiB) and enforce it on individual output notes ([#2205](https://github.com/0xMiden/miden-base/pull/2205), [#2651](https://github.com/0xMiden/miden-base/pull/2651)). - Restructured `miden-agglayer/asm` directory to separate bridge and faucet into per-component libraries, preventing cross-component procedure exposure ([#2294](https://github.com/0xMiden/miden-base/issues/2294)). From cac1568d4e8001189d2751ab1adf6e508aa1b560 Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 26 Mar 2026 16:50:23 -0300 Subject: [PATCH 6/7] style: clarify guardian masm comments --- .../asm/standards/auth/guardian.masm | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/crates/miden-standards/asm/standards/auth/guardian.masm b/crates/miden-standards/asm/standards/auth/guardian.masm index 7b3bee2f1b..73f2322b73 100644 --- a/crates/miden-standards/asm/standards/auth/guardian.masm +++ b/crates/miden-standards/asm/standards/auth/guardian.masm @@ -1,8 +1,8 @@ -# Guardian account component. +# State Guardian account component. # This component is composed into account auth flows especially for multisig and adds # an extra signature check by a dedicated guardian signer. # -# A guardian can help coordinate state availability for private accounts. +# A state guardian can help coordinate state availability for private accounts. use miden::protocol::auth::AUTH_UNAUTHORIZED_EVENT use miden::protocol::native_account @@ -15,8 +15,8 @@ use miden::standards::auth::signature # - If `update_guardian_public_key` is the only non-auth account procedure called in the current # transaction, `verify_signature` skips the guardian signature check so key rotation can proceed # without the old guardian signer. -# - `update_guardian_public_key` rotates the guardian public key and corresponding scheme id using the fixed -# map key `GUARDIAN_MAP_KEY`. +# - `update_guardian_public_key` rotates the guardian public key and corresponding +# scheme id using the fixed map key `GUARDIAN_MAP_KEY`. # CONSTANTS @@ -37,7 +37,8 @@ use miden::standards::auth::signature # Map entries: [GUARDIAN_MAP_KEY] => [GUARDIAN_PUBLIC_KEY] const GUARDIAN_PUBLIC_KEYS_SLOT = word("miden::standards::auth::guardian::pub_key") -# The slot in this component's storage layout where the scheme id for the corresponding guardian public key map is stored. +# The slot in this component's storage layout where the scheme id for the corresponding guardian +# public key map is stored. # Map entries: [GUARDIAN_MAP_KEY] => [scheme_id, 0, 0, 0] const GUARDIAN_SCHEME_ID_SLOT = word("miden::standards::auth::guardian::scheme") @@ -75,7 +76,8 @@ pub proc update_guardian_public_key(new_guardian_scheme_id: felt, new_guardian_p # => [GUARDIAN_MAP_KEY, NEW_GUARDIAN_PUBLIC_KEY] push.GUARDIAN_PUBLIC_KEYS_SLOT[0..2] - # => [guardian_pubkeys_slot_prefix, guardian_pubkeys_slot_suffix, GUARDIAN_MAP_KEY, NEW_GUARDIAN_PUBLIC_KEY] + # => [guardian_pubkeys_slot_prefix, guardian_pubkeys_slot_suffix, + # GUARDIAN_MAP_KEY, NEW_GUARDIAN_PUBLIC_KEY] exec.native_account::set_map_item # => [OLD_GUARDIAN_PUBLIC_KEY] @@ -94,7 +96,8 @@ pub proc update_guardian_public_key(new_guardian_scheme_id: felt, new_guardian_p # => [GUARDIAN_MAP_KEY, NEW_GUARDIAN_SCHEME_ID_WORD] push.GUARDIAN_SCHEME_ID_SLOT[0..2] - # => [guardian_scheme_slot_prefix, guardian_scheme_slot_suffix, GUARDIAN_MAP_KEY, NEW_GUARDIAN_SCHEME_ID_WORD] + # => [guardian_scheme_slot_prefix, guardian_scheme_slot_suffix, + # GUARDIAN_MAP_KEY, NEW_GUARDIAN_SCHEME_ID_WORD] exec.native_account::set_map_item # => [OLD_GUARDIAN_SCHEME_ID_WORD] @@ -110,7 +113,8 @@ end #! #! Panics if: #! - `update_guardian_public_key` is called together with another non-auth account procedure. -#! - `update_guardian_public_key` was not called and a valid guardian signature is missing or invalid. +#! - `update_guardian_public_key` was not called and a valid guardian signature is missing or +#! invalid. #! #! Invocation: exec pub proc verify_signature(msg: word) @@ -137,7 +141,8 @@ pub proc verify_signature(msg: word) # => [guardian_pubkeys_slot_prefix, guardian_pubkeys_slot_suffix, 1, MSG] push.GUARDIAN_SCHEME_ID_SLOT[0..2] - # => [guardian_scheme_slot_prefix, guardian_scheme_slot_suffix, guardian_pubkeys_slot_prefix, guardian_pubkeys_slot_suffix, 1, MSG] + # => [guardian_scheme_slot_prefix, guardian_scheme_slot_suffix, + # guardian_pubkeys_slot_prefix, guardian_pubkeys_slot_suffix, 1, MSG] exec.signature::verify_signatures # => [num_verified_signatures, MSG] From ae3d1f0ffa2f7a4c6e66b33e863376acab50e0a1 Mon Sep 17 00:00:00 2001 From: Marcos Date: Thu, 26 Mar 2026 16:52:59 -0300 Subject: [PATCH 7/7] fix: comment --- crates/miden-standards/src/account/auth/guarded_multisig.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/miden-standards/src/account/auth/guarded_multisig.rs b/crates/miden-standards/src/account/auth/guarded_multisig.rs index 179ef4f7a0..e988542972 100644 --- a/crates/miden-standards/src/account/auth/guarded_multisig.rs +++ b/crates/miden-standards/src/account/auth/guarded_multisig.rs @@ -177,7 +177,7 @@ impl AuthGuardedMultisigConfig { } } -/// An [`AccountComponent`] implementing guarded multisig authentication with a guardian. +/// An [`AccountComponent`] implementing multisig authentication integrated with a state guardian. /// /// It enforces a threshold of approver signatures for every transaction, with optional /// per-procedure threshold overrides. When a guardian is configured, multisig authorization is