use alloc::collections::{BTreeMap, BTreeSet};
use alloc::vec::Vec;
use crate::keys::{KeyPackage, PublicKeyPackage};
use crate::serialization::SerializableScalar;
use crate::{
compute_lagrange_coefficient, Ciphersuite, CryptoRng, Error, Field, Group, Identifier, RngCore,
Scalar,
};
use super::{generate_coefficients, SigningShare};
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct Delta<C: Ciphersuite>(pub(crate) SerializableScalar<C>);
impl<C> Delta<C>
where
C: Ciphersuite,
{
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn new(scalar: Scalar<C>) -> Self {
Self(SerializableScalar(scalar))
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn to_scalar(&self) -> Scalar<C> {
self.0 .0
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableScalar::deserialize(bytes)?))
}
pub fn serialize(&self) -> Vec<u8> {
self.0.serialize()
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct Sigma<C: Ciphersuite>(pub(crate) SerializableScalar<C>);
impl<C> Sigma<C>
where
C: Ciphersuite,
{
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn new(scalar: Scalar<C>) -> Self {
Self(SerializableScalar(scalar))
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn to_scalar(&self) -> Scalar<C> {
self.0 .0
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableScalar::deserialize(bytes)?))
}
pub fn serialize(&self) -> Vec<u8> {
self.0.serialize()
}
}
pub fn repair_share_part1<C: Ciphersuite, R: RngCore + CryptoRng>(
helpers: &[Identifier<C>],
key_package_i: &KeyPackage<C>,
rng: &mut R,
participant: Identifier<C>,
) -> Result<BTreeMap<Identifier<C>, Delta<C>>, Error<C>> {
if helpers.len() < *key_package_i.min_signers() as usize {
return Err(Error::IncorrectNumberOfIdentifiers);
}
if !helpers.contains(&key_package_i.identifier) {
return Err(Error::UnknownIdentifier);
}
let xset: BTreeSet<_> = helpers.iter().cloned().collect();
if xset.len() != helpers.len() {
return Err(Error::DuplicatedIdentifier);
}
let rand_val: Vec<Scalar<C>> = generate_coefficients::<C, R>(helpers.len() - 1, rng);
compute_last_random_value(&xset, key_package_i, &rand_val, participant)
}
fn compute_last_random_value<C: Ciphersuite>(
helpers: &BTreeSet<Identifier<C>>,
key_package_i: &KeyPackage<C>,
random_values: &Vec<Scalar<C>>,
participant: Identifier<C>,
) -> Result<BTreeMap<Identifier<C>, Delta<C>>, Error<C>> {
let zeta_i =
compute_lagrange_coefficient(helpers, Some(participant), key_package_i.identifier)?;
let lhs = zeta_i * key_package_i.signing_share.to_scalar();
let mut out: BTreeMap<Identifier<C>, Delta<C>> = helpers
.iter()
.copied()
.zip(random_values.iter().map(|v| Delta::new(*v)))
.collect();
let mut sum_i_deltas = <<C::Group as Group>::Field>::zero();
for v in random_values {
sum_i_deltas = sum_i_deltas + *v;
}
out.insert(
*helpers.last().ok_or(Error::IncorrectNumberOfIdentifiers)?,
Delta::new(lhs - sum_i_deltas),
);
Ok(out)
}
pub fn repair_share_part2<C: Ciphersuite>(deltas: &[Delta<C>]) -> Sigma<C> {
let mut sigma_j = <<C::Group as Group>::Field>::zero();
for d in deltas {
sigma_j = sigma_j + d.to_scalar();
}
Sigma::new(sigma_j)
}
pub fn repair_share_part3<C: Ciphersuite>(
sigmas: &[Sigma<C>],
identifier: Identifier<C>,
public_key_package: &PublicKeyPackage<C>,
) -> Result<KeyPackage<C>, Error<C>> {
let mut share = <<C::Group as Group>::Field>::zero();
for s in sigmas {
share = share + s.to_scalar();
}
let signing_share = SigningShare::new(share);
let verifying_share = signing_share.into();
Ok(KeyPackage {
header: Default::default(),
identifier,
signing_share,
verifying_share,
verifying_key: *public_key_package.verifying_key(),
min_signers: public_key_package
.min_signers()
.ok_or(Error::InvalidMinSigners)?,
})
}