use super::*;
use generic_array::{ArrayLength, GenericArray};
use hybrid_array::{Array, ArraySize};
use rand_core::{CryptoRng, RngCore};
pub trait Shamir<S>
where
S: Share,
{
type InnerPolynomial: Polynomial<S>;
type ShareSet: WriteableShareSet<S>;
fn split_secret(
threshold: usize,
limit: usize,
secret: &S::Value,
rng: impl RngCore + CryptoRng,
) -> VsssResult<Self::ShareSet> {
check_params(threshold, limit)?;
let generator = ParticipantIdGeneratorType::<S::Identifier>::default();
Self::split_secret_with_participant_generator(threshold, limit, secret, rng, &[generator])
}
fn split_secret_with_participant_generator(
threshold: usize,
limit: usize,
secret: &S::Value,
rng: impl RngCore + CryptoRng,
participant_generators: &[ParticipantIdGeneratorType<S::Identifier>],
) -> VsssResult<Self::ShareSet> {
check_params(threshold, limit)?;
let mut polynomial = Self::InnerPolynomial::create(threshold);
polynomial.fill(secret, rng, threshold)?;
let ss = create_shares_with_participant_generator(
&polynomial,
threshold,
limit,
participant_generators,
)?;
Ok(ss)
}
}
pub(crate) fn create_shares_with_participant_generator<P, S, SS>(
polynomial: &P,
threshold: usize,
limit: usize,
participant_generators: &[ParticipantIdGeneratorType<S::Identifier>],
) -> VsssResult<SS>
where
P: Polynomial<S>,
S: Share,
SS: WriteableShareSet<S>,
{
let mut shares = SS::create(limit);
let indexer = shares.as_mut();
let participant_id_collection = ParticipantIdGeneratorCollection::from(participant_generators);
let mut participant_id_iter = participant_id_collection.iter();
for s in indexer.iter_mut().take(limit) {
let id = participant_id_iter
.next()
.ok_or(Error::NotEnoughShareIdentifiers)?;
let value = polynomial.evaluate(&id, threshold);
let share = S::with_identifier_and_value(id, value);
*s = share;
}
Ok(shares)
}
pub(crate) fn check_params(threshold: usize, limit: usize) -> VsssResult<()> {
if limit < threshold {
return Err(Error::SharingLimitLessThanThreshold);
}
if threshold < 2 {
return Err(Error::SharingMinThreshold);
}
Ok(())
}
impl<S: Share, const L: usize> Shamir<S> for [S; L] {
type InnerPolynomial = [S; L];
type ShareSet = [S; L];
}
impl<S: Share, L: ArrayLength> Shamir<S> for GenericArray<S, L> {
type InnerPolynomial = GenericArray<S, L>;
type ShareSet = GenericArray<S, L>;
}
impl<S: Share, L: ArraySize> Shamir<S> for Array<S, L> {
type InnerPolynomial = Array<S, L>;
type ShareSet = Array<S, L>;
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<S: Share> Shamir<S> for Vec<S> {
type InnerPolynomial = Vec<S>;
type ShareSet = Vec<S>;
}
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn split_secret<S: Share>(
threshold: usize,
limit: usize,
secret: &S::Value,
rng: impl RngCore + CryptoRng,
) -> VsssResult<Vec<S>> {
StdVsssShamir::split_secret(threshold, limit, secret, rng)
}
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn split_secret_with_participant_generator<S: Share>(
threshold: usize,
limit: usize,
secret: &S::Value,
rng: impl RngCore + CryptoRng,
participant_generators: &[ParticipantIdGeneratorType<S::Identifier>],
) -> VsssResult<Vec<S>> {
StdVsssShamir::split_secret_with_participant_generator(
threshold,
limit,
secret,
rng,
participant_generators,
)
}
#[cfg(any(feature = "alloc", feature = "std"))]
struct StdVsssShamir<S: Share> {
_marker: core::marker::PhantomData<S>,
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<S: Share> Shamir<S> for StdVsssShamir<S> {
type InnerPolynomial = Vec<S>;
type ShareSet = Vec<S>;
}