#[cfg(zisk_guest)]
use crate::alloc_extern::vec::Vec;
use crate::zisklib::{eq, fcall_msb_pos_256, is_one, is_two, is_zero, lt};
use super::{
constants::{
ETWISTED_B, EXT_U, EXT_U_INV, FROBENIUS_GAMMA13, FROBENIUS_GAMMA14, G2_IDENTITY, P,
PSI2_C1, PSI_C1, PSI_C2, X_ABS_BIN_BE,
},
fp2::{
add_fp2_bls12_381, conjugate_fp2_bls12_381, dbl_fp2_bls12_381, inv_fp2_bls12_381,
mul_fp2_bls12_381, neg_fp2_bls12_381, scalar_mul_fp2_bls12_381, sqrt_fp2_bls12_381,
square_fp2_bls12_381, sub_fp2_bls12_381,
},
fr::{reduce_fr_bls12_381, scalar_bytes_be_to_u64_le_bls12_381},
};
pub const G2_ADD_SUCCESS: u8 = 0;
pub const G2_ADD_SUCCESS_INFINITY: u8 = 1;
pub const G2_ADD_ERR_NOT_IN_FIELD: u8 = 2;
pub const G2_ADD_ERR_NOT_ON_CURVE: u8 = 3;
pub const G2_MSM_SUCCESS: u8 = 0;
pub const G2_MSM_SUCCESS_INFINITY: u8 = 1;
pub const G2_MSM_ERR_NOT_IN_FIELD: u8 = 2;
pub const G2_MSM_ERR_NOT_ON_CURVE: u8 = 3;
pub const G2_MSM_ERR_NOT_IN_SUBGROUP: u8 = 4;
pub fn decompress_twist_bls12_381(
input: &[u8; 96],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Result<([u64; 24], bool), &'static str> {
let flags = input[0];
if (flags & 0x80) == 0 {
return Err("decompress_twist_bls12_381: Expected compressed point (0x80 flag not set)");
}
if (flags & 0x40) != 0 {
if (flags & 0x3f) != 0 {
return Err("Invalid infinity encoding");
}
for item in input.iter().skip(1) {
if *item != 0 {
return Err("Invalid infinity encoding");
}
}
return Ok((G2_IDENTITY, true));
}
let y_sign = (flags & 0x20) != 0;
let mut x_i = [0u64; 6];
let mut x_r = [0u64; 6];
let mut bytes_i = [0u8; 48];
bytes_i.copy_from_slice(&input[0..48]);
bytes_i[0] &= 0x1f;
for i in 0..6 {
for j in 0..8 {
x_i[5 - i] |= (bytes_i[i * 8 + j] as u64) << (8 * (7 - j));
}
}
for i in 0..6 {
for j in 0..8 {
x_r[5 - i] |= (input[48 + i * 8 + j] as u64) << (8 * (7 - j));
}
}
if !lt(&x_r, &P) {
return Err("x_r coordinate >= field modulus");
}
if !lt(&x_i, &P) {
return Err("x_i coordinate >= field modulus");
}
let mut x = [0u64; 12];
x[0..6].copy_from_slice(&x_r);
x[6..12].copy_from_slice(&x_i);
let x_sq = square_fp2_bls12_381(
&x,
#[cfg(feature = "hints")]
hints,
);
let x_cb = mul_fp2_bls12_381(
&x_sq,
&x,
#[cfg(feature = "hints")]
hints,
);
let y_sq = add_fp2_bls12_381(
&x_cb,
&ETWISTED_B,
#[cfg(feature = "hints")]
hints,
);
let (y, has_sqrt) = sqrt_fp2_bls12_381(
&y_sq,
#[cfg(feature = "hints")]
hints,
);
if !has_sqrt {
return Err("No square root exists - point not on curve");
}
let y_neg = neg_fp2_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
let y_r: [u64; 6] = y[0..6].try_into().unwrap();
let y_i: [u64; 6] = y[6..12].try_into().unwrap();
let y_neg_r: [u64; 6] = y_neg[0..6].try_into().unwrap();
let y_neg_i: [u64; 6] = y_neg[6..12].try_into().unwrap();
let y_is_larger = if !eq(&y_i, &y_neg_i) {
lt(&y_neg_i, &y_i)
} else {
lt(&y_neg_r, &y_r)
};
let final_y = if y_is_larger == y_sign { y } else { y_neg };
let mut result = [0u64; 24];
result[0..12].copy_from_slice(&x);
result[12..24].copy_from_slice(&final_y);
Ok((result, false))
}
pub fn is_on_curve_twist_bls12_381(
p: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> bool {
let x: [u64; 12] = p[0..12].try_into().unwrap();
let y: [u64; 12] = p[12..24].try_into().unwrap();
let x_sq = square_fp2_bls12_381(
&x,
#[cfg(feature = "hints")]
hints,
);
let x_cubed = mul_fp2_bls12_381(
&x_sq,
&x,
#[cfg(feature = "hints")]
hints,
);
let x_cubed_plus_b = add_fp2_bls12_381(
&x_cubed,
&ETWISTED_B,
#[cfg(feature = "hints")]
hints,
);
let y_sq = square_fp2_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
eq(&x_cubed_plus_b, &y_sq) || eq(p, &G2_IDENTITY)
}
pub fn is_on_subgroup_twist_bls12_381(
p: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> bool {
let utf1 = utf_endomorphism_twist_bls12_381(
p,
#[cfg(feature = "hints")]
hints,
);
let rhs = utf_endomorphism_twist_bls12_381(
&utf1,
#[cfg(feature = "hints")]
hints,
);
let utf3 = utf_endomorphism_twist_bls12_381(
&rhs,
#[cfg(feature = "hints")]
hints,
);
let xutf3: [u64; 24] = scalar_mul_by_abs_x_complete_twist_bls12_381(
&utf3,
#[cfg(feature = "hints")]
hints,
);
let mut lhs = neg_twist_bls12_381(
&xutf3,
#[cfg(feature = "hints")]
hints,
);
lhs = add_complete_twist_bls12_381(
&lhs,
p,
#[cfg(feature = "hints")]
hints,
);
eq(&lhs, &rhs)
}
fn psi_twist_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 mut frobx = conjugate_fp2_bls12_381(
&x,
#[cfg(feature = "hints")]
hints,
);
frobx = mul_fp2_bls12_381(
&frobx,
&PSI_C1,
#[cfg(feature = "hints")]
hints,
);
let mut froby = conjugate_fp2_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
froby = mul_fp2_bls12_381(
&froby,
&PSI_C2,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0u64; 24];
result[0..12].copy_from_slice(&frobx);
result[12..24].copy_from_slice(&froby);
result
}
fn psi2_twist_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 xa = mul_fp2_bls12_381(
&x,
&PSI2_C1,
#[cfg(feature = "hints")]
hints,
);
let ya = neg_fp2_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0u64; 24];
result[0..12].copy_from_slice(&xa);
result[12..24].copy_from_slice(&ya);
result
}
pub fn utf_endomorphism_twist_bls12_381(
p: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let mut x: [u64; 12] = p[0..12].try_into().unwrap();
let mut y: [u64; 12] = p[12..24].try_into().unwrap();
x = mul_fp2_bls12_381(
&x,
&EXT_U_INV,
#[cfg(feature = "hints")]
hints,
);
y = mul_fp2_bls12_381(
&y,
&EXT_U_INV,
#[cfg(feature = "hints")]
hints,
);
x = conjugate_fp2_bls12_381(
&x,
#[cfg(feature = "hints")]
hints,
);
x = scalar_mul_fp2_bls12_381(
&x,
&FROBENIUS_GAMMA14,
#[cfg(feature = "hints")]
hints,
);
y = conjugate_fp2_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
y = mul_fp2_bls12_381(
&y,
&FROBENIUS_GAMMA13,
#[cfg(feature = "hints")]
hints,
);
x = mul_fp2_bls12_381(
&x,
&EXT_U,
#[cfg(feature = "hints")]
hints,
);
y = mul_fp2_bls12_381(
&y,
&EXT_U,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0u64; 24];
result[0..12].copy_from_slice(&x);
result[12..24].copy_from_slice(&y);
result
}
pub fn clear_cofactor_twist_bls12_381(
p: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let mut t1 = scalar_mul_by_abs_x_complete_twist_bls12_381(
p,
#[cfg(feature = "hints")]
hints,
);
t1 = neg_twist_bls12_381(
&t1,
#[cfg(feature = "hints")]
hints,
);
let mut t2 = psi_twist_bls12_381(
p,
#[cfg(feature = "hints")]
hints,
);
let mut t3 = dbl_complete_twist_bls12_381(
p,
#[cfg(feature = "hints")]
hints,
);
t3 = psi2_twist_bls12_381(
&t3,
#[cfg(feature = "hints")]
hints,
);
t3 = sub_complete_twist_bls12_381(
&t3,
&t2,
#[cfg(feature = "hints")]
hints,
);
t2 = add_complete_twist_bls12_381(
&t1,
&t2,
#[cfg(feature = "hints")]
hints,
);
t2 = scalar_mul_by_abs_x_complete_twist_bls12_381(
&t2,
#[cfg(feature = "hints")]
hints,
);
t2 = neg_twist_bls12_381(
&t2,
#[cfg(feature = "hints")]
hints,
);
t3 = add_complete_twist_bls12_381(
&t3,
&t2,
#[cfg(feature = "hints")]
hints,
);
t3 = sub_complete_twist_bls12_381(
&t3,
&t1,
#[cfg(feature = "hints")]
hints,
);
sub_complete_twist_bls12_381(
&t3,
p,
#[cfg(feature = "hints")]
hints,
)
}
pub fn add_complete_twist_bls12_381(
p1: &[u64; 24],
p2: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
if eq(p1, &G2_IDENTITY) {
return *p2;
} else if eq(p2, &G2_IDENTITY) {
return *p1;
}
add_twist_bls12_381(
p1,
p2,
#[cfg(feature = "hints")]
hints,
)
}
pub fn add_twist_bls12_381(
p1: &[u64; 24],
p2: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let x1: [u64; 12] = p1[0..12].try_into().unwrap();
let y1: [u64; 12] = p1[12..24].try_into().unwrap();
let x2: [u64; 12] = p2[0..12].try_into().unwrap();
let y2: [u64; 12] = p2[12..24].try_into().unwrap();
if eq(&x1, &x2) {
if eq(&y1, &y2) {
return dbl_twist_bls12_381(
p1,
#[cfg(feature = "hints")]
hints,
);
} else {
return G2_IDENTITY;
}
}
let mut den = sub_fp2_bls12_381(
&x2,
&x1,
#[cfg(feature = "hints")]
hints,
);
den = inv_fp2_bls12_381(
&den,
#[cfg(feature = "hints")]
hints,
);
let mut lambda = sub_fp2_bls12_381(
&y2,
&y1,
#[cfg(feature = "hints")]
hints,
);
lambda = mul_fp2_bls12_381(
&lambda,
&den,
#[cfg(feature = "hints")]
hints,
);
let mut x3 = square_fp2_bls12_381(
&lambda,
#[cfg(feature = "hints")]
hints,
);
x3 = sub_fp2_bls12_381(
&x3,
&x1,
#[cfg(feature = "hints")]
hints,
);
x3 = sub_fp2_bls12_381(
&x3,
&x2,
#[cfg(feature = "hints")]
hints,
);
let mut y3 = sub_fp2_bls12_381(
&x1,
&x3,
#[cfg(feature = "hints")]
hints,
);
y3 = mul_fp2_bls12_381(
&lambda,
&y3,
#[cfg(feature = "hints")]
hints,
);
y3 = sub_fp2_bls12_381(
&y3,
&y1,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0u64; 24];
result[0..12].copy_from_slice(&x3);
result[12..24].copy_from_slice(&y3);
result
}
pub fn add_complete_safe_twist_bls12_381(
p1: &[u64; 24],
p2: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Result<[u64; 24], u8> {
let p1_is_inf = eq(p1, &G2_IDENTITY);
let p2_is_inf = eq(p2, &G2_IDENTITY);
if p1_is_inf && p2_is_inf {
return Ok(G2_IDENTITY);
}
if p1_is_inf {
let x2_0: [u64; 6] = p2[0..6].try_into().unwrap();
let x2_1: [u64; 6] = p2[6..12].try_into().unwrap();
let y2_0: [u64; 6] = p2[12..18].try_into().unwrap();
let y2_1: [u64; 6] = p2[18..24].try_into().unwrap();
if !lt(&x2_0, &P) || !lt(&x2_1, &P) || !lt(&y2_0, &P) || !lt(&y2_1, &P) {
return Err(G2_ADD_ERR_NOT_IN_FIELD);
}
if !is_on_curve_twist_bls12_381(
p2,
#[cfg(feature = "hints")]
hints,
) {
return Err(G2_ADD_ERR_NOT_ON_CURVE);
}
return Ok(*p2);
}
if p2_is_inf {
let x1_0: [u64; 6] = p1[0..6].try_into().unwrap();
let x1_1: [u64; 6] = p1[6..12].try_into().unwrap();
let y1_0: [u64; 6] = p1[12..18].try_into().unwrap();
let y1_1: [u64; 6] = p1[18..24].try_into().unwrap();
if !lt(&x1_0, &P) || !lt(&x1_1, &P) || !lt(&y1_0, &P) || !lt(&y1_1, &P) {
return Err(G2_ADD_ERR_NOT_IN_FIELD);
}
if !is_on_curve_twist_bls12_381(
p1,
#[cfg(feature = "hints")]
hints,
) {
return Err(G2_ADD_ERR_NOT_ON_CURVE);
}
return Ok(*p1);
}
let x1_0: [u64; 6] = p1[0..6].try_into().unwrap();
let x1_1: [u64; 6] = p1[6..12].try_into().unwrap();
let y1_0: [u64; 6] = p1[12..18].try_into().unwrap();
let y1_1: [u64; 6] = p1[18..24].try_into().unwrap();
if !lt(&x1_0, &P) || !lt(&x1_1, &P) || !lt(&y1_0, &P) || !lt(&y1_1, &P) {
return Err(G2_ADD_ERR_NOT_IN_FIELD);
}
if !is_on_curve_twist_bls12_381(
p1,
#[cfg(feature = "hints")]
hints,
) {
return Err(G2_ADD_ERR_NOT_ON_CURVE);
}
let x2_0: [u64; 6] = p2[0..6].try_into().unwrap();
let x2_1: [u64; 6] = p2[6..12].try_into().unwrap();
let y2_0: [u64; 6] = p2[12..18].try_into().unwrap();
let y2_1: [u64; 6] = p2[18..24].try_into().unwrap();
if !lt(&x2_0, &P) || !lt(&x2_1, &P) || !lt(&y2_0, &P) || !lt(&y2_1, &P) {
return Err(G2_ADD_ERR_NOT_IN_FIELD);
}
if !is_on_curve_twist_bls12_381(
p2,
#[cfg(feature = "hints")]
hints,
) {
return Err(G2_ADD_ERR_NOT_ON_CURVE);
}
Ok(add_twist_bls12_381(
p1,
p2,
#[cfg(feature = "hints")]
hints,
))
}
pub fn neg_twist_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 y_neg = neg_fp2_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0u64; 24];
result[0..12].copy_from_slice(&x);
result[12..24].copy_from_slice(&y_neg);
result
}
pub fn dbl_complete_twist_bls12_381(
p: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
if eq(p, &G2_IDENTITY) {
return G2_IDENTITY;
}
dbl_twist_bls12_381(
p,
#[cfg(feature = "hints")]
hints,
)
}
pub fn dbl_twist_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 mut lambda = dbl_fp2_bls12_381(
&y,
#[cfg(feature = "hints")]
hints,
);
lambda = inv_fp2_bls12_381(
&lambda,
#[cfg(feature = "hints")]
hints,
);
lambda = scalar_mul_fp2_bls12_381(
&lambda,
&[0x3, 0, 0, 0, 0, 0],
#[cfg(feature = "hints")]
hints,
);
lambda = mul_fp2_bls12_381(
&lambda,
&x,
#[cfg(feature = "hints")]
hints,
);
lambda = mul_fp2_bls12_381(
&lambda,
&x,
#[cfg(feature = "hints")]
hints,
);
let mut x3 = square_fp2_bls12_381(
&lambda,
#[cfg(feature = "hints")]
hints,
);
x3 = sub_fp2_bls12_381(
&x3,
&x,
#[cfg(feature = "hints")]
hints,
);
x3 = sub_fp2_bls12_381(
&x3,
&x,
#[cfg(feature = "hints")]
hints,
);
let mut y3 = sub_fp2_bls12_381(
&x,
&x3,
#[cfg(feature = "hints")]
hints,
);
y3 = mul_fp2_bls12_381(
&lambda,
&y3,
#[cfg(feature = "hints")]
hints,
);
y3 = sub_fp2_bls12_381(
&y3,
&y,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0u64; 24];
result[0..12].copy_from_slice(&x3);
result[12..24].copy_from_slice(&y3);
result
}
pub fn sub_twist_bls12_381(
p1: &[u64; 24],
p2: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let x2: [u64; 12] = p2[0..12].try_into().unwrap();
let y2: [u64; 12] = p2[12..24].try_into().unwrap();
let y2_neg = neg_fp2_bls12_381(
&y2,
#[cfg(feature = "hints")]
hints,
);
let mut p2_neg = [0u64; 24];
p2_neg[0..12].copy_from_slice(&x2);
p2_neg[12..24].copy_from_slice(&y2_neg);
add_twist_bls12_381(
p1,
&p2_neg,
#[cfg(feature = "hints")]
hints,
)
}
pub fn sub_complete_twist_bls12_381(
p1: &[u64; 24],
p2: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let p1_is_inf = *p1 == G2_IDENTITY;
let p2_is_inf = *p2 == G2_IDENTITY;
if p1_is_inf && p2_is_inf {
return G2_IDENTITY;
} else if p1_is_inf {
return neg_twist_bls12_381(
p2,
#[cfg(feature = "hints")]
hints,
);
} else if p2_is_inf {
return *p1;
}
sub_twist_bls12_381(
p1,
p2,
#[cfg(feature = "hints")]
hints,
)
}
pub fn scalar_mul_twist_bls12_381(
p: &[u64; 24],
k: &[u64; 4],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
let k = reduce_fr_bls12_381(
k,
#[cfg(feature = "hints")]
hints,
);
if is_zero(&k) {
return G2_IDENTITY;
} else if is_one(&k) {
return *p;
} else if is_two(&k) {
return dbl_twist_bls12_381(
p,
#[cfg(feature = "hints")]
hints,
);
}
let (max_limb, max_bit) = fcall_msb_pos_256(
&k,
#[cfg(feature = "hints")]
hints,
);
assert!(max_limb < 4 && max_bit < 64, "msb_pos hint out of range");
let max_limb = max_limb as usize;
let max_bit = max_bit as usize;
assert_eq!((k[max_limb] >> max_bit) & 1, 1, "The first received bit of k should be 1");
let mut q = *p;
let mut k_rec = [0u64; 4];
k_rec[max_limb] |= 1 << max_bit;
let mut limb = max_limb;
let mut bit = if max_bit == 0 {
limb -= 1;
63
} else {
max_bit - 1
};
for i in (0..=limb).rev() {
for j in (0..=bit).rev() {
q = dbl_twist_bls12_381(
&q,
#[cfg(feature = "hints")]
hints,
);
if ((k[i] >> j) & 1) == 1 {
q = add_twist_bls12_381(
&q,
p,
#[cfg(feature = "hints")]
hints,
);
k_rec[i] |= 1 << j;
}
}
bit = 63;
}
assert!(eq(&k, &k_rec), "Reconstructed scalar does not match input scalar");
q
}
pub fn scalar_mul_by_abs_x_complete_twist_bls12_381(
p: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 24] {
if eq(p, &G2_IDENTITY) {
return G2_IDENTITY;
}
let mut r = *p;
for &bit in X_ABS_BIN_BE.iter().skip(1) {
r = dbl_complete_twist_bls12_381(
&r,
#[cfg(feature = "hints")]
hints,
);
if bit == 1 {
r = add_complete_twist_bls12_381(
&r,
p,
#[cfg(feature = "hints")]
hints,
);
}
}
r
}
pub fn msm_complete_safe_twist_bls12_381(
points: &[[u64; 24]],
scalars: &[[u64; 4]],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Result<[u64; 24], u8> {
debug_assert_eq!(points.len(), scalars.len(), "Points and scalars must have the same length");
let mut acc = G2_IDENTITY;
let mut acc_is_inf = true;
for (point, scalar) in points.iter().zip(scalars.iter()) {
if *point == G2_IDENTITY {
continue;
}
let x_0: [u64; 6] = point[0..6].try_into().unwrap();
let x_1: [u64; 6] = point[6..12].try_into().unwrap();
let y_0: [u64; 6] = point[12..18].try_into().unwrap();
let y_1: [u64; 6] = point[18..24].try_into().unwrap();
if !lt(&x_0, &P) || !lt(&x_1, &P) || !lt(&y_0, &P) || !lt(&y_1, &P) {
return Err(G2_MSM_ERR_NOT_IN_FIELD);
}
if !is_on_curve_twist_bls12_381(
point,
#[cfg(feature = "hints")]
hints,
) {
return Err(G2_MSM_ERR_NOT_ON_CURVE);
}
if !is_on_subgroup_twist_bls12_381(
point,
#[cfg(feature = "hints")]
hints,
) {
return Err(G2_MSM_ERR_NOT_IN_SUBGROUP);
}
let scalar = reduce_fr_bls12_381(
scalar,
#[cfg(feature = "hints")]
hints,
);
if is_zero(&scalar) {
continue;
}
let product = scalar_mul_twist_bls12_381(
point,
&scalar,
#[cfg(feature = "hints")]
hints,
);
if product == G2_IDENTITY {
continue;
}
if acc_is_inf {
acc = product;
acc_is_inf = false;
} else {
acc = add_twist_bls12_381(
&acc,
&product,
#[cfg(feature = "hints")]
hints,
);
acc_is_inf = acc == G2_IDENTITY;
}
}
Ok(acc)
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_decompress_twist_bls12_381_c")]
pub unsafe extern "C" fn decompress_twist_bls12_381_c(
input_ptr: *const u8,
result_ptr: *mut u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let input = &*(input_ptr as *const [u8; 96]);
match decompress_twist_bls12_381(
input,
#[cfg(feature = "hints")]
hints,
) {
Ok((p, is_infinity)) => {
let result = &mut *(result_ptr as *mut [u64; 24]);
*result = p;
if is_infinity {
1
} else {
0
}
}
Err(_) => 2,
}
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_is_on_curve_twist_bls12_381_c")]
pub unsafe extern "C" fn is_on_curve_twist_bls12_381_c(
p_ptr: *const u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let p = &*(p_ptr as *const [u64; 24]);
is_on_curve_twist_bls12_381(
p,
#[cfg(feature = "hints")]
hints,
) as u8
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_is_on_subgroup_twist_bls12_381_c")]
pub unsafe extern "C" fn is_on_subgroup_twist_bls12_381_c(
p_ptr: *const u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let p = &*(p_ptr as *const [u64; 24]);
is_on_subgroup_twist_bls12_381(
p,
#[cfg(feature = "hints")]
hints,
) as u8
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_add_twist_bls12_381_c")]
pub unsafe extern "C" fn add_twist_bls12_381_c(
p1_ptr: *const u64,
p2_ptr: *const u64,
result_ptr: *mut u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let p1 = &*(p1_ptr as *const [u64; 24]);
let p2 = &*(p2_ptr as *const [u64; 24]);
let result = &mut *(result_ptr as *mut [u64; 24]);
*result = add_twist_bls12_381(
p1,
p2,
#[cfg(feature = "hints")]
hints,
);
if eq(result, &G2_IDENTITY) {
1
} else {
0
}
}
#[allow(dead_code)]
#[inline]
pub(crate) unsafe fn add_safe_twist_bls12_381_c(
ret: *mut u8,
a: *const u8,
b: *const u8,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let a_bytes: &[u8; 192] = &*(a as *const [u8; 192]);
let b_bytes: &[u8; 192] = &*(b as *const [u8; 192]);
let ret_bytes: &mut [u8; 192] = &mut *(ret as *mut [u8; 192]);
let a_u64 = g2_bytes_be_to_u64_le_bls12_381(a_bytes);
let b_u64 = g2_bytes_be_to_u64_le_bls12_381(b_bytes);
let result = match add_complete_safe_twist_bls12_381(
&a_u64,
&b_u64,
#[cfg(feature = "hints")]
hints,
) {
Ok(r) => r,
Err(code) => return code,
};
g2_u64_le_to_bytes_be_bls12_381(&result, ret_bytes);
if result == G2_IDENTITY {
G2_ADD_SUCCESS_INFINITY
} else {
G2_ADD_SUCCESS
}
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_scalar_mul_twist_bls12_381_c")]
pub unsafe extern "C" fn scalar_mul_twist_bls12_381_c(
p_ptr: *const u64,
k_ptr: *const u64,
result_ptr: *mut u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let p = &*(p_ptr as *const [u64; 24]);
let k = &*(k_ptr as *const [u64; 4]);
let result = &mut *(result_ptr as *mut [u64; 24]);
*result = scalar_mul_twist_bls12_381(
p,
k,
#[cfg(feature = "hints")]
hints,
);
if eq(result, &G2_IDENTITY) {
1
} else {
0
}
}
#[allow(dead_code)]
#[inline]
pub(crate) unsafe fn msm_safe_twist_bls12_381_c(
ret: *mut u8,
pairs: *const u8,
num_pairs: usize,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let ret_bytes: &mut [u8; 192] = &mut *(ret as *mut [u8; 192]);
let mut points = Vec::with_capacity(num_pairs);
let mut scalars = Vec::with_capacity(num_pairs);
for i in 0..num_pairs {
let pair_ptr = pairs.add(i * 224);
let point_bytes: &[u8; 192] = &*(pair_ptr as *const [u8; 192]);
let scalar_bytes: &[u8; 32] = &*(pair_ptr.add(192) as *const [u8; 32]);
let point_u64 = g2_bytes_be_to_u64_le_bls12_381(point_bytes);
let scalar_u64 = scalar_bytes_be_to_u64_le_bls12_381(scalar_bytes);
points.push(point_u64);
scalars.push(scalar_u64);
}
let result = match msm_complete_safe_twist_bls12_381(
&points,
&scalars,
#[cfg(feature = "hints")]
hints,
) {
Ok(r) => r,
Err(code) => return code,
};
g2_u64_le_to_bytes_be_bls12_381(&result, ret_bytes);
if result == G2_IDENTITY {
G2_MSM_SUCCESS_INFINITY
} else {
G2_MSM_SUCCESS
}
}
pub fn g2_bytes_be_to_u64_le_bls12_381(bytes: &[u8; 192]) -> [u64; 24] {
let mut result = [0u64; 24];
for i in 0..6 {
for j in 0..8 {
result[5 - i] |= (bytes[i * 8 + j] as u64) << (8 * (7 - j));
}
}
for i in 0..6 {
for j in 0..8 {
result[11 - i] |= (bytes[48 + i * 8 + j] as u64) << (8 * (7 - j));
}
}
for i in 0..6 {
for j in 0..8 {
result[17 - i] |= (bytes[96 + i * 8 + j] as u64) << (8 * (7 - j));
}
}
for i in 0..6 {
for j in 0..8 {
result[23 - i] |= (bytes[144 + i * 8 + j] as u64) << (8 * (7 - j));
}
}
result
}
pub fn g2_u64_le_to_bytes_be_bls12_381(limbs: &[u64; 24], bytes: &mut [u8; 192]) {
for i in 0..6 {
let limb = limbs[5 - i];
for j in 0..8 {
bytes[i * 8 + j] = ((limb >> (8 * (7 - j))) & 0xFF) as u8;
}
}
for i in 0..6 {
let limb = limbs[11 - i];
for j in 0..8 {
bytes[48 + i * 8 + j] = ((limb >> (8 * (7 - j))) & 0xFF) as u8;
}
}
for i in 0..6 {
let limb = limbs[17 - i];
for j in 0..8 {
bytes[96 + i * 8 + j] = ((limb >> (8 * (7 - j))) & 0xFF) as u8;
}
}
for i in 0..6 {
let limb = limbs[23 - i];
for j in 0..8 {
bytes[144 + i * 8 + j] = ((limb >> (8 * (7 - j))) & 0xFF) as u8;
}
}
}