miden_standards/account/auth/
approver.rs1use alloc::collections::BTreeSet;
2use alloc::vec::Vec;
3use core::num::NonZeroU32;
4
5use miden_protocol::account::auth::{AuthScheme, PublicKey, PublicKeyCommitment};
6use miden_protocol::errors::AccountError;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct Approver {
21 pub_key: PublicKeyCommitment,
22 auth_scheme: AuthScheme,
23}
24
25impl Approver {
26 pub fn new(pub_key: PublicKeyCommitment, auth_scheme: AuthScheme) -> Self {
28 Self { pub_key, auth_scheme }
29 }
30
31 pub fn pub_key(&self) -> PublicKeyCommitment {
33 self.pub_key
34 }
35
36 pub fn auth_scheme(&self) -> AuthScheme {
38 self.auth_scheme
39 }
40}
41
42impl From<&PublicKey> for Approver {
43 fn from(pub_key: &PublicKey) -> Self {
44 Self::new(pub_key.to_commitment(), pub_key.auth_scheme())
45 }
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct ApproverSet {
58 approvers: Vec<Approver>,
59 threshold: NonZeroU32,
60}
61
62impl ApproverSet {
63 pub fn new(approvers: Vec<Approver>, threshold: u32) -> Result<Self, AccountError> {
72 let threshold = NonZeroU32::new(threshold)
73 .ok_or_else(|| AccountError::other("threshold must be at least 1"))?;
74
75 if threshold.get() > approvers.len() as u32 {
76 return Err(AccountError::other(
77 "threshold cannot be greater than number of approvers",
78 ));
79 }
80
81 let unique_approvers: BTreeSet<_> = approvers.iter().map(Approver::pub_key).collect();
82 if unique_approvers.len() != approvers.len() {
83 return Err(AccountError::other("duplicate approver public keys are not allowed"));
84 }
85
86 Ok(Self { approvers, threshold })
87 }
88
89 pub fn approvers(&self) -> &[Approver] {
91 &self.approvers
92 }
93
94 pub fn threshold(&self) -> NonZeroU32 {
96 self.threshold
97 }
98}
99
100#[cfg(test)]
104mod tests {
105 use alloc::string::ToString;
106
107 use miden_protocol::Word;
108 use miden_protocol::account::auth::AuthScheme;
109
110 use super::*;
111
112 fn approver(seed: u32) -> Approver {
113 Approver::new(PublicKeyCommitment::from(Word::from([seed; 4])), AuthScheme::EcdsaK256Keccak)
114 }
115
116 #[test]
117 fn rejects_zero_threshold() {
118 let err = ApproverSet::new(vec![approver(1)], 0).unwrap_err();
119 assert!(err.to_string().contains("threshold must be at least 1"));
120 }
121
122 #[test]
123 fn rejects_threshold_above_approver_count() {
124 let err = ApproverSet::new(vec![approver(1)], 2).unwrap_err();
125 assert!(err.to_string().contains("threshold cannot be greater than number of approvers"));
126 }
127
128 #[test]
129 fn rejects_duplicate_approvers() {
130 let err = ApproverSet::new(vec![approver(1), approver(1)], 2).unwrap_err();
131 assert!(err.to_string().contains("duplicate approver public keys are not allowed"));
132 }
133
134 #[test]
135 fn accepts_valid_set() {
136 let set = ApproverSet::new(vec![approver(1), approver(2)], 2).unwrap();
137 assert_eq!(set.approvers().len(), 2);
138 assert_eq!(set.threshold().get(), 2);
139 }
140}