use ark_ff::Zero;
use std::collections::HashMap;
use super::single::SignedMessage;
use super::verifiers::verify_with_distinct_messages;
use super::*;
#[derive(Debug)]
pub struct AttackViaDuplicateMessages;
impl ::std::fmt::Display for AttackViaDuplicateMessages {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "Attempted to aggregate duplicate messages.")
}
}
impl ::std::error::Error for AttackViaDuplicateMessages {
fn description(&self) -> &str {
"Attempted to aggregate duplicate messages."
}
}
#[derive(Clone)]
pub struct DistinctMessages<E: EngineBLS> {
messages_n_publickeys: HashMap<Message, PublicKey<E>>,
signature: Signature<E>,
}
impl<'a, E: EngineBLS> Signed for &'a DistinctMessages<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, false)
}
}
impl<E: EngineBLS> DistinctMessages<E> {
pub fn new() -> DistinctMessages<E> {
DistinctMessages {
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>,
) -> DistinctMessagesResult<E> {
if let Some(_old_publickey) = self.messages_n_publickeys.insert(message, publickey) {
return Err(AttackViaDuplicateMessages);
}
Ok(self)
}
pub fn add(self, signed: &SignedMessage<E>) -> DistinctMessagesResult<E> {
let mut me = self.add_message_n_publickey(signed.message.clone(), signed.publickey)?;
me.add_signature(&signed.signature);
Ok(me)
}
pub fn merge(mut self, signed: &DistinctMessages<E>) -> DistinctMessagesResult<E> {
for (m, pk) in signed.messages_n_publickeys.iter() {
if self.messages_n_publickeys.insert(m.clone(), *pk).is_some() {
return Err(AttackViaDuplicateMessages);
}
}
self.add_signature(&signed.signature);
Ok(self)
}
}
pub type DistinctMessagesResult<E> = Result<DistinctMessages<E>, AttackViaDuplicateMessages>;
#[cfg(all(test, feature = "std"))]
mod tests {
use rand::thread_rng;
use super::*;
#[test]
fn distinct_messages() {
let msgs = [
Message::new(b"ctx", b"Message1"),
Message::new(b"ctx", b"Message1"),
Message::new(b"ctx", b"Message2"),
Message::new(b"ctx", b"Message3"),
Message::new(b"ctx", b"Message4"),
];
let k = |_| Keypair::<ZBLS>::generate(thread_rng());
let mut keypairs = (0..4).into_iter().map(k).collect::<Vec<_>>();
let dup = keypairs[3].clone();
keypairs.push(dup);
let sigs = msgs
.iter()
.zip(keypairs.iter_mut())
.map(|(m, k)| k.signed_message(m))
.collect::<Vec<_>>();
let dm_new = || DistinctMessages::<ZBLS>::new();
fn dm_add(
dm: DistinctMessages<ZBLS>,
sig: &SignedMessage<ZBLS>,
) -> Result<DistinctMessages<ZBLS>, AttackViaDuplicateMessages> {
dm.add(sig)
}
let mut dms = sigs.iter().skip(1).try_fold(dm_new(), dm_add).unwrap();
assert!(dms.messages_and_publickeys().len() == 4);
let dms0 = sigs.iter().skip(1).try_fold(dm_new(), dm_add).unwrap();
assert!(dms0.merge(&dms).is_err());
assert!(sigs.iter().try_fold(dm_new(), dm_add).is_err());
assert!(dms.verify()); assert!(verifiers::verify_unoptimized(&dms));
assert!(verifiers::verify_simple(&dms));
assert!(verifiers::verify_with_distinct_messages(&dms, true));
let dms1 = sigs
.iter()
.skip(1)
.take(2)
.try_fold(dm_new(), dm_add)
.unwrap();
let dms2 = sigs.iter().skip(3).try_fold(dm_new(), dm_add).unwrap();
assert!(dms1.merge(&dms2).unwrap().signature == dms.signature);
*(dms.messages_n_publickeys.get_mut(&msgs[1]).unwrap()) = keypairs[0].public.clone();
assert!(!dms.verify(), "Verification by an incorrect signer passed");
}
}