use core::borrow::Borrow;
use alloc::collections::BTreeMap;
use ark_ff::Zero;
use super::verifiers::{
verify_using_aggregated_auxiliary_public_keys, verify_with_distinct_messages,
};
use super::*;
use digest::FixedOutputReset;
use nugget::PublicKeyInSignatureGroup;
use single::PublicKey;
#[derive(Clone)]
pub struct SignatureAggregatorAssumingPoP<E: EngineBLS> {
messages_n_publickeys: BTreeMap<Message, (PublicKey<E>, PublicKeyInSignatureGroup<E>)>,
signature: Signature<E>,
}
impl<E: EngineBLS> SignatureAggregatorAssumingPoP<E> {
pub fn new() -> SignatureAggregatorAssumingPoP<E> {
SignatureAggregatorAssumingPoP {
messages_n_publickeys: BTreeMap::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: &impl GeneralizedBLSPublicKey<E>,
) {
let pk = publickey.public_key();
let aux = publickey.public_key_in_signature_group();
self.messages_n_publickeys
.entry(message.clone())
.and_modify(|(pk0, aux0)| {
pk0.0 += &pk.0;
aux0.0 += &aux.0;
})
.or_insert((pk, aux));
}
pub fn aggregate_aux_publickey_for_message_n_publickey(
&mut self,
message: &Message,
publickey: &PublicKey<E>,
aux: &PublicKeyInSignatureGroup<E>,
) -> Result<(), &'static str> {
match self.messages_n_publickeys.get_mut(message) {
Some((existing_pk, existing_aux)) if existing_pk.0 == publickey.0 => {
existing_aux.0 += &aux.0;
Ok(())
}
Some(_) => Err("message already exists with a different public key"),
None => {
self.messages_n_publickeys
.insert(message.clone(), (*publickey, *aux));
Ok(())
}
}
}
pub fn aggregate<'a, S>(&mut self, signed: &'a S)
where
&'a S: Signed<E = E>,
{
let signature = signed.signature();
for (message, publickey) in signed.messages_and_publickeys() {
self.add_message_n_publickey(message.borrow(), &publickey);
}
self.add_signature(&signature);
}
pub fn verify_using_aggregated_auxiliary_public_keys<
RandomOracle: FixedOutputReset + Default + Clone,
>(
&self,
) -> bool {
verify_using_aggregated_auxiliary_public_keys::<_, RandomOracle>(self, true)
}
}
impl<'a, E: EngineBLS> Signed for &'a SignatureAggregatorAssumingPoP<E> {
type E = E;
type M = &'a Message;
type PKG = &'a (PublicKey<E>, PublicKeyInSignatureGroup<E>);
fn messages_and_publickeys(
self,
) -> impl Iterator<
Item = (
&'a Message,
&'a (PublicKey<E>, PublicKeyInSignatureGroup<E>),
),
> + ExactSizeIterator {
self.messages_n_publickeys.iter()
}
fn signature(&self) -> Signature<E> {
self.signature
}
fn verify(self) -> bool {
verify_with_distinct_messages(self, true)
}
}
#[cfg(test)]
mod tests {
use crate::EngineBLS;
use crate::Keypair;
use crate::Message;
use crate::TinyBLS;
use crate::UsualBLS;
use rand::SeedableRng;
use rand::rngs::StdRng;
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(
StdRng::from_seed([0u8; 32]),
);
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(
StdRng::from_seed([0u8; 32]),
);
let good_sig0 = keypair0.sign(&good);
let mut keypair1 = Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(
StdRng::from_seed([1u8; 32]),
);
let good_sig1 = keypair1.sign(&good);
let mut aggregated_sigs =
SignatureAggregatorAssumingPoP::<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(
StdRng::from_seed([0u8; 32]),
);
let good_sig0 = keypair.sign(&good0);
let good_sig1 = keypair.sign(&good1);
let mut aggregated_sigs =
SignatureAggregatorAssumingPoP::<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(
StdRng::from_seed([0u8; 32]),
);
let good_sig0 = keypair0.sign(&good0);
let mut keypair1 = Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(
StdRng::from_seed([1u8; 32]),
);
let good_sig1 = keypair1.sign(&good1);
let mut aggregated_sigs =
SignatureAggregatorAssumingPoP::<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(
StdRng::from_seed([0u8; 32]),
);
let good_sig = keypair.sign(&good);
let mut aggregated_sigs =
SignatureAggregatorAssumingPoP::<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(
StdRng::from_seed([0u8; 32]),
);
let good_sig0 = keypair0.sign(&good0);
let mut keypair1 = Keypair::<UsualBLS<Bls12_381, ark_bls12_381::Config>>::generate(
StdRng::from_seed([1u8; 32]),
);
let bad_sig1 = keypair1.sign(&bad1);
let mut aggregated_sigs =
SignatureAggregatorAssumingPoP::<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"
);
}
#[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(|i| {
Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(StdRng::from_seed(
[i; 32],
))
})
.collect();
let pub_keys_in_sig_grp: Vec<PublicKeyInSignatureGroup<TinyBLS377>> = keypairs
.iter()
.map(|k| {
nugget::NuggetBLS::<
TinyBLS<Bls12_377, ark_bls12_377::Config>,
<TinyBLS<Bls12_377, ark_bls12_377::Config> as EngineBLS>::SignatureGroup,
>::to_public_key_in_signature_group(k)
})
.collect();
let mut prover_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
for (k, aux) in keypairs.iter_mut().zip(pub_keys_in_sig_grp.iter()) {
prover_aggregator.add_signature(&k.sign(&message));
prover_aggregator.add_message_n_publickey(&message, &(k.public, *aux));
}
assert!(
prover_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"prover: verifying with honest auxilary public key should pass"
);
let mut verifier_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
verifier_aggregator.add_signature(&(&prover_aggregator).signature());
for (msg, (pk, _aux)) in (&prover_aggregator).messages_and_publickeys() {
verifier_aggregator.add_message_n_publickey(msg, pk);
}
let aggregated_pk = (&prover_aggregator)
.messages_and_publickeys()
.next()
.unwrap()
.1
.0;
for aux in &pub_keys_in_sig_grp {
verifier_aggregator
.aggregate_aux_publickey_for_message_n_publickey(&message, &aggregated_pk, aux)
.expect("public key should match");
}
assert!(
verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifier: verifying with honest auxilary public key should pass"
);
let mut bad_verifier = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
bad_verifier.add_signature(&(&prover_aggregator).signature());
for (msg, (pk, _aux)) in (&prover_aggregator).messages_and_publickeys() {
bad_verifier.add_message_n_publickey(msg, pk);
}
bad_verifier
.aggregate_aux_publickey_for_message_n_publickey(
&message,
&aggregated_pk,
&pub_keys_in_sig_grp[1],
)
.unwrap();
bad_verifier
.aggregate_aux_publickey_for_message_n_publickey(
&message,
&aggregated_pk,
&pub_keys_in_sig_grp[1],
)
.unwrap();
bad_verifier
.aggregate_aux_publickey_for_message_n_publickey(
&message,
&aggregated_pk,
&pub_keys_in_sig_grp[2],
)
.unwrap();
assert!(
!bad_verifier.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifier: non-matching auxilary public key should fail"
);
let mut mismatched_verifier = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
mismatched_verifier.add_signature(&(&prover_aggregator).signature());
mismatched_verifier.add_message_n_publickey(&message, &aggregated_pk);
let result = mismatched_verifier.aggregate_aux_publickey_for_message_n_publickey(
&message,
&keypairs[0].public, &pub_keys_in_sig_grp[0],
);
assert!(
result.is_err(),
"aggregate_aux should error when public key does not match existing entry"
);
}
#[test]
fn test_aggregate_tiny_sigs_multi_messages_and_verify_in_g1() {
let messages: Vec<Message> = (0..3)
.map(|i| Message::new(b"ctx", &[b'm', b'0' + i as u8]))
.collect();
let mut keypairs: Vec<_> = (0..3)
.map(|i| {
Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(StdRng::from_seed(
[i; 32],
))
})
.collect();
let pub_keys_in_sig_grp: Vec<PublicKeyInSignatureGroup<TinyBLS377>> = keypairs
.iter()
.map(|k| {
nugget::NuggetBLS::<
TinyBLS<Bls12_377, ark_bls12_377::Config>,
<TinyBLS<Bls12_377, ark_bls12_377::Config> as EngineBLS>::SignatureGroup,
>::to_public_key_in_signature_group(k)
})
.collect();
let mut prover_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
for ((k, m), aux) in keypairs
.iter_mut()
.zip(messages.iter())
.zip(pub_keys_in_sig_grp.iter())
{
prover_aggregator.add_signature(&k.sign(m));
prover_aggregator.add_message_n_publickey(m, &(k.public, *aux));
}
assert!(
prover_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"prover: multi-message aggregate with honest auxilary public keys should pass"
);
let prover_entries: Vec<_> = (&prover_aggregator)
.messages_and_publickeys()
.map(|(m, (pk, aux))| (m.clone(), *pk, *aux))
.collect();
let mut verifier_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
verifier_aggregator.add_signature(&(&prover_aggregator).signature());
for (msg, pk, _) in &prover_entries {
verifier_aggregator.add_message_n_publickey(msg, pk);
}
for (msg, pk, aux) in &prover_entries {
verifier_aggregator
.aggregate_aux_publickey_for_message_n_publickey(msg, pk, aux)
.expect("public key should match");
}
assert!(
verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifier: multi-message aggregate with honest auxilary public keys should pass"
);
let mut bad_verifier = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
bad_verifier.add_signature(&(&prover_aggregator).signature());
for (msg, pk, _) in &prover_entries {
bad_verifier.add_message_n_publickey(msg, pk);
}
for (i, (msg, pk, _)) in prover_entries.iter().enumerate() {
let wrong_aux = &prover_entries[(i + 1) % prover_entries.len()].2;
bad_verifier
.aggregate_aux_publickey_for_message_n_publickey(msg, pk, wrong_aux)
.unwrap();
}
assert!(
!bad_verifier.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifier: non-matching auxilary public key should fail"
);
}
#[test]
fn test_aggregate_tiny_sigs_with_mislabeled_message_fails_verification_in_g1() {
let real_messages: Vec<Message> = (0..3)
.map(|i| Message::new(b"ctx", &[b'm', b'0' + i as u8]))
.collect();
let mut keypairs: Vec<_> = (0..3)
.map(|i| {
Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(StdRng::from_seed(
[i; 32],
))
})
.collect();
let pub_keys_in_sig_grp: Vec<PublicKeyInSignatureGroup<TinyBLS377>> = keypairs
.iter()
.map(|k| {
nugget::NuggetBLS::<
TinyBLS<Bls12_377, ark_bls12_377::Config>,
<TinyBLS<Bls12_377, ark_bls12_377::Config> as EngineBLS>::SignatureGroup,
>::to_public_key_in_signature_group(k)
})
.collect();
let mut prover_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
for ((i, k), aux) in keypairs
.iter_mut()
.enumerate()
.zip(pub_keys_in_sig_grp.iter())
{
prover_aggregator.add_signature(&k.sign(&real_messages[i]));
prover_aggregator.add_message_n_publickey(&real_messages[i], &(k.public, *aux));
}
let prover_entries: Vec<_> = (&prover_aggregator)
.messages_and_publickeys()
.map(|(m, (pk, _))| (m.clone(), *pk))
.collect();
let mut verifier_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
verifier_aggregator.add_signature(&(&prover_aggregator).signature());
for (i, (_msg, pk)) in prover_entries.iter().enumerate() {
let wrong_message = &real_messages[(i + 1) % real_messages.len()];
verifier_aggregator.add_message_n_publickey(wrong_message, pk);
}
for (i, (_msg, pk)) in prover_entries.iter().enumerate() {
let wrong_message = &real_messages[(i + 1) % real_messages.len()];
verifier_aggregator
.aggregate_aux_publickey_for_message_n_publickey(
wrong_message,
pk,
&pub_keys_in_sig_grp[i],
)
.expect("public key should match");
}
assert!(
!verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verification must fail when public keys are paired with the wrong messages"
);
}
#[test]
fn aggregate_tiny_sigs_overlapping_signers_multi_messages_in_g1() {
let messages: Vec<Message> = (0..2)
.map(|i| Message::new(b"ctx", &[b'm', b'0' + i as u8]))
.collect();
let mut keypairs: Vec<_> = (0..3)
.map(|i| {
Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(StdRng::from_seed(
[i; 32],
))
})
.collect();
let signer_list: Vec<(PublicKey<TinyBLS377>, PublicKeyInSignatureGroup<TinyBLS377>)> =
keypairs
.iter()
.map(|k| {
let aux = nugget::NuggetBLS::<
TinyBLS<Bls12_377, ark_bls12_377::Config>,
<TinyBLS<Bls12_377, ark_bls12_377::Config> as EngineBLS>::SignatureGroup,
>::to_public_key_in_signature_group(k);
(k.public, aux)
})
.collect();
let bitfields: [u8; 2] = [0b011, 0b110];
let mut prover_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
for (msg, &bits) in messages.iter().zip(bitfields.iter()) {
for i in 0..signer_list.len() {
if bits & (1 << i) != 0 {
prover_aggregator.add_signature(&keypairs[i].sign(msg));
prover_aggregator
.add_message_n_publickey(msg, &(signer_list[i].0, signer_list[i].1));
}
}
}
assert!(
prover_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"prover: overlapping-signer multi-message aggregate must verify"
);
let aux_key_list: Vec<PublicKeyInSignatureGroup<TinyBLS377>> =
signer_list.iter().map(|(_, aux)| *aux).collect();
let prover_signature = (&prover_aggregator).signature();
let lookup_agg_pk = |target: &Message| -> PublicKey<TinyBLS377> {
(&prover_aggregator)
.messages_and_publickeys()
.find(|(m, _)| *m == target)
.map(|(_, (pk, _aux))| *pk)
.expect("prover must have an entry for every transmitted message")
};
let mut verifier_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
verifier_aggregator.add_signature(&prover_signature);
for (msg, &bits) in messages.iter().zip(bitfields.iter()) {
let agg_pk = lookup_agg_pk(msg);
verifier_aggregator.add_message_n_publickey(msg, &agg_pk);
for i in 0..aux_key_list.len() {
if bits & (1 << i) != 0 {
verifier_aggregator
.aggregate_aux_publickey_for_message_n_publickey(
msg,
&agg_pk,
&aux_key_list[i],
)
.expect("aggregated pk must match the existing entry");
}
}
}
assert!(
verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifier: overlapping-signer multi-message aggregate must verify after attaching aux keys from bitfield"
);
let bad_bitfields: [u8; 2] = [0b110, 0b011];
let mut bad_verifier = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
bad_verifier.add_signature(&prover_signature);
for (msg, &bits) in messages.iter().zip(bad_bitfields.iter()) {
let agg_pk = lookup_agg_pk(msg);
bad_verifier.add_message_n_publickey(msg, &agg_pk);
for i in 0..aux_key_list.len() {
if bits & (1 << i) != 0 {
bad_verifier
.aggregate_aux_publickey_for_message_n_publickey(
msg,
&agg_pk,
&aux_key_list[i],
)
.expect("aggregated pk must match the existing entry");
}
}
}
assert!(
!bad_verifier.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifier: mismatched bitfield must fail"
);
}
#[test]
fn aggregate_tiny_sigs_full_overlap_triggers_message_sum_in_g1() {
let messages: Vec<Message> = (0..2)
.map(|i| Message::new(b"ctx", &[b'm', b'0' + i as u8]))
.collect();
let mut keypairs: Vec<_> = (0..2)
.map(|i| {
Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(StdRng::from_seed(
[i; 32],
))
})
.collect();
let signer_list: Vec<(PublicKey<TinyBLS377>, PublicKeyInSignatureGroup<TinyBLS377>)> =
keypairs
.iter()
.map(|k| {
let aux = nugget::NuggetBLS::<
TinyBLS<Bls12_377, ark_bls12_377::Config>,
<TinyBLS<Bls12_377, ark_bls12_377::Config> as EngineBLS>::SignatureGroup,
>::to_public_key_in_signature_group(k);
(k.public, aux)
})
.collect();
let bitfields: [u8; 2] = [0b11, 0b11];
let mut prover_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
for (msg, &bits) in messages.iter().zip(bitfields.iter()) {
for i in 0..signer_list.len() {
if bits & (1 << i) != 0 {
prover_aggregator.add_signature(&keypairs[i].sign(msg));
prover_aggregator
.add_message_n_publickey(msg, &(signer_list[i].0, signer_list[i].1));
}
}
}
let pks: Vec<_> = (&prover_aggregator)
.messages_and_publickeys()
.map(|(_, (pk, _))| pk.0)
.collect();
assert_eq!(pks.len(), 2);
assert_eq!(
pks[0], pks[1],
"both messages should aggregate to the same pk so the verifier-side merge sums their hashes"
);
assert!(
prover_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"prover: full-overlap aggregate must verify (exercises message-summing merge)"
);
let aux_key_list: Vec<PublicKeyInSignatureGroup<TinyBLS377>> =
signer_list.iter().map(|(_, aux)| *aux).collect();
let prover_signature = (&prover_aggregator).signature();
let lookup_agg_pk = |target: &Message| -> PublicKey<TinyBLS377> {
(&prover_aggregator)
.messages_and_publickeys()
.find(|(m, _)| *m == target)
.map(|(_, (pk, _aux))| *pk)
.expect("prover must have an entry for every transmitted message")
};
let mut verifier_aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
verifier_aggregator.add_signature(&prover_signature);
for (msg, &bits) in messages.iter().zip(bitfields.iter()) {
let agg_pk = lookup_agg_pk(msg);
verifier_aggregator.add_message_n_publickey(msg, &agg_pk);
for i in 0..aux_key_list.len() {
if bits & (1 << i) != 0 {
verifier_aggregator
.aggregate_aux_publickey_for_message_n_publickey(
msg,
&agg_pk,
&aux_key_list[i],
)
.expect("aggregated pk must match the existing entry");
}
}
}
assert!(
verifier_aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifier: full-overlap aggregate must verify"
);
let bad_bitfields: [u8; 2] = [0b01, 0b11];
let mut bad_verifier = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
bad_verifier.add_signature(&prover_signature);
for (msg, &bits) in messages.iter().zip(bad_bitfields.iter()) {
let agg_pk = lookup_agg_pk(msg);
bad_verifier.add_message_n_publickey(msg, &agg_pk);
for i in 0..aux_key_list.len() {
if bits & (1 << i) != 0 {
bad_verifier
.aggregate_aux_publickey_for_message_n_publickey(
msg,
&agg_pk,
&aux_key_list[i],
)
.expect("aggregated pk must match the existing entry");
}
}
}
assert!(
!bad_verifier.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verifier: a bitfield that yields conflicting aux per pk must fail"
);
}
#[test]
fn empty_aggregator_with_identity_signature_is_rejected() {
use crate::verifiers::{verify_simple, verify_unoptimized, verify_with_distinct_messages};
let aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
assert_eq!((&aggregator).messages_and_publickeys().count(), 0);
assert!(!verify_simple(&aggregator), "verify_simple must reject n=0");
assert!(
!verify_unoptimized(&aggregator),
"verify_unoptimized must reject n=0"
);
assert!(
!verify_with_distinct_messages(&aggregator, true),
"verify_with_distinct_messages must reject n=0"
);
assert!(
!aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"verify_using_aggregated_auxiliary_public_keys must reject n=0"
);
}
#[test]
fn aux_key_verifier_rejects_aggregator_without_aux_keys() {
let message = Message::new(b"ctx", b"test message");
let mut keypairs: Vec<_> = (0..3)
.map(|i| {
Keypair::<TinyBLS<Bls12_377, ark_bls12_377::Config>>::generate(StdRng::from_seed(
[i; 32],
))
})
.collect();
let mut aggregator = SignatureAggregatorAssumingPoP::<TinyBLS377>::new();
for k in keypairs.iter_mut() {
aggregator.add_signature(&k.sign(&message));
aggregator.add_message_n_publickey(&message, &k.public);
}
assert!(
(&aggregator).verify(),
"the aggregate without aux keys is itself a valid BLS signature"
);
assert!(
!aggregator.verify_using_aggregated_auxiliary_public_keys::<Sha256>(),
"aux-key verification must reject an aggregator with no auxiliary keys"
);
}
}