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::Group;
use ark_ff::fields::field_hashers::DefaultFieldHasher;
use ark_serialize::CanonicalDeserialize;
use ark_serialize::CanonicalSerialize;
use ark_std::UniformRand;
use libsecp256k1;
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.0.serialize();
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)?;
let sk = libsecp256k1::SecretKey::parse(&data)?;
Ok(SecretKey(sk))
}
}
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 {
use super::*;
#[test]
fn test_sign_and_verify() {
let key = random_sk().unwrap();
let msg = "hello world";
let pk = public_key(&key).unwrap();
let h = hash_to_curve(msg.as_bytes()).unwrap();
let sig = sign_hash(key, &h).unwrap();
assert!(super::verify_hash(vec![h].as_slice(), &sig, vec![pk].as_slice()).unwrap());
assert!(super::verify(vec![msg.as_bytes()].as_slice(), &sig, vec![pk].as_slice()).unwrap());
}
#[test]
fn test_hash_result() {
let hashed_data: [u8; 96] = [
138, 203, 106, 10, 25, 0, 11, 120, 167, 254, 109, 207, 27, 42, 63, 46, 108, 179, 30,
196, 146, 10, 94, 148, 237, 209, 198, 48, 23, 211, 67, 188, 147, 170, 94, 52, 176, 113,
111, 214, 28, 35, 235, 16, 215, 69, 185, 65, 15, 66, 199, 2, 245, 101, 145, 144, 209,
52, 71, 179, 27, 209, 127, 155, 231, 9, 235, 11, 82, 89, 83, 171, 47, 179, 253, 128,
26, 104, 238, 91, 182, 207, 152, 70, 243, 206, 65, 226, 81, 113, 69, 125, 85, 142, 27,
254,
];
let msg = "hello world";
let h = hash_to_curve(msg.as_bytes()).unwrap();
assert_eq!(h, hashed_data);
}
#[test]
fn test_aggregate() {
let key1 = random_sk().unwrap();
let key2 = random_sk().unwrap();
let msg1 = "hello alice";
let msg2 = "hello bob";
let pk1 = public_key(&key1).unwrap();
let pk2 = public_key(&key2).unwrap();
let h1 = hash_to_curve(msg1.as_bytes()).unwrap();
let h2 = hash_to_curve(msg2.as_bytes()).unwrap();
let sig1 = sign_hash(key1, &h1).unwrap();
let sig2 = sign_hash(key2, &h2).unwrap();
let sig_agg = aggregate(&[sig1, sig2]).unwrap();
assert!(
super::verify_hash(vec![h1, h2].as_slice(), &sig_agg, vec![pk1, pk2].as_slice())
.unwrap()
);
}
}