zksync_pairing/compact_bn256/
mod.rs

1mod ec;
2pub mod fq;
3pub mod fq12;
4pub mod fq2;
5pub mod fq6;
6pub mod fr;
7
8// #[cfg(test)]
9// mod tests;
10
11pub use self::ec::{G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2Affine, G2Compressed, G2Prepared, G2Uncompressed, G1, G2};
12pub use self::fq::{Fq, FqRepr, FROBENIUS_COEFF_FQ6_C1, XI_TO_Q_MINUS_1_OVER_2};
13pub use self::fq12::Fq12;
14pub use self::fq2::Fq2;
15pub use self::fq6::Fq6;
16pub use self::fr::{Fr, FrRepr};
17
18use super::{CurveAffine, Engine};
19
20use ff::{Field, ScalarEngine};
21
22#[derive(Clone, Copy, Debug)]
23pub struct Bn256;
24
25// U value that originates this particular curve
26pub const BN_U: u64 = 4965661367192848881;
27
28// // 6U+2 for in NAF form
29pub const SIX_U_PLUS_2_NAF: [i8; 65] = [
30    0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1,
31    0, 1, 1,
32];
33
34impl ScalarEngine for Bn256 {
35    type Fr = Fr;
36}
37
38impl Engine for Bn256 {
39    type G1 = G1;
40    type G1Affine = G1Affine;
41    type G2 = G2;
42    type G2Affine = G2Affine;
43    type Fq = Fq;
44    type Fqe = Fq2;
45    type Fqk = Fq12;
46
47    fn miller_loop<'a, I>(i: I) -> Self::Fqk
48    where
49        I: IntoIterator<Item = &'a (&'a <Self::G1Affine as CurveAffine>::Prepared, &'a <Self::G2Affine as CurveAffine>::Prepared)>,
50    {
51        let mut pairs = vec![];
52        for &(p, q) in i {
53            if !p.is_zero() && !q.is_zero() {
54                pairs.push((p, q.coeffs.iter()));
55            }
56        }
57
58        // Final steps of the line function on prepared coefficients
59        fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) {
60            let mut c0 = coeffs.0;
61            let mut c1 = coeffs.1;
62
63            c0.c0.mul_assign(&p.y);
64            c0.c1.mul_assign(&p.y);
65
66            c1.c0.mul_assign(&p.x);
67            c1.c1.mul_assign(&p.x);
68
69            // Sparse multiplication in Fq12
70            f.mul_by_034(&c0, &c1, &coeffs.2);
71        }
72
73        let mut f = Fq12::one();
74
75        for i in (1..SIX_U_PLUS_2_NAF.len()).rev() {
76            if i != SIX_U_PLUS_2_NAF.len() - 1 {
77                f.square();
78            }
79            for &mut (p, ref mut coeffs) in &mut pairs {
80                ell(&mut f, coeffs.next().unwrap(), &p.0);
81            }
82            let x = SIX_U_PLUS_2_NAF[i - 1];
83            match x {
84                1 => {
85                    for &mut (p, ref mut coeffs) in &mut pairs {
86                        ell(&mut f, coeffs.next().unwrap(), &p.0);
87                    }
88                }
89                -1 => {
90                    for &mut (p, ref mut coeffs) in &mut pairs {
91                        ell(&mut f, coeffs.next().unwrap(), &p.0);
92                    }
93                }
94                _ => continue,
95            }
96        }
97
98        // two additional steps: for q1 and minus q2
99
100        for &mut (p, ref mut coeffs) in &mut pairs {
101            ell(&mut f, coeffs.next().unwrap(), &p.0);
102        }
103
104        for &mut (p, ref mut coeffs) in &mut pairs {
105            ell(&mut f, coeffs.next().unwrap(), &p.0);
106        }
107
108        for &mut (_p, ref mut coeffs) in &mut pairs {
109            assert_eq!(coeffs.next(), None);
110        }
111
112        f
113    }
114
115    fn final_exponentiation(r: &Fq12) -> Option<Fq12> {
116        let mut f1 = *r;
117        f1.conjugate();
118
119        match r.inverse() {
120            Some(mut f2) => {
121                let mut r = f1;
122                r.mul_assign(&f2);
123                f2 = r;
124                r.frobenius_map(2);
125                r.mul_assign(&f2);
126
127                fn exp_by_x(f: &mut Fq12, x: u64) {
128                    *f = f.pow(&[x]);
129                }
130
131                let x = BN_U;
132
133                let mut fp = r;
134                fp.frobenius_map(1);
135
136                let mut fp2 = r;
137                fp2.frobenius_map(2);
138                let mut fp3 = fp2;
139                fp3.frobenius_map(1);
140
141                let mut fu = r;
142                exp_by_x(&mut fu, x);
143
144                let mut fu2 = fu;
145                exp_by_x(&mut fu2, x);
146
147                let mut fu3 = fu2;
148                exp_by_x(&mut fu3, x);
149
150                let mut y3 = fu;
151                y3.frobenius_map(1);
152
153                let mut fu2p = fu2;
154                fu2p.frobenius_map(1);
155
156                let mut fu3p = fu3;
157                fu3p.frobenius_map(1);
158
159                let mut y2 = fu2;
160                y2.frobenius_map(2);
161
162                let mut y0 = fp;
163                y0.mul_assign(&fp2);
164                y0.mul_assign(&fp3);
165
166                let mut y1 = r;
167                y1.conjugate();
168
169                let mut y5 = fu2;
170                y5.conjugate();
171
172                y3.conjugate();
173
174                let mut y4 = fu;
175                y4.mul_assign(&fu2p);
176                y4.conjugate();
177
178                let mut y6 = fu3;
179                y6.mul_assign(&fu3p);
180                y6.conjugate();
181
182                y6.square();
183                y6.mul_assign(&y4);
184                y6.mul_assign(&y5);
185
186                let mut t1 = y3;
187                t1.mul_assign(&y5);
188                t1.mul_assign(&y6);
189
190                y6.mul_assign(&y2);
191
192                t1.square();
193                t1.mul_assign(&y6);
194                t1.square();
195
196                let mut t0 = t1;
197                t0.mul_assign(&y1);
198
199                t1.mul_assign(&y0);
200
201                t0.square();
202                t0.mul_assign(&t1);
203
204                Some(t0)
205            }
206            None => None,
207        }
208    }
209}
210
211impl G2Prepared {
212    pub fn is_zero(&self) -> bool {
213        self.infinity
214    }
215
216    pub fn from_affine(q: G2Affine) -> Self {
217        if q.is_zero() {
218            return G2Prepared { coeffs: vec![], infinity: true };
219        }
220
221        fn doubling_step(r: &mut G2) -> (Fq2, Fq2, Fq2) {
222            // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf
223            let mut tmp0 = r.x;
224            tmp0.square();
225
226            let mut tmp1 = r.y;
227            tmp1.square();
228
229            let mut tmp2 = tmp1;
230            tmp2.square();
231
232            let mut tmp3 = tmp1;
233            tmp3.add_assign(&r.x);
234            tmp3.square();
235            tmp3.sub_assign(&tmp0);
236            tmp3.sub_assign(&tmp2);
237            tmp3.double();
238
239            let mut tmp4 = tmp0;
240            tmp4.double();
241            tmp4.add_assign(&tmp0);
242
243            let mut tmp6 = r.x;
244            tmp6.add_assign(&tmp4);
245
246            let mut tmp5 = tmp4;
247            tmp5.square();
248
249            let mut zsquared = r.z;
250            zsquared.square();
251
252            r.x = tmp5;
253            r.x.sub_assign(&tmp3);
254            r.x.sub_assign(&tmp3);
255
256            r.z.add_assign(&r.y);
257            r.z.square();
258            r.z.sub_assign(&tmp1);
259            r.z.sub_assign(&zsquared);
260
261            r.y = tmp3;
262            r.y.sub_assign(&r.x);
263            r.y.mul_assign(&tmp4);
264
265            tmp2.double();
266            tmp2.double();
267            tmp2.double();
268
269            r.y.sub_assign(&tmp2);
270
271            // up to here everything was by algorith, line 11
272            // use R instead of new T
273
274            // tmp3 is the first part of line 12
275            tmp3 = tmp4;
276            tmp3.mul_assign(&zsquared);
277            tmp3.double();
278            tmp3.negate();
279
280            // tmp6 is from line 14
281            tmp6.square();
282            tmp6.sub_assign(&tmp0);
283            tmp6.sub_assign(&tmp5);
284
285            tmp1.double();
286            tmp1.double();
287
288            tmp6.sub_assign(&tmp1);
289
290            // tmp0 is the first part of line 16
291            tmp0 = r.z;
292            tmp0.mul_assign(&zsquared);
293            tmp0.double();
294
295            (tmp0, tmp3, tmp6)
296        }
297
298        fn addition_step(r: &mut G2, q: &G2Affine) -> (Fq2, Fq2, Fq2) {
299            // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf
300            let mut zsquared = r.z;
301            zsquared.square();
302
303            let mut ysquared = q.y;
304            ysquared.square();
305
306            // t0 corresponds to line 1
307            let mut t0 = zsquared;
308            t0.mul_assign(&q.x);
309
310            // t1 corresponds to lines 2 and 3
311            let mut t1 = q.y;
312            t1.add_assign(&r.z);
313            t1.square();
314            t1.sub_assign(&ysquared);
315            t1.sub_assign(&zsquared);
316            t1.mul_assign(&zsquared);
317
318            // t2 corresponds to line 4
319            let mut t2 = t0;
320            t2.sub_assign(&r.x);
321
322            // t3 corresponds to line 5
323            let mut t3 = t2;
324            t3.square();
325
326            // t4 corresponds to line 6
327            let mut t4 = t3;
328            t4.double();
329            t4.double();
330
331            // t5 corresponds to line 7
332            let mut t5 = t4;
333            t5.mul_assign(&t2);
334
335            // t6 corresponds to line 8
336            let mut t6 = t1;
337            t6.sub_assign(&r.y);
338            t6.sub_assign(&r.y);
339
340            // t9 corresponds to line 9
341            let mut t9 = t6;
342            t9.mul_assign(&q.x);
343
344            // corresponds to line 10
345            let mut t7 = t4;
346            t7.mul_assign(&r.x);
347
348            // corresponds to line 11, but assigns to r.x instead of T.x
349            r.x = t6;
350            r.x.square();
351            r.x.sub_assign(&t5);
352            r.x.sub_assign(&t7);
353            r.x.sub_assign(&t7);
354
355            // corresponds to line 12, but assigns to r.z instead of T.z
356            r.z.add_assign(&t2);
357            r.z.square();
358            r.z.sub_assign(&zsquared);
359            r.z.sub_assign(&t3);
360
361            // corresponds to line 13
362            let mut t10 = q.y;
363            t10.add_assign(&r.z);
364
365            // corresponds to line 14
366            let mut t8 = t7;
367            t8.sub_assign(&r.x);
368            t8.mul_assign(&t6);
369
370            // corresponds to line 15
371            t0 = r.y;
372            t0.mul_assign(&t5);
373            t0.double();
374
375            // corresponds to line 12, but assigns to r.y instead of T.y
376            r.y = t8;
377            r.y.sub_assign(&t0);
378
379            // corresponds to line 17
380            t10.square();
381            t10.sub_assign(&ysquared);
382
383            let mut ztsquared = r.z;
384            ztsquared.square();
385
386            t10.sub_assign(&ztsquared);
387
388            // corresponds to line 18
389            t9.double();
390            t9.sub_assign(&t10);
391
392            // t10 = 2*Zt from Algo 27, line 19
393            t10 = r.z;
394            t10.double();
395
396            // t1 = first multiplicator of line 21
397            t6.negate();
398
399            t1 = t6;
400            t1.double();
401
402            // t9 corresponds to t9 from Algo 27
403            (t10, t1, t9)
404        }
405
406        let mut coeffs = vec![];
407        let mut r: G2 = q.into();
408
409        let mut negq = q;
410        negq.negate();
411
412        for i in (1..SIX_U_PLUS_2_NAF.len()).rev() {
413            coeffs.push(doubling_step(&mut r));
414            let x = SIX_U_PLUS_2_NAF[i - 1];
415            match x {
416                1 => {
417                    coeffs.push(addition_step(&mut r, &q));
418                }
419                -1 => {
420                    coeffs.push(addition_step(&mut r, &negq));
421                }
422                _ => continue,
423            }
424        }
425
426        let mut q1 = q;
427
428        q1.x.c1.negate();
429        q1.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[1]);
430
431        q1.y.c1.negate();
432        q1.y.mul_assign(&XI_TO_Q_MINUS_1_OVER_2);
433
434        coeffs.push(addition_step(&mut r, &q1));
435
436        let mut minusq2 = q;
437        minusq2.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[2]);
438
439        coeffs.push(addition_step(&mut r, &minusq2));
440
441        G2Prepared { coeffs, infinity: false }
442    }
443}
444
445#[cfg(test)]
446use rand::{Rand, SeedableRng, XorShiftRng};
447
448#[test]
449fn test_pairing() {
450    use crate::CurveProjective;
451    let mut g1 = G1::one();
452
453    let mut g2 = G2::one();
454    g2.double();
455
456    let pair12 = Bn256::pairing(g1, g2);
457
458    g1 = G1::one();
459    g1.double();
460
461    g2 = G2::one();
462
463    let pair21 = Bn256::pairing(g1, g2);
464
465    assert_eq!(pair12, pair21);
466
467    // print!("GT = {}\n", pair12);
468
469    g1 = G1::one();
470    g1.double();
471    g1.double();
472
473    let pair41 = Bn256::pairing(g1, g2);
474
475    g1 = G1::one();
476    g1.double();
477
478    g2.double();
479
480    let pair22 = Bn256::pairing(g1, g2);
481
482    assert_eq!(pair41, pair22);
483
484    g1 = G1::one();
485    g1.double();
486    g1.add_assign(&G1::one());
487
488    g2 = G2::one();
489    g2.double();
490
491    let pair32 = Bn256::pairing(g1, g2);
492
493    g2 = G2::one();
494    g2.double();
495    g2.add_assign(&G2::one());
496
497    g1 = G1::one();
498    g1.double();
499
500    let pair23 = Bn256::pairing(g1, g2);
501
502    assert_eq!(pair23, pair32);
503
504    let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
505
506    for _ in 0..1000 {
507        let a = Fr::rand(&mut rng);
508        let b = Fr::rand(&mut rng);
509
510        let mut g1 = G1::one();
511        g1.mul_assign(a);
512
513        let mut g2 = G2::one();
514        g1.mul_assign(b);
515
516        let pair_ab = Bn256::pairing(g1, g2);
517
518        g1 = G1::one();
519        g1.mul_assign(b);
520
521        g2 = G2::one();
522        g1.mul_assign(a);
523
524        let pair_ba = Bn256::pairing(g1, g2);
525
526        assert_eq!(pair_ab, pair_ba);
527    }
528}
529
530#[test]
531fn random_bilinearity_tests() {
532    use crate::CurveProjective;
533    use ff::PrimeField;
534
535    let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
536
537    for _ in 0..1000 {
538        let mut a = G1::one();
539        let ka = Fr::rand(&mut rng);
540        a.mul_assign(ka);
541        let mut b = G2::one();
542        let kb = Fr::rand(&mut rng);
543        b.mul_assign(kb);
544
545        let c = Fr::rand(&mut rng);
546        let d = Fr::rand(&mut rng);
547
548        let mut ac = a;
549        ac.mul_assign(c);
550
551        let mut ad = a;
552        ad.mul_assign(d);
553
554        let mut bc = b;
555        bc.mul_assign(c);
556
557        let mut bd = b;
558        bd.mul_assign(d);
559
560        let acbd = Bn256::pairing(ac, bd);
561        let adbc = Bn256::pairing(ad, bc);
562
563        let mut cd = c;
564        cd.mul_assign(&d);
565
566        let abcd = Bn256::pairing(a, b).pow(cd.into_repr());
567
568        assert_eq!(acbd, adbc);
569        assert_eq!(acbd, abcd);
570    }
571}
572
573#[test]
574#[ignore] // TODO(ignored-test): Timeout.
575fn bn256_engine_tests() {
576    crate::tests::engine::engine_tests::<Bn256>();
577}