use crate::*;
use std::collections::HashMap;
#[derive(PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum AggregateSignature<C: BlsSignatureImpl> {
Basic(
#[serde(serialize_with = "traits::signature::serialize::<C, _>")]
#[serde(deserialize_with = "traits::signature::deserialize::<C, _>")]
<C as Pairing>::Signature,
),
MessageAugmentation(
#[serde(serialize_with = "traits::signature::serialize::<C, _>")]
#[serde(deserialize_with = "traits::signature::deserialize::<C, _>")]
<C as Pairing>::Signature,
),
ProofOfPossession(
#[serde(serialize_with = "traits::signature::serialize::<C, _>")]
#[serde(deserialize_with = "traits::signature::deserialize::<C, _>")]
<C as Pairing>::Signature,
),
}
impl<C: BlsSignatureImpl> Default for AggregateSignature<C> {
fn default() -> Self {
Self::ProofOfPossession(<C as Pairing>::Signature::default())
}
}
impl_signature_enum_traits!(AggregateSignature, <C as Pairing>::Signature);
impl<C: BlsSignatureImpl> TryFrom<&[Signature<C>]> for AggregateSignature<C> {
type Error = BlsError;
fn try_from(sigs: &[Signature<C>]) -> Result<Self, Self::Error> {
if sigs.len() < 2 {
return Err(BlsError::InvalidSignature);
}
let first = &sigs[0];
let mut aggregate = *first.as_raw_value();
for s in &sigs[1..] {
if !s.same_scheme(first) {
return Err(BlsError::InvalidSignatureScheme);
}
aggregate += s.as_raw_value();
}
match first {
Signature::Basic(_) => Ok(Self::Basic(aggregate)),
Signature::MessageAugmentation(_) => Ok(Self::MessageAugmentation(aggregate)),
Signature::ProofOfPossession(_) => Ok(Self::ProofOfPossession(aggregate)),
}
}
}
impl_from_derivatives_generic!(AggregateSignature);
impl<C: BlsSignatureImpl> TryFrom<&AggregateSignature<C>> for Vec<u8> {
type Error = BlsError;
fn try_from(value: &AggregateSignature<C>) -> BlsResult<Self> {
serde_bare::to_vec(value).map_err(|e| BlsError::SerializationError(e.to_string()))
}
}
impl<C: BlsSignatureImpl> TryFrom<&[u8]> for AggregateSignature<C> {
type Error = BlsError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
serde_bare::from_slice(value).map_err(BlsError::from)
}
}
impl<C: BlsSignatureImpl> AggregateSignature<C> {
pub const fn scheme(&self) -> SignatureSchemes {
match self {
Self::Basic(_) => SignatureSchemes::Basic,
Self::MessageAugmentation(_) => SignatureSchemes::MessageAugmentation,
Self::ProofOfPossession(_) => SignatureSchemes::ProofOfPossession,
}
}
pub fn from_signatures<B: AsRef<[Signature<C>]>>(signatures: B) -> BlsResult<Self> {
Self::try_from(signatures.as_ref())
}
pub fn verify<B: AsRef<[u8]>>(&self, data: &[(PublicKey<C>, B)]) -> BlsResult<()> {
if data.len() < 2 {
return Err(BlsError::InvalidInputs(
"at least two public key and message pairs are required".to_string(),
));
}
match self {
Self::Basic(sig) => {
let mut messages = HashMap::with_capacity(data.len());
for (index, (_, message)) in data.iter().enumerate() {
if let Some(previous) = messages.insert(message.as_ref(), index) {
return Err(BlsError::InvalidInputs(format!(
"duplicate messages detected at {} and {}",
previous, index
)));
}
}
<C as BlsSignatureCore>::core_aggregate_verify(
data.iter().map(|(pk, message)| (pk.0, message.as_ref())),
*sig,
<C as BlsSignatureBasic>::DST,
)
}
Self::MessageAugmentation(sig) => {
<C as BlsSignatureMessageAugmentation>::aggregate_verify(
data.iter().map(|(pk, message)| (pk.0, message)),
*sig,
)
}
Self::ProofOfPossession(sig) => <C as BlsSignaturePop>::aggregate_verify(
data.iter().map(|(pk, message)| (pk.0, message)),
*sig,
),
}
}
}