use std::borrow::Borrow;
use crate::dl_verification::{batch_coefficients, get_random_scalars};
use crate::polynomial::Poly;
use crate::types::{IndexedValue, UnindexedValues};
use fastcrypto::error::{FastCryptoError, FastCryptoResult};
use fastcrypto::groups::{GroupElement, HashToGroupElement, MultiScalarMul, Scalar};
use fastcrypto::traits::AllowedRng;
use itertools::Itertools;
pub type Share<S> = IndexedValue<S>;
pub type PartialSignature<S> = IndexedValue<S>;
pub type UnindexedPartialSignatures<S> = UnindexedValues<S>;
pub trait ThresholdBls {
type Private: Scalar;
type Public: GroupElement<ScalarType = Self::Private> + MultiScalarMul;
type Signature: GroupElement<ScalarType = Self::Private> + HashToGroupElement + MultiScalarMul;
fn verify(public: &Self::Public, msg: &[u8], sig: &Self::Signature) -> FastCryptoResult<()>;
fn partial_sign(share: &Share<Self::Private>, msg: &[u8]) -> PartialSignature<Self::Signature> {
Self::partial_sign_batch(std::iter::once(share), msg)[0].clone()
}
fn partial_sign_batch(
shares: impl Iterator<Item = impl Borrow<Share<Self::Private>>>,
msg: &[u8],
) -> Vec<PartialSignature<Self::Signature>> {
let h = Self::Signature::hash_to_group_element(msg);
shares
.map(|share| {
let share = share.borrow();
PartialSignature {
index: share.index,
value: h * share.value,
}
})
.collect()
}
fn partial_verify(
vss_pk: &Poly<Self::Public>,
msg: &[u8],
partial_sig: &PartialSignature<Self::Signature>,
) -> FastCryptoResult<()> {
let pk_i = vss_pk.eval(partial_sig.index);
Self::verify(&pk_i.value, msg, &partial_sig.value)
}
fn partial_verify_batch<R: AllowedRng>(
vss_pk: &Poly<Self::Public>,
msg: &[u8],
partial_sigs: impl Iterator<Item = impl Borrow<PartialSignature<Self::Signature>>>,
rng: &mut R,
) -> FastCryptoResult<()> {
assert!(vss_pk.degree() > 0 || !msg.is_empty());
let (evals_as_scalars, points): (Vec<_>, Vec<_>) = partial_sigs
.map(|sig| {
let sig = sig.borrow();
(Self::Private::from(sig.index.get().into()), sig.value)
})
.unzip();
if points.is_empty() {
return Ok(());
}
let rs = get_random_scalars::<Self::Private, R>(points.len(), rng);
let coeffs = batch_coefficients(&rs, &evals_as_scalars, vss_pk.degree());
let pk = Self::Public::multi_scalar_mul(&coeffs, vss_pk.as_vec()).expect("sizes match");
let aggregated_sig = Self::Signature::multi_scalar_mul(&rs, &points).expect("sizes match");
Self::verify(&pk, msg, &aggregated_sig)
}
fn aggregate(
threshold: u16,
partials: impl Iterator<Item = impl Borrow<PartialSignature<Self::Signature>>> + Clone,
) -> FastCryptoResult<Self::Signature> {
let unique_partials = partials
.unique_by(|p| p.borrow().index)
.take(threshold as usize);
if unique_partials.clone().count() != threshold as usize {
return Err(FastCryptoError::NotEnoughInputs);
}
Poly::<Self::Signature>::recover_c0_msm(threshold, unique_partials)
}
}