use ark_bls12_381::fr::Fr;
use ark_bls12_381::g2::Config as G2Config;
use ark_bls12_381::Bls12_381;
use ark_bls12_381::G1Projective;
use ark_bls12_381::G2Projective;
use ark_ec::hashing::curve_maps::wb::WBMap;
use ark_ec::hashing::map_to_curve_hasher::MapToCurveBasedHasher;
use ark_ec::hashing::HashToCurve;
use ark_ec::pairing::Pairing;
use ark_ec::PrimeGroup;
use ark_ff::fields::field_hashers::DefaultFieldHasher;
use ark_serialize::CanonicalDeserialize;
use ark_serialize::CanonicalSerialize;
use ark_std::UniformRand;
use rand::SeedableRng;
use rand_hc::Hc128Rng;
use crate::ecc::PublicKey;
use crate::ecc::SecretKey;
use crate::error::Error;
use crate::error::Result;
const CSUITE: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_";
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Signature(pub [u8; 96]);
pub fn random_sk() -> Result<SecretKey> {
let mut rng = Hc128Rng::from_entropy();
Fr::rand(&mut rng).try_into()
}
fn from_compressed<T: CanonicalDeserialize, const S: usize>(a: &[u8; S]) -> Result<T> {
T::deserialize_compressed(&a[..]).map_err(|_| Error::EccDeserializeFailed)
}
fn to_compressed<T: CanonicalSerialize, const S: usize>(s: &T) -> Result<[u8; S]> {
let mut data: Vec<u8> = vec![];
s.serialize_compressed(&mut data)
.map_err(|_| Error::EccSerializeFailed)?;
assert_eq!(s.compressed_size(), S);
assert_eq!(data.len(), S);
let ret: [u8; S] = data.try_into().map_err(|_| Error::EccSerializeFailed)?;
Ok(ret)
}
impl TryFrom<SecretKey> for Fr {
type Error = Error;
fn try_from(sk: SecretKey) -> Result<Fr> {
let data: [u8; 32] = sk.ser();
let ret: Fr = from_compressed(&data)?;
Ok(ret)
}
}
impl TryFrom<Fr> for SecretKey {
type Error = Error;
fn try_from(sk: Fr) -> Result<SecretKey> {
let data: [u8; 32] = to_compressed(&sk)?;
SecretKey::from_bytes(data)
}
}
impl TryFrom<Signature> for G2Projective {
type Error = Error;
fn try_from(s: Signature) -> Result<Self> {
from_compressed(&s.0)
}
}
impl TryFrom<G2Projective> for Signature {
type Error = Error;
fn try_from(s: G2Projective) -> Result<Self> {
Ok(Signature(to_compressed(&s)?))
}
}
impl TryFrom<G1Projective> for PublicKey<48> {
type Error = Error;
fn try_from(p: G1Projective) -> Result<Self> {
Ok(PublicKey(to_compressed::<G1Projective, 48>(&p)?))
}
}
impl TryFrom<PublicKey<48>> for G1Projective {
type Error = Error;
fn try_from(pk: PublicKey<48>) -> Result<Self> {
let data: [u8; 48] = pk.0;
let ret: Self = from_compressed(&data)?;
Ok(ret)
}
}
pub fn hash_to_curve(msg: &[u8]) -> Result<[u8; 96]> {
let hasher = MapToCurveBasedHasher::<
G2Projective,
DefaultFieldHasher<sha2::Sha256, 128>,
WBMap<G2Config>,
>::new(CSUITE)
.map_err(|_| Error::CurveHasherInitFailed)?;
let hashed = hasher.hash(msg).map_err(|_| Error::CurveHasherFailed)?;
let ret: [u8; 96] = to_compressed(&hashed)?;
Ok(ret)
}
pub fn sign_hash(sk: SecretKey, hashed_msg: &[u8; 96]) -> Result<Signature> {
let sk: Fr = sk.try_into()?;
let msg: G2Projective = from_compressed(hashed_msg)?;
Ok(Signature(to_compressed(&(msg * sk))?))
}
pub fn sign(sk: SecretKey, msg: &[u8]) -> Result<Signature> {
let sk: Fr = sk.try_into()?;
let hashed_msg = hash_to_curve(msg)?;
let msg: G2Projective = from_compressed(&hashed_msg)?;
Ok(Signature(to_compressed(&(msg * sk))?))
}
pub fn verify_hash(hashes: &[[u8; 96]], sig: &Signature, pks: &[PublicKey<48>]) -> Result<bool> {
let sig: G2Projective = sig.clone().try_into()?;
let g1 = G1Projective::generator();
let e1 = Bls12_381::pairing(g1, sig);
let hashes: Vec<G2Projective> = hashes
.iter()
.map(from_compressed)
.collect::<Result<Vec<G2Projective>>>()?;
let pks: Vec<G1Projective> = pks
.iter()
.map(|pk| (*pk).try_into())
.collect::<Result<Vec<G1Projective>>>()?;
let mm_out = Bls12_381::multi_miller_loop(pks, hashes);
if let Some(e2) = Bls12_381::final_exponentiation(mm_out) {
Ok(e1 == e2)
} else {
Ok(false)
}
}
pub fn verify(msgs: &[&[u8]], sig: &Signature, pks: &[PublicKey<48>]) -> Result<bool> {
let hashes: Vec<[u8; 96]> = msgs
.iter()
.map(|msg| hash_to_curve(msg))
.collect::<Result<Vec<[u8; 96]>>>()?;
verify_hash(hashes.as_slice(), sig, pks)
}
pub fn aggregate(signatures: &[Signature]) -> Result<Signature> {
signatures
.iter()
.map(|sig| sig.clone().try_into())
.collect::<Result<Vec<G2Projective>>>()?
.iter()
.sum::<G2Projective>()
.try_into()
}
pub fn public_key(key: &SecretKey) -> Result<PublicKey<48>> {
let sk: Fr = (*key).try_into()?;
let g1 = G1Projective::generator();
(g1 * sk).try_into()
}
#[cfg(test)]
mod test_bls;