use crate::zisklib::{eq, is_zero, lt};
use super::{
constants::{
COFACTOR_G1, ISO_A_G1, ISO_A_G2, ISO_B_G1, ISO_B_G2, ISO_X_DEN_G1, ISO_X_DEN_G2,
ISO_X_NUM_G1, ISO_X_NUM_G2, ISO_Y_DEN_G1, ISO_Y_DEN_G2, ISO_Y_NUM_G1, ISO_Y_NUM_G2, P,
SWU_Z2_G1, SWU_Z_G1, SWU_Z_G2,
},
curve::{g1_u64_le_to_bytes_be_bls12_381, scalar_mul_complete_bls12_381},
fp::{
add_fp_bls12_381, bytes_be_to_u64_le_fp_bls12_381, inv_fp_bls12_381, mul_fp_bls12_381,
neg_fp_bls12_381, sgn0_fp_bls12_381, sqrt_fp_bls12_381, square_fp_bls12_381,
},
fp2::{
add_fp2_bls12_381, bytes_be_to_u64_le_fp2_bls12_381, inv_fp2_bls12_381, mul_fp2_bls12_381,
neg_fp2_bls12_381, sgn0_fp2_bls12_381, sqrt_fp2_bls12_381, square_fp2_bls12_381,
},
twist::{
clear_cofactor_twist_bls12_381, g2_u64_le_to_bytes_be_bls12_381, scalar_mul_twist_bls12_381,
},
};
#[allow(dead_code)]
const G1_MAP_TO_CURVE_SUCCESS: u8 = 0;
const G1_MAP_TO_CURVE_ERR_NOT_IN_FIELD: u8 = 1;
#[allow(dead_code)]
const G2_MAP_TO_CURVE_SUCCESS: u8 = 0;
const G2_MAP_TO_CURVE_ERR_NOT_IN_FIELD: u8 = 1;
pub fn map_to_curve_g1_bls12_381(
u: &[u64; 6],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Result<[u64; 12], u8> {
if !lt(u, &P) {
return Err(G1_MAP_TO_CURVE_ERR_NOT_IN_FIELD);
}
let p_prime = map_to_curve_simple_swu_g1_bls12_381(
u,
#[cfg(feature = "hints")]
hints,
);
let p = isogeny_map_g1_bls12_381(
&p_prime,
#[cfg(feature = "hints")]
hints,
);
Ok(scalar_mul_complete_bls12_381(
&p,
&COFACTOR_G1,
#[cfg(feature = "hints")]
hints,
))
}
pub fn map_to_curve_g2_bls12_381(
u: &[u64; 12],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Result<[u64; 24], u8> {
let p = map_to_curve_g2_no_cofactor_bls12_381(
u,
#[cfg(feature = "hints")]
hints,
)?;
Ok(clear_cofactor_twist_bls12_381(
&p,
#[cfg(feature = "hints")]
hints,
))
}
pub(super) fn map_to_curve_g2_no_cofactor_bls12_381(
u: &[u64; 12],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Result<[u64; 24], u8> {
let u_0: [u64; 6] = u[0..6].try_into().unwrap();
let u_1: [u64; 6] = u[6..12].try_into().unwrap();
if !lt(&u_0, &P) || !lt(&u_1, &P) {
return Err(G2_MAP_TO_CURVE_ERR_NOT_IN_FIELD);
}
let p_prime = map_to_curve_simple_swu_g2_bls12_381(
u,
#[cfg(feature = "hints")]
hints,
);
Ok(isogeny_map_g2_bls12_381(
&p_prime,
#[cfg(feature = "hints")]
hints,
))
}
fn map_to_curve_simple_swu_g1_bls12_381(
u: &[u64; 6],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 12] {
let u2 = square_fp_bls12_381(
u,
#[cfg(feature = "hints")]
hints,
);
let u4 = square_fp_bls12_381(
&u2,
#[cfg(feature = "hints")]
hints,
);
let z_u2 = mul_fp_bls12_381(
&SWU_Z_G1,
&u2,
#[cfg(feature = "hints")]
hints,
);
let z2_u4 = mul_fp_bls12_381(
&SWU_Z2_G1,
&u4,
#[cfg(feature = "hints")]
hints,
);
let tv1_denom = add_fp_bls12_381(
&z2_u4,
&z_u2,
#[cfg(feature = "hints")]
hints,
);
let tv1 = inv_fp_bls12_381(
&tv1_denom,
#[cfg(feature = "hints")]
hints,
);
let neg_b = neg_fp_bls12_381(
&ISO_B_G1,
#[cfg(feature = "hints")]
hints,
);
let a_inv = inv_fp_bls12_381(
&ISO_A_G1,
#[cfg(feature = "hints")]
hints,
);
let neg_b_over_a = mul_fp_bls12_381(
&neg_b,
&a_inv,
#[cfg(feature = "hints")]
hints,
);
let one = [1u64, 0, 0, 0, 0, 0];
let one_plus_tv1 = add_fp_bls12_381(
&one,
&tv1,
#[cfg(feature = "hints")]
hints,
);
let mut x1 = mul_fp_bls12_381(
&neg_b_over_a,
&one_plus_tv1,
#[cfg(feature = "hints")]
hints,
);
if is_zero(&tv1) {
let z_a = mul_fp_bls12_381(
&SWU_Z_G1,
&ISO_A_G1,
#[cfg(feature = "hints")]
hints,
);
let z_a_inv = inv_fp_bls12_381(
&z_a,
#[cfg(feature = "hints")]
hints,
);
x1 = mul_fp_bls12_381(
&ISO_B_G1,
&z_a_inv,
#[cfg(feature = "hints")]
hints,
);
}
let gx1 = compute_y2_iso_g1_bls12_381(
&x1,
#[cfg(feature = "hints")]
hints,
);
let (y1, gx1_is_qr) = sqrt_fp_bls12_381(
&gx1,
#[cfg(feature = "hints")]
hints,
);
let (x, mut y) = if gx1_is_qr {
(x1, y1)
} else {
let x2 = mul_fp_bls12_381(
&z_u2,
&x1,
#[cfg(feature = "hints")]
hints,
);
let gx2 = compute_y2_iso_g1_bls12_381(
&x2,
#[cfg(feature = "hints")]
hints,
);
let (y2, _) = sqrt_fp_bls12_381(
&gx2,
#[cfg(feature = "hints")]
hints,
);
(x2, y2)
};
if sgn0_fp_bls12_381(u) != sgn0_fp_bls12_381(&y) {
y = neg_fp_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
}
let mut point = [0u64; 12];
point[0..6].copy_from_slice(&x);
point[6..12].copy_from_slice(&y);
point
}
fn map_to_curve_simple_swu_g2_bls12_381(
u: &[u64; 12],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let u2 = square_fp2_bls12_381(
u,
#[cfg(feature = "hints")]
hints,
);
let u4 = square_fp2_bls12_381(
&u2,
#[cfg(feature = "hints")]
hints,
);
let z_u2 = mul_fp2_bls12_381(
&SWU_Z_G2,
&u2,
#[cfg(feature = "hints")]
hints,
);
let z2 = square_fp2_bls12_381(
&SWU_Z_G2,
#[cfg(feature = "hints")]
hints,
);
let z2_u4 = mul_fp2_bls12_381(
&z2,
&u4,
#[cfg(feature = "hints")]
hints,
);
let tv1_denom = add_fp2_bls12_381(
&z2_u4,
&z_u2,
#[cfg(feature = "hints")]
hints,
);
let tv1 = inv_fp2_bls12_381(
&tv1_denom,
#[cfg(feature = "hints")]
hints,
);
let neg_b = neg_fp2_bls12_381(
&ISO_B_G2,
#[cfg(feature = "hints")]
hints,
);
let a_inv = inv_fp2_bls12_381(
&ISO_A_G2,
#[cfg(feature = "hints")]
hints,
);
let neg_b_over_a = mul_fp2_bls12_381(
&neg_b,
&a_inv,
#[cfg(feature = "hints")]
hints,
);
let one: [u64; 12] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let one_plus_tv1 = add_fp2_bls12_381(
&one,
&tv1,
#[cfg(feature = "hints")]
hints,
);
let mut x1 = mul_fp2_bls12_381(
&neg_b_over_a,
&one_plus_tv1,
#[cfg(feature = "hints")]
hints,
);
if is_zero(&tv1) {
let z_a = mul_fp2_bls12_381(
&SWU_Z_G2,
&ISO_A_G2,
#[cfg(feature = "hints")]
hints,
);
let z_a_inv = inv_fp2_bls12_381(
&z_a,
#[cfg(feature = "hints")]
hints,
);
x1 = mul_fp2_bls12_381(
&ISO_B_G2,
&z_a_inv,
#[cfg(feature = "hints")]
hints,
);
}
let gx1 = compute_y2_iso_g2_bls12_381(
&x1,
#[cfg(feature = "hints")]
hints,
);
let (y1, gx1_is_qr) = sqrt_fp2_bls12_381(
&gx1,
#[cfg(feature = "hints")]
hints,
);
let (x, mut y) = if gx1_is_qr {
(x1, y1)
} else {
let x2 = mul_fp2_bls12_381(
&z_u2,
&x1,
#[cfg(feature = "hints")]
hints,
);
let gx2 = compute_y2_iso_g2_bls12_381(
&x2,
#[cfg(feature = "hints")]
hints,
);
let (y2, _) = sqrt_fp2_bls12_381(
&gx2,
#[cfg(feature = "hints")]
hints,
);
(x2, y2)
};
if sgn0_fp2_bls12_381(u) != sgn0_fp2_bls12_381(&y) {
y = neg_fp2_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
}
let mut point = [0u64; 24];
point[0..12].copy_from_slice(&x);
point[12..24].copy_from_slice(&y);
point
}
fn compute_y2_iso_g1_bls12_381(
x: &[u64; 6],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 6] {
let x2 = square_fp_bls12_381(
x,
#[cfg(feature = "hints")]
hints,
);
let x3 = mul_fp_bls12_381(
&x2,
x,
#[cfg(feature = "hints")]
hints,
);
let ax = mul_fp_bls12_381(
&ISO_A_G1,
x,
#[cfg(feature = "hints")]
hints,
);
let x3_ax = add_fp_bls12_381(
&x3,
&ax,
#[cfg(feature = "hints")]
hints,
);
add_fp_bls12_381(
&x3_ax,
&ISO_B_G1,
#[cfg(feature = "hints")]
hints,
)
}
fn compute_y2_iso_g2_bls12_381(
x: &[u64; 12],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 12] {
let x2 = square_fp2_bls12_381(
x,
#[cfg(feature = "hints")]
hints,
);
let x3 = mul_fp2_bls12_381(
&x2,
x,
#[cfg(feature = "hints")]
hints,
);
let ax = mul_fp2_bls12_381(
&ISO_A_G2,
x,
#[cfg(feature = "hints")]
hints,
);
let x3_ax = add_fp2_bls12_381(
&x3,
&ax,
#[cfg(feature = "hints")]
hints,
);
add_fp2_bls12_381(
&x3_ax,
&ISO_B_G2,
#[cfg(feature = "hints")]
hints,
)
}
fn isogeny_map_g1_bls12_381(
p: &[u64; 12],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 12] {
let x: [u64; 6] = p[0..6].try_into().unwrap();
let y: [u64; 6] = p[6..12].try_into().unwrap();
let x_num = eval_poly_fp(
&ISO_X_NUM_G1,
&x,
#[cfg(feature = "hints")]
hints,
);
let x_den = eval_poly_fp(
&ISO_X_DEN_G1,
&x,
#[cfg(feature = "hints")]
hints,
);
let x_den_inv = inv_fp_bls12_381(
&x_den,
#[cfg(feature = "hints")]
hints,
);
let x_out = mul_fp_bls12_381(
&x_num,
&x_den_inv,
#[cfg(feature = "hints")]
hints,
);
let y_num = eval_poly_fp(
&ISO_Y_NUM_G1,
&x,
#[cfg(feature = "hints")]
hints,
);
let y_den = eval_poly_fp(
&ISO_Y_DEN_G1,
&x,
#[cfg(feature = "hints")]
hints,
);
let y_den_inv = inv_fp_bls12_381(
&y_den,
#[cfg(feature = "hints")]
hints,
);
let y_frac = mul_fp_bls12_381(
&y_num,
&y_den_inv,
#[cfg(feature = "hints")]
hints,
);
let y_out = mul_fp_bls12_381(
&y,
&y_frac,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0u64; 12];
result[0..6].copy_from_slice(&x_out);
result[6..12].copy_from_slice(&y_out);
result
}
fn isogeny_map_g2_bls12_381(
p: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let x: [u64; 12] = p[0..12].try_into().unwrap();
let y: [u64; 12] = p[12..24].try_into().unwrap();
let x_num = eval_poly_fp2(
&ISO_X_NUM_G2,
&x,
#[cfg(feature = "hints")]
hints,
);
let x_den = eval_poly_fp2(
&ISO_X_DEN_G2,
&x,
#[cfg(feature = "hints")]
hints,
);
let x_den_inv = inv_fp2_bls12_381(
&x_den,
#[cfg(feature = "hints")]
hints,
);
let x_out = mul_fp2_bls12_381(
&x_num,
&x_den_inv,
#[cfg(feature = "hints")]
hints,
);
let y_num = eval_poly_fp2(
&ISO_Y_NUM_G2,
&x,
#[cfg(feature = "hints")]
hints,
);
let y_den = eval_poly_fp2(
&ISO_Y_DEN_G2,
&x,
#[cfg(feature = "hints")]
hints,
);
let y_den_inv = inv_fp2_bls12_381(
&y_den,
#[cfg(feature = "hints")]
hints,
);
let y_frac = mul_fp2_bls12_381(
&y_num,
&y_den_inv,
#[cfg(feature = "hints")]
hints,
);
let y_out = mul_fp2_bls12_381(
&y,
&y_frac,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0u64; 24];
result[0..12].copy_from_slice(&x_out);
result[12..24].copy_from_slice(&y_out);
result
}
fn eval_poly_fp<const N: usize>(
coeffs: &[[u64; 6]; N],
x: &[u64; 6],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 6] {
let mut result = coeffs[N - 1];
for i in (0..N - 1).rev() {
result = mul_fp_bls12_381(
&result,
x,
#[cfg(feature = "hints")]
hints,
);
result = add_fp_bls12_381(
&result,
&coeffs[i],
#[cfg(feature = "hints")]
hints,
);
}
result
}
fn eval_poly_fp2<const N: usize>(
coeffs: &[[u64; 12]; N],
x: &[u64; 12],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 12] {
let mut result = coeffs[N - 1];
for i in (0..N - 1).rev() {
result = mul_fp2_bls12_381(
&result,
x,
#[cfg(feature = "hints")]
hints,
);
result = add_fp2_bls12_381(
&result,
&coeffs[i],
#[cfg(feature = "hints")]
hints,
);
}
result
}
#[allow(dead_code)]
pub(crate) const FP_TO_G1_SUCCESS: u8 = 0;
#[allow(dead_code)]
pub(crate) const FP2_TO_G2_SUCCESS: u8 = 0;
#[allow(dead_code)]
#[inline]
pub(crate) unsafe fn bls12_381_fp_to_g1_c(
ret: *mut u8,
fp: *const u8,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let fp_bytes: &[u8; 48] = &*(fp as *const [u8; 48]);
let ret_bytes: &mut [u8; 96] = &mut *(ret as *mut [u8; 96]);
let u = bytes_be_to_u64_le_fp_bls12_381(fp_bytes);
let result = match map_to_curve_g1_bls12_381(
&u,
#[cfg(feature = "hints")]
hints,
) {
Ok(p) => p,
Err(code) => return code,
};
g1_u64_le_to_bytes_be_bls12_381(&result, ret_bytes);
G1_MAP_TO_CURVE_SUCCESS
}
#[allow(dead_code)]
#[inline]
pub(crate) unsafe fn bls12_381_fp2_to_g2_c(
ret: *mut u8,
fp2: *const u8,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let fp2_bytes: &[u8; 96] = &*(fp2 as *const [u8; 96]);
let ret_bytes: &mut [u8; 192] = &mut *(ret as *mut [u8; 192]);
let u = bytes_be_to_u64_le_fp2_bls12_381(fp2_bytes);
let result = match map_to_curve_g2_bls12_381(
&u,
#[cfg(feature = "hints")]
hints,
) {
Ok(p) => p,
Err(code) => return code,
};
g2_u64_le_to_bytes_be_bls12_381(&result, ret_bytes);
G2_MAP_TO_CURVE_SUCCESS
}