1#![no_std]
17#![doc = include_str!("../README.md")]
18
19use bls_12_381::params::{BLS_X, BLS_X_IS_NEGATIVE};
20use bls_12_381::{Fq12, Fr, G1Affine, G1Projective, G2Affine, G2PairingAffine, G2Projective, Gt};
21use jub_jub::EDWARDS_D;
22use zkstd::common::Vec;
23use zkstd::common::*;
24
25#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Encode, Decode, Copy)]
29pub struct TatePairing;
30
31impl Pairing for TatePairing {
32 type G1Affine = G1Affine;
33 type G2Affine = G2Affine;
34 type G1Projective = G1Projective;
35 type G2Projective = G2Projective;
36 type G2PairngRepr = G2PairingAffine;
37 type PairingRange = Fq12;
38 type Gt = Gt;
39 type ScalarField = Fr;
40 const PARAM_D: Fr = EDWARDS_D;
41 const X: u64 = BLS_X;
42 const X_IS_NEGATIVE: bool = BLS_X_IS_NEGATIVE;
43
44 fn pairing(g1: Self::G1Affine, g2: Self::G2Affine) -> Self::Gt {
45 Self::miller_loop(g1, g2).final_exp()
46 }
47
48 fn miller_loop(g1: Self::G1Affine, g2: Self::G2Affine) -> Self::PairingRange {
49 let mut acc = Self::PairingRange::one();
50 let mut g2_projective = Self::G2Projective::from(g2);
51 let mut found_one = false;
52
53 for i in (0..64).rev().map(|b| (((BLS_X >> 1) >> b) & 1) == 1) {
54 if !found_one {
55 found_one = i;
56 continue;
57 }
58
59 acc = acc.untwist(g2_projective.double_eval(), g1);
60
61 if i {
62 acc = acc.untwist(g2_projective.add_eval(g2), g1);
63 }
64
65 acc.square_assign();
66 }
67
68 acc = acc.untwist(g2_projective.double_eval(), g1);
69
70 if Self::X_IS_NEGATIVE {
71 acc.conjugate()
72 } else {
73 acc
74 }
75 }
76
77 fn multi_miller_loop(pairs: &[(Self::G1Affine, Self::G2PairngRepr)]) -> Self::PairingRange {
78 let pairs = pairs
79 .iter()
80 .filter(|(a, b)| !a.is_identity() && !b.is_identity())
81 .collect::<Vec<_>>();
82 let mut acc = Self::PairingRange::one();
83 let mut counter = 0;
84 let mut found_one = false;
85
86 for i in (0..64).rev().map(|b| (((BLS_X >> 1) >> b) & 1) == 1) {
87 if !found_one {
88 found_one = i;
89 continue;
90 }
91
92 for (g1, g2) in pairs.iter() {
93 acc = acc.untwist(g2.coeffs[counter], *g1);
94 }
95 counter += 1;
96
97 if i {
98 for (g1, g2) in pairs.iter() {
99 acc = acc.untwist(g2.coeffs[counter], *g1);
100 }
101 counter += 1;
102 }
103
104 acc.square_assign();
105 }
106
107 for (g1, g2) in pairs {
108 acc = acc.untwist(g2.coeffs[counter], *g1);
109 }
110
111 if Self::X_IS_NEGATIVE {
112 acc.conjugate()
113 } else {
114 acc
115 }
116 }
117}