mirror of
https://github.com/mii443/RustySecrets.git
synced 2025-08-22 16:25:32 +00:00
* Update rustfmt compliance Looks like rustfmt has made some improvements recently, so wanted to bring the code up to date. * Add rustfmt to nightly item in Travis matrix * Use Travis Cargo cache * Allow fast_finish in Travis Items that match the `allow_failures` predicate (right now, just Rust nightly), will still finish, but Travis won't wait for them to report a result if the other builds have already finished. * Run kcov in a separate matrix build in Travis * Rework allowed_failures logic We don't want rustfmt to match `allow_failures` just because it needs to use nightly, while we do want nightly to match `allow_failures`. Env vars provide a solution. * Add --all switch to rustfmt Travis * Test building docs in Travis * Use exact Ubuntu dependencies listed for kcov Some of the dependencies we were installing were not listed on https://github.com/SimonKagstrom/kcov/blob/master/INSTALL.md, and we were missing one dependency that was listed there. When `sudo: true` Travis uses Ubuntu Trusty. * No need to build before running kcov kcov builds its own test executables. * Generate `Cargo.lock` w/ `cargo update` before running kcov As noted in aeb3906cce8e3e26c7bc80d6aec417b365f3d2f1 it is not necessary to build the project before running kcov, but kcov does require a `Cargo.lock` file, which can be generated with `cargo update`.
134 lines
4.0 KiB
Rust
134 lines
4.0 KiB
Rust
//! Simple threshold secret sharing scheme
|
|
|
|
use std::fmt;
|
|
|
|
use ring::rand::{SecureRandom, SystemRandom};
|
|
|
|
use dss::random::{random_bytes, random_bytes_count, MAX_MESSAGE_SIZE};
|
|
use errors::*;
|
|
use gf256::Gf256;
|
|
use lagrange;
|
|
use share::validation::{validate_share_count, validate_shares};
|
|
|
|
use super::AccessStructure;
|
|
use super::encode::encode_secret;
|
|
use super::share::*;
|
|
|
|
/// We bound the message size at about 16MB to avoid overflow in `random_bytes_count`.
|
|
/// Moreover, given the current performances, it is almost unpractical to run
|
|
/// the sharing scheme on message larger than that.
|
|
const MAX_SECRET_SIZE: usize = MAX_MESSAGE_SIZE;
|
|
|
|
/// A simple threshold sharing scheme
|
|
#[allow(missing_debug_implementations)]
|
|
pub(crate) struct ThSS {
|
|
/// The randomness source
|
|
random: Box<SecureRandom>,
|
|
}
|
|
|
|
impl fmt::Debug for ThSS {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "ThSS")
|
|
}
|
|
}
|
|
|
|
impl Default for ThSS {
|
|
fn default() -> Self {
|
|
Self::new(Box::new(SystemRandom::new()))
|
|
}
|
|
}
|
|
|
|
impl ThSS {
|
|
/// Constructs a new sharing scheme
|
|
pub fn new(random: Box<SecureRandom>) -> Self {
|
|
Self { random }
|
|
}
|
|
|
|
/// Split a secret following a given sharing `scheme`,
|
|
/// with `threshold` being the number of shares necessary to recover the secret,
|
|
/// and `shares_count` the total number of shares to be dealt.
|
|
pub fn split_secret(
|
|
&self,
|
|
threshold: u8,
|
|
shares_count: u8,
|
|
secret: &[u8],
|
|
metadata: &Option<MetaData>,
|
|
) -> Result<Vec<Share>> {
|
|
let (threshold, shares_count) = validate_share_count(threshold, shares_count)?;
|
|
let secret_len = secret.len();
|
|
|
|
if secret_len == 0 {
|
|
bail!(ErrorKind::EmptySecret);
|
|
}
|
|
if secret_len > MAX_SECRET_SIZE {
|
|
bail!(ErrorKind::SecretTooBig(secret_len, MAX_SECRET_SIZE));
|
|
}
|
|
|
|
let rands_len = random_bytes_count(threshold, secret_len);
|
|
let rands = random_bytes(self.random.as_ref(), rands_len)?;
|
|
|
|
let shares = (1..shares_count + 1)
|
|
.map(|id| {
|
|
let data = encode_secret(secret, threshold, id, &rands);
|
|
|
|
Share {
|
|
id,
|
|
threshold,
|
|
shares_count,
|
|
data,
|
|
metadata: metadata.clone(),
|
|
}
|
|
})
|
|
.collect();
|
|
|
|
Ok(shares)
|
|
}
|
|
|
|
/// Recover the secret from the given set of shares
|
|
pub fn recover_secret(
|
|
&self,
|
|
shares: &[Share],
|
|
) -> Result<(Vec<u8>, AccessStructure, Option<MetaData>)> {
|
|
let shares = shares.to_vec();
|
|
let (threshold, cypher_len) = validate_shares(&shares)?;
|
|
|
|
let polys = (0..cypher_len)
|
|
.map(|i| {
|
|
let points = shares
|
|
.iter()
|
|
.take(threshold as usize)
|
|
.map(|share| (Gf256::from_byte(share.id), Gf256::from_byte(share.data[i])))
|
|
.collect::<Vec<_>>();
|
|
|
|
lagrange::interpolate(&points)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
for (i, poly) in polys.iter().enumerate() {
|
|
// Check remaining shares for consistency.
|
|
// See Figure 7 of the paper
|
|
let remaining_shares = shares.iter().enumerate().skip(threshold as usize);
|
|
|
|
for (u, share) in remaining_shares {
|
|
let value = poly.evaluate_at(Gf256::from_byte(u as u8 + 1)).to_byte();
|
|
if value != share.data[i] {
|
|
bail!(ErrorKind::InconsistentShares);
|
|
}
|
|
}
|
|
}
|
|
|
|
let metadata = shares[0].metadata.clone();
|
|
let secret = polys
|
|
.iter()
|
|
.map(|p| p.evaluate_at_zero().to_byte())
|
|
.collect();
|
|
|
|
let access_structure = AccessStructure {
|
|
threshold: threshold,
|
|
shares_count: shares.first().unwrap().shares_count,
|
|
};
|
|
|
|
Ok((secret, access_structure, metadata))
|
|
}
|
|
}
|