1use bc_shamir::MAX_SHARE_COUNT;
2
3use crate::{Error, Result};
4
5#[derive(Debug, Clone, PartialEq)]
7pub struct Spec {
8 group_threshold: usize,
9 groups: Vec<GroupSpec>,
10}
11
12impl Spec {
13 pub fn new(group_threshold: usize, groups: Vec<GroupSpec>) -> Result<Self> {
28 if group_threshold == 0 {
29 return Err(Error::GroupThresholdInvalid);
30 }
31 if group_threshold > groups.len() {
32 return Err(Error::GroupThresholdInvalid);
33 }
34 if groups.len() > MAX_SHARE_COUNT {
35 return Err(Error::GroupCountInvalid);
36 }
37 Ok(Self { group_threshold, groups })
38 }
39
40 pub fn group_threshold(&self) -> usize { self.group_threshold }
42
43 pub fn groups(&self) -> &[GroupSpec] { &self.groups }
45
46 pub fn group_count(&self) -> usize { self.groups.len() }
48
49 pub fn share_count(&self) -> usize {
51 self.groups.iter().map(|g| g.member_count()).sum()
52 }
53}
54
55#[derive(Debug, Clone, PartialEq)]
57pub struct GroupSpec {
58 member_threshold: usize,
59 member_count: usize,
60}
61
62impl GroupSpec {
63 pub fn new(member_threshold: usize, member_count: usize) -> Result<Self> {
78 if member_count == 0 {
79 return Err(Error::MemberCountInvalid);
80 }
81 if member_count > MAX_SHARE_COUNT {
82 return Err(Error::MemberCountInvalid);
83 }
84 if member_threshold > member_count {
85 return Err(Error::MemberThresholdInvalid);
86 }
87 Ok(Self { member_threshold, member_count })
88 }
89
90 pub fn member_threshold(&self) -> usize { self.member_threshold }
92
93 pub fn member_count(&self) -> usize { self.member_count }
95
96 pub fn parse(s: &str) -> Result<Self> {
98 let parts: Vec<&str> = s.split('-').collect();
99 if parts.len() != 3 {
100 return Err(Error::GroupSpecInvalid);
101 }
102 let member_threshold = parts[0]
103 .parse::<usize>()
104 .map_err(|_| Error::GroupSpecInvalid)?;
105 if parts[1] != "of" {
106 return Err(Error::GroupSpecInvalid);
107 }
108 let member_count = parts[2]
109 .parse::<usize>()
110 .map_err(|_| Error::GroupSpecInvalid)?;
111 Self::new(member_threshold, member_count)
112 }
113}
114
115impl Default for GroupSpec {
116 fn default() -> Self { Self::new(1, 1).unwrap() }
117}
118
119impl std::fmt::Display for GroupSpec {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 write!(f, "{}-of-{}", self.member_threshold, self.member_count)
122 }
123}