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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
#![doc(html_root_url = "https://docs.rs/bc-shamir/0.1.0")]
#![warn(rust_2018_idioms)]
//! ## Introduction
//!
//! This is a pure-Rust implementation of [Shamir's Secret Sharing
//! (SSS)](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing) is a
//! cryptographic technique in which a *secret* is divided into parts, called
//! *shares*, in such a way that a *threshold* of several shares are needed to
//! reconstruct the secret. The shares are distributed in a way that makes it
//! impossible for an attacker to know anything about the secret without having
//! a threshold of shares. If the number of shares is less than the threshold,
//! then no information about the secret is revealed.
//!
//! ## Getting Started
//!
//! ```toml
//! [dependencies]
//! bc-shamir = "0.1.0"
//!```
//!
//! ## Usage
//!
//! ### Splitting a secret
//!
//! ```
//! # use bc_shamir::split_secret;
//! # fn main() {
//! let secret = b"my secret belongs to me.";
//! let threshold = 2;
//! let share_count = 3;
//! let mut random_generator = bc_crypto::SecureRandomNumberGenerator;
//!
//! let shares = split_secret(threshold, share_count, secret, &mut random_generator).unwrap();
//!
//! assert_eq!(shares.len(), share_count);
//! # }
//! ```
//!
//! ### Recovering a secret
//!
//! ```
//! # use bc_shamir::recover_secret;
//! # fn main() {
//! let indexes = vec![0, 2];
//! let shares = vec![
//!     vec![47, 165, 102, 232, 218, 99, 6, 94, 39, 6, 253, 215, 12, 88, 64, 32, 105, 40, 222, 146, 93, 197, 48, 129],
//!     vec![221, 174, 116, 201, 90, 99, 136, 33, 64, 215, 60, 84, 207, 28, 74, 10, 111, 243, 43, 224, 48, 64, 199, 172],
//! ];
//!
//! let secret = recover_secret(&indexes, &shares).unwrap();
//!
//! assert_eq!(secret, b"my secret belongs to me.");
//! # }
//! ```
/// The minimum length of a secret.
pub const MIN_SECRET_LEN: usize = 16;
/// The maximum length of a secret.
pub const MAX_SECRET_LEN: usize = 32;
/// The maximum number of shares that can be generated from a secret.
pub const MAX_SHARE_COUNT: usize = 16;
mod hazmat;
mod interpolate;
mod error;
pub use error::Error;
mod shamir;
pub use shamir::{split_secret, recover_secret};
#[cfg(test)]
mod tests {
    use super::*;
    use bc_crypto::RandomNumberGenerator;
    use hex_literal::hex;
    struct FakeRandomNumberGenerator;
    impl RandomNumberGenerator for FakeRandomNumberGenerator {
        fn next_u64(&mut self) -> u64 {
            unimplemented!()
        }
        fn random_data(&mut self, size: usize) -> Vec<u8> {
            let mut b = vec![0u8; size];
            self.fill_random_data(&mut b);
            b
        }
        fn fill_random_data(&mut self, data: &mut [u8]) {
            let mut b = 0u8;
            data.iter_mut().for_each(|x| {
                *x = b;
                b = b.wrapping_add(17);
            });
        }
    }
    #[test]
    fn test_split_secret_3_5() {
        let mut rng = FakeRandomNumberGenerator;
        let secret = hex!("0ff784df000c4380a5ed683f7e6e3dcf");
        //println!("secret: {}", hex::encode(secret));
        let shares = split_secret(3, 5, &secret, &mut rng).unwrap();
        assert_eq!(shares.len(), 5);
        //shares.iter().enumerate().for_each(|(index, share)| println!("{}: {}", index, hex::encode(share)));
        assert_eq!(shares[0], hex!("00112233445566778899aabbccddeeff"));
        assert_eq!(shares[1], hex!("d43099fe444807c46921a4f33a2a798b"));
        assert_eq!(shares[2], hex!("d9ad4e3bec2e1a7485698823abf05d36"));
        assert_eq!(shares[3], hex!("0d8cf5f6ec337bc764d1866b5d07ca42"));
        assert_eq!(shares[4], hex!("1aa7fe3199bc5092ef3816b074cabdf2"));
        let recovered_share_indexes = vec![1, 2, 4];
        let recovered_shares = recovered_share_indexes.iter().map(|index| shares[*index].clone()).collect::<Vec<_>>();
        let recovered_secret = recover_secret(&recovered_share_indexes, &recovered_shares).unwrap();
        assert_eq!(recovered_secret, secret);
    }
    #[test]
    fn test_split_secret_2_7() {
        let mut rng = FakeRandomNumberGenerator;
        let secret = hex!("204188bfa6b440a1bdfd6753ff55a8241e07af5c5be943db917e3efabc184b1a");
        //println!("secret: {}", hex::encode(secret));
        let shares = split_secret(2, 7, &secret, &mut rng).unwrap();
        assert_eq!(shares.len(), 7);
        //shares.iter().enumerate().for_each(|(index, share)| println!("{}: {}", index, hex::encode(share)));
        assert_eq!(shares[0], hex!("2dcd14c2252dc8489af3985030e74d5a48e8eff1478ab86e65b43869bf39d556"));
        assert_eq!(shares[1], hex!("a1dfdd798388aada635b9974472b4fc59a32ae520c42c9f6a0af70149b882487"));
        assert_eq!(shares[2], hex!("2ee99daf727c0c7773b89a18de64497ff7476dacd1015a45f482a893f7402cef"));
        assert_eq!(shares[3], hex!("a2fb5414d4d96ee58a109b3ca9a84be0259d2c0f9ac92bdd3199e0eed3f1dd3e"));
        assert_eq!(shares[4], hex!("2b851d188b8f5b3653659cc0f7fa45102dadf04b708767385cd803862fcb3c3f"));
        assert_eq!(shares[5], hex!("a797d4a32d2a39a4aacd9de48036478fff77b1e83b4f16a099c34bfb0b7acdee"));
        assert_eq!(shares[6], hex!("28a19475dcde9f09ba2e9e881979413592027216e60c8513cdee937c67b2c586"));
        let recovered_share_indexes = vec![3, 4];
        let recovered_shares = recovered_share_indexes.iter().map(|index| shares[*index].clone()).collect::<Vec<_>>();
        let recovered_secret = recover_secret(&recovered_share_indexes, &recovered_shares).unwrap();
        assert_eq!(recovered_secret, secret);
    }
    #[test]
    fn test_readme_deps() {
        version_sync::assert_markdown_deps_updated!("README.md");
    }
    #[test]
    fn test_html_root_url() {
        version_sync::assert_html_root_url_updated!("src/lib.rs");
    }
}