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
use bc_shamir::MAX_SHARE_COUNT;

use crate::Error;

/// A specification for an SSKR split.
#[derive(Debug, PartialEq)]
pub struct Spec {
    group_threshold: usize,
    groups: Vec<GroupSpec>,
}

impl Spec {
    /// Creates a new `Spec` instance with the given group threshold and groups.
    ///
    /// # Arguments
    ///
    /// * `group_threshold` - The minimum number of groups required to
    ///   reconstruct the secret.
    /// * `groups` - The list of `GroupSpec` instances that define the groups
    ///   and their members.
    ///
    /// # Errors
    ///
    /// Returns an error if the group threshold is zero, if the group threshold
    /// is greater than the number of groups, or if the number of groups is
    /// greater than the maximum share count.
    pub fn new(group_threshold: usize, groups: Vec<GroupSpec>) -> Result<Self, Error> {
        if group_threshold == 0 {
            return Err(Error::GroupThresholdInvalid);
        }
        if group_threshold > groups.len() {
            return Err(Error::GroupThresholdInvalid);
        }
        if groups.len() > MAX_SHARE_COUNT {
            return Err(Error::GroupCountInvalid);
        }
        Ok(Self {
            group_threshold,
            groups,
        })
    }

    /// Returns the group threshold.
    pub fn group_threshold(&self) -> usize {
        self.group_threshold
    }

    /// Returns a slice of the group specifications.
    pub fn groups(&self) -> &[GroupSpec] {
        &self.groups
    }

    /// Returns the number of groups.
    pub fn group_count(&self) -> usize {
        self.groups.len()
    }

    /// Returns the total number of shares across all groups.
    pub fn share_count(&self) -> usize {
        self.groups.iter().map(|g| g.member_count()).sum()
    }
}

/// A specification for a group of shares within an SSKR split.
#[derive(Debug, PartialEq)]
pub struct GroupSpec {
    member_threshold: usize,
    member_count: usize,
}

impl GroupSpec {
    /// Creates a new `GroupSpec` instance with the given member threshold and
    /// count.
    ///
    /// # Arguments
    ///
    /// * `member_threshold` - The minimum number of member shares required to
    ///   reconstruct the secret within the group.
    /// * `member_count` - The total number of member shares in the group.
    ///
    /// # Errors
    ///
    /// Returns an error if the member count is zero, if the member count is
    /// greater than the maximum share count, or if the member threshold is
    /// greater than the member count.
    pub fn new(member_threshold: usize, member_count: usize) -> Result<Self, Error> {
        if member_count == 0 {
            return Err(Error::MemberCountInvalid);
        }
        if member_count > MAX_SHARE_COUNT {
            return Err(Error::MemberCountInvalid);
        }
        if member_threshold > member_count {
            return Err(Error::MemberThresholdInvalid);
        }
        Ok(Self { member_threshold, member_count })
    }

    /// Returns the member share threshold for this group.
    pub fn member_threshold(&self) -> usize {
        self.member_threshold
    }

    /// Returns the number of member shares in this group.
    pub fn member_count(&self) -> usize {
        self.member_count
    }
}