use ark_bls12_381::{g1, g2};
use ark_ec::{
hashing::{
curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurveBasedHasher, HashToCurve as _,
},
short_weierstrass::Projective,
};
use ark_ff::field_hashers::DefaultFieldHasher;
use ark_serialize::CanonicalSerialize;
use cosmwasm_core::{BLS12_381_G1_POINT_LEN, BLS12_381_G2_POINT_LEN};
use sha2::Sha256;
use crate::CryptoError;
type HashToCurve<CurveConfig, Hash> =
MapToCurveBasedHasher<Projective<CurveConfig>, DefaultFieldHasher<Hash>, WBMap<CurveConfig>>;
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum HashFunction {
Sha256 = 0,
}
#[doc(hidden)]
impl HashFunction {
pub fn from_u32(idx: u32) -> Result<Self, CryptoError> {
let hash = match idx {
0 => Self::Sha256,
_ => return Err(CryptoError::unknown_hash_function()),
};
Ok(hash)
}
}
pub fn bls12_381_hash_to_g1(
hash: HashFunction,
msg: &[u8],
dst: &[u8],
) -> [u8; BLS12_381_G1_POINT_LEN] {
let point = match hash {
HashFunction::Sha256 => HashToCurve::<g1::Config, Sha256>::new(dst)
.unwrap()
.hash(msg)
.unwrap(),
};
let mut serialized = [0; BLS12_381_G1_POINT_LEN];
point.serialize_compressed(&mut serialized[..]).unwrap();
serialized
}
pub fn bls12_381_hash_to_g2(
hash: HashFunction,
msg: &[u8],
dst: &[u8],
) -> [u8; BLS12_381_G2_POINT_LEN] {
let point = match hash {
HashFunction::Sha256 => HashToCurve::<g2::Config, Sha256>::new(dst)
.unwrap()
.hash(msg)
.unwrap(),
};
let mut serialized = [0; BLS12_381_G2_POINT_LEN];
point.serialize_compressed(&mut serialized[..]).unwrap();
serialized
}
#[cfg(test)]
mod test {
use hex_literal::hex;
use crate::{bls12_381_hash_to_g1, bls12_381_hash_to_g2, HashFunction};
#[test]
fn hash_to_g1_works() {
let msg = b"abc";
let dst = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_";
let hashed_point = bls12_381_hash_to_g1(HashFunction::Sha256, msg, dst);
let mut serialized_expected_compressed = hex!("03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a7943388a49a3aee664ba5379a7655d3c68900be2f6903");
serialized_expected_compressed[0] |= 0b1000_0000;
assert_eq!(hashed_point, serialized_expected_compressed);
}
#[test]
fn hash_to_g2_works() {
let msg = b"abc";
let dst = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_";
let hashed_point = bls12_381_hash_to_g2(HashFunction::Sha256, msg, dst);
let mut serialized_expected_compressed = hex!("139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd802c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e6");
serialized_expected_compressed[0] |= 0b1000_0000;
assert_eq!(hashed_point, serialized_expected_compressed);
}
}