snarkvm_curves/templates/bls12/
bls12.rs1use crate::{
17 AffineCurve,
18 templates::{
19 bls12::{
20 g1::{G1Affine, G1Prepared, G1Projective},
21 g2::{G2Affine, G2Prepared, G2Projective},
22 },
23 short_weierstrass_jacobian,
24 },
25 traits::{ModelParameters, PairingCurve, PairingEngine, ShortWeierstrassParameters},
26};
27use snarkvm_fields::{
28 Field,
29 Fp2,
30 Fp2Parameters,
31 Fp12,
32 Fp12Parameters,
33 One,
34 PrimeField,
35 SquareRootField,
36 Zero,
37 fp6_3over2::Fp6Parameters,
38};
39use snarkvm_utilities::bititerator::BitIteratorBE;
40
41use core::{fmt::Debug, hash::Hash, marker::PhantomData};
42use serde::{Deserialize, Serialize};
43
44pub enum TwistType {
45 M,
46 D,
47}
48
49pub trait Bls12Parameters: 'static + Copy + Clone + Debug + PartialEq + Eq + Hash + Send + Sync + Sized {
50 const X: &'static [u64];
51 const X_IS_NEGATIVE: bool;
52 const TWIST_TYPE: TwistType;
53 type Fp: PrimeField + SquareRootField + Into<<Self::Fp as PrimeField>::BigInteger>;
54 type Fp2Params: Fp2Parameters<Fp = Self::Fp>;
55 type Fp6Params: Fp6Parameters<Fp2Params = Self::Fp2Params>;
56 type Fp12Params: Fp12Parameters<Fp6Params = Self::Fp6Params>;
57 type G1Parameters: ShortWeierstrassParameters<BaseField = Self::Fp>;
58 type G2Parameters: ShortWeierstrassParameters<
59 BaseField = Fp2<Self::Fp2Params>,
60 ScalarField = <Self::G1Parameters as ModelParameters>::ScalarField,
61 >;
62
63 fn g1_is_in_correct_subgroup(p: &short_weierstrass_jacobian::Affine<Self::G1Parameters>) -> bool {
64 p.mul_bits(BitIteratorBE::new(<Self::G1Parameters as ModelParameters>::ScalarField::characteristic())).is_zero()
65 }
66
67 fn g2_is_in_correct_subgroup(p: &short_weierstrass_jacobian::Affine<Self::G1Parameters>) -> bool {
68 p.mul_bits(BitIteratorBE::new(<Self::G1Parameters as ModelParameters>::ScalarField::characteristic())).is_zero()
69 }
70}
71
72#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
73pub struct Bls12<P: Bls12Parameters>(PhantomData<P>);
74
75type CoeffTriplet<T> = (Fp2<T>, Fp2<T>, Fp2<T>);
76
77impl<P: Bls12Parameters> Bls12<P> {
78 fn ell(f: &mut Fp12<P::Fp12Params>, coeffs: &CoeffTriplet<P::Fp2Params>, p: &G1Affine<P>) {
80 let mut c0 = coeffs.0;
81 let mut c1 = coeffs.1;
82 let mut c2 = coeffs.2;
83
84 match P::TWIST_TYPE {
85 TwistType::M => {
86 c2.mul_by_fp(&p.y);
87 c1.mul_by_fp(&p.x);
88 f.mul_by_014(&c0, &c1, &c2);
89 }
90 TwistType::D => {
91 c0.mul_by_fp(&p.y);
92 c1.mul_by_fp(&p.x);
93 f.mul_by_034(&c0, &c1, &c2);
94 }
95 }
96 }
97
98 fn exp_by_x(mut f: Fp12<P::Fp12Params>) -> Fp12<P::Fp12Params> {
99 f = f.cyclotomic_exp(P::X);
100 if P::X_IS_NEGATIVE {
101 f.conjugate();
102 }
103 f
104 }
105}
106
107impl<P: Bls12Parameters> PairingEngine for Bls12<P>
108where
109 G1Affine<P>: PairingCurve<
110 BaseField = <P::G1Parameters as ModelParameters>::BaseField,
111 ScalarField = <P::G1Parameters as ModelParameters>::ScalarField,
112 Projective = G1Projective<P>,
113 PairWith = G2Affine<P>,
114 Prepared = G1Prepared<P>,
115 PairingResult = Fp12<P::Fp12Params>,
116 >,
117 G2Affine<P>: PairingCurve<
118 BaseField = <P::G2Parameters as ModelParameters>::BaseField,
119 ScalarField = <P::G1Parameters as ModelParameters>::ScalarField,
120 Projective = G2Projective<P>,
121 PairWith = G1Affine<P>,
122 Prepared = G2Prepared<P>,
123 PairingResult = Fp12<P::Fp12Params>,
124 >,
125{
126 type Fq = P::Fp;
127 type Fqe = Fp2<P::Fp2Params>;
128 type Fqk = Fp12<P::Fp12Params>;
129 type Fr = <P::G1Parameters as ModelParameters>::ScalarField;
130 type G1Affine = G1Affine<P>;
131 type G1Projective = G1Projective<P>;
132 type G2Affine = G2Affine<P>;
133 type G2Projective = G2Projective<P>;
134
135 fn miller_loop<'a, I>(i: I) -> Self::Fqk
136 where
137 I: Iterator<
138 Item = (&'a <Self::G1Affine as PairingCurve>::Prepared, &'a <Self::G2Affine as PairingCurve>::Prepared),
139 >,
140 {
141 let mut pairs = vec![];
142 for (p, q) in i {
143 if !p.is_zero() && !q.is_zero() {
144 pairs.push((p, q.ell_coeffs.iter()));
145 }
146 }
147
148 let mut f = Self::Fqk::one();
149
150 for i in BitIteratorBE::new(P::X).skip(1) {
151 f.square_in_place();
152
153 for &mut (p, ref mut coeffs) in &mut pairs {
154 Self::ell(&mut f, coeffs.next().unwrap(), &p.0);
155 }
156
157 if i {
158 for &mut (p, ref mut coeffs) in &mut pairs {
159 Self::ell(&mut f, coeffs.next().unwrap(), &p.0);
160 }
161 }
162 }
163
164 if P::X_IS_NEGATIVE {
165 f.conjugate();
166 }
167
168 f
169 }
170
171 fn final_exponentiation(f: &Self::Fqk) -> Option<Self::Fqk> {
172 let mut f1 = *f;
180 f1.conjugate();
181
182 match f.inverse() {
183 Some(mut f2) => {
184 let mut r = f1 * f2;
187
188 f2 = r;
190 r.frobenius_map(2);
192
193 r *= &f2;
196
197 let mut y0 = r.cyclotomic_square();
200 y0.conjugate();
201
202 let mut y5 = Self::exp_by_x(r);
203
204 let mut y1 = y5.cyclotomic_square();
205 let mut y3 = y0 * y5;
206 y0 = Self::exp_by_x(y3);
207 let y2 = Self::exp_by_x(y0);
208 let mut y4 = Self::exp_by_x(y2);
209 y4 *= &y1;
210 y1 = Self::exp_by_x(y4);
211 y3.conjugate();
212 y1 *= &y3;
213 y1 *= &r;
214 y3 = r;
215 y3.conjugate();
216 y0 *= &r;
217 y0.frobenius_map(3);
218 y4 *= &y3;
219 y4.frobenius_map(1);
220 y5 *= &y2;
221 y5.frobenius_map(2);
222 y5 *= &y0;
223 y5 *= &y4;
224 y5 *= &y1;
225 Some(y5)
226 }
227 None => None,
228 }
229 }
230}