use core::borrow::Borrow; use std::collections::HashMap;
use ark_ff::Zero;
use super::verifiers::verify_with_distinct_messages;
use super::*;
use single::PublicKey;
#[derive(Clone)]
pub struct MultiMessageSignatureAggregatorAssumingPoP<E: EngineBLS> {
messages_n_publickeys: HashMap<Message, PublicKey<E>>,
signature: Signature<E>,
}
impl<E: EngineBLS> MultiMessageSignatureAggregatorAssumingPoP<E> {
pub fn new() -> MultiMessageSignatureAggregatorAssumingPoP<E> {
MultiMessageSignatureAggregatorAssumingPoP {
messages_n_publickeys: HashMap::new(),
signature: Signature(E::SignatureGroup::zero()),
}
}
pub fn add_signature(&mut self, signature: &Signature<E>) {
self.signature.0 += &signature.0;
}
pub fn add_message_n_publickey(&mut self, message: &Message, publickey: &PublicKey<E>) {
self.messages_n_publickeys
.entry(message.clone())
.and_modify(|pk0| pk0.0 += &publickey.0)
.or_insert(*publickey);
}
pub fn aggregate<'a, S>(&mut self, signed: &'a S)
where
&'a S: Signed<E = E>,
<&'a S as Signed>::PKG: Borrow<PublicKey<E>>,
{
let signature = signed.signature();
for (message, pubickey) in signed.messages_and_publickeys() {
self.add_message_n_publickey(message.borrow(), pubickey.borrow());
}
self.add_signature(&signature);
}
}
impl<'a, E: EngineBLS> Signed for &'a MultiMessageSignatureAggregatorAssumingPoP<E> {
type E = E;
type M = &'a Message;
type PKG = &'a PublicKey<Self::E>;
type PKnM = ::std::collections::hash_map::Iter<'a, Message, PublicKey<E>>;
fn messages_and_publickeys(self) -> Self::PKnM {
self.messages_n_publickeys.iter()
}
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::Keypair;
use crate::Message;
use crate::UsualBLS;
use rand::thread_rng;
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 = MultiMessageSignatureAggregatorAssumingPoP::<
UsualBLS<Bls12_381, ark_bls12_381::Config>,
>::new();
aggregated_sigs.add_signature(&good_sig0);
aggregated_sigs.add_signature(&good_sig1);
aggregated_sigs.add_message_n_publickey(&good, &keypair0.public);
aggregated_sigs.add_message_n_publickey(&good, &keypair1.public);
assert!(
aggregated_sigs.verify() == true,
"good aggregated signature of a single message with multiple key does not verify"
);
}
#[test]
fn verify_aggregate_multi_messages_single_signer() {
let good0 = Message::new(b"ctx", b"Tab over Space");
let good1 = Message::new(b"ctx", b"Space over Tab");
let mut keypair =
Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(thread_rng());
let good_sig0 = keypair.sign(&good0);
let good_sig1 = keypair.sign(&good1);
let mut aggregated_sigs = MultiMessageSignatureAggregatorAssumingPoP::<
UsualBLS<Bls12_381, ark_bls12_381::Config>,
>::new();
aggregated_sigs.add_signature(&good_sig0);
aggregated_sigs.add_signature(&good_sig1);
aggregated_sigs.add_message_n_publickey(&good0, &keypair.public);
aggregated_sigs.add_message_n_publickey(&good1, &keypair.public);
assert!(
aggregated_sigs.verify() == true,
"good aggregated signature of multiple messages with a single key does not verify"
);
}
#[test]
fn verify_aggregate_multi_messages_multi_signers() {
let good0 = Message::new(b"ctx", b"in the beginning");
let good1 = Message::new(b"ctx", b"there was a flying spaghetti monster");
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 good_sig1 = keypair1.sign(&good1);
let mut aggregated_sigs = MultiMessageSignatureAggregatorAssumingPoP::<
UsualBLS<Bls12_381, ark_bls12_381::Config>,
>::new();
aggregated_sigs.add_signature(&good_sig0);
aggregated_sigs.add_signature(&good_sig1);
aggregated_sigs.add_message_n_publickey(&good0, &keypair0.public);
aggregated_sigs.add_message_n_publickey(&good1, &keypair1.public);
assert!(
aggregated_sigs.verify() == true,
"good aggregated signature of multiple messages with multiple keys 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 = MultiMessageSignatureAggregatorAssumingPoP::<
UsualBLS<Bls12_381, ark_bls12_381::Config>,
>::new();
aggregated_sigs.add_signature(&good_sig);
aggregated_sigs.add_signature(&good_sig);
aggregated_sigs.add_message_n_publickey(&good, &keypair.public);
aggregated_sigs.add_message_n_publickey(&good, &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 = MultiMessageSignatureAggregatorAssumingPoP::<
UsualBLS<Bls12_381, ark_bls12_381::Config>,
>::new();
aggregated_sigs.add_signature(&good_sig0);
aggregated_sigs.add_signature(&bad_sig1);
aggregated_sigs.add_message_n_publickey(&good0, &keypair0.public);
aggregated_sigs.add_message_n_publickey(&good0, &keypair1.public);
assert!(
aggregated_sigs.verify() == false,
"aggregated signature of a wrong message should not verify"
);
}
}