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::EcdsaK256Keccak`].
102    ///
103    /// ECDSA verifies much faster than Falcon, making it the better choice for tests where the
104    /// auth scheme itself is not under test.
105    pub fn basic_ecdsa() -> Self {
106        Auth::BasicAuth { auth_scheme: AuthScheme::EcdsaK256Keccak }
107    }
108
109    /// Converts `self` into the [`AccountComponent`]s implementing this authentication scheme and
110    /// an optional [`BasicAuthenticator`].
111    ///
112    /// The authentication component is always the first component of the returned vector; variants
113    /// that expand into multiple components (e.g. [`Auth::NetworkAccount`]) yield their companion
114    /// components after it. The authenticator is only `Some` when [`Auth::BasicAuth`] is passed.
115    pub fn build_components(&self) -> (Vec<AccountComponent>, Option<BasicAuthenticator>) {
116        match self {
117            Auth::BasicAuth { auth_scheme } => {
118                let mut rng = ChaCha20Rng::from_seed(Default::default());
119                let sec_key = AuthSecretKey::with_scheme_and_rng(*auth_scheme, &mut rng)
120                    .expect("failed to create secret key");
121                let pub_key = sec_key.public_key().to_commitment();
122
123                let component = AuthSingleSig::new(Approver::new(pub_key, *auth_scheme)).into();
124                let authenticator = BasicAuthenticator::new(&[sec_key]);
125
126                (vec![component], Some(authenticator))
127            },
128            Auth::Multisig { approver_set, proc_threshold_map } => {
129                let config = AuthMultisigConfig::new(approver_set.clone())
130                    .with_proc_thresholds(proc_threshold_map.clone())
131                    .expect("invalid multisig config");
132                let component =
133                    AuthMultisig::new(config).expect("multisig component creation failed").into();
134
135                (vec![component], None)
136            },
137            Auth::GuardedMultisig {
138                approver_set,
139                guardian_config,
140                proc_threshold_map,
141            } => {
142                let config = AuthGuardedMultisigConfig::new(approver_set.clone(), *guardian_config)
143                    .and_then(|cfg| cfg.with_proc_thresholds(proc_threshold_map.clone()))
144                    .expect("invalid guarded multisig config");
145                let component = AuthGuardedMultisig::new(config)
146                    .expect("guarded multisig component creation failed")
147                    .into();
148
149                (vec![component], None)
150            },
151            Auth::MultisigSmart { approver_set, proc_policy_map } => {
152                let config = AuthMultisigSmartConfig::new(approver_set.clone())
153                    .with_proc_policies(proc_policy_map.clone())
154                    .expect("invalid multisig smart config");
155
156                let component = AuthMultisigSmart::new(config)
157                    .expect("multisig smart component creation failed")
158                    .into();
159
160                (vec![component], None)
161            },
162            Auth::IncrNonce => (vec![IncrNonceAuthComponent.into()], None),
163            Auth::Noop => (vec![NoopAuthComponent.into()], None),
164            Auth::Conditional => (vec![ConditionalAuthComponent.into()], None),
165            Auth::NetworkAccount {
166                allowed_script_roots,
167                allowed_tx_script_roots,
168                fee_policy_manager,
169                sponsorship_policy,
170            } => {
171                let components = AuthNetworkAccount::new(
172                    allowed_script_roots.clone(),
173                    fee_policy_manager.clone(),
174                )
175                .expect("network account allowlist must be non-empty")
176                .with_allowed_tx_scripts(allowed_tx_script_roots.clone())
177                .with_sponsorship_policy(*sponsorship_policy)
178                .into_iter()
179                .collect();
180                (components, None)
181            },
182        }
183    }
184}
185
186impl IntoIterator for Auth {
187    type Item = AccountComponent;
188    type IntoIter = alloc::vec::IntoIter<AccountComponent>;
189
190    /// Yields the [`AccountComponent`]s implementing this authentication scheme, discarding the
191    /// authenticator. Use [`Auth::build_components`] when the authenticator is needed.
192    fn into_iter(self) -> Self::IntoIter {
193        let (components, _) = self.build_components();
194        components.into_iter()
195    }
196}