use crate::errors::{BBSError, BBSErrorKind};
use crate::keys::prelude::*;
use crate::{
multi_scalar_mul_const_time_g1, multi_scalar_mul_var_time_g1, rand_non_zero_fr, Commitment,
RandomElem, SignatureBlinding, SignatureMessage, FR_COMPRESSED_SIZE, G1_COMPRESSED_SIZE,
G1_UNCOMPRESSED_SIZE,
};
use ff_zeroize::{Field, PrimeField};
use pairing_plus::{
bls12_381::{Bls12, Fq12, Fr, FrRepr, G1, G2},
serdes::SerDes,
CurveAffine, CurveProjective, Engine,
};
use serde::{
de::{Error as DError, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fmt::{Display, Formatter};
use std::io::Cursor;
#[cfg(feature = "wasm")]
use wasm_bindgen::JsValue;
pub mod prelude {
pub use super::{
BlindSignature, Signature, SIGNATURE_COMPRESSED_SIZE, SIGNATURE_UNCOMPRESSED_SIZE,
};
}
macro_rules! check_verkey_message {
($statment:expr, $count1:expr, $count2:expr) => {
if $statment {
return Err(
BBSErrorKind::PublicKeyGeneratorMessageCountMismatch($count1, $count2).into(),
);
}
};
}
pub const SIGNATURE_UNCOMPRESSED_SIZE: usize = G1_UNCOMPRESSED_SIZE + FR_COMPRESSED_SIZE * 2;
pub const SIGNATURE_COMPRESSED_SIZE: usize = G1_COMPRESSED_SIZE + FR_COMPRESSED_SIZE * 2;
macro_rules! to_bytes_impl {
($name:ident, $sigsize:expr, $g1size:expr, $compressed:expr) => {
pub fn $name(&self) -> [u8; $sigsize] {
let mut out = Vec::with_capacity($sigsize);
self.a.serialize(&mut out, $compressed).unwrap();
self.e.serialize(&mut out, $compressed).unwrap();
self.s.serialize(&mut out, $compressed).unwrap();
*array_ref![out, 0, $sigsize]
}
};
}
macro_rules! from_bytes_impl {
($name:ident, $sigsize:expr, $g1size:expr, $compressed:expr) => {
impl From<[u8; $sigsize]> for $name {
fn from(data: [u8; $sigsize]) -> Self {
Self::from(&data)
}
}
impl From<&[u8; $sigsize]> for $name {
fn from(data: &[u8; $sigsize]) -> Self {
let mut c = Cursor::new(data.as_ref());
let a = G1::deserialize(&mut c, $compressed).unwrap();
let e = Fr::deserialize(&mut c, $compressed).unwrap();
let s = Fr::deserialize(&mut c, $compressed).unwrap();
Self { a, e, s }
}
}
};
}
macro_rules! try_from_impl {
($name:ident) => {
impl TryFrom<&[u8]> for $name {
type Error = BBSError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let mut value = value;
let compressed = value.len() == SIGNATURE_COMPRESSED_SIZE;
let a = G1::deserialize(&mut value, compressed)?;
let e = Fr::deserialize(&mut value, compressed)?;
let s = Fr::deserialize(&mut value, compressed)?;
Ok(Self { a, e, s })
}
}
impl TryFrom<Vec<u8>> for $name {
type Error = BBSError;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(value.as_slice())
}
}
impl Default for $name {
fn default() -> Self {
Self {
a: G1::zero(),
e: Fr::zero(),
s: Fr::zero(),
}
}
}
impl From<Box<[u8]>> for $name {
fn from(data: Box<[u8]>) -> $name {
let data = Vec::from(data);
match $name::try_from(data) {
Ok(t) => t,
Err(_) => $name::default(),
}
}
}
impl Into<Box<[u8]>> for $name {
fn into(self) -> Box<[u8]> {
self.to_bytes_compressed_form().to_vec().into()
}
}
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BlindSignature {
pub(crate) a: G1,
pub(crate) e: Fr,
pub(crate) s: Fr,
}
impl BlindSignature {
pub fn new(
commitment: &Commitment,
messages: &BTreeMap<usize, SignatureMessage>,
signkey: &SecretKey,
verkey: &PublicKey,
) -> Result<Self, BBSError> {
check_verkey_message!(
messages.len() > verkey.message_count(),
verkey.message_count(),
messages.len()
);
signkey.validate()?;
verkey.validate()?;
let e = rand_non_zero_fr();
let s = rand_non_zero_fr();
let mut points = Vec::with_capacity(messages.len() + 3);
let mut scalars = Vec::with_capacity(messages.len() + 3);
points.push(commitment.0);
scalars.push(Fr::from_repr(FrRepr::from(1)).unwrap());
points.push(G1::one());
scalars.push(Fr::from_repr(FrRepr::from(1)).unwrap());
points.push(verkey.h0.0);
scalars.push(s);
for (i, m) in messages.iter() {
points.push(verkey.h[*i].0);
scalars.push(m.0);
}
let mut b = multi_scalar_mul_const_time_g1(&points, &scalars);
let mut exp = signkey.0;
exp.add_assign(&e);
b.mul_assign(exp.inverse().unwrap());
Ok(Self { a: b, e, s })
}
pub fn to_unblinded(&self, blinding: &SignatureBlinding) -> Signature {
let mut s = self.s;
s.add_assign(&blinding.0);
Signature {
a: self.a,
s,
e: self.e,
}
}
to_bytes_impl!(
to_bytes_compressed_form,
SIGNATURE_COMPRESSED_SIZE,
G1_COMPRESSED_SIZE,
true
);
to_bytes_impl!(
to_bytes_uncompressed_form,
SIGNATURE_UNCOMPRESSED_SIZE,
G1_UNCOMPRESSED_SIZE,
false
);
}
from_bytes_impl!(
BlindSignature,
SIGNATURE_COMPRESSED_SIZE,
G1_COMPRESSED_SIZE,
true
);
from_bytes_impl!(
BlindSignature,
SIGNATURE_UNCOMPRESSED_SIZE,
G1_UNCOMPRESSED_SIZE,
false
);
try_from_impl!(BlindSignature);
serdes_impl!(BlindSignature);
display_impl!(BlindSignature);
#[cfg(feature = "wasm")]
wasm_slice_impl!(BlindSignature);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Signature {
pub(crate) a: G1,
pub(crate) e: Fr,
pub(crate) s: Fr,
}
impl Signature {
pub fn new(
messages: &[SignatureMessage],
signkey: &SecretKey,
verkey: &PublicKey,
) -> Result<Self, BBSError> {
check_verkey_message!(
messages.len() > verkey.message_count(),
verkey.message_count(),
messages.len()
);
signkey.validate()?;
verkey.validate()?;
let e = rand_non_zero_fr();
let s = rand_non_zero_fr();
let mut b = Self::compute_b(&s, messages, verkey);
let mut exp = signkey.0;
exp.add_assign(&e);
b.mul_assign(exp.inverse().unwrap());
Ok(Self { a: b, e, s })
}
pub fn generate_blinding() -> SignatureBlinding {
SignatureBlinding::random()
}
pub fn verify(
&self,
messages: &[SignatureMessage],
verkey: &PublicKey,
) -> Result<bool, BBSError> {
check_verkey_message!(
messages.len() != verkey.message_count(),
verkey.message_count(),
messages.len()
);
verkey.validate()?;
self.validate()?;
let mut pqz = Vec::new();
let mut a = G2::one();
a.mul_assign(self.e);
a.add_assign(&verkey.w.0);
let mut b = self.get_b(messages, verkey);
b.negate();
let b = b.into_affine().prepare();
let g2 = G2::one().into_affine().prepare();
let a1 = self.a.into_affine().prepare();
let a2 = a.into_affine().prepare();
pqz.push((&a1, &a2));
pqz.push((&b, &g2));
Ok(
match Bls12::final_exponentiation(&Bls12::miller_loop(&pqz[..])) {
None => false,
Some(product) => product == Fq12::one(),
},
)
}
pub fn validate(&self) -> Result<(), BBSError> {
if self.a.is_zero() || self.e.is_zero() || self.s.is_zero() {
return Err(BBSErrorKind::MalformedSignature.into());
}
Ok(())
}
pub(crate) fn get_b(&self, messages: &[SignatureMessage], verkey: &PublicKey) -> G1 {
let mut bases = Vec::with_capacity(messages.len() + 2);
let mut scalars = Vec::with_capacity(messages.len() + 2);
bases.push(G1::one());
scalars.push(Fr::from_repr(FrRepr::from(1)).unwrap());
bases.push(verkey.h0.0);
scalars.push(self.s);
for i in 0..verkey.message_count() {
bases.push(verkey.h[i].0);
scalars.push(messages[i].0);
}
multi_scalar_mul_var_time_g1(&bases, &scalars)
}
fn compute_b(s: &Fr, messages: &[SignatureMessage], verkey: &PublicKey) -> G1 {
let mut bases = Vec::with_capacity(messages.len() + 2);
let mut scalars = Vec::with_capacity(messages.len() + 2);
bases.push(G1::one());
scalars.push(Fr::from_repr(FrRepr::from(1)).unwrap());
bases.push(verkey.h0.0);
scalars.push(*s);
let min = std::cmp::min(verkey.message_count(), messages.len());
for i in 0..min {
bases.push(verkey.h[i].0);
scalars.push(messages[i].0);
}
multi_scalar_mul_const_time_g1(&bases, &scalars)
}
to_bytes_impl!(
to_bytes_compressed_form,
SIGNATURE_COMPRESSED_SIZE,
G1_COMPRESSED_SIZE,
true
);
to_bytes_impl!(
to_bytes_uncompressed_form,
SIGNATURE_UNCOMPRESSED_SIZE,
G1_UNCOMPRESSED_SIZE,
false
);
}
from_bytes_impl!(
Signature,
SIGNATURE_COMPRESSED_SIZE,
G1_COMPRESSED_SIZE,
true
);
from_bytes_impl!(
Signature,
SIGNATURE_UNCOMPRESSED_SIZE,
G1_UNCOMPRESSED_SIZE,
false
);
try_from_impl!(Signature);
serdes_impl!(Signature);
display_impl!(Signature);
#[cfg(feature = "wasm")]
wasm_slice_impl!(Signature);
#[cfg(test)]
mod tests {
use super::*;
use crate::keys::generate;
use crate::pok_vc::ProverCommittingG1;
use crate::CommitmentBuilder;
use rand::prelude::*;
#[test]
fn signature_serialization() {
let mut rng = thread_rng();
let sig = Signature {
a: G1::random(&mut rng),
e: Fr::random(&mut rng),
s: Fr::random(&mut rng),
};
let bytes = sig.to_bytes_uncompressed_form();
assert_eq!(bytes.len(), SIGNATURE_UNCOMPRESSED_SIZE);
let sig_2 = Signature::from(bytes);
assert_eq!(sig, sig_2);
let bytes = sig.to_bytes_compressed_form();
assert_eq!(bytes.len(), SIGNATURE_COMPRESSED_SIZE);
let sig_2 = Signature::from(bytes);
assert_eq!(sig, sig_2);
}
#[test]
fn gen_signature() {
let message_count = 5;
let mut messages = Vec::new();
for _ in 0..message_count {
messages.push(SignatureMessage::random());
}
let (verkey, signkey) = generate(message_count).unwrap();
let res = Signature::new(messages.as_slice(), &signkey, &verkey);
assert!(res.is_ok());
let messages = Vec::new();
let res = Signature::new(messages.as_slice(), &signkey, &verkey);
assert!(res.is_ok());
}
#[test]
fn signature_validation() {
let message_count = 5;
let mut messages = Vec::new();
for _ in 0..message_count {
messages.push(SignatureMessage::random());
}
let (verkey, signkey) = generate(message_count).unwrap();
let sig = Signature::new(messages.as_slice(), &signkey, &verkey).unwrap();
let res = sig.verify(messages.as_slice(), &verkey);
assert!(res.is_ok());
assert!(res.unwrap());
let mut messages = Vec::new();
for _ in 0..message_count {
messages.push(SignatureMessage::random());
}
let res = sig.verify(messages.as_slice(), &verkey);
assert!(res.is_ok());
assert!(!res.unwrap());
}
#[test]
fn signature_committed_messages() {
let message_count = 4;
let mut messages = Vec::new();
for _ in 0..message_count {
messages.push(SignatureMessage::random());
}
let (verkey, signkey) = generate(message_count).unwrap();
let blinding = Signature::generate_blinding();
let mut builder = CommitmentBuilder::new();
builder.add(verkey.h0.clone(), &blinding);
builder.add(verkey.h[0].clone(), &messages[0]);
let commitment = builder.finalize();
let mut committing = ProverCommittingG1::new();
committing.commit(verkey.h0.clone());
committing.commit(verkey.h[0].clone());
let committed = committing.finish();
let mut hidden_msgs = Vec::new();
hidden_msgs.push(SignatureMessage(blinding.0.clone()));
hidden_msgs.push(messages[0].clone());
let mut bases = Vec::new();
bases.push(verkey.h0.clone());
bases.push(verkey.h[0].clone());
let nonce = vec![1u8, 1u8, 1u8, 1u8, 2u8, 2u8, 2u8, 2u8];
let mut extra = Vec::new();
extra.extend_from_slice(&commitment.to_bytes_uncompressed_form());
extra.extend_from_slice(nonce.as_slice());
let challenge_hash = committed.gen_challenge(extra);
let proof = committed
.gen_proof(&challenge_hash, hidden_msgs.as_slice())
.unwrap();
assert!(proof
.verify(bases.as_slice(), &commitment, &challenge_hash)
.unwrap());
let mut known = BTreeMap::new();
for i in 1..message_count {
known.insert(i, messages[i].clone());
}
let sig = BlindSignature::new(&commitment, &known, &signkey, &verkey);
assert!(proof
.verify_complete_proof(
bases.as_slice(),
&commitment,
&challenge_hash,
nonce.as_slice()
)
.unwrap());
assert!(sig.is_ok());
let sig = sig.unwrap();
let sig = sig.to_unblinded(&blinding);
let res = sig.verify(messages.as_slice(), &verkey);
assert!(res.is_ok());
assert!(res.unwrap());
}
#[test]
fn signature_zero() {
let message_count = 5;
let mut messages = Vec::new();
for _ in 0..message_count {
messages.push(SignatureMessage::random());
}
let (verkey, signkey) = generate(message_count).unwrap();
let sig = Signature::new(messages.as_slice(), &signkey, &verkey).unwrap();
let mut badsig1 = sig.clone();
badsig1.a = G1::zero();
assert!(badsig1.validate().is_err());
let mut badsig2 = sig.clone();
badsig2.e = Fr::zero();
assert!(badsig2.validate().is_err());
let mut badsig3 = sig.clone();
badsig3.s = Fr::zero();
assert!(badsig3.validate().is_err());
}
}