pairing_plus/bls12_381/ec/
g2.rs

1use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr};
2use super::g1::G1Affine;
3use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
4use std::fmt;
5use {CurveAffine, CurveProjective, EncodedPoint, Engine, GroupDecodingError, SubgroupCheck};
6
7curve_impl!(
8    "G2",
9    G2,
10    G2Affine,
11    G2Prepared,
12    Fq2,
13    Fr,
14    G2Uncompressed,
15    G2Compressed,
16    G1Affine
17);
18
19#[derive(Copy, Clone)]
20pub struct G2Uncompressed([u8; 192]);
21
22impl AsRef<[u8]> for G2Uncompressed {
23    fn as_ref(&self) -> &[u8] {
24        &self.0
25    }
26}
27
28impl AsMut<[u8]> for G2Uncompressed {
29    fn as_mut(&mut self) -> &mut [u8] {
30        &mut self.0
31    }
32}
33
34impl fmt::Debug for G2Uncompressed {
35    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
36        self.0[..].fmt(formatter)
37    }
38}
39
40impl EncodedPoint for G2Uncompressed {
41    type Affine = G2Affine;
42
43    fn empty() -> Self {
44        G2Uncompressed([0; 192])
45    }
46    fn size() -> usize {
47        192
48    }
49    fn into_affine(&self) -> Result<G2Affine, GroupDecodingError> {
50        let affine = self.into_affine_unchecked()?;
51
52        if !affine.is_on_curve() {
53            Err(GroupDecodingError::NotOnCurve)
54        } else if !affine.in_subgroup() {
55            Err(GroupDecodingError::NotInSubgroup)
56        } else {
57            Ok(affine)
58        }
59    }
60    fn into_affine_unchecked(&self) -> Result<G2Affine, GroupDecodingError> {
61        // Create a copy of this representation.
62        let mut copy = self.0;
63
64        if copy[0] & (1 << 7) != 0 {
65            // Distinguisher bit is set, but this should be uncompressed!
66            return Err(GroupDecodingError::UnexpectedCompressionMode);
67        }
68
69        if copy[0] & (1 << 6) != 0 {
70            // This is the point at infinity, which means that if we mask away
71            // the first two bits, the entire representation should consist
72            // of zeroes.
73            copy[0] &= 0x3f;
74
75            if copy.iter().all(|b| *b == 0) {
76                Ok(G2Affine::zero())
77            } else {
78                Err(GroupDecodingError::UnexpectedInformation)
79            }
80        } else {
81            if copy[0] & (1 << 5) != 0 {
82                // The bit indicating the y-coordinate should be lexicographically
83                // largest is set, but this is an uncompressed element.
84                return Err(GroupDecodingError::UnexpectedInformation);
85            }
86
87            // Unset the three most significant bits.
88            copy[0] &= 0x1f;
89
90            let mut x_c0 = FqRepr([0; 6]);
91            let mut x_c1 = FqRepr([0; 6]);
92            let mut y_c0 = FqRepr([0; 6]);
93            let mut y_c1 = FqRepr([0; 6]);
94
95            {
96                let mut reader = &copy[..];
97
98                x_c1.read_be(&mut reader).unwrap();
99                x_c0.read_be(&mut reader).unwrap();
100                y_c1.read_be(&mut reader).unwrap();
101                y_c0.read_be(&mut reader).unwrap();
102            }
103
104            Ok(G2Affine {
105                x: Fq2 {
106                    c0: Fq::from_repr(x_c0).map_err(|e| {
107                        GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e)
108                    })?,
109                    c1: Fq::from_repr(x_c1).map_err(|e| {
110                        GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e)
111                    })?,
112                },
113                y: Fq2 {
114                    c0: Fq::from_repr(y_c0).map_err(|e| {
115                        GroupDecodingError::CoordinateDecodingError("y coordinate (c0)", e)
116                    })?,
117                    c1: Fq::from_repr(y_c1).map_err(|e| {
118                        GroupDecodingError::CoordinateDecodingError("y coordinate (c1)", e)
119                    })?,
120                },
121                infinity: false,
122            })
123        }
124    }
125    fn from_affine(affine: G2Affine) -> Self {
126        let mut res = Self::empty();
127
128        if affine.is_zero() {
129            // Set the second-most significant bit to indicate this point
130            // is at infinity.
131            res.0[0] |= 1 << 6;
132        } else {
133            let mut writer = &mut res.0[..];
134
135            affine.x.c1.into_repr().write_be(&mut writer).unwrap();
136            affine.x.c0.into_repr().write_be(&mut writer).unwrap();
137            affine.y.c1.into_repr().write_be(&mut writer).unwrap();
138            affine.y.c0.into_repr().write_be(&mut writer).unwrap();
139        }
140
141        res
142    }
143}
144
145#[derive(Copy, Clone)]
146pub struct G2Compressed([u8; 96]);
147
148impl AsRef<[u8]> for G2Compressed {
149    fn as_ref(&self) -> &[u8] {
150        &self.0
151    }
152}
153
154impl AsMut<[u8]> for G2Compressed {
155    fn as_mut(&mut self) -> &mut [u8] {
156        &mut self.0
157    }
158}
159
160impl fmt::Debug for G2Compressed {
161    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
162        self.0[..].fmt(formatter)
163    }
164}
165
166impl EncodedPoint for G2Compressed {
167    type Affine = G2Affine;
168
169    fn empty() -> Self {
170        G2Compressed([0; 96])
171    }
172    fn size() -> usize {
173        96
174    }
175    fn into_affine(&self) -> Result<G2Affine, GroupDecodingError> {
176        let affine = self.into_affine_unchecked()?;
177
178        // NB: Decompression guarantees that it is on the curve already.
179
180        if !affine.in_subgroup() {
181            Err(GroupDecodingError::NotInSubgroup)
182        } else {
183            Ok(affine)
184        }
185    }
186    fn into_affine_unchecked(&self) -> Result<G2Affine, GroupDecodingError> {
187        // Create a copy of this representation.
188        let mut copy = self.0;
189
190        if copy[0] & (1 << 7) == 0 {
191            // Distinguisher bit isn't set.
192            return Err(GroupDecodingError::UnexpectedCompressionMode);
193        }
194
195        if copy[0] & (1 << 6) != 0 {
196            // This is the point at infinity, which means that if we mask away
197            // the first two bits, the entire representation should consist
198            // of zeroes.
199            copy[0] &= 0x3f;
200
201            if copy.iter().all(|b| *b == 0) {
202                Ok(G2Affine::zero())
203            } else {
204                Err(GroupDecodingError::UnexpectedInformation)
205            }
206        } else {
207            // Determine if the intended y coordinate must be greater
208            // lexicographically.
209            let greatest = copy[0] & (1 << 5) != 0;
210
211            // Unset the three most significant bits.
212            copy[0] &= 0x1f;
213
214            let mut x_c1 = FqRepr([0; 6]);
215            let mut x_c0 = FqRepr([0; 6]);
216
217            {
218                let mut reader = &copy[..];
219
220                x_c1.read_be(&mut reader).unwrap();
221                x_c0.read_be(&mut reader).unwrap();
222            }
223
224            // Interpret as Fq element.
225            let x = Fq2 {
226                c0: Fq::from_repr(x_c0).map_err(|e| {
227                    GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e)
228                })?,
229                c1: Fq::from_repr(x_c1).map_err(|e| {
230                    GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e)
231                })?,
232            };
233
234            G2Affine::get_point_from_x(x, greatest).ok_or(GroupDecodingError::NotOnCurve)
235        }
236    }
237    fn from_affine(affine: G2Affine) -> Self {
238        let mut res = Self::empty();
239
240        if affine.is_zero() {
241            // Set the second-most significant bit to indicate this point
242            // is at infinity.
243            res.0[0] |= 1 << 6;
244        } else {
245            {
246                let mut writer = &mut res.0[..];
247
248                affine.x.c1.into_repr().write_be(&mut writer).unwrap();
249                affine.x.c0.into_repr().write_be(&mut writer).unwrap();
250            }
251
252            let mut negy = affine.y;
253            negy.negate();
254
255            // Set the third most significant bit if the correct y-coordinate
256            // is lexicographically largest.
257            if affine.y > negy {
258                res.0[0] |= 1 << 5;
259            }
260        }
261
262        // Set highest bit to distinguish this as a compressed element.
263        res.0[0] |= 1 << 7;
264
265        res
266    }
267}
268
269impl G2Affine {
270    fn get_generator() -> Self {
271        G2Affine {
272            x: Fq2 {
273                c0: super::super::fq::G2_GENERATOR_X_C0,
274                c1: super::super::fq::G2_GENERATOR_X_C1,
275            },
276            y: Fq2 {
277                c0: super::super::fq::G2_GENERATOR_Y_C0,
278                c1: super::super::fq::G2_GENERATOR_Y_C1,
279            },
280            infinity: false,
281        }
282    }
283
284    fn get_coeff_b() -> Fq2 {
285        Fq2 {
286            c0: super::super::fq::B_COEFF,
287            c1: super::super::fq::B_COEFF,
288        }
289    }
290
291    fn scale_by_cofactor(&self) -> G2 {
292        // G2 cofactor = (x^8 - 4 x^7 + 5 x^6) - (4 x^4 + 6 x^3 - 4 x^2 - 4 x + 13) // 9
293        // 0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5
294        let cofactor = BitIterator::new([
295            0xcf1c38e31c7238e5,
296            0x1616ec6e786f0c70,
297            0x21537e293a6691ae,
298            0xa628f1cb4d9e82ef,
299            0xa68a205b2e5a7ddf,
300            0xcd91de4547085aba,
301            0x91d50792876a202,
302            0x5d543a95414e7f1,
303        ]);
304        self.mul_bits(cofactor)
305    }
306
307    fn perform_pairing(&self, other: &G1Affine) -> Fq12 {
308        super::super::Bls12::pairing(*other, *self)
309    }
310}
311
312impl G2 {
313    fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> usize {
314        let num_bits = scalar.num_bits() as usize;
315
316        if num_bits >= 103 {
317            4
318        } else if num_bits >= 37 {
319            3
320        } else {
321            2
322        }
323    }
324
325    fn empirical_recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
326        const RECOMMENDATIONS: [usize; 11] = [1, 3, 8, 20, 47, 126, 260, 826, 1501, 4555, 84071];
327
328        let mut ret = 4;
329        for r in &RECOMMENDATIONS {
330            if num_scalars > *r {
331                ret += 1;
332            } else {
333                break;
334            }
335        }
336
337        ret
338    }
339}
340
341#[derive(Clone, Debug)]
342pub struct G2Prepared {
343    pub(crate) coeffs: Vec<(Fq2, Fq2, Fq2)>,
344    pub(crate) infinity: bool,
345}
346
347mod subgroup_check {
348    use super::G2Affine;
349    #[cfg(test)]
350    use rand_core::SeedableRng;
351    #[cfg(test)]
352    use CurveAffine;
353    use SubgroupCheck;
354
355    impl SubgroupCheck for G2Affine {
356        fn in_subgroup(&self) -> bool {
357            self.is_on_curve() && self.is_in_correct_subgroup_assuming_on_curve()
358        }
359    }
360
361    #[test]
362    fn test_g2_subgroup_check() {
363        use bls12_381::{ClearH, G2};
364        use CurveProjective;
365        let mut rng = rand_xorshift::XorShiftRng::from_seed([
366            0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
367            0xbc, 0xe5,
368        ]);
369
370        for _ in 0..32 {
371            let p = G2::random(&mut rng).into_affine();
372            assert_eq!(
373                p.in_subgroup(),
374                p.is_in_correct_subgroup_assuming_on_curve()
375            );
376
377            let mut pp = p.into_projective();
378            pp.clear_h();
379            let p = pp.into_affine();
380            assert!(p.in_subgroup() && p.is_in_correct_subgroup_assuming_on_curve());
381        }
382    }
383}
384
385#[test]
386fn g2_generator() {
387    use SqrtField;
388
389    let mut x = Fq2::zero();
390    let mut i = 0;
391    loop {
392        // y^2 = x^3 + b
393        let mut rhs = x;
394        rhs.square();
395        rhs.mul_assign(&x);
396        rhs.add_assign(&G2Affine::get_coeff_b());
397
398        if let Some(y) = rhs.sqrt() {
399            let mut negy = y;
400            negy.negate();
401
402            let p = G2Affine {
403                x,
404                y: if y < negy { y } else { negy },
405                infinity: false,
406            };
407
408            assert!(!p.in_subgroup());
409
410            let g2 = p.scale_by_cofactor();
411            if !g2.is_zero() {
412                assert_eq!(i, 2);
413                let g2 = G2Affine::from(g2);
414
415                assert!(g2.in_subgroup());
416                assert_eq!(g2, G2Affine::one());
417                break;
418            }
419        }
420
421        i += 1;
422        x.add_assign(&Fq2::one());
423    }
424}
425
426#[test]
427fn g2_test_is_valid() {
428    // Reject point on isomorphic twist (b = 3 * (u + 1))
429    {
430        let p = G2Affine {
431            x: Fq2 {
432                c0: Fq::from_repr(FqRepr([
433                    0xa757072d9fa35ba9,
434                    0xae3fb2fb418f6e8a,
435                    0xc1598ec46faa0c7c,
436                    0x7a17a004747e3dbe,
437                    0xcc65406a7c2e5a73,
438                    0x10b8c03d64db4d0c,
439                ]))
440                .unwrap(),
441                c1: Fq::from_repr(FqRepr([
442                    0xd30e70fe2f029778,
443                    0xda30772df0f5212e,
444                    0x5b47a9ff9a233a50,
445                    0xfb777e5b9b568608,
446                    0x789bac1fec71a2b9,
447                    0x1342f02e2da54405,
448                ]))
449                .unwrap(),
450            },
451            y: Fq2 {
452                c0: Fq::from_repr(FqRepr([
453                    0xfe0812043de54dca,
454                    0xe455171a3d47a646,
455                    0xa493f36bc20be98a,
456                    0x663015d9410eb608,
457                    0x78e82a79d829a544,
458                    0x40a00545bb3c1e,
459                ]))
460                .unwrap(),
461                c1: Fq::from_repr(FqRepr([
462                    0x4709802348e79377,
463                    0xb5ac4dc9204bcfbd,
464                    0xda361c97d02f42b2,
465                    0x15008b1dc399e8df,
466                    0x68128fd0548a3829,
467                    0x16a613db5c873aaa,
468                ]))
469                .unwrap(),
470            },
471            infinity: false,
472        };
473        assert!(!p.is_on_curve());
474    }
475
476    // Reject point on a twist (b = 2 * (u + 1))
477    {
478        let p = G2Affine {
479            x: Fq2 {
480                c0: Fq::from_repr(FqRepr([
481                    0xf4fdfe95a705f917,
482                    0xc2914df688233238,
483                    0x37c6b12cca35a34b,
484                    0x41abba710d6c692c,
485                    0xffcc4b2b62ce8484,
486                    0x6993ec01b8934ed,
487                ]))
488                .unwrap(),
489                c1: Fq::from_repr(FqRepr([
490                    0xb94e92d5f874e26,
491                    0x44516408bc115d95,
492                    0xe93946b290caa591,
493                    0xa5a0c2b7131f3555,
494                    0x83800965822367e7,
495                    0x10cf1d3ad8d90bfa,
496                ]))
497                .unwrap(),
498            },
499            y: Fq2 {
500                c0: Fq::from_repr(FqRepr([
501                    0xbf00334c79701d97,
502                    0x4fe714f9ff204f9a,
503                    0xab70b28002f3d825,
504                    0x5a9171720e73eb51,
505                    0x38eb4fd8d658adb7,
506                    0xb649051bbc1164d,
507                ]))
508                .unwrap(),
509                c1: Fq::from_repr(FqRepr([
510                    0x9225814253d7df75,
511                    0xc196c2513477f887,
512                    0xe05e2fbd15a804e0,
513                    0x55f2b8efad953e04,
514                    0x7379345eda55265e,
515                    0x377f2e6208fd4cb,
516                ]))
517                .unwrap(),
518            },
519            infinity: false,
520        };
521        assert!(!p.is_on_curve());
522        assert!(!p.in_subgroup());
523    }
524
525    // Reject point in an invalid subgroup
526    // There is only one r-order subgroup, as r does not divide the cofactor.
527    {
528        let p = G2Affine {
529            x: Fq2 {
530                c0: Fq::from_repr(FqRepr([
531                    0x262cea73ea1906c,
532                    0x2f08540770fabd6,
533                    0x4ceb92d0a76057be,
534                    0x2199bc19c48c393d,
535                    0x4a151b732a6075bf,
536                    0x17762a3b9108c4a7,
537                ]))
538                .unwrap(),
539                c1: Fq::from_repr(FqRepr([
540                    0x26f461e944bbd3d1,
541                    0x298f3189a9cf6ed6,
542                    0x74328ad8bc2aa150,
543                    0x7e147f3f9e6e241,
544                    0x72a9b63583963fff,
545                    0x158b0083c000462,
546                ]))
547                .unwrap(),
548            },
549            y: Fq2 {
550                c0: Fq::from_repr(FqRepr([
551                    0x91fb0b225ecf103b,
552                    0x55d42edc1dc46ba0,
553                    0x43939b11997b1943,
554                    0x68cad19430706b4d,
555                    0x3ccfb97b924dcea8,
556                    0x1660f93434588f8d,
557                ]))
558                .unwrap(),
559                c1: Fq::from_repr(FqRepr([
560                    0xaaed3985b6dcb9c7,
561                    0xc1e985d6d898d9f4,
562                    0x618bd2ac3271ac42,
563                    0x3940a2dbb914b529,
564                    0xbeb88137cf34f3e7,
565                    0x1699ee577c61b694,
566                ]))
567                .unwrap(),
568            },
569            infinity: false,
570        };
571        assert!(p.is_on_curve());
572        assert!(!p.in_subgroup());
573    }
574}
575
576#[test]
577fn test_g2_addition_correctness() {
578    let mut p = G2 {
579        x: Fq2 {
580            c0: Fq::from_repr(FqRepr([
581                0x6c994cc1e303094e,
582                0xf034642d2c9e85bd,
583                0x275094f1352123a9,
584                0x72556c999f3707ac,
585                0x4617f2e6774e9711,
586                0x100b2fe5bffe030b,
587            ]))
588            .unwrap(),
589            c1: Fq::from_repr(FqRepr([
590                0x7a33555977ec608,
591                0xe23039d1fe9c0881,
592                0x19ce4678aed4fcb5,
593                0x4637c4f417667e2e,
594                0x93ebe7c3e41f6acc,
595                0xde884f89a9a371b,
596            ]))
597            .unwrap(),
598        },
599        y: Fq2 {
600            c0: Fq::from_repr(FqRepr([
601                0xe073119472e1eb62,
602                0x44fb3391fe3c9c30,
603                0xaa9b066d74694006,
604                0x25fd427b4122f231,
605                0xd83112aace35cae,
606                0x191b2432407cbb7f,
607            ]))
608            .unwrap(),
609            c1: Fq::from_repr(FqRepr([
610                0xf68ae82fe97662f5,
611                0xe986057068b50b7d,
612                0x96c30f0411590b48,
613                0x9eaa6d19de569196,
614                0xf6a03d31e2ec2183,
615                0x3bdafaf7ca9b39b,
616            ]))
617            .unwrap(),
618        },
619        z: Fq2::one(),
620    };
621
622    p.add_assign(&G2 {
623        x: Fq2 {
624            c0: Fq::from_repr(FqRepr([
625                0xa8c763d25910bdd3,
626                0x408777b30ca3add4,
627                0x6115fcc12e2769e,
628                0x8e73a96b329ad190,
629                0x27c546f75ee1f3ab,
630                0xa33d27add5e7e82,
631            ]))
632            .unwrap(),
633            c1: Fq::from_repr(FqRepr([
634                0x93b1ebcd54870dfe,
635                0xf1578300e1342e11,
636                0x8270dca3a912407b,
637                0x2089faf462438296,
638                0x828e5848cd48ea66,
639                0x141ecbac1deb038b,
640            ]))
641            .unwrap(),
642        },
643        y: Fq2 {
644            c0: Fq::from_repr(FqRepr([
645                0xf5d2c28857229c3f,
646                0x8c1574228757ca23,
647                0xe8d8102175f5dc19,
648                0x2767032fc37cc31d,
649                0xd5ee2aba84fd10fe,
650                0x16576ccd3dd0a4e8,
651            ]))
652            .unwrap(),
653            c1: Fq::from_repr(FqRepr([
654                0x4da9b6f6a96d1dd2,
655                0x9657f7da77f1650e,
656                0xbc150712f9ffe6da,
657                0x31898db63f87363a,
658                0xabab040ddbd097cc,
659                0x11ad236b9ba02990,
660            ]))
661            .unwrap(),
662        },
663        z: Fq2::one(),
664    });
665
666    let p = G2Affine::from(p);
667
668    assert_eq!(
669        p,
670        G2Affine {
671            x: Fq2 {
672                c0: Fq::from_repr(FqRepr([
673                    0xcde7ee8a3f2ac8af,
674                    0xfc642eb35975b069,
675                    0xa7de72b7dd0e64b7,
676                    0xf1273e6406eef9cc,
677                    0xababd760ff05cb92,
678                    0xd7c20456617e89
679                ]))
680                .unwrap(),
681                c1: Fq::from_repr(FqRepr([
682                    0xd1a50b8572cbd2b8,
683                    0x238f0ac6119d07df,
684                    0x4dbe924fe5fd6ac2,
685                    0x8b203284c51edf6b,
686                    0xc8a0b730bbb21f5e,
687                    0x1a3b59d29a31274
688                ]))
689                .unwrap(),
690            },
691            y: Fq2 {
692                c0: Fq::from_repr(FqRepr([
693                    0x9e709e78a8eaa4c9,
694                    0xd30921c93ec342f4,
695                    0x6d1ef332486f5e34,
696                    0x64528ab3863633dc,
697                    0x159384333d7cba97,
698                    0x4cb84741f3cafe8
699                ]))
700                .unwrap(),
701                c1: Fq::from_repr(FqRepr([
702                    0x242af0dc3640e1a4,
703                    0xe90a73ad65c66919,
704                    0x2bd7ca7f4346f9ec,
705                    0x38528f92b689644d,
706                    0xb6884deec59fb21f,
707                    0x3c075d3ec52ba90
708                ]))
709                .unwrap(),
710            },
711            infinity: false,
712        }
713    );
714}
715
716#[test]
717fn test_g2_doubling_correctness() {
718    let mut p = G2 {
719        x: Fq2 {
720            c0: Fq::from_repr(FqRepr([
721                0x6c994cc1e303094e,
722                0xf034642d2c9e85bd,
723                0x275094f1352123a9,
724                0x72556c999f3707ac,
725                0x4617f2e6774e9711,
726                0x100b2fe5bffe030b,
727            ]))
728            .unwrap(),
729            c1: Fq::from_repr(FqRepr([
730                0x7a33555977ec608,
731                0xe23039d1fe9c0881,
732                0x19ce4678aed4fcb5,
733                0x4637c4f417667e2e,
734                0x93ebe7c3e41f6acc,
735                0xde884f89a9a371b,
736            ]))
737            .unwrap(),
738        },
739        y: Fq2 {
740            c0: Fq::from_repr(FqRepr([
741                0xe073119472e1eb62,
742                0x44fb3391fe3c9c30,
743                0xaa9b066d74694006,
744                0x25fd427b4122f231,
745                0xd83112aace35cae,
746                0x191b2432407cbb7f,
747            ]))
748            .unwrap(),
749            c1: Fq::from_repr(FqRepr([
750                0xf68ae82fe97662f5,
751                0xe986057068b50b7d,
752                0x96c30f0411590b48,
753                0x9eaa6d19de569196,
754                0xf6a03d31e2ec2183,
755                0x3bdafaf7ca9b39b,
756            ]))
757            .unwrap(),
758        },
759        z: Fq2::one(),
760    };
761
762    p.double();
763
764    let p = G2Affine::from(p);
765
766    assert_eq!(
767        p,
768        G2Affine {
769            x: Fq2 {
770                c0: Fq::from_repr(FqRepr([
771                    0x91ccb1292727c404,
772                    0x91a6cb182438fad7,
773                    0x116aee59434de902,
774                    0xbcedcfce1e52d986,
775                    0x9755d4a3926e9862,
776                    0x18bab73760fd8024
777                ]))
778                .unwrap(),
779                c1: Fq::from_repr(FqRepr([
780                    0x4e7c5e0a2ae5b99e,
781                    0x96e582a27f028961,
782                    0xc74d1cf4ef2d5926,
783                    0xeb0cf5e610ef4fe7,
784                    0x7b4c2bae8db6e70b,
785                    0xf136e43909fca0
786                ]))
787                .unwrap(),
788            },
789            y: Fq2 {
790                c0: Fq::from_repr(FqRepr([
791                    0x954d4466ab13e58,
792                    0x3ee42eec614cf890,
793                    0x853bb1d28877577e,
794                    0xa5a2a51f7fde787b,
795                    0x8b92866bc6384188,
796                    0x81a53fe531d64ef
797                ]))
798                .unwrap(),
799                c1: Fq::from_repr(FqRepr([
800                    0x4c5d607666239b34,
801                    0xeddb5f48304d14b3,
802                    0x337167ee6e8e3cb6,
803                    0xb271f52f12ead742,
804                    0x244e6c2015c83348,
805                    0x19e2deae6eb9b441
806                ]))
807                .unwrap(),
808            },
809            infinity: false,
810        }
811    );
812}
813
814#[test]
815fn g2_curve_tests() {
816    ::tests::curve::curve_tests::<G2>();
817}