use ark_ec::CurveGroup;
use ark_ff::BigInteger;
use ark_ff::{PrimeField, Zero};
use ark_serialize::CanonicalSerialize;
use arrayref::array_refs;
#[cfg(feature = "std")]
use rand::thread_rng;
use rand::Rng;
use sha3::{
digest::{ExtendableOutput, Update, XofReader},
Shake128,
};
use std::collections::HashMap;
use super::single::SignedMessage;
use super::verifiers::verify_with_distinct_messages;
use super::*;
pub struct Delinearized<E: EngineBLS> {
key: Shake128,
messages_n_publickeys: HashMap<Message, PublicKey<E>>,
signature: Signature<E>,
}
impl<E: EngineBLS> Clone for Delinearized<E> {
fn clone(&self) -> Delinearized<E> {
Delinearized {
key: self.key.clone(),
messages_n_publickeys: self.messages_n_publickeys.clone(),
signature: self.signature.clone(),
}
}
}
impl<'a, E: EngineBLS> Signed for &'a Delinearized<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)
}
}
impl<E: EngineBLS> Delinearized<E> {
pub fn new(key: Shake128) -> Delinearized<E> {
Delinearized {
key,
messages_n_publickeys: HashMap::new(),
signature: Signature(E::SignatureGroup::zero()),
}
}
pub fn new_keyed(key: &[u8]) -> Delinearized<E> {
let mut t = Shake128::default();
t.update(b"Delinearised BLS with key:");
let l = key.len() as u64;
t.update(&l.to_le_bytes());
t.update(key);
Delinearized::new(t)
}
pub fn new_batched_rng<R: Rng>(mut rng: R) -> Delinearized<E> {
let r = rng.gen::<[u8; 32]>();
Delinearized::new_keyed(&r[..])
}
#[cfg(feature = "std")]
pub fn new_batched() -> Delinearized<E> {
Delinearized::new_batched_rng(thread_rng())
}
pub fn mask(&self, publickey: &PublicKey<E>) -> E::Scalar {
let mut t = self.key.clone();
let pk_affine = publickey.0.into_affine();
let mut pk_uncompressed = vec![0; pk_affine.uncompressed_size()];
pk_affine
.serialize_uncompressed(&mut pk_uncompressed[..])
.unwrap();
t.update(&pk_uncompressed);
let mut b = [0u8; 16];
t.finalize_xof().read(&mut b[..]);
let (x, y) = array_refs!(&b, 8, 8);
let mut x: <E::Scalar as PrimeField>::BigInt = u64::from_le_bytes(*x).into();
let y: <E::Scalar as PrimeField>::BigInt = u64::from_le_bytes(*y).into();
x.muln(64);
x.add_with_carry(&y);
<E::Scalar as PrimeField>::from_bigint(x).unwrap()
}
pub fn add_delinearized_signature(&mut self, signature: &Signature<E>) {
self.signature.0 += signature.0;
}
pub fn add_message_n_publickey(
&mut self,
message: &Message,
mut publickey: PublicKey<E>,
) -> E::Scalar {
let mask = self.mask(&publickey);
publickey.0 *= mask;
self.messages_n_publickeys
.entry(message.clone())
.and_modify(|pk0| pk0.0 += publickey.0)
.or_insert(publickey);
mask
}
pub fn add(&mut self, signed: &SignedMessage<E>) {
let mut signature = signed.signature;
let mask = self.add_message_n_publickey(&signed.message, signed.publickey);
signature.0 *= mask;
self.add_delinearized_signature(&signature);
}
pub fn agreement(&self, other: &Delinearized<E>) -> bool {
let mut c = [[0u8; 16]; 2];
self.key.clone().finalize_xof().read(&mut c[0]);
other.key.clone().finalize_xof().read(&mut c[1]);
c[0] == c[1]
}
pub fn merge(&mut self, other: &Delinearized<E>) {
for (message, publickey) in other.messages_n_publickeys.iter() {
self.messages_n_publickeys
.entry(message.clone())
.and_modify(|pk0| pk0.0 += publickey.0)
.or_insert(*publickey);
}
self.signature.0 += other.signature.0;
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
#[test]
fn delinearized() {
let msg1 = Message::new(b"ctx", b"some message");
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 sigs1 = keypairs
.iter_mut()
.map(|k| k.signed_message(&msg1))
.collect::<Vec<_>>();
let mut dl = Delinearized::<ZBLS>::new_batched();
for sig in sigs1.iter() {
dl.add(sig);
assert!(dl.verify()); }
assert!(verifiers::verify_unoptimized(&dl));
assert!(verifiers::verify_simple(&dl));
assert!(verifiers::verify_with_distinct_messages(&dl, false));
assert!(dl.agreement(&dl));
let dl_too = dl.clone();
dl.merge(&dl_too);
assert!(dl.verify());
}
}