use bls12_381::{G1Affine, G1Projective};
use bls12_381::{G2Affine, G2Projective};
use sha2::{Digest, Sha512};
macro_rules! make_hash {
($message:ident, $i:ident, $array_size:literal) => {{
let mut result = [0u8; $array_size];
let i_data = $i.to_le_bytes();
const HASH_SIZE: usize = 64;
let mut j = 0;
while j * HASH_SIZE < $array_size {
let j_data = j.to_le_bytes();
let mut hasher = Sha512::new();
hasher.input($message);
hasher.input(&i_data);
hasher.input(&j_data);
let hash_result = hasher.result();
let start = j * HASH_SIZE;
let end = if start + HASH_SIZE > $array_size {
$array_size
} else {
start + HASH_SIZE
};
result.copy_from_slice(&hash_result[start..end]);
j += 1;
}
result
}};
}
trait AffinePoint {
fn is_valid(&self) -> bool;
fn clear_cofactor(&self) -> Self;
}
impl AffinePoint for G1Affine {
fn is_valid(&self) -> bool {
bool::from(self.is_on_curve()) && bool::from(self.is_torsion_free())
}
fn clear_cofactor(&self) -> Self {
let projective_point = G1Projective::from(self).clear_cofactor();
Self::from(projective_point)
}
}
impl AffinePoint for G2Affine {
fn is_valid(&self) -> bool {
bool::from(self.is_on_curve()) && bool::from(self.is_torsion_free())
}
fn clear_cofactor(&self) -> Self {
let projective_point = G2Projective::from(self).clear_cofactor();
Self::from(projective_point)
}
}
pub trait HashableGenerator {
fn hash_to_point(message: &[u8]) -> Self;
}
impl HashableGenerator for G1Affine {
fn hash_to_point(message: &[u8]) -> Self {
for i in 0u32.. {
let hash = make_hash!(message, i, 48);
let point = {
let point_optional = Self::from_compressed_unchecked(&hash);
if point_optional.is_none().unwrap_u8() == 1 {
continue;
}
let affine_point = point_optional.unwrap();
affine_point.clear_cofactor()
};
assert_eq!(point.is_valid(), true);
return point;
}
unreachable!();
}
}
impl HashableGenerator for G1Projective {
fn hash_to_point(message: &[u8]) -> Self {
Self::from(G1Affine::hash_to_point(&message))
}
}
impl HashableGenerator for G2Affine {
fn hash_to_point(message: &[u8]) -> Self {
for i in 0u32.. {
let hash = make_hash!(message, i, 96);
let point = {
let point_optional = Self::from_compressed_unchecked(&hash);
if point_optional.is_none().unwrap_u8() == 1 {
continue;
}
let affine_point = point_optional.unwrap();
affine_point.clear_cofactor()
};
assert_eq!(point.is_valid(), true);
return point;
}
unreachable!();
}
}
impl HashableGenerator for G2Projective {
fn hash_to_point(message: &[u8]) -> Self {
Self::from(G2Affine::hash_to_point(&message))
}
}
#[test]
fn test_hash_to_point_g1affine() {
}