use alloc::collections::BTreeSet;
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,
AuthSingleSigAcl,
AuthSingleSigAclConfig,
GuardianConfig,
};
use miden_standards::testing::account_component::{
ConditionalAuthComponent,
IncrNonceAuthComponent,
};
use miden_tx::auth::BasicAuthenticator;
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
#[derive(Debug, Clone)]
pub enum Auth {
BasicAuth { auth_scheme: AuthScheme },
Multisig {
approver_set: ApproverSet,
proc_threshold_map: Vec<(AccountProcedureRoot, u32)>,
},
GuardedMultisig {
approver_set: ApproverSet,
guardian_config: GuardianConfig,
proc_threshold_map: Vec<(AccountProcedureRoot, u32)>,
},
MultisigSmart {
approver_set: ApproverSet,
proc_policy_map: Vec<(Word, ProcedurePolicy)>,
},
Acl {
exempt_procedures: BTreeSet<AccountProcedureRoot>,
auth_scheme: AuthScheme,
},
IncrNonce,
Noop,
Conditional,
NetworkAccount {
allowed_script_roots: BTreeSet<NoteScriptRoot>,
allowed_tx_script_roots: BTreeSet<TransactionScriptRoot>,
},
}
impl Default for Auth {
fn default() -> Self {
Auth::BasicAuth {
auth_scheme: AuthScheme::Falcon512Poseidon2,
}
}
}
impl Auth {
pub fn build_component(&self) -> (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]);
(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();
(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();
(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();
(component, None)
},
Auth::Acl { exempt_procedures, 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 = AuthSingleSigAcl::new(
Approver::new(pub_key, *auth_scheme),
AuthSingleSigAclConfig::new(exempt_procedures.clone()).expect(
"AuthSingleSigAcl component creation failed: too many exempt procedures",
),
)
.into();
let authenticator = BasicAuthenticator::new(&[sec_key]);
(component, Some(authenticator))
},
Auth::IncrNonce => (IncrNonceAuthComponent.into(), None),
Auth::Noop => (NoopAuthComponent.into(), None),
Auth::Conditional => (ConditionalAuthComponent.into(), None),
Auth::NetworkAccount {
allowed_script_roots,
allowed_tx_script_roots,
} => {
let component =
AuthNetworkAccount::with_allowed_notes(allowed_script_roots.clone())
.expect("network account allowlist must be non-empty")
.with_allowed_tx_scripts(allowed_tx_script_roots.clone())
.into();
(component, None)
},
}
}
}
impl From<Auth> for AccountComponent {
fn from(auth: Auth) -> Self {
let (component, _) = auth.build_component();
component
}
}