use alloc::collections::BTreeSet;
use alloc::vec::Vec;
use core::num::NonZeroU32;
use miden_protocol::account::auth::{AuthScheme, PublicKey, PublicKeyCommitment};
use miden_protocol::errors::AccountError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Approver {
pub_key: PublicKeyCommitment,
auth_scheme: AuthScheme,
}
impl Approver {
pub fn new(pub_key: PublicKeyCommitment, auth_scheme: AuthScheme) -> Self {
Self { pub_key, auth_scheme }
}
pub fn pub_key(&self) -> PublicKeyCommitment {
self.pub_key
}
pub fn auth_scheme(&self) -> AuthScheme {
self.auth_scheme
}
}
impl From<&PublicKey> for Approver {
fn from(pub_key: &PublicKey) -> Self {
Self::new(pub_key.to_commitment(), pub_key.auth_scheme())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ApproverSet {
approvers: Vec<Approver>,
threshold: NonZeroU32,
}
impl ApproverSet {
pub fn new(approvers: Vec<Approver>, threshold: u32) -> Result<Self, AccountError> {
let threshold = NonZeroU32::new(threshold)
.ok_or_else(|| AccountError::other("threshold must be at least 1"))?;
if threshold.get() > approvers.len() as u32 {
return Err(AccountError::other(
"threshold cannot be greater than number of approvers",
));
}
let unique_approvers: BTreeSet<_> = approvers.iter().map(Approver::pub_key).collect();
if unique_approvers.len() != approvers.len() {
return Err(AccountError::other("duplicate approver public keys are not allowed"));
}
Ok(Self { approvers, threshold })
}
pub fn approvers(&self) -> &[Approver] {
&self.approvers
}
pub fn threshold(&self) -> NonZeroU32 {
self.threshold
}
}
#[cfg(test)]
mod tests {
use alloc::string::ToString;
use miden_protocol::Word;
use miden_protocol::account::auth::AuthScheme;
use super::*;
fn approver(seed: u32) -> Approver {
Approver::new(PublicKeyCommitment::from(Word::from([seed; 4])), AuthScheme::EcdsaK256Keccak)
}
#[test]
fn rejects_zero_threshold() {
let err = ApproverSet::new(vec![approver(1)], 0).unwrap_err();
assert!(err.to_string().contains("threshold must be at least 1"));
}
#[test]
fn rejects_threshold_above_approver_count() {
let err = ApproverSet::new(vec![approver(1)], 2).unwrap_err();
assert!(err.to_string().contains("threshold cannot be greater than number of approvers"));
}
#[test]
fn rejects_duplicate_approvers() {
let err = ApproverSet::new(vec![approver(1), approver(1)], 2).unwrap_err();
assert!(err.to_string().contains("duplicate approver public keys are not allowed"));
}
#[test]
fn accepts_valid_set() {
let set = ApproverSet::new(vec![approver(1), approver(2)], 2).unwrap();
assert_eq!(set.approvers().len(), 2);
assert_eq!(set.threshold().get(), 2);
}
}