use crate::sm9::fields::fp::Fp;
use crate::sm9::fields::fp12::{
fp12_conjugate, fp12_frobenius_p, fp12_frobenius_p2, fp12_frobenius_p3, fp12_inv, fp12_mul,
fp12_mul_by_line, fp12_square, Fp12, LineEval, G2_FROB_X1_INV, G2_FROB_X2_INV, G2_FROB_Y1_INV,
};
use crate::sm9::fields::fp2::{fp2_frobenius, fp2_mul, fp2_mul_fp};
use crate::sm9::groups::g1::G1Affine;
use crate::sm9::groups::g2::{G2Affine, G2Jacobian};
const T_LOOP_PARAM: u128 = 0x2400000000215D93E;
fn g2_frobenius_p(q: &G2Affine) -> G2Affine {
G2Affine {
x: fp2_mul(&fp2_frobenius(&q.x), &G2_FROB_X1_INV),
y: fp2_mul(&fp2_frobenius(&q.y), &G2_FROB_Y1_INV),
}
}
fn g2_frobenius_p2_neg(q: &G2Affine) -> G2Affine {
G2Affine {
x: fp2_mul(&q.x, &G2_FROB_X2_INV),
y: q.y,
}
}
fn eval_line_at_p(line: &LineEval, px: &Fp, py: &Fp) -> LineEval {
LineEval {
a: fp2_mul_fp(&line.a, py), b: line.b, c: fp2_mul_fp(&line.c, px), }
}
pub fn miller_loop(q: &G2Affine, p: &G1Affine) -> Fp12 {
let mut t = G2Jacobian::from_affine(q);
let mut f = Fp12::ONE;
let px = &p.x;
let py = &p.y;
const BITS: u32 = 65;
for i in (0..BITS).rev() {
f = fp12_square(&f);
let (t2, line) = t.double_with_line();
t = t2;
f = fp12_mul_by_line(&f, &eval_line_at_p(&line, px, py));
if (T_LOOP_PARAM >> i) & 1 == 1 {
let (t_new, line2) = t.add_with_line(q);
t = t_new;
f = fp12_mul_by_line(&f, &eval_line_at_p(&line2, px, py));
}
}
let q1 = g2_frobenius_p(q);
let q2 = g2_frobenius_p2_neg(q);
let (t_new, line_q1) = t.add_with_line(&q1);
let t = t_new;
f = fp12_mul_by_line(&f, &eval_line_at_p(&line_q1, px, py));
let (_t_final, line_q2) = t.add_with_line(&q2);
f = fp12_mul_by_line(&f, &eval_line_at_p(&line_q2, px, py));
f
}
fn final_exp_easy(f: &Fp12) -> Fp12 {
let f_conj = fp12_conjugate(f);
let f_inv = match fp12_inv(f) {
Some(v) => v,
None => return Fp12::ONE,
};
let f1 = fp12_mul(&f_conj, &f_inv);
fp12_mul(&fp12_frobenius_p2(&f1), &f1)
}
fn fp12_cyclotomic_pow(f: &Fp12, mut n: u128) -> Fp12 {
let mut result = Fp12::ONE;
let mut base = *f;
while n > 0 {
if n & 1 == 1 {
result = fp12_mul(&result, &base);
}
base = fp12_square(&base);
n >>= 1;
}
result
}
const SM9_A3: u128 = 0x2400000000215d941; const SM9_A2: u128 = 0xd8000000019062ed0000b98b0cb27659; const SM9_NINE: u128 = 9;
fn final_exp_hard(f: &Fp12) -> Fp12 {
let a = fp12_cyclotomic_pow(f, SM9_A3); let b = fp12_inv(&a).unwrap_or(Fp12::ONE); let c = fp12_frobenius_p(&b); let d = fp12_mul(&c, &b); let e = fp12_mul(&d, &b); let f_p1 = fp12_frobenius_p(f); let g = fp12_mul(f, &f_p1); let h = fp12_cyclotomic_pow(&g, SM9_NINE); let i = fp12_mul(&e, &h); let j = fp12_square(f); let k = fp12_square(&j); let l = fp12_mul(&k, &i); let m = fp12_square(&f_p1); let n = fp12_mul(&d, &m); let o = fp12_frobenius_p2(f); let p_var = fp12_mul(&o, &n); let q = fp12_cyclotomic_pow(&p_var, SM9_A2); let r = fp12_mul(&q, &l);
let s = fp12_frobenius_p3(f); fp12_mul(&s, &r)
}
pub fn final_exp(f: &Fp12) -> Fp12 {
let f_easy = final_exp_easy(f);
final_exp_hard(&f_easy)
}
pub fn pairing(p: &G1Affine, q: &G2Affine) -> Fp12 {
let f = miller_loop(q, p);
final_exp(&f)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sm9::groups::g1::G1Affine;
use crate::sm9::groups::g2::G2Affine;
#[test]
fn test_pairing_no_panic() {
let p = G1Affine::generator();
let q = G2Affine::generator();
let _gt = pairing(&p, &q);
}
}