use ark_ff::Zero;
use super::verifiers::{
verify_using_aggregated_auxiliary_public_keys, verify_with_distinct_messages,
};
use super::*;
use digest::{DynDigest, FixedOutputReset};
use core::iter::once;
use double::PublicKeyInSignatureGroup;
use single::PublicKey;
#[derive(Clone)]
pub struct SignatureAggregatorAssumingPoP<E: EngineBLS> {
message: Message,
aggregated_publickey: PublicKey<E>,
signature: Signature<E>,
aggregated_auxiliary_public_key: PublicKeyInSignatureGroup<E>,
}
impl<E: EngineBLS> SignatureAggregatorAssumingPoP<E> {
pub fn new(message: Message) -> SignatureAggregatorAssumingPoP<E> {
SignatureAggregatorAssumingPoP {
message: message,
aggregated_publickey: PublicKey(E::PublicKeyGroup::zero()),
signature: Signature(E::SignatureGroup::zero()),
aggregated_auxiliary_public_key: PublicKeyInSignatureGroup(E::SignatureGroup::zero()),
}
}
pub fn add_signature(&mut self, signature: &Signature<E>) {
self.signature.0 += &signature.0;
}
pub fn add_publickey(&mut self, publickey: &PublicKey<E>) {
self.aggregated_publickey.0 += publickey.0;
}
pub fn add_auxiliary_public_key(
&mut self,
publickey_in_signature_group: &PublicKeyInSignatureGroup<E>,
) {
self.aggregated_auxiliary_public_key.0 += publickey_in_signature_group.0;
}
pub fn aggregated_publickey(&self) -> PublicKey<E> {
self.aggregated_publickey
}
pub fn verify_using_aggregated_auxiliary_public_keys<
RandomOracle: DynDigest + FixedOutputReset + Default + Clone,
>(
&self,
) -> bool {
verify_using_aggregated_auxiliary_public_keys::<E, RandomOracle>(
self,
true,
self.aggregated_auxiliary_public_key.0,
)
}
}
impl<'a, E: EngineBLS> Signed for &'a SignatureAggregatorAssumingPoP<E> {
type E = E;
type M = Message;
type PKG = PublicKey<Self::E>;
type PKnM = ::core::iter::Once<(Message, PublicKey<E>)>;
fn messages_and_publickeys(self) -> Self::PKnM {
once((self.message.clone(), self.aggregated_publickey)) }
fn signature(&self) -> Signature<E> {
self.signature
}
fn verify(self) -> bool {
verify_with_distinct_messages(self, true)
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use crate::EngineBLS;
use crate::Keypair;
use crate::Message;
use crate::TinyBLS;
use crate::UsualBLS;
use rand::thread_rng;
use sha2::Sha256;
use ark_bls12_377::Bls12_377;
use ark_bls12_381::Bls12_381;
use super::*;
#[test]
fn verify_aggregate_single_message_single_signer() {
let good = Message::new(b"ctx", b"test message");
let mut keypair =
Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(thread_rng());
let good_sig0 = keypair.sign(&good);
assert!(good_sig0.verify(&good, &keypair.public));
}
#[test]
fn verify_aggregate_single_message_multi_signers() {
let good = Message::new(b"ctx", b"test message");
let mut keypair0 =
Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(thread_rng());
let good_sig0 = keypair0.sign(&good);
let mut keypair1 =
Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(thread_rng());
let good_sig1 = keypair1.sign(&good);
let mut aggregated_sigs =
SignatureAggregatorAssumingPoP::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::new(good);
aggregated_sigs.add_signature(&good_sig0);
aggregated_sigs.add_signature(&good_sig1);
aggregated_sigs.add_publickey(&keypair0.public);
aggregated_sigs.add_publickey(&keypair1.public);
assert!(
aggregated_sigs.verify() == true,
"good aggregated signature of a single message with multiple key does not verify"
);
}
#[test]
fn verify_aggregate_single_message_repetative_signers() {
let good = Message::new(b"ctx", b"test message");
let mut keypair =
Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(thread_rng());
let good_sig = keypair.sign(&good);
let mut aggregated_sigs =
SignatureAggregatorAssumingPoP::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::new(good);
aggregated_sigs.add_signature(&good_sig);
aggregated_sigs.add_signature(&good_sig);
aggregated_sigs.add_publickey(&keypair.public);
aggregated_sigs.add_publickey(&keypair.public);
assert!(
aggregated_sigs.verify() == true,
"good aggregate of a repetitive signature does not verify"
);
}
#[test]
fn aggregate_of_signature_of_a_wrong_message_should_not_verify() {
let good0 = Message::new(b"ctx", b"Space over Tab");
let bad1 = Message::new(b"ctx", b"Tab over Space");
let mut keypair0 =
Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(thread_rng());
let good_sig0 = keypair0.sign(&good0);
let mut keypair1 =
Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(thread_rng());
let bad_sig1 = keypair1.sign(&bad1);
let mut aggregated_sigs = SignatureAggregatorAssumingPoP::<
UsualBLS<Bls12_381, ark_bls12_381::Config>,
>::new(good0);
aggregated_sigs.add_signature(&good_sig0);
aggregated_sigs.add_signature(&bad_sig1);
aggregated_sigs.add_publickey(&keypair0.public);
aggregated_sigs.add_publickey(&keypair1.public);
assert!(
aggregated_sigs.verify() == false,
"aggregated signature of a wrong message should not verify"
);
}
#[test]
fn test_aggregate_tiny_sigs_and_verify_in_g1() {
let message = Message::new(b"ctx", b"test message");
let mut keypairs: Vec<_> = (0..3)
.into_iter()
.map(|_| Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(thread_rng()))
.collect();
let pub_keys_in_sig_grp: Vec<PublicKeyInSignatureGroup<TinyBLS377>> = keypairs
.iter()
.map(|k| k.into_public_key_in_signature_group())
.collect();
let mut aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new(message.clone());
let mut aggregated_public_key =
PublicKey::<TinyBLS377>(<TinyBLS377 as EngineBLS>::PublicKeyGroup::zero());
for k in &mut keypairs {
aggregator.add_signature(&k.sign(&message));
aggregated_public_key.0 += k.public.0;
}
let mut verifier_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new(message);
verifier_aggregator.add_signature(&aggregator.signature);
verifier_aggregator.add_publickey(&aggregated_public_key);
for k in &pub_keys_in_sig_grp {
verifier_aggregator.add_auxiliary_public_key(k);
}
assert!(
verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifying with honest auxilary public key should pass"
);
verifier_aggregator
.add_auxiliary_public_key(&keypairs[0].into_public_key_in_signature_group());
assert!(
!verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verification using non-matching auxilary public key should fail"
);
}
}