devolutions_crypto/secret_sharing/
secret_sharing_v1.rs

1//! Secret Sharing V1: Shamir's Secret Sharing
2use super::Error;
3use super::Result;
4
5use std::convert::TryFrom;
6
7use rand::rngs::OsRng;
8
9use blahaj::{Share, Sharks};
10use zeroize::Zeroizing;
11
12#[cfg(feature = "fuzz")]
13use arbitrary::Arbitrary;
14
15// This will need some work in the Sharks crate to get the zeroize working.
16//#[derive(Zeroize)]
17//#[zeroize(drop)]
18#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
19#[derive(Clone)]
20pub struct ShareV1 {
21    threshold: u8,
22    share: Share,
23}
24
25impl core::fmt::Debug for ShareV1 {
26    fn fmt(&self, f: &mut core::fmt::Formatter) -> std::result::Result<(), core::fmt::Error> {
27        write!(f, "Share with threshold {}", self.threshold)
28    }
29}
30
31impl From<ShareV1> for Vec<u8> {
32    fn from(share: ShareV1) -> Vec<u8> {
33        let mut data: Vec<u8> = vec![share.threshold];
34        data.append(&mut (&share.share).into());
35
36        data
37    }
38}
39
40impl TryFrom<&[u8]> for ShareV1 {
41    type Error = Error;
42
43    fn try_from(data: &[u8]) -> Result<ShareV1> {
44        if data.len() < 3 {
45            return Err(Error::InvalidLength);
46        };
47
48        let threshold = data[0];
49
50        let share = match Share::try_from(&data[1..]) {
51            Ok(s) => s,
52            Err(_) => return Err(Error::InvalidData),
53        };
54
55        Ok(ShareV1 { threshold, share })
56    }
57}
58
59impl ShareV1 {
60    pub fn generate_shared_key(
61        n_shares: u8,
62        threshold: u8,
63        length: usize,
64    ) -> Result<impl Iterator<Item = ShareV1>> {
65        if n_shares < threshold {
66            return Err(Error::NotEnoughShares);
67        }
68
69        let secret = Zeroizing::new(crate::utils::generate_key(length));
70        let sharks = Sharks(threshold);
71        let dealer = sharks.dealer_rng(&secret, &mut OsRng);
72
73        Ok(dealer.take(n_shares as usize).map(move |s| ShareV1 {
74            threshold,
75            share: s,
76        }))
77    }
78
79    pub fn join_shares<'a, I, J>(shares: I) -> Result<Vec<u8>>
80    where
81        I: IntoIterator<Item = &'a ShareV1, IntoIter = J>,
82        J: Iterator<Item = &'a ShareV1> + Clone,
83    {
84        let shares = shares.into_iter();
85        let threshold = match shares.clone().peekable().peek() {
86            Some(x) => x.threshold,
87            None => return Err(Error::NotEnoughShares),
88        };
89
90        let sharks = Sharks(threshold);
91
92        let shares = shares.map(|s| &s.share);
93        match sharks.recover(shares) {
94            Ok(x) => Ok(x),
95            Err(_) => Err(Error::NotEnoughShares),
96        }
97    }
98}