Skip to main content

miden_testing/mock_chain/
auth.rs

1// AUTH
2// ================================================================================================
3use alloc::collections::BTreeSet;
4use alloc::vec;
5use alloc::vec::Vec;
6
7use miden_protocol::Word;
8use miden_protocol::account::auth::{AuthScheme, AuthSecretKey};
9use miden_protocol::account::{AccountComponent, AccountProcedureRoot};
10use miden_protocol::note::NoteScriptRoot;
11use miden_protocol::testing::noop_auth_component::NoopAuthComponent;
12use miden_protocol::transaction::TransactionScriptRoot;
13use miden_standards::account::auth::multisig_smart::ProcedurePolicy;
14use miden_standards::account::auth::{
15    Approver,
16    ApproverSet,
17    AuthGuardedMultisig,
18    AuthGuardedMultisigConfig,
19    AuthMultisig,
20    AuthMultisigConfig,
21    AuthMultisigSmart,
22    AuthMultisigSmartConfig,
23    AuthNetworkAccount,
24    AuthSingleSig,
25    GuardianConfig,
26    SponsorshipPolicy,
27};
28use miden_standards::account::fees::FeePolicyManager;
29use miden_standards::testing::account_component::{
30    ConditionalAuthComponent,
31    IncrNonceAuthComponent,
32};
33use miden_tx::auth::BasicAuthenticator;
34use rand::SeedableRng;
35use rand_chacha::ChaCha20Rng;
36
37/// Specifies which authentication mechanism is desired for accounts
38#[derive(Debug, Clone)]
39pub enum Auth {
40    /// Creates a secret key for the account and creates a [BasicAuthenticator] used to
41    /// authenticate the account with [AuthSingleSig].
42    BasicAuth { auth_scheme: AuthScheme },
43
44    /// Multisig
45    Multisig {
46        approver_set: ApproverSet,
47        proc_threshold_map: Vec<(AccountProcedureRoot, u32)>,
48    },
49
50    /// Guarded multisig.
51    GuardedMultisig {
52        approver_set: ApproverSet,
53        guardian_config: GuardianConfig,
54        proc_threshold_map: Vec<(AccountProcedureRoot, u32)>,
55    },
56
57    /// Multisig with smart per-procedure policy configuration.
58    MultisigSmart {
59        approver_set: ApproverSet,
60        proc_policy_map: Vec<(Word, ProcedurePolicy)>,
61    },
62
63    /// Creates a mock authentication mechanism for the account that only increments the nonce.
64    IncrNonce,
65
66    /// Creates a mock authentication mechanism for the account that does nothing.
67    Noop,
68
69    /// Creates a mock authentication mechanism for the account that conditionally succeeds and
70    /// conditionally increments the nonce based on the authentication arguments.
71    ///
72    /// The auth procedure expects the first three arguments as [99, 98, 97] to succeed.
73    /// In case it succeeds, it conditionally increments the nonce based on the fourth argument.
74    Conditional,
75
76    /// Network-account authentication that restricts the account to consuming only notes whose
77    /// script roots appear in `allowed_script_roots` (must be non-empty), and to executing only
78    /// transaction scripts whose roots appear in `allowed_tx_script_roots` (may be empty).
79    ///
80    /// The `fee_policy_manager` initializes the fee-policy storage the auth component owns and
81    /// contributes the components making its fee policies dispatchable.
82    NetworkAccount {
83        allowed_script_roots: BTreeSet<NoteScriptRoot>,
84        allowed_tx_script_roots: BTreeSet<TransactionScriptRoot>,
85        fee_policy_manager: FeePolicyManager,
86        sponsorship_policy: SponsorshipPolicy,
87    },
88}
89
90impl Default for Auth {
91    /// Returns the most common authentication scheme used in tests:
92    /// [`Auth::BasicAuth`] with [`AuthScheme::Falcon512Poseidon2`].
93    fn default() -> Self {
94        Auth::BasicAuth {
95            auth_scheme: AuthScheme::Falcon512Poseidon2,
96        }
97    }
98}
99
100impl Auth {
101    /// Returns [`Auth::BasicAuth`] with [`AuthScheme::Falcon512Poseidon2`].
102    ///
103    /// Prefer ECDSA over Falcon for tests where the auth scheme itself is not under test.
104    pub fn basic_falcon() -> Self {
105        Auth::BasicAuth {
106            auth_scheme: AuthScheme::Falcon512Poseidon2,
107        }
108    }
109
110    /// Returns [`Auth::BasicAuth`] with [`AuthScheme::EcdsaK256Keccak`].
111    ///
112    /// ECDSA verifies much faster than Falcon, making it the better choice for tests where the
113    /// auth scheme itself is not under test.
114    pub fn basic_ecdsa() -> Self {
115        Auth::BasicAuth { auth_scheme: AuthScheme::EcdsaK256Keccak }
116    }
117
118    /// Converts `self` into the [`AccountComponent`]s implementing this authentication scheme and
119    /// an optional [`BasicAuthenticator`].
120    ///
121    /// The authentication component is always the first component of the returned vector; variants
122    /// that expand into multiple components (e.g. [`Auth::NetworkAccount`]) yield their companion
123    /// components after it. The authenticator is only `Some` when [`Auth::BasicAuth`] is passed.
124    pub fn build_components(&self) -> (Vec<AccountComponent>, Option<BasicAuthenticator>) {
125        match self {
126            Auth::BasicAuth { auth_scheme } => {
127                let mut rng = ChaCha20Rng::from_seed(Default::default());
128                let sec_key = AuthSecretKey::with_scheme_and_rng(*auth_scheme, &mut rng)
129                    .expect("failed to create secret key");
130                let pub_key = sec_key.public_key().to_commitment();
131
132                let component = AuthSingleSig::new(Approver::new(pub_key, *auth_scheme)).into();
133                let authenticator = BasicAuthenticator::new(&[sec_key]);
134
135                (vec![component], Some(authenticator))
136            },
137            Auth::Multisig { approver_set, proc_threshold_map } => {
138                let config = AuthMultisigConfig::new(approver_set.clone())
139                    .with_proc_thresholds(proc_threshold_map.clone())
140                    .expect("invalid multisig config");
141                let component =
142                    AuthMultisig::new(config).expect("multisig component creation failed").into();
143
144                (vec![component], None)
145            },
146            Auth::GuardedMultisig {
147                approver_set,
148                guardian_config,
149                proc_threshold_map,
150            } => {
151                let config = AuthGuardedMultisigConfig::new(approver_set.clone(), *guardian_config)
152                    .and_then(|cfg| cfg.with_proc_thresholds(proc_threshold_map.clone()))
153                    .expect("invalid guarded multisig config");
154                let component = AuthGuardedMultisig::new(config)
155                    .expect("guarded multisig component creation failed")
156                    .into();
157
158                (vec![component], None)
159            },
160            Auth::MultisigSmart { approver_set, proc_policy_map } => {
161                let config = AuthMultisigSmartConfig::new(approver_set.clone())
162                    .with_proc_policies(proc_policy_map.clone())
163                    .expect("invalid multisig smart config");
164
165                let component = AuthMultisigSmart::new(config)
166                    .expect("multisig smart component creation failed")
167                    .into();
168
169                (vec![component], None)
170            },
171            Auth::IncrNonce => (vec![IncrNonceAuthComponent.into()], None),
172            Auth::Noop => (vec![NoopAuthComponent.into()], None),
173            Auth::Conditional => (vec![ConditionalAuthComponent.into()], None),
174            Auth::NetworkAccount {
175                allowed_script_roots,
176                allowed_tx_script_roots,
177                fee_policy_manager,
178                sponsorship_policy,
179            } => {
180                let components = AuthNetworkAccount::new(
181                    allowed_script_roots.clone(),
182                    fee_policy_manager.clone(),
183                )
184                .expect("network account allowlist must be non-empty")
185                .with_allowed_tx_scripts(allowed_tx_script_roots.clone())
186                .with_sponsorship_policy(*sponsorship_policy)
187                .into_iter()
188                .collect();
189                (components, None)
190            },
191        }
192    }
193}
194
195impl IntoIterator for Auth {
196    type Item = AccountComponent;
197    type IntoIter = alloc::vec::IntoIter<AccountComponent>;
198
199    /// Yields the [`AccountComponent`]s implementing this authentication scheme, discarding the
200    /// authenticator. Use [`Auth::build_components`] when the authenticator is needed.
201    fn into_iter(self) -> Self::IntoIter {
202        let (components, _) = self.build_components();
203        components.into_iter()
204    }
205}