#[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},
curve::{g1_bytes_be_to_u64_le_bn254, is_on_curve_bn254},
final_exp::final_exp_bn254,
miller_loop::{miller_loop_batch_bn254, miller_loop_bn254},
twist::{g2_bytes_be_to_u64_le_bn254, is_on_curve_twist_bn254, is_on_subgroup_twist_bn254},
};
#[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_G2_NOT_CANONICAL: u8 = 4;
const PAIRING_CHECK_ERR_G2_NOT_ON_CURVE: u8 = 5;
const PAIRING_CHECK_ERR_G2_NOT_IN_SUBGROUP: u8 = 6;
pub fn pairing_bn254(
p: &[u64; 8],
q: &[u64; 16],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
if *p == G1_IDENTITY || *q == G2_IDENTITY {
let mut one = [0; 48];
one[0] = 1;
return one;
}
let miller_loop = miller_loop_bn254(
p,
q,
#[cfg(feature = "hints")]
hints,
);
final_exp_bn254(
&miller_loop,
#[cfg(feature = "hints")]
hints,
)
}
pub fn pairing_batch_bn254(
g1_points: &[[u64; 8]],
g2_points: &[[u64; 16]],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let num_points = g1_points.len();
assert_eq!(num_points, g2_points.len(), "Number of G1 and G2 points must be equal");
let mut g1_points_ml = Vec::with_capacity(num_points);
let mut g2_points_ml = Vec::with_capacity(num_points);
for (p, q) in g1_points.iter().zip(g2_points.iter()) {
if *p == G1_IDENTITY || *q == G2_IDENTITY {
continue;
}
g1_points_ml.push(*p);
g2_points_ml.push(*q);
}
if g1_points_ml.is_empty() {
let mut one = [0; 48];
one[0] = 1;
return one;
}
let miller_loop = miller_loop_batch_bn254(
&g1_points_ml,
&g2_points_ml,
#[cfg(feature = "hints")]
hints,
);
final_exp_bn254(
&miller_loop,
#[cfg(feature = "hints")]
hints,
)
}
pub fn pairing_check_safe_bn254(
g1_points: &[[u64; 8]],
g2_points: &[[u64; 16]],
#[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");
for (g1, g2) in g1_points.iter().zip(g2_points.iter()) {
let x1: [u64; 4] = g1[0..4].try_into().unwrap();
let y1: [u64; 4] = g1[4..8].try_into().unwrap();
if !lt(&x1, &P) || !lt(&y1, &P) {
return Err(PAIRING_CHECK_ERR_G1_NOT_CANONICAL);
}
if !eq(g1, &G1_IDENTITY)
&& !is_on_curve_bn254(
g1,
#[cfg(feature = "hints")]
hints,
)
{
return Err(PAIRING_CHECK_ERR_G1_NOT_ON_CURVE);
}
let x2_r: [u64; 4] = g2[0..4].try_into().unwrap();
let x2_i: [u64; 4] = g2[4..8].try_into().unwrap();
let y2_r: [u64; 4] = g2[8..12].try_into().unwrap();
let y2_i: [u64; 4] = g2[12..16].try_into().unwrap();
if !lt(&x2_r, &P) || !lt(&x2_i, &P) || !lt(&y2_r, &P) || !lt(&y2_i, &P) {
return Err(PAIRING_CHECK_ERR_G2_NOT_CANONICAL);
}
if !eq(g2, &G2_IDENTITY) {
if !is_on_curve_twist_bn254(
g2,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G2_NOT_ON_CURVE);
}
if !is_on_subgroup_twist_bn254(
g2,
#[cfg(feature = "hints")]
hints,
) {
return Err(PAIRING_CHECK_ERR_G2_NOT_IN_SUBGROUP);
}
}
}
let pairing = pairing_batch_bn254(
g1_points,
g2_points,
#[cfg(feature = "hints")]
hints,
);
Ok(is_one(&pairing))
}
#[allow(dead_code)]
#[inline]
pub(crate) unsafe fn pairing_check_safe_bn254_c(
pairs: *const u8,
num_pairs: usize,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let mut g1_points: Vec<[u64; 8]> = Vec::with_capacity(num_pairs);
let mut g2_points: Vec<[u64; 16]> = Vec::with_capacity(num_pairs);
for i in 0..num_pairs {
let pair_ptr = pairs.add(i * 192);
let g1_bytes: &[u8; 64] = &*(pair_ptr as *const [u8; 64]);
let g2_bytes: &[u8; 128] = &*(pair_ptr.add(64) as *const [u8; 128]);
g1_points.push(g1_bytes_be_to_u64_le_bn254(g1_bytes));
g2_points.push(g2_bytes_be_to_u64_le_bn254(g2_bytes));
}
match pairing_check_safe_bn254(
&g1_points,
&g2_points,
#[cfg(feature = "hints")]
hints,
) {
Ok(true) => PAIRING_CHECK_SUCCESS,
Ok(false) => PAIRING_CHECK_FAILED,
Err(code) => code,
}
}