#[cfg(zisk_guest)]
use crate::alloc_extern::vec::Vec;
use crate::zisklib::lib::sha256::sha256;
use super::{
fp::{add_fp_bls12_381, mul_fp_bls12_381},
map_to_curve::map_to_curve_g2_no_cofactor_bls12_381,
twist::{add_complete_safe_twist_bls12_381, clear_cofactor_twist_bls12_381},
};
pub fn hash_to_curve_g2_bls12_381(
msg: &[u8],
dst: &[u8],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let u = hash_to_field_fp2_count2_bls12_381(
msg,
dst,
#[cfg(feature = "hints")]
hints,
);
let q0 = map_to_curve_g2_no_cofactor_bls12_381(
&u[0],
#[cfg(feature = "hints")]
hints,
)
.expect("hash_to_field output is reduced mod p");
let q1 = map_to_curve_g2_no_cofactor_bls12_381(
&u[1],
#[cfg(feature = "hints")]
hints,
)
.expect("hash_to_field output is reduced mod p");
let r = add_complete_safe_twist_bls12_381(
&q0,
&q1,
#[cfg(feature = "hints")]
hints,
)
.expect("Q0 and Q1 are on the curve by construction");
clear_cofactor_twist_bls12_381(
&r,
#[cfg(feature = "hints")]
hints,
)
}
fn expand_message_xmd_sha256(
msg: &[u8],
dst: &[u8],
len_in_bytes: usize,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Vec<u8> {
const B_IN_BYTES: usize = 32; const S_IN_BYTES: usize = 64;
assert!(dst.len() <= 255, "DST too long for expand_message_xmd");
assert!(len_in_bytes <= 0xFFFF, "len_in_bytes exceeds its limit");
let ell = len_in_bytes.div_ceil(B_IN_BYTES);
assert!(ell <= 255, "expand_message_xmd requires ell <= 255");
let mut dst_prime = Vec::with_capacity(dst.len() + 1);
dst_prime.extend_from_slice(dst);
dst_prime.push(dst.len() as u8);
let mut msg_prime = Vec::with_capacity(S_IN_BYTES + msg.len() + 3 + dst_prime.len());
msg_prime.extend(core::iter::repeat(0u8).take(S_IN_BYTES));
msg_prime.extend_from_slice(msg);
msg_prime.push((len_in_bytes >> 8) as u8);
msg_prime.push((len_in_bytes & 0xff) as u8);
msg_prime.push(0);
msg_prime.extend_from_slice(&dst_prime);
let b_0 = sha256(
&msg_prime,
#[cfg(feature = "hints")]
hints,
);
let mut buf: Vec<u8> = Vec::with_capacity(B_IN_BYTES + 1 + dst_prime.len());
buf.extend_from_slice(&b_0);
buf.push(1);
buf.extend_from_slice(&dst_prime);
let mut b_prev = sha256(
&buf,
#[cfg(feature = "hints")]
hints,
);
let mut uniform_bytes = Vec::with_capacity(B_IN_BYTES * ell);
uniform_bytes.extend_from_slice(&b_prev);
for i in 2..=ell {
let mut xored = [0u8; B_IN_BYTES];
for j in 0..B_IN_BYTES {
xored[j] = b_0[j] ^ b_prev[j];
}
buf.clear();
buf.extend_from_slice(&xored);
buf.push(i as u8);
buf.extend_from_slice(&dst_prime);
b_prev = sha256(
&buf,
#[cfg(feature = "hints")]
hints,
);
uniform_bytes.extend_from_slice(&b_prev);
}
uniform_bytes.truncate(len_in_bytes);
uniform_bytes
}
fn os2ip_64_be_mod_p(bytes: &[u8; 64], #[cfg(feature = "hints")] hints: &mut Vec<u64>) -> [u64; 6] {
const R256_FP: [u64; 6] = [0, 0, 0, 0, 1, 0];
let mut d_hi = [0u64; 6];
let mut d_lo = [0u64; 6];
for i in 0..4 {
for j in 0..8 {
d_hi[3 - i] |= (bytes[i * 8 + j] as u64) << (8 * (7 - j));
d_lo[3 - i] |= (bytes[32 + i * 8 + j] as u64) << (8 * (7 - j));
}
}
let shifted = mul_fp_bls12_381(
&d_hi,
&R256_FP,
#[cfg(feature = "hints")]
hints,
);
add_fp_bls12_381(
&shifted,
&d_lo,
#[cfg(feature = "hints")]
hints,
)
}
fn hash_to_field_fp2_count2_bls12_381(
msg: &[u8],
dst: &[u8],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [[u64; 12]; 2] {
const L: usize = 64; const M: usize = 2; const COUNT: usize = 2;
let uniform = expand_message_xmd_sha256(
msg,
dst,
L * M * COUNT,
#[cfg(feature = "hints")]
hints,
);
let mut result = [[0u64; 12]; COUNT];
for (i, fp2) in result.iter_mut().enumerate() {
for j in 0..M {
let off = L * (j + i * M);
let chunk: &[u8; L] = uniform[off..off + L].try_into().unwrap();
let e_j = os2ip_64_be_mod_p(
chunk,
#[cfg(feature = "hints")]
hints,
);
let limb_off = j * 6;
fp2[limb_off..limb_off + 6].copy_from_slice(&e_j);
}
}
result
}