devolutions_crypto/secret_sharing/
mod.rs1mod secret_sharing_v1;
24
25use super::DataType;
26use super::Error;
27use super::Header;
28use super::HeaderType;
29use super::Result;
30pub use super::SecretSharingVersion;
31use super::ShareSubtype;
32
33use secret_sharing_v1::ShareV1;
34
35use std::borrow::Borrow;
36use std::convert::TryFrom;
37
38#[cfg(feature = "fuzz")]
39use arbitrary::Arbitrary;
40
41#[derive(Clone, Debug)]
43#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
44pub struct Share {
45 pub(crate) header: Header<Share>,
46 payload: SharePayload,
47}
48
49impl HeaderType for Share {
50 type Version = SecretSharingVersion;
51 type Subtype = ShareSubtype;
52
53 fn data_type() -> DataType {
54 DataType::Share
55 }
56}
57
58#[derive(Clone, Debug)]
59#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
60enum SharePayload {
61 V1(ShareV1),
62}
63
64pub fn generate_shared_key(
82 n_shares: u8,
83 threshold: u8,
84 length: usize,
85 version: SecretSharingVersion,
86) -> Result<Vec<Share>> {
87 let mut header = Header::default();
88
89 match version {
90 SecretSharingVersion::V1 | SecretSharingVersion::Latest => {
91 header.version = SecretSharingVersion::V1;
92
93 let shares = ShareV1::generate_shared_key(n_shares, threshold, length)?;
94
95 Ok(shares
96 .map(|s| Share {
97 header: header.clone(),
98 payload: SharePayload::V1(s),
99 })
100 .collect())
101 }
102 }
103}
104
105pub fn join_shares<'a, I, J>(shares: I) -> Result<Vec<u8>>
121where
122 I: IntoIterator<Item = &'a Share, IntoIter = J>,
123 J: Iterator<Item = &'a Share> + Clone,
124{
125 let shares = shares.into_iter();
126
127 let version = match shares.clone().peekable().peek() {
128 Some(x) => x.header.version,
129 None => return Err(Error::NotEnoughShares),
130 };
131
132 if !shares.clone().all(|share| match share.payload {
133 SharePayload::V1(_) => version == SecretSharingVersion::V1,
134 }) {
135 return Err(Error::InconsistentVersion);
136 }
137
138 match version {
139 SecretSharingVersion::V1 => {
140 let shares = shares.map(|share| match &share.payload {
141 SharePayload::V1(s) => s,
142 });
144
145 ShareV1::join_shares(shares)
146 }
147 _ => Err(Error::UnknownVersion),
148 }
149}
150
151impl From<Share> for Vec<u8> {
152 fn from(data: Share) -> Self {
154 let mut header: Self = data.header.borrow().into();
155 let mut payload: Self = data.payload.into();
156 header.append(&mut payload);
157 header
158 }
159}
160
161impl TryFrom<&[u8]> for Share {
162 type Error = Error;
163
164 fn try_from(data: &[u8]) -> Result<Self> {
166 if data.len() < Header::len() {
167 return Err(Error::InvalidLength);
168 };
169
170 let header = Header::try_from(&data[0..Header::len()])?;
171
172 let payload = match header.version {
173 SecretSharingVersion::V1 => {
174 SharePayload::V1(ShareV1::try_from(&data[Header::len()..])?)
175 }
176 _ => return Err(Error::UnknownVersion),
177 };
178
179 Ok(Self { header, payload })
180 }
181}
182
183impl From<SharePayload> for Vec<u8> {
184 fn from(data: SharePayload) -> Self {
185 match data {
186 SharePayload::V1(x) => x.into(),
187 }
188 }
189}
190
191#[test]
192fn secret_sharing_test() {
193 let shares = generate_shared_key(5, 3, 32, SecretSharingVersion::Latest).unwrap();
194
195 assert_eq!(shares.len(), 5);
196
197 let key1 = join_shares(&shares[0..3]).unwrap();
198 let key2 = join_shares(&shares[2..5]).unwrap();
199 assert_eq!(key1.len(), 32);
200 assert_eq!(key2.len(), 32);
201 assert!(join_shares(&shares[2..4]).is_err());
202}