#[cfg(zisk_guest)]
use crate::alloc_extern::vec::Vec;
use crate::zisklib::lib::utils::{eq, is_one, lt};
use super::{
constants::{G1_IDENTITY, G2_IDENTITY, P, P_MINUS_ONE},
curve::{
g1_bytes_be_to_u64_le_bls12_381, is_on_curve_bls12_381, is_on_subgroup_bls12_381,
neg_bls12_381,
},
final_exp::final_exp_bls12_381,
miller_loop::{miller_loop_batch_bls12_381, miller_loop_bls12_381},
twist::{
g2_bytes_be_to_u64_le_bls12_381, is_on_curve_twist_bls12_381,
is_on_subgroup_twist_bls12_381,
},
};
#[allow(dead_code)]
pub(crate) const PAIRING_CHECK_SUCCESS: u8 = 0;
#[allow(dead_code)]
pub(crate) const PAIRING_CHECK_FAILED: u8 = 1;
const PAIRING_CHECK_ERR_G1_NOT_CANONICAL: u8 = 2;
const PAIRING_CHECK_ERR_G1_NOT_ON_CURVE: u8 = 3;
const PAIRING_CHECK_ERR_G1_NOT_IN_SUBGROUP: u8 = 4;
const PAIRING_CHECK_ERR_G2_NOT_CANONICAL: u8 = 5;
const PAIRING_CHECK_ERR_G2_NOT_ON_CURVE: u8 = 6;
const PAIRING_CHECK_ERR_G2_NOT_IN_SUBGROUP: u8 = 7;
pub fn pairing_bls12_381(
p: &[u64; 12],
q: &[u64; 24],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 72] {
if *p == G1_IDENTITY || *q == G2_IDENTITY {
let mut one = [0; 72];
one[0] = 1;
return one;
}
let miller_loop = miller_loop_bls12_381(
p,
q,
#[cfg(feature = "hints")]
hints,
);
final_exp_bls12_381(
&miller_loop,
#[cfg(feature = "hints")]
hints,
)
}
pub fn pairing_batch_bls12_381(
g1_points: &[[u64; 12]],
g2_points: &[[u64; 24]],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 72] {
let n = g1_points.len();
assert_eq!(n, g2_points.len(), "Number of G1 and G2 points must be equal");
if n == 0 {
let mut one = [0; 72];
one[0] = 1;
return one;
}
let miller_loop = miller_loop_batch_bls12_381(
g1_points,
g2_points,
#[cfg(feature = "hints")]
hints,
);
final_exp_bls12_381(
&miller_loop,
#[cfg(feature = "hints")]
hints,
)
}
pub fn pairing_check_safe_bls12_381(
g1_points: &[[u64; 12]],
g2_points: &[[u64; 24]],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Result<bool, u8> {
assert_eq!(g1_points.len(), g2_points.len(), "Number of G1 and G2 points must be equal");
let mut valid_g1: Vec<[u64; 12]> = Vec::with_capacity(g1_points.len());
let mut valid_g2: Vec<[u64; 24]> = Vec::with_capacity(g2_points.len());
for (g1, g2) in g1_points.iter().zip(g2_points.iter()) {
let g1_is_inf = eq(g1, &G1_IDENTITY);
let g2_is_inf = eq(g2, &G2_IDENTITY);
if g1_is_inf && g2_is_inf {
continue;
}
if g2_is_inf {
let x1: [u64; 6] = g1[0..6].try_into().unwrap();
let y1: [u64; 6] = g1[6..12].try_into().unwrap();
if !lt(&x1, &P) || !lt(&y1, &P) {
return Err(PAIRING_CHECK_ERR_G1_NOT_CANONICAL);
}
if !is_on_curve_bls12_381(
g1,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G1_NOT_ON_CURVE);
}
if !is_on_subgroup_bls12_381(
g1,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G1_NOT_IN_SUBGROUP);
}
continue;
}
if g1_is_inf {
let x2_0: [u64; 6] = g2[0..6].try_into().unwrap();
let x2_1: [u64; 6] = g2[6..12].try_into().unwrap();
let y2_0: [u64; 6] = g2[12..18].try_into().unwrap();
let y2_1: [u64; 6] = g2[18..24].try_into().unwrap();
if !lt(&x2_0, &P) || !lt(&x2_1, &P) || !lt(&y2_0, &P) || !lt(&y2_1, &P) {
return Err(PAIRING_CHECK_ERR_G2_NOT_CANONICAL);
}
if !is_on_curve_twist_bls12_381(
g2,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G2_NOT_ON_CURVE);
}
if !is_on_subgroup_twist_bls12_381(
g2,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G2_NOT_IN_SUBGROUP);
}
continue;
}
let x1: [u64; 6] = g1[0..6].try_into().unwrap();
let y1: [u64; 6] = g1[6..12].try_into().unwrap();
if !lt(&x1, &P) || !lt(&y1, &P) {
return Err(PAIRING_CHECK_ERR_G1_NOT_CANONICAL);
}
if !is_on_curve_bls12_381(
g1,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G1_NOT_ON_CURVE);
}
if !is_on_subgroup_bls12_381(
g1,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G1_NOT_IN_SUBGROUP);
}
let x2_0: [u64; 6] = g2[0..6].try_into().unwrap();
let x2_1: [u64; 6] = g2[6..12].try_into().unwrap();
let y2_0: [u64; 6] = g2[12..18].try_into().unwrap();
let y2_1: [u64; 6] = g2[18..24].try_into().unwrap();
if !lt(&x2_0, &P) || !lt(&x2_1, &P) || !lt(&y2_0, &P) || !lt(&y2_1, &P) {
return Err(PAIRING_CHECK_ERR_G2_NOT_CANONICAL);
}
if !is_on_curve_twist_bls12_381(
g2,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G2_NOT_ON_CURVE);
}
if !is_on_subgroup_twist_bls12_381(
g2,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G2_NOT_IN_SUBGROUP);
}
valid_g1.push(*g1);
valid_g2.push(*g2);
}
if valid_g1.is_empty() {
return Ok(true);
}
Ok(is_one(&pairing_batch_bls12_381(
&valid_g1,
&valid_g2,
#[cfg(feature = "hints")]
hints,
)))
}
#[allow(dead_code)]
#[inline]
pub(crate) unsafe fn pairing_check_safe_bls12_381_c(
pairs: *const u8,
num_pairs: usize,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let mut g1_points: Vec<[u64; 12]> = Vec::with_capacity(num_pairs);
let mut g2_points: Vec<[u64; 24]> = Vec::with_capacity(num_pairs);
for i in 0..num_pairs {
let pair_ptr = pairs.add(i * 288);
let g1_bytes: &[u8; 96] = &*(pair_ptr as *const [u8; 96]);
let g2_bytes: &[u8; 192] = &*(pair_ptr.add(96) as *const [u8; 192]);
g1_points.push(g1_bytes_be_to_u64_le_bls12_381(g1_bytes));
g2_points.push(g2_bytes_be_to_u64_le_bls12_381(g2_bytes));
}
match pairing_check_safe_bls12_381(
&g1_points,
&g2_points,
#[cfg(feature = "hints")]
hints,
) {
Ok(true) => PAIRING_CHECK_SUCCESS,
Ok(false) => PAIRING_CHECK_FAILED,
Err(code) => code,
}
}