#![cfg_attr(not(feature = "std"), no_std)]
mod field;
mod math;
mod share;
extern crate alloc;
use alloc::vec::Vec;
use hashbrown::HashSet;
use field::GF256;
pub use share::Share;
pub struct Sharks(pub u8);
impl Sharks {
pub fn dealer_rng<R: rand::Rng>(
&self,
secret: &[u8],
rng: &mut R,
) -> impl Iterator<Item = Share> {
let mut polys = Vec::with_capacity(secret.len());
for chunk in secret {
polys.push(math::random_polynomial(GF256(*chunk), self.0, rng))
}
math::get_evaluator(polys)
}
#[cfg(feature = "std")]
pub fn dealer(&self, secret: &[u8]) -> impl Iterator<Item = Share> {
let mut rng = rand::thread_rng();
self.dealer_rng(secret, &mut rng)
}
pub fn recover<'a, T>(&self, shares: T) -> Result<Vec<u8>, &str>
where
T: IntoIterator<Item = &'a Share>,
T::IntoIter: Iterator<Item = &'a Share>,
{
let mut share_length: Option<usize> = None;
let mut keys: HashSet<u8> = HashSet::new();
let mut values: Vec<Share> = Vec::new();
for share in shares.into_iter() {
if share_length.is_none() {
share_length = Some(share.y.len());
}
if Some(share.y.len()) != share_length {
return Err("All shares must have the same length");
} else {
keys.insert(share.x.0);
values.push(share.clone());
}
}
if keys.is_empty() || (keys.len() < self.0 as usize) {
Err("Not enough shares to recover original secret")
} else {
Ok(math::interpolate(values.as_slice()))
}
}
}
#[cfg(test)]
mod tests {
use super::{Share, Sharks};
use alloc::{vec, vec::Vec};
impl Sharks {
#[cfg(not(feature = "std"))]
fn make_shares(&self, secret: &[u8]) -> impl Iterator<Item = Share> {
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
let mut rng = ChaCha8Rng::from_seed([0x90; 32]);
self.dealer_rng(secret, &mut rng)
}
#[cfg(feature = "std")]
fn make_shares(&self, secret: &[u8]) -> impl Iterator<Item = Share> {
self.dealer(secret)
}
}
#[test]
fn test_insufficient_shares_err() {
let sharks = Sharks(255);
let shares: Vec<Share> = sharks.make_shares(&[1]).take(254).collect();
let secret = sharks.recover(&shares);
assert!(secret.is_err());
}
#[test]
fn test_duplicate_shares_err() {
let sharks = Sharks(255);
let mut shares: Vec<Share> = sharks.make_shares(&[1]).take(255).collect();
shares[1] = Share {
x: shares[0].x.clone(),
y: shares[0].y.clone(),
};
let secret = sharks.recover(&shares);
assert!(secret.is_err());
}
#[test]
fn test_integration_works() {
let sharks = Sharks(255);
let shares: Vec<Share> = sharks.make_shares(&[1, 2, 3, 4]).take(255).collect();
let secret = sharks.recover(&shares).unwrap();
assert_eq!(secret, vec![1, 2, 3, 4]);
}
}