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