1#![allow(non_snake_case)]
2use super::{Fp12Chip, Fp2Chip, FpChip, FpPoint, Fq, FqPoint};
3use crate::fields::vector::FieldVector;
4use crate::halo2_proofs::halo2curves::bn256::{
5 G1Affine, G2Affine, FROBENIUS_COEFF_FQ12_C1, SIX_U_PLUS_2_NAF,
6};
7use crate::{
8 ecc::{EcPoint, EccChip},
9 fields::fp12::mul_no_carry_w6,
10 fields::FieldChip,
11};
12use halo2_base::utils::BigPrimeField;
13use halo2_base::Context;
14
15const XI_0: i64 = 9;
16
17pub fn sparse_line_function_unequal<F: BigPrimeField>(
26 fp2_chip: &Fp2Chip<F>,
27 ctx: &mut Context<F>,
28 Q: (&EcPoint<F, FqPoint<F>>, &EcPoint<F, FqPoint<F>>),
29 P: &EcPoint<F, FpPoint<F>>,
30) -> Vec<Option<FqPoint<F>>> {
31 let (x_1, y_1) = (&Q.0.x, &Q.0.y);
32 let (x_2, y_2) = (&Q.1.x, &Q.1.y);
33 let (X, Y) = (&P.x, &P.y);
34 assert_eq!(x_1.0.len(), 2);
35 assert_eq!(y_1.0.len(), 2);
36 assert_eq!(x_2.0.len(), 2);
37 assert_eq!(y_2.0.len(), 2);
38
39 let y1_minus_y2 = fp2_chip.sub_no_carry(ctx, y_1, y_2);
40 let x2_minus_x1 = fp2_chip.sub_no_carry(ctx, x_2, x_1);
41 let x1y2 = fp2_chip.mul_no_carry(ctx, x_1, y_2);
42 let x2y1 = fp2_chip.mul_no_carry(ctx, x_2, y_1);
43
44 let out3 = fp2_chip.0.fp_mul_no_carry(ctx, y1_minus_y2, X);
45 let out2 = fp2_chip.0.fp_mul_no_carry(ctx, x2_minus_x1, Y);
46 let out5 = fp2_chip.sub_no_carry(ctx, &x1y2, &x2y1);
47
48 [None, None, Some(out2), Some(out3), None, Some(out5)]
51 .into_iter()
52 .map(|option_nc| option_nc.map(|nocarry| fp2_chip.carry_mod(ctx, nocarry)))
53 .collect()
54}
55
56pub fn sparse_line_function_equal<F: BigPrimeField>(
65 fp2_chip: &Fp2Chip<F>,
66 ctx: &mut Context<F>,
67 Q: &EcPoint<F, FqPoint<F>>,
68 P: &EcPoint<F, FpPoint<F>>,
69) -> Vec<Option<FqPoint<F>>> {
70 let (x, y) = (&Q.x, &Q.y);
71 assert_eq!(x.0.len(), 2);
72 assert_eq!(y.0.len(), 2);
73
74 let x_sq = fp2_chip.mul(ctx, x, x);
75
76 let x_cube = fp2_chip.mul_no_carry(ctx, &x_sq, x);
77 let three_x_cu = fp2_chip.scalar_mul_no_carry(ctx, &x_cube, 3);
78 let y_sq = fp2_chip.mul_no_carry(ctx, y, y);
79 let two_y_sq = fp2_chip.scalar_mul_no_carry(ctx, &y_sq, 2);
80 let out0_left = fp2_chip.sub_no_carry(ctx, &three_x_cu, &two_y_sq);
81 let out0 = mul_no_carry_w6::<_, _, XI_0>(fp2_chip.fp_chip(), ctx, out0_left);
82
83 let x_sq_Px = fp2_chip.0.fp_mul_no_carry(ctx, x_sq, &P.x);
84 let out4 = fp2_chip.scalar_mul_no_carry(ctx, x_sq_Px, -3);
85
86 let y_Py = fp2_chip.0.fp_mul_no_carry(ctx, y.clone(), &P.y);
87 let out3 = fp2_chip.scalar_mul_no_carry(ctx, &y_Py, 2);
88
89 [Some(out0), None, None, Some(out3), Some(out4), None]
92 .into_iter()
93 .map(|option_nc| option_nc.map(|nocarry| fp2_chip.carry_mod(ctx, nocarry)))
94 .collect()
95}
96
97pub fn sparse_fp12_multiply<F: BigPrimeField>(
100 fp2_chip: &Fp2Chip<F>,
101 ctx: &mut Context<F>,
102 a: &FqPoint<F>,
103 b_fp2_coeffs: &[Option<FqPoint<F>>],
104) -> FqPoint<F> {
105 assert_eq!(a.0.len(), 12);
106 assert_eq!(b_fp2_coeffs.len(), 6);
107 let mut a_fp2_coeffs = Vec::with_capacity(6);
108 for i in 0..6 {
109 a_fp2_coeffs.push(FieldVector(vec![a[i].clone(), a[i + 6].clone()]));
110 }
111 let mut prod_2d = vec![None; 11];
113 for i in 0..6 {
114 for j in 0..6 {
115 prod_2d[i + j] =
116 match (prod_2d[i + j].clone(), &a_fp2_coeffs[i], b_fp2_coeffs[j].as_ref()) {
117 (a, _, None) => a,
118 (None, a, Some(b)) => {
119 let ab = fp2_chip.mul_no_carry(ctx, a, b);
120 Some(ab)
121 }
122 (Some(a), b, Some(c)) => {
123 let bc = fp2_chip.mul_no_carry(ctx, b, c);
124 let out = fp2_chip.add_no_carry(ctx, &a, &bc);
125 Some(out)
126 }
127 };
128 }
129 }
130
131 let mut out_fp2 = Vec::with_capacity(6);
132 for i in 0..6 {
133 let prod_nocarry = if i != 5 {
135 let eval_w6 = prod_2d[i + 6]
136 .as_ref()
137 .map(|a| mul_no_carry_w6::<_, _, XI_0>(fp2_chip.fp_chip(), ctx, a.clone()));
138 match (prod_2d[i].as_ref(), eval_w6) {
139 (None, b) => b.unwrap(), (Some(a), None) => a.clone(),
141 (Some(a), Some(b)) => fp2_chip.add_no_carry(ctx, a, &b),
142 }
143 } else {
144 prod_2d[i].clone().unwrap()
145 };
146 let prod = fp2_chip.carry_mod(ctx, prod_nocarry);
147 out_fp2.push(prod);
148 }
149
150 let mut out_coeffs = Vec::with_capacity(12);
151 for fp2_coeff in &out_fp2 {
152 out_coeffs.push(fp2_coeff[0].clone());
153 }
154 for fp2_coeff in &out_fp2 {
155 out_coeffs.push(fp2_coeff[1].clone());
156 }
157 FieldVector(out_coeffs)
158}
159
160pub fn fp12_multiply_with_line_unequal<F: BigPrimeField>(
167 fp2_chip: &Fp2Chip<F>,
168 ctx: &mut Context<F>,
169 g: &FqPoint<F>,
170 Q: (&EcPoint<F, FqPoint<F>>, &EcPoint<F, FqPoint<F>>),
171 P: &EcPoint<F, FpPoint<F>>,
172) -> FqPoint<F> {
173 let line = sparse_line_function_unequal::<F>(fp2_chip, ctx, Q, P);
174 sparse_fp12_multiply::<F>(fp2_chip, ctx, g, &line)
175}
176
177pub fn fp12_multiply_with_line_equal<F: BigPrimeField>(
184 fp2_chip: &Fp2Chip<F>,
185 ctx: &mut Context<F>,
186 g: &FqPoint<F>,
187 Q: &EcPoint<F, FqPoint<F>>,
188 P: &EcPoint<F, FpPoint<F>>,
189) -> FqPoint<F> {
190 let line = sparse_line_function_equal::<F>(fp2_chip, ctx, Q, P);
191 sparse_fp12_multiply::<F>(fp2_chip, ctx, g, &line)
192}
193
194pub fn miller_loop_BN<F: BigPrimeField>(
213 ecc_chip: &EccChip<F, Fp2Chip<F>>,
214 ctx: &mut Context<F>,
215 Q: &EcPoint<F, FqPoint<F>>,
216 P: &EcPoint<F, FpPoint<F>>,
217 pseudo_binary_encoding: &[i8],
218) -> FqPoint<F> {
219 let mut i = pseudo_binary_encoding.len() - 1;
220 while pseudo_binary_encoding[i] == 0 {
221 i -= 1;
222 }
223 let last_index = i;
224
225 let neg_Q = ecc_chip.negate(ctx, Q.clone());
226 assert!(pseudo_binary_encoding[i] == 1 || pseudo_binary_encoding[i] == -1);
227 let mut R = if pseudo_binary_encoding[i] == 1 { Q.clone() } else { neg_Q.clone() };
228 i -= 1;
229
230 let sparse_f = sparse_line_function_equal::<F>(ecc_chip.field_chip(), ctx, &R, P);
232 assert_eq!(sparse_f.len(), 6);
233
234 let fp_chip = ecc_chip.field_chip.fp_chip();
235 let zero_fp = fp_chip.load_constant(ctx, Fq::zero());
236 let mut f_coeffs = Vec::with_capacity(12);
237 for coeff in &sparse_f {
238 if let Some(fp2_point) = coeff {
239 f_coeffs.push(fp2_point[0].clone());
240 } else {
241 f_coeffs.push(zero_fp.clone());
242 }
243 }
244 for coeff in &sparse_f {
245 if let Some(fp2_point) = coeff {
246 f_coeffs.push(fp2_point[1].clone());
247 } else {
248 f_coeffs.push(zero_fp.clone());
249 }
250 }
251
252 let mut f = FieldVector(f_coeffs);
253
254 let fp12_chip = Fp12Chip::<F>::new(fp_chip);
255 loop {
256 if i != last_index - 1 {
257 let f_sq = fp12_chip.mul(ctx, &f, &f);
258 f = fp12_multiply_with_line_equal::<F>(ecc_chip.field_chip(), ctx, &f_sq, &R, P);
259 }
260 R = ecc_chip.double(ctx, &R);
261
262 assert!(pseudo_binary_encoding[i] <= 1 && pseudo_binary_encoding[i] >= -1);
263 if pseudo_binary_encoding[i] != 0 {
264 let sign_Q = if pseudo_binary_encoding[i] == 1 { Q } else { &neg_Q };
265 f = fp12_multiply_with_line_unequal::<F>(
266 ecc_chip.field_chip(),
267 ctx,
268 &f,
269 (&R, sign_Q),
270 P,
271 );
272 R = ecc_chip.add_unequal(ctx, &R, sign_Q, false);
273 }
274 if i == 0 {
275 break;
276 }
277 i -= 1;
278 }
279
280 let c2 = FROBENIUS_COEFF_FQ12_C1[1] * FROBENIUS_COEFF_FQ12_C1[1];
283 let c3 = c2 * FROBENIUS_COEFF_FQ12_C1[1];
284 let c2 = ecc_chip.field_chip.load_constant(ctx, c2);
285 let c3 = ecc_chip.field_chip.load_constant(ctx, c3);
286
287 let Q_1 = twisted_frobenius::<F>(ecc_chip, ctx, Q, &c2, &c3);
288 let neg_Q_2 = neg_twisted_frobenius::<F>(ecc_chip, ctx, &Q_1, &c2, &c3);
289 f = fp12_multiply_with_line_unequal::<F>(ecc_chip.field_chip(), ctx, &f, (&R, &Q_1), P);
290 R = ecc_chip.add_unequal(ctx, &R, &Q_1, false);
291 f = fp12_multiply_with_line_unequal::<F>(ecc_chip.field_chip(), ctx, &f, (&R, &neg_Q_2), P);
292
293 f
294}
295
296pub fn multi_miller_loop_BN<F: BigPrimeField>(
299 ecc_chip: &EccChip<F, Fp2Chip<F>>,
300 ctx: &mut Context<F>,
301 pairs: Vec<(&EcPoint<F, FpPoint<F>>, &EcPoint<F, FqPoint<F>>)>,
302 pseudo_binary_encoding: &[i8],
303) -> FqPoint<F> {
304 let mut i = pseudo_binary_encoding.len() - 1;
305 while pseudo_binary_encoding[i] == 0 {
306 i -= 1;
307 }
308 let last_index = i;
309 assert_eq!(pseudo_binary_encoding[last_index], 1);
310
311 let neg_b = pairs.iter().map(|pair| ecc_chip.negate(ctx, pair.1)).collect::<Vec<_>>();
312
313 let fp_chip = ecc_chip.field_chip.fp_chip();
314 let mut f = {
316 let sparse_f =
317 sparse_line_function_equal::<F>(ecc_chip.field_chip(), ctx, pairs[0].1, pairs[0].0);
318 assert_eq!(sparse_f.len(), 6);
319
320 let zero_fp = fp_chip.load_constant(ctx, Fq::zero());
321 let mut f_coeffs = Vec::with_capacity(12);
322 for coeff in &sparse_f {
323 if let Some(fp2_point) = coeff {
324 f_coeffs.push(fp2_point[0].clone());
325 } else {
326 f_coeffs.push(zero_fp.clone());
327 }
328 }
329 for coeff in &sparse_f {
330 if let Some(fp2_point) = coeff {
331 f_coeffs.push(fp2_point[1].clone());
332 } else {
333 f_coeffs.push(zero_fp.clone());
334 }
335 }
336 FieldVector(f_coeffs)
337 };
338 for &(a, b) in pairs.iter().skip(1) {
339 f = fp12_multiply_with_line_equal::<F>(ecc_chip.field_chip(), ctx, &f, b, a);
340 }
341
342 i -= 1;
343 let mut r = pairs.iter().map(|pair| pair.1.clone()).collect::<Vec<_>>();
344 let fp12_chip = Fp12Chip::<F>::new(fp_chip);
345 loop {
346 if i != last_index - 1 {
347 f = fp12_chip.mul(ctx, &f, &f);
348 for (r, &(a, _)) in r.iter().zip(pairs.iter()) {
349 f = fp12_multiply_with_line_equal::<F>(ecc_chip.field_chip(), ctx, &f, r, a);
350 }
351 }
352 for r in r.iter_mut() {
353 *r = ecc_chip.double(ctx, r.clone());
354 }
355
356 assert!(pseudo_binary_encoding[i] <= 1 && pseudo_binary_encoding[i] >= -1);
357 if pseudo_binary_encoding[i] != 0 {
358 for ((r, neg_b), &(a, b)) in r.iter_mut().zip(neg_b.iter()).zip(pairs.iter()) {
359 let sign_b = if pseudo_binary_encoding[i] == 1 { b } else { neg_b };
360 f = fp12_multiply_with_line_unequal::<F>(
361 ecc_chip.field_chip(),
362 ctx,
363 &f,
364 (r, sign_b),
365 a,
366 );
367 *r = ecc_chip.add_unequal(ctx, r.clone(), sign_b, false);
368 }
369 }
370 if i == 0 {
371 break;
372 }
373 i -= 1;
374 }
375
376 let c2 = FROBENIUS_COEFF_FQ12_C1[1] * FROBENIUS_COEFF_FQ12_C1[1];
379 let c3 = c2 * FROBENIUS_COEFF_FQ12_C1[1];
380 let c2 = ecc_chip.field_chip.load_constant(ctx, c2);
381 let c3 = ecc_chip.field_chip.load_constant(ctx, c3);
382
383 for (r, (a, b)) in r.iter_mut().zip(pairs) {
385 let b_1 = twisted_frobenius(ecc_chip, ctx, b, &c2, &c3);
386 let neg_b_2 = neg_twisted_frobenius(ecc_chip, ctx, &b_1, &c2, &c3);
387 f = fp12_multiply_with_line_unequal(ecc_chip.field_chip(), ctx, &f, (r, &b_1), a);
388 *r = ecc_chip.add_unequal(ctx, r.clone(), b_1, false);
389 f = fp12_multiply_with_line_unequal::<F>(ecc_chip.field_chip(), ctx, &f, (r, &neg_b_2), a);
390 }
391 f
392}
393
394pub fn twisted_frobenius<F: BigPrimeField>(
402 ecc_chip: &EccChip<F, Fp2Chip<F>>,
403 ctx: &mut Context<F>,
404 Q: impl Into<EcPoint<F, FqPoint<F>>>,
405 c2: impl Into<FqPoint<F>>,
406 c3: impl Into<FqPoint<F>>,
407) -> EcPoint<F, FqPoint<F>> {
408 let Q = Q.into();
409 let c2 = c2.into();
410 let c3 = c3.into();
411 assert_eq!(c2.0.len(), 2);
412 assert_eq!(c3.0.len(), 2);
413
414 let frob_x = ecc_chip.field_chip.conjugate(ctx, Q.x);
415 let frob_y = ecc_chip.field_chip.conjugate(ctx, Q.y);
416 let out_x = ecc_chip.field_chip.mul(ctx, c2, frob_x);
417 let out_y = ecc_chip.field_chip.mul(ctx, c3, frob_y);
418 EcPoint::new(out_x, out_y)
419}
420
421pub fn neg_twisted_frobenius<F: BigPrimeField>(
428 ecc_chip: &EccChip<F, Fp2Chip<F>>,
429 ctx: &mut Context<F>,
430 Q: impl Into<EcPoint<F, FqPoint<F>>>,
431 c2: impl Into<FqPoint<F>>,
432 c3: impl Into<FqPoint<F>>,
433) -> EcPoint<F, FqPoint<F>> {
434 let Q = Q.into();
435 let c2 = c2.into();
436 let c3 = c3.into();
437 assert_eq!(c2.0.len(), 2);
438 assert_eq!(c3.0.len(), 2);
439
440 let frob_x = ecc_chip.field_chip.conjugate(ctx, Q.x);
441 let neg_frob_y = ecc_chip.field_chip.neg_conjugate(ctx, Q.y);
442 let out_x = ecc_chip.field_chip.mul(ctx, c2, frob_x);
443 let out_y = ecc_chip.field_chip.mul(ctx, c3, neg_frob_y);
444 EcPoint::new(out_x, out_y)
445}
446
447pub struct PairingChip<'chip, F: BigPrimeField> {
449 pub fp_chip: &'chip FpChip<'chip, F>,
450}
451
452impl<'chip, F: BigPrimeField> PairingChip<'chip, F> {
453 pub fn new(fp_chip: &'chip FpChip<F>) -> Self {
454 Self { fp_chip }
455 }
456
457 pub fn load_private_g1_unchecked(
458 &self,
459 ctx: &mut Context<F>,
460 point: G1Affine,
461 ) -> EcPoint<F, FpPoint<F>> {
462 let g1_chip = EccChip::new(self.fp_chip);
463 g1_chip.load_private_unchecked(ctx, (point.x, point.y))
464 }
465
466 pub fn load_private_g2_unchecked(
467 &self,
468 ctx: &mut Context<F>,
469 point: G2Affine,
470 ) -> EcPoint<F, FqPoint<F>> {
471 let fp2_chip = Fp2Chip::new(self.fp_chip);
472 let g2_chip = EccChip::new(&fp2_chip);
473 g2_chip.load_private_unchecked(ctx, (point.x, point.y))
474 }
475
476 pub fn miller_loop(
477 &self,
478 ctx: &mut Context<F>,
479 Q: &EcPoint<F, FqPoint<F>>,
480 P: &EcPoint<F, FpPoint<F>>,
481 ) -> FqPoint<F> {
482 let fp2_chip = Fp2Chip::<F>::new(self.fp_chip);
483 let g2_chip = EccChip::new(&fp2_chip);
484 miller_loop_BN::<F>(
485 &g2_chip,
486 ctx,
487 Q,
488 P,
489 &SIX_U_PLUS_2_NAF, )
491 }
492
493 pub fn multi_miller_loop(
494 &self,
495 ctx: &mut Context<F>,
496 pairs: Vec<(&EcPoint<F, FpPoint<F>>, &EcPoint<F, FqPoint<F>>)>,
497 ) -> FqPoint<F> {
498 let fp2_chip = Fp2Chip::<F>::new(self.fp_chip);
499 let g2_chip = EccChip::new(&fp2_chip);
500 multi_miller_loop_BN::<F>(
501 &g2_chip,
502 ctx,
503 pairs,
504 &SIX_U_PLUS_2_NAF, )
506 }
507
508 pub fn final_exp(&self, ctx: &mut Context<F>, f: FqPoint<F>) -> FqPoint<F> {
509 let fp12_chip = Fp12Chip::<F>::new(self.fp_chip);
510 fp12_chip.final_exp(ctx, f)
511 }
512
513 pub fn pairing(
515 &self,
516 ctx: &mut Context<F>,
517 Q: &EcPoint<F, FqPoint<F>>,
518 P: &EcPoint<F, FpPoint<F>>,
519 ) -> FqPoint<F> {
520 let f0 = self.miller_loop(ctx, Q, P);
521 let fp12_chip = Fp12Chip::<F>::new(self.fp_chip);
522 fp12_chip.final_exp(ctx, f0)
524 }
525}