use crate::group::{Element, PairingCurve, Point};
use crate::sig::{Scheme, SignatureScheme};
use std::{fmt::Debug, marker::PhantomData};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum BLSError {
#[error("invalid signature")]
InvalidSig,
#[error("could not hash to curve")]
HashingError,
#[error("could not deserialize: {0}")]
DeserializationError(#[from] bincode::Error),
}
pub mod common {
use super::*;
pub trait BLSScheme: Scheme {
fn internal_sign(
private: &Self::Private,
msg: &[u8],
should_hash: bool,
) -> Result<Vec<u8>, BLSError> {
let mut h = if should_hash {
let mut h = Self::Signature::new();
h.map(msg).map_err(|_| BLSError::HashingError)?;
h
} else {
bincode::deserialize_from(msg)?
};
h.mul(private);
let serialized = bincode::serialize(&h)?;
Ok(serialized)
}
fn internal_verify(
public: &Self::Public,
msg: &[u8],
sig_bytes: &[u8],
should_hash: bool,
) -> Result<(), BLSError> {
let sig: Self::Signature = bincode::deserialize_from(sig_bytes)?;
let h = if should_hash {
let mut h = Self::Signature::new();
h.map(msg).map_err(|_| BLSError::HashingError)?;
h
} else {
bincode::deserialize_from(msg)?
};
let success = Self::final_exp(public, &sig, &h);
if !success {
return Err(BLSError::InvalidSig);
}
Ok(())
}
fn internal_aggregation_verify_on_the_same_msg(
partial_publics: &[Self::Public],
msg: &[u8],
sigs: &[&[u8]],
should_hash: bool,
) -> Result<(), BLSError> {
let sig_aggregation =
sigs.iter()
.try_fold(Self::Signature::zero(), |mut acc, sig| {
let sig: Self::Signature = bincode::deserialize_from(*sig)?;
acc.add(&sig);
Ok::<Self::Signature, BLSError>(acc)
})?;
let mut public_aggregation: Self::Public = Self::Public::zero();
for partial_public in partial_publics {
public_aggregation.add(partial_public);
}
let h = if should_hash {
let mut h = Self::Signature::new();
h.map(msg).map_err(|_| BLSError::HashingError)?;
h
} else {
bincode::deserialize_from(msg)?
};
let success = Self::final_exp(&public_aggregation, &sig_aggregation, &h);
if !success {
return Err(BLSError::InvalidSig);
}
Ok(())
}
fn final_exp(p: &Self::Public, sig: &Self::Signature, hm: &Self::Signature) -> bool;
}
impl<T> SignatureScheme for T
where
T: BLSScheme,
{
type Error = BLSError;
fn sign(private: &Self::Private, msg: &[u8]) -> Result<Vec<u8>, Self::Error> {
T::internal_sign(private, msg, true)
}
fn verify(
public: &Self::Public,
msg_bytes: &[u8],
sig_bytes: &[u8],
) -> Result<(), Self::Error> {
T::internal_verify(public, msg_bytes, sig_bytes, true)
}
fn aggregation_verify_on_the_same_msg(
partial_publics: &[Self::Public],
msg_bytes: &[u8],
sig_bytes: &[&[u8]],
) -> Result<(), Self::Error> {
T::internal_aggregation_verify_on_the_same_msg(
partial_publics,
msg_bytes,
sig_bytes,
true,
)
}
}
}
#[derive(Clone, Debug)]
pub struct G1Scheme<C: PairingCurve> {
m: PhantomData<C>,
}
impl<C> Scheme for G1Scheme<C>
where
C: PairingCurve,
{
type Private = C::Scalar;
type Public = C::G1;
type Signature = C::G2;
}
impl<C> common::BLSScheme for G1Scheme<C>
where
C: PairingCurve,
{
fn final_exp(p: &Self::Public, sig: &Self::Signature, hm: &Self::Signature) -> bool {
let left = C::pair(&C::G1::one(), sig);
let right = C::pair(p, hm);
left == right
}
}
#[derive(Clone, Debug)]
pub struct G2Scheme<C: PairingCurve> {
m: PhantomData<C>,
}
impl<C> Scheme for G2Scheme<C>
where
C: PairingCurve,
{
type Private = C::Scalar;
type Public = C::G2;
type Signature = C::G1;
}
impl<C> common::BLSScheme for G2Scheme<C>
where
C: PairingCurve,
{
fn final_exp(p: &Self::Public, sig: &Self::Signature, hm: &Self::Signature) -> bool {
let left = C::pair(sig, &Self::Public::one());
let right = C::pair(hm, p);
left == right
}
}
#[cfg(feature = "bn254")]
#[cfg(test)]
mod tests {
use super::*;
use crate::curve::bn254::{G1Curve, G2Curve, PairingCurve as PCurve};
use crate::group::Curve;
use rand::prelude::*;
fn keypair<C: Curve>() -> (C::Scalar, C::Point) {
let private = C::Scalar::rand(&mut thread_rng());
let mut public = C::Point::one();
public.mul(&private);
(private, public)
}
#[test]
fn nbls_g2() {
let (private, public) = keypair::<G2Curve>();
let msg = vec![1, 9, 6, 9];
let sig = G2Scheme::<PCurve>::sign(&private, &msg).unwrap();
G2Scheme::<PCurve>::verify(&public, &msg, &sig).expect("that should not happen");
}
#[test]
fn nbls_g1() {
let (private, public) = keypair::<G1Curve>();
let msg = vec![1, 9, 6, 9];
let sig = G1Scheme::<PCurve>::sign(&private, &msg).unwrap();
G1Scheme::<PCurve>::verify(&public, &msg, &sig).expect("that should not happen");
}
}