use std::ops::Neg;
use ark_bls12_381::{G1Affine, G2Affine, g1, g2};
use ark_ec::{
AffineRepr,
bls12::Bls12,
hashing::{HashToCurve, curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurveBasedHasher},
models::short_weierstrass,
pairing::Pairing,
};
use ark_ff::{Zero, field_hashers::DefaultFieldHasher};
use ark_serialize::CanonicalDeserialize;
use thiserror::Error;
use crate::{DrandError, Result};
pub const G1_DOMAIN: &[u8] = b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_";
pub const G2_DOMAIN: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_";
#[derive(Error, Debug)]
pub enum VerificationError {
#[error("deserialization failed")]
Deserialization,
#[error("cannot initialise mapper for sha2 to BLS12-381 {curve}")]
Initialisation { curve: String },
#[error("invalid point")]
InvalidPoint,
}
pub fn verify(dst: &[u8], signature: &[u8], hash: &[u8], public_key: &[u8]) -> Result<bool> {
if signature.len() == 48 {
verify_g1_on_g2(dst, signature, hash, public_key)
} else {
verify_g2_on_g1(dst, signature, hash, public_key)
}
}
pub fn verify_g2_on_g1(
dst: &[u8],
signature: &[u8],
hash: &[u8],
public_key: &[u8],
) -> Result<bool> {
let mapper = MapToCurveBasedHasher::<
short_weierstrass::Projective<g2::Config>,
DefaultFieldHasher<sha2::Sha256, 128>,
WBMap<g2::Config>,
>::new(dst)
.map_err(|_| -> DrandError {
Box::new(VerificationError::Initialisation {
curve: "G2".to_owned(),
})
.into()
})?;
let hash_on_curve = mapper.hash(hash).map_err(|_| -> DrandError {
Box::new(VerificationError::Initialisation {
curve: "G2".to_owned(),
})
.into()
})?;
let g1 = G1Affine::generator();
let sigma = g2_from_variable(signature)?;
let r = g1_from_variable(public_key)?;
Ok(fast_pairing_equality(&g1, &sigma, &r, &hash_on_curve))
}
pub fn verify_g1_on_g2(
dst: &[u8],
signature: &[u8],
hash: &[u8],
public_key: &[u8],
) -> Result<bool> {
let mapper = MapToCurveBasedHasher::<
short_weierstrass::Projective<g1::Config>,
DefaultFieldHasher<sha2::Sha256, 128>,
WBMap<g1::Config>,
>::new(dst)
.map_err(|_| -> DrandError {
Box::new(VerificationError::Initialisation {
curve: "G1".to_owned(),
})
.into()
})?;
let hash_on_curve = mapper.hash(hash).map_err(|_| -> DrandError {
Box::new(VerificationError::Initialisation {
curve: "G1".to_owned(),
})
.into()
})?;
let g2 = G2Affine::generator();
let sigma = g1_from_variable(signature)?;
let s = g2_from_variable(public_key)?;
Ok(fast_pairing_equality(&sigma, &g2, &hash_on_curve, &s))
}
fn fast_pairing_equality(p: &G1Affine, q: &G2Affine, r: &G1Affine, s: &G2Affine) -> bool {
let minus_p = p.neg();
let looped = Bls12::<ark_bls12_381::Config>::multi_miller_loop([minus_p, *r], [*q, *s]);
let value = Bls12::final_exponentiation(looped);
value.unwrap().is_zero()
}
fn g1_from_variable(data: &[u8]) -> Result<G1Affine> {
if data.len() != 48 {
return Err(Box::new(VerificationError::InvalidPoint).into());
}
G1Affine::deserialize_compressed(data)
.map_err(|_| Box::new(VerificationError::Deserialization).into())
}
fn g2_from_variable(data: &[u8]) -> Result<G2Affine> {
if data.len() != 96 {
return Err(Box::new(VerificationError::InvalidPoint).into());
}
G2Affine::deserialize_compressed(data)
.map_err(|_| Box::new(VerificationError::Deserialization).into())
}