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