Skip to main content

miden_testing/mock_chain/
auth.rs

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