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