openvm_pairing_guest/halo2curves_shims/bn254/
final_exp.rs
1use halo2curves_axiom::{
2 bn256::{Fq, Fq12, Fq2},
3 ff::Field,
4};
5use openvm_ecc_guest::{algebra::field::FieldExtension, AffinePoint};
6
7use super::{Bn254, EXP1, EXP2, M_INV, R_INV, U27_COEFF_0, U27_COEFF_1};
8use crate::pairing::{FinalExp, MultiMillerLoop};
9
10#[allow(non_snake_case)]
11impl FinalExp for Bn254 {
12 type Fp = Fq;
13 type Fp2 = Fq2;
14 type Fp12 = Fq12;
15
16 fn assert_final_exp_is_one(
17 f: &Self::Fp12,
18 P: &[AffinePoint<Self::Fp>],
19 Q: &[AffinePoint<Self::Fp2>],
20 ) {
21 let (c, u) = Self::final_exp_hint(f);
22 let c_inv = c.invert().unwrap();
23
24 let c_q3_inv = FieldExtension::frobenius_map(&c_inv, 3);
32 let c_q2 = FieldExtension::frobenius_map(&c, 2);
33 let c_q_inv = FieldExtension::frobenius_map(&c_inv, 1);
34 let c_mul = c_q3_inv * c_q2 * c_q_inv;
35
36 let fc = Self::multi_miller_loop_embedded_exp(P, Q, Some(c_inv));
38
39 assert_eq!(fc * c_mul * u, Fq12::ONE);
40 }
41
42 fn final_exp_hint(f: &Self::Fp12) -> (Self::Fp12, Self::Fp12) {
47 let mut c;
49 let u;
51
52 let u0 = U27_COEFF_0.to_u64_digits();
54 let u1 = U27_COEFF_1.to_u64_digits();
55 let u_coeffs = Fq2::from_coeffs([
56 Fq::from_raw([u0[0], u0[1], u0[2], u0[3]]),
57 Fq::from_raw([u1[0], u1[1], u1[2], u1[3]]),
58 ]);
59 let unity_root_27 = Fq12::from_coeffs([
60 Fq2::ZERO,
61 Fq2::ZERO,
62 u_coeffs,
63 Fq2::ZERO,
64 Fq2::ZERO,
65 Fq2::ZERO,
66 ]);
67 debug_assert_eq!(unity_root_27.pow([27]), Fq12::one());
68
69 if f.pow(EXP1.to_u64_digits()) == Fq12::ONE {
70 c = *f;
71 u = Fq12::ONE;
72 } else {
73 let f_mul_unity_root_27 = f * unity_root_27;
74 if f_mul_unity_root_27.pow(EXP1.to_u64_digits()) == Fq12::ONE {
75 c = f_mul_unity_root_27;
76 u = unity_root_27;
77 } else {
78 c = f_mul_unity_root_27 * unity_root_27;
79 u = unity_root_27.square();
80 }
81 }
82
83 c = c.pow(R_INV.to_u64_digits());
86
87 c = c.pow(M_INV.to_u64_digits());
92
93 let mut x = c.pow(EXP2.to_u64_digits());
99
100 let c_inv = c.invert().unwrap();
102 let mut x3 = x.square() * x * c_inv;
103 let mut t = 0;
104 let mut tmp = x3.square();
105
106 fn tonelli_shanks_loop(x3: &mut Fq12, tmp: &mut Fq12, t: &mut i32) {
108 while *x3 != Fq12::ONE {
109 *tmp = (*x3).square();
110 *x3 *= *tmp;
111 *t += 1;
112 }
113 }
114
115 tonelli_shanks_loop(&mut x3, &mut tmp, &mut t);
116
117 while t != 0 {
118 tmp = unity_root_27.pow(EXP2.to_u64_digits());
119 x *= tmp;
120
121 x3 = x.square() * x * c_inv;
122 t = 0;
123 tonelli_shanks_loop(&mut x3, &mut tmp, &mut t);
124 }
125
126 debug_assert_eq!(c, x * x * x);
127 c = x;
129
130 (c, u)
131 }
132}