pairing_ce/bls12_381/
fq2.rs

1use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE};
2use ff::{Field, SqrtField};
3use rand::{Rand, Rng};
4
5use std::cmp::Ordering;
6
7/// An element of Fq2, represented by c0 + c1 * u.
8#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default, ::serde::Serialize, ::serde::Deserialize)]
9pub struct Fq2 {
10    pub c0: Fq,
11    pub c1: Fq,
12}
13
14impl ::std::fmt::Display for Fq2 {
15    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
16        write!(f, "Fq2({} + {} * u)", self.c0, self.c1)
17    }
18}
19
20/// `Fq2` elements are ordered lexicographically.
21impl Ord for Fq2 {
22    #[inline(always)]
23    fn cmp(&self, other: &Fq2) -> Ordering {
24        match self.c1.cmp(&other.c1) {
25            Ordering::Greater => Ordering::Greater,
26            Ordering::Less => Ordering::Less,
27            Ordering::Equal => self.c0.cmp(&other.c0),
28        }
29    }
30}
31
32impl PartialOrd for Fq2 {
33    #[inline(always)]
34    fn partial_cmp(&self, other: &Fq2) -> Option<Ordering> {
35        Some(self.cmp(other))
36    }
37}
38
39impl Fq2 {
40    /// Multiply this element by the cubic and quadratic nonresidue 1 + u.
41    pub fn mul_by_nonresidue(&mut self) {
42        let t0 = self.c0;
43        self.c0.sub_assign(&self.c1);
44        self.c1.add_assign(&t0);
45    }
46
47    /// Norm of Fq2 as extension field in i over Fq
48    pub fn norm(&self) -> Fq {
49        let mut t0 = self.c0;
50        let mut t1 = self.c1;
51        t0.square();
52        t1.square();
53        t1.add_assign(&t0);
54
55        t1
56    }
57}
58
59impl Rand for Fq2 {
60    fn rand<R: Rng>(rng: &mut R) -> Self {
61        Fq2 {
62            c0: rng.gen(),
63            c1: rng.gen(),
64        }
65    }
66}
67
68impl Field for Fq2 {
69    fn zero() -> Self {
70        Fq2 {
71            c0: Fq::zero(),
72            c1: Fq::zero(),
73        }
74    }
75
76    fn one() -> Self {
77        Fq2 {
78            c0: Fq::one(),
79            c1: Fq::zero(),
80        }
81    }
82
83    fn is_zero(&self) -> bool {
84        self.c0.is_zero() && self.c1.is_zero()
85    }
86
87    fn square(&mut self) {
88        let mut ab = self.c0;
89        ab.mul_assign(&self.c1);
90        let mut c0c1 = self.c0;
91        c0c1.add_assign(&self.c1);
92        let mut c0 = self.c1;
93        c0.negate();
94        c0.add_assign(&self.c0);
95        c0.mul_assign(&c0c1);
96        c0.sub_assign(&ab);
97        self.c1 = ab;
98        self.c1.add_assign(&ab);
99        c0.add_assign(&ab);
100        self.c0 = c0;
101    }
102
103    fn double(&mut self) {
104        self.c0.double();
105        self.c1.double();
106    }
107
108    fn negate(&mut self) {
109        self.c0.negate();
110        self.c1.negate();
111    }
112
113    fn add_assign(&mut self, other: &Self) {
114        self.c0.add_assign(&other.c0);
115        self.c1.add_assign(&other.c1);
116    }
117
118    fn sub_assign(&mut self, other: &Self) {
119        self.c0.sub_assign(&other.c0);
120        self.c1.sub_assign(&other.c1);
121    }
122
123    fn mul_assign(&mut self, other: &Self) {
124        let mut aa = self.c0;
125        aa.mul_assign(&other.c0);
126        let mut bb = self.c1;
127        bb.mul_assign(&other.c1);
128        let mut o = other.c0;
129        o.add_assign(&other.c1);
130        self.c1.add_assign(&self.c0);
131        self.c1.mul_assign(&o);
132        self.c1.sub_assign(&aa);
133        self.c1.sub_assign(&bb);
134        self.c0 = aa;
135        self.c0.sub_assign(&bb);
136    }
137
138    fn inverse(&self) -> Option<Self> {
139        let mut t1 = self.c1;
140        t1.square();
141        let mut t0 = self.c0;
142        t0.square();
143        t0.add_assign(&t1);
144        t0.inverse().map(|t| {
145            let mut tmp = Fq2 {
146                c0: self.c0,
147                c1: self.c1,
148            };
149            tmp.c0.mul_assign(&t);
150            tmp.c1.mul_assign(&t);
151            tmp.c1.negate();
152
153            tmp
154        })
155    }
156
157    fn frobenius_map(&mut self, power: usize) {
158        self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]);
159    }
160}
161
162impl SqrtField for Fq2 {
163    fn legendre(&self) -> ::ff::LegendreSymbol {
164        self.norm().legendre()
165    }
166
167    fn sqrt(&self) -> Option<Self> {
168        // Algorithm 9, https://eprint.iacr.org/2012/685.pdf
169
170        if self.is_zero() {
171            Some(Self::zero())
172        } else {
173            // a1 = self^((q - 3) / 4)
174            let mut a1 = self.pow([
175                0xee7fbfffffffeaaa,
176                0x7aaffffac54ffff,
177                0xd9cc34a83dac3d89,
178                0xd91dd2e13ce144af,
179                0x92c6e9ed90d2eb35,
180                0x680447a8e5ff9a6,
181            ]);
182            let mut alpha = a1;
183            alpha.square();
184            alpha.mul_assign(self);
185            let mut a0 = alpha;
186            a0.frobenius_map(1);
187            a0.mul_assign(&alpha);
188
189            let neg1 = Fq2 {
190                c0: NEGATIVE_ONE,
191                c1: Fq::zero(),
192            };
193
194            if a0 == neg1 {
195                None
196            } else {
197                a1.mul_assign(self);
198
199                if alpha == neg1 {
200                    a1.mul_assign(&Fq2 {
201                        c0: Fq::zero(),
202                        c1: Fq::one(),
203                    });
204                } else {
205                    alpha.add_assign(&Fq2::one());
206                    // alpha = alpha^((q - 1) / 2)
207                    alpha = alpha.pow([
208                        0xdcff7fffffffd555,
209                        0xf55ffff58a9ffff,
210                        0xb39869507b587b12,
211                        0xb23ba5c279c2895f,
212                        0x258dd3db21a5d66b,
213                        0xd0088f51cbff34d,
214                    ]);
215                    a1.mul_assign(&alpha);
216                }
217
218                Some(a1)
219            }
220        }
221    }
222}
223
224#[test]
225fn test_fq2_ordering() {
226    let mut a = Fq2 {
227        c0: Fq::zero(),
228        c1: Fq::zero(),
229    };
230
231    let mut b = a.clone();
232
233    assert!(a.cmp(&b) == Ordering::Equal);
234    b.c0.add_assign(&Fq::one());
235    assert!(a.cmp(&b) == Ordering::Less);
236    a.c0.add_assign(&Fq::one());
237    assert!(a.cmp(&b) == Ordering::Equal);
238    b.c1.add_assign(&Fq::one());
239    assert!(a.cmp(&b) == Ordering::Less);
240    a.c0.add_assign(&Fq::one());
241    assert!(a.cmp(&b) == Ordering::Less);
242    a.c1.add_assign(&Fq::one());
243    assert!(a.cmp(&b) == Ordering::Greater);
244    b.c0.add_assign(&Fq::one());
245    assert!(a.cmp(&b) == Ordering::Equal);
246}
247
248#[test]
249fn test_fq2_basics() {
250    assert_eq!(
251        Fq2 {
252            c0: Fq::zero(),
253            c1: Fq::zero(),
254        },
255        Fq2::zero()
256    );
257    assert_eq!(
258        Fq2 {
259            c0: Fq::one(),
260            c1: Fq::zero(),
261        },
262        Fq2::one()
263    );
264    assert!(Fq2::zero().is_zero());
265    assert!(!Fq2::one().is_zero());
266    assert!(
267        !Fq2 {
268            c0: Fq::zero(),
269            c1: Fq::one(),
270        }.is_zero()
271    );
272}
273
274#[test]
275fn test_fq2_squaring() {
276    use super::fq::FqRepr;
277    use ff::PrimeField;
278
279    let mut a = Fq2 {
280        c0: Fq::one(),
281        c1: Fq::one(),
282    }; // u + 1
283    a.square();
284    assert_eq!(
285        a,
286        Fq2 {
287            c0: Fq::zero(),
288            c1: Fq::from_repr(FqRepr::from(2)).unwrap(),
289        }
290    ); // 2u
291
292    let mut a = Fq2 {
293        c0: Fq::zero(),
294        c1: Fq::one(),
295    }; // u
296    a.square();
297    assert_eq!(a, {
298        let mut neg1 = Fq::one();
299        neg1.negate();
300        Fq2 {
301            c0: neg1,
302            c1: Fq::zero(),
303        }
304    }); // -1
305
306    let mut a = Fq2 {
307        c0: Fq::from_repr(FqRepr([
308            0x9c2c6309bbf8b598,
309            0x4eef5c946536f602,
310            0x90e34aab6fb6a6bd,
311            0xf7f295a94e58ae7c,
312            0x41b76dcc1c3fbe5e,
313            0x7080c5fa1d8e042,
314        ])).unwrap(),
315        c1: Fq::from_repr(FqRepr([
316            0x38f473b3c870a4ab,
317            0x6ad3291177c8c7e5,
318            0xdac5a4c911a4353e,
319            0xbfb99020604137a0,
320            0xfc58a7b7be815407,
321            0x10d1615e75250a21,
322        ])).unwrap(),
323    };
324    a.square();
325    assert_eq!(
326        a,
327        Fq2 {
328            c0: Fq::from_repr(FqRepr([
329                0xf262c28c538bcf68,
330                0xb9f2a66eae1073ba,
331                0xdc46ab8fad67ae0,
332                0xcb674157618da176,
333                0x4cf17b5893c3d327,
334                0x7eac81369c43361
335            ])).unwrap(),
336            c1: Fq::from_repr(FqRepr([
337                0xc1579cf58e980cf8,
338                0xa23eb7e12dd54d98,
339                0xe75138bce4cec7aa,
340                0x38d0d7275a9689e1,
341                0x739c983042779a65,
342                0x1542a61c8a8db994
343            ])).unwrap(),
344        }
345    );
346}
347
348#[test]
349fn test_fq2_mul() {
350    use super::fq::FqRepr;
351    use ff::PrimeField;
352
353    let mut a = Fq2 {
354        c0: Fq::from_repr(FqRepr([
355            0x85c9f989e1461f03,
356            0xa2e33c333449a1d6,
357            0x41e461154a7354a3,
358            0x9ee53e7e84d7532e,
359            0x1c202d8ed97afb45,
360            0x51d3f9253e2516f,
361        ])).unwrap(),
362        c1: Fq::from_repr(FqRepr([
363            0xa7348a8b511aedcf,
364            0x143c215d8176b319,
365            0x4cc48081c09b8903,
366            0x9533e4a9a5158be,
367            0x7a5e1ecb676d65f9,
368            0x180c3ee46656b008,
369        ])).unwrap(),
370    };
371    a.mul_assign(&Fq2 {
372        c0: Fq::from_repr(FqRepr([
373            0xe21f9169805f537e,
374            0xfc87e62e179c285d,
375            0x27ece175be07a531,
376            0xcd460f9f0c23e430,
377            0x6c9110292bfa409,
378            0x2c93a72eb8af83e,
379        ])).unwrap(),
380        c1: Fq::from_repr(FqRepr([
381            0x4b1c3f936d8992d4,
382            0x1d2a72916dba4c8a,
383            0x8871c508658d1e5f,
384            0x57a06d3135a752ae,
385            0x634cd3c6c565096d,
386            0x19e17334d4e93558,
387        ])).unwrap(),
388    });
389    assert_eq!(
390        a,
391        Fq2 {
392            c0: Fq::from_repr(FqRepr([
393                0x95b5127e6360c7e4,
394                0xde29c31a19a6937e,
395                0xf61a96dacf5a39bc,
396                0x5511fe4d84ee5f78,
397                0x5310a202d92f9963,
398                0x1751afbe166e5399
399            ])).unwrap(),
400            c1: Fq::from_repr(FqRepr([
401                0x84af0e1bd630117a,
402                0x6c63cd4da2c2aa7,
403                0x5ba6e5430e883d40,
404                0xc975106579c275ee,
405                0x33a9ac82ce4c5083,
406                0x1ef1a36c201589d
407            ])).unwrap(),
408        }
409    );
410}
411
412#[test]
413fn test_fq2_inverse() {
414    use super::fq::FqRepr;
415    use ff::PrimeField;
416
417    assert!(Fq2::zero().inverse().is_none());
418
419    let a = Fq2 {
420        c0: Fq::from_repr(FqRepr([
421            0x85c9f989e1461f03,
422            0xa2e33c333449a1d6,
423            0x41e461154a7354a3,
424            0x9ee53e7e84d7532e,
425            0x1c202d8ed97afb45,
426            0x51d3f9253e2516f,
427        ])).unwrap(),
428        c1: Fq::from_repr(FqRepr([
429            0xa7348a8b511aedcf,
430            0x143c215d8176b319,
431            0x4cc48081c09b8903,
432            0x9533e4a9a5158be,
433            0x7a5e1ecb676d65f9,
434            0x180c3ee46656b008,
435        ])).unwrap(),
436    };
437    let a = a.inverse().unwrap();
438    assert_eq!(
439        a,
440        Fq2 {
441            c0: Fq::from_repr(FqRepr([
442                0x70300f9bcb9e594,
443                0xe5ecda5fdafddbb2,
444                0x64bef617d2915a8f,
445                0xdfba703293941c30,
446                0xa6c3d8f9586f2636,
447                0x1351ef01941b70c4
448            ])).unwrap(),
449            c1: Fq::from_repr(FqRepr([
450                0x8c39fd76a8312cb4,
451                0x15d7b6b95defbff0,
452                0x947143f89faedee9,
453                0xcbf651a0f367afb2,
454                0xdf4e54f0d3ef15a6,
455                0x103bdf241afb0019
456            ])).unwrap(),
457        }
458    );
459}
460
461#[test]
462fn test_fq2_addition() {
463    use super::fq::FqRepr;
464    use ff::PrimeField;
465
466    let mut a = Fq2 {
467        c0: Fq::from_repr(FqRepr([
468            0x2d0078036923ffc7,
469            0x11e59ea221a3b6d2,
470            0x8b1a52e0a90f59ed,
471            0xb966ce3bc2108b13,
472            0xccc649c4b9532bf3,
473            0xf8d295b2ded9dc,
474        ])).unwrap(),
475        c1: Fq::from_repr(FqRepr([
476            0x977df6efcdaee0db,
477            0x946ae52d684fa7ed,
478            0xbe203411c66fb3a5,
479            0xb3f8afc0ee248cad,
480            0x4e464dea5bcfd41e,
481            0x12d1137b8a6a837,
482        ])).unwrap(),
483    };
484    a.add_assign(&Fq2 {
485        c0: Fq::from_repr(FqRepr([
486            0x619a02d78dc70ef2,
487            0xb93adfc9119e33e8,
488            0x4bf0b99a9f0dca12,
489            0x3b88899a42a6318f,
490            0x986a4a62fa82a49d,
491            0x13ce433fa26027f5,
492        ])).unwrap(),
493        c1: Fq::from_repr(FqRepr([
494            0x66323bf80b58b9b9,
495            0xa1379b6facf6e596,
496            0x402aef1fb797e32f,
497            0x2236f55246d0d44d,
498            0x4c8c1800eb104566,
499            0x11d6e20e986c2085,
500        ])).unwrap(),
501    });
502    assert_eq!(
503        a,
504        Fq2 {
505            c0: Fq::from_repr(FqRepr([
506                0x8e9a7adaf6eb0eb9,
507                0xcb207e6b3341eaba,
508                0xd70b0c7b481d23ff,
509                0xf4ef57d604b6bca2,
510                0x65309427b3d5d090,
511                0x14c715d5553f01d2
512            ])).unwrap(),
513            c1: Fq::from_repr(FqRepr([
514                0xfdb032e7d9079a94,
515                0x35a2809d15468d83,
516                0xfe4b23317e0796d5,
517                0xd62fa51334f560fa,
518                0x9ad265eb46e01984,
519                0x1303f3465112c8bc
520            ])).unwrap(),
521        }
522    );
523}
524
525#[test]
526fn test_fq2_subtraction() {
527    use super::fq::FqRepr;
528    use ff::PrimeField;
529
530    let mut a = Fq2 {
531        c0: Fq::from_repr(FqRepr([
532            0x2d0078036923ffc7,
533            0x11e59ea221a3b6d2,
534            0x8b1a52e0a90f59ed,
535            0xb966ce3bc2108b13,
536            0xccc649c4b9532bf3,
537            0xf8d295b2ded9dc,
538        ])).unwrap(),
539        c1: Fq::from_repr(FqRepr([
540            0x977df6efcdaee0db,
541            0x946ae52d684fa7ed,
542            0xbe203411c66fb3a5,
543            0xb3f8afc0ee248cad,
544            0x4e464dea5bcfd41e,
545            0x12d1137b8a6a837,
546        ])).unwrap(),
547    };
548    a.sub_assign(&Fq2 {
549        c0: Fq::from_repr(FqRepr([
550            0x619a02d78dc70ef2,
551            0xb93adfc9119e33e8,
552            0x4bf0b99a9f0dca12,
553            0x3b88899a42a6318f,
554            0x986a4a62fa82a49d,
555            0x13ce433fa26027f5,
556        ])).unwrap(),
557        c1: Fq::from_repr(FqRepr([
558            0x66323bf80b58b9b9,
559            0xa1379b6facf6e596,
560            0x402aef1fb797e32f,
561            0x2236f55246d0d44d,
562            0x4c8c1800eb104566,
563            0x11d6e20e986c2085,
564        ])).unwrap(),
565    });
566    assert_eq!(
567        a,
568        Fq2 {
569            c0: Fq::from_repr(FqRepr([
570                0x8565752bdb5c9b80,
571                0x7756bed7c15982e9,
572                0xa65a6be700b285fe,
573                0xe255902672ef6c43,
574                0x7f77a718021c342d,
575                0x72ba14049fe9881
576            ])).unwrap(),
577            c1: Fq::from_repr(FqRepr([
578                0xeb4abaf7c255d1cd,
579                0x11df49bc6cacc256,
580                0xe52617930588c69a,
581                0xf63905f39ad8cb1f,
582                0x4cd5dd9fb40b3b8f,
583                0x957411359ba6e4c
584            ])).unwrap(),
585        }
586    );
587}
588
589#[test]
590fn test_fq2_negation() {
591    use super::fq::FqRepr;
592    use ff::PrimeField;
593
594    let mut a = Fq2 {
595        c0: Fq::from_repr(FqRepr([
596            0x2d0078036923ffc7,
597            0x11e59ea221a3b6d2,
598            0x8b1a52e0a90f59ed,
599            0xb966ce3bc2108b13,
600            0xccc649c4b9532bf3,
601            0xf8d295b2ded9dc,
602        ])).unwrap(),
603        c1: Fq::from_repr(FqRepr([
604            0x977df6efcdaee0db,
605            0x946ae52d684fa7ed,
606            0xbe203411c66fb3a5,
607            0xb3f8afc0ee248cad,
608            0x4e464dea5bcfd41e,
609            0x12d1137b8a6a837,
610        ])).unwrap(),
611    };
612    a.negate();
613    assert_eq!(
614        a,
615        Fq2 {
616            c0: Fq::from_repr(FqRepr([
617                0x8cfe87fc96dbaae4,
618                0xcc6615c8fb0492d,
619                0xdc167fc04da19c37,
620                0xab107d49317487ab,
621                0x7e555df189f880e3,
622                0x19083f5486a10cbd
623            ])).unwrap(),
624            c1: Fq::from_repr(FqRepr([
625                0x228109103250c9d0,
626                0x8a411ad149045812,
627                0xa9109e8f3041427e,
628                0xb07e9bc405608611,
629                0xfcd559cbe77bd8b8,
630                0x18d400b280d93e62
631            ])).unwrap(),
632        }
633    );
634}
635
636#[test]
637fn test_fq2_doubling() {
638    use super::fq::FqRepr;
639    use ff::PrimeField;
640
641    let mut a = Fq2 {
642        c0: Fq::from_repr(FqRepr([
643            0x2d0078036923ffc7,
644            0x11e59ea221a3b6d2,
645            0x8b1a52e0a90f59ed,
646            0xb966ce3bc2108b13,
647            0xccc649c4b9532bf3,
648            0xf8d295b2ded9dc,
649        ])).unwrap(),
650        c1: Fq::from_repr(FqRepr([
651            0x977df6efcdaee0db,
652            0x946ae52d684fa7ed,
653            0xbe203411c66fb3a5,
654            0xb3f8afc0ee248cad,
655            0x4e464dea5bcfd41e,
656            0x12d1137b8a6a837,
657        ])).unwrap(),
658    };
659    a.double();
660    assert_eq!(
661        a,
662        Fq2 {
663            c0: Fq::from_repr(FqRepr([
664                0x5a00f006d247ff8e,
665                0x23cb3d4443476da4,
666                0x1634a5c1521eb3da,
667                0x72cd9c7784211627,
668                0x998c938972a657e7,
669                0x1f1a52b65bdb3b9
670            ])).unwrap(),
671            c1: Fq::from_repr(FqRepr([
672                0x2efbeddf9b5dc1b6,
673                0x28d5ca5ad09f4fdb,
674                0x7c4068238cdf674b,
675                0x67f15f81dc49195b,
676                0x9c8c9bd4b79fa83d,
677                0x25a226f714d506e
678            ])).unwrap(),
679        }
680    );
681}
682
683#[test]
684fn test_fq2_frobenius_map() {
685    use super::fq::FqRepr;
686    use ff::PrimeField;
687
688    let mut a = Fq2 {
689        c0: Fq::from_repr(FqRepr([
690            0x2d0078036923ffc7,
691            0x11e59ea221a3b6d2,
692            0x8b1a52e0a90f59ed,
693            0xb966ce3bc2108b13,
694            0xccc649c4b9532bf3,
695            0xf8d295b2ded9dc,
696        ])).unwrap(),
697        c1: Fq::from_repr(FqRepr([
698            0x977df6efcdaee0db,
699            0x946ae52d684fa7ed,
700            0xbe203411c66fb3a5,
701            0xb3f8afc0ee248cad,
702            0x4e464dea5bcfd41e,
703            0x12d1137b8a6a837,
704        ])).unwrap(),
705    };
706    a.frobenius_map(0);
707    assert_eq!(
708        a,
709        Fq2 {
710            c0: Fq::from_repr(FqRepr([
711                0x2d0078036923ffc7,
712                0x11e59ea221a3b6d2,
713                0x8b1a52e0a90f59ed,
714                0xb966ce3bc2108b13,
715                0xccc649c4b9532bf3,
716                0xf8d295b2ded9dc
717            ])).unwrap(),
718            c1: Fq::from_repr(FqRepr([
719                0x977df6efcdaee0db,
720                0x946ae52d684fa7ed,
721                0xbe203411c66fb3a5,
722                0xb3f8afc0ee248cad,
723                0x4e464dea5bcfd41e,
724                0x12d1137b8a6a837
725            ])).unwrap(),
726        }
727    );
728    a.frobenius_map(1);
729    assert_eq!(
730        a,
731        Fq2 {
732            c0: Fq::from_repr(FqRepr([
733                0x2d0078036923ffc7,
734                0x11e59ea221a3b6d2,
735                0x8b1a52e0a90f59ed,
736                0xb966ce3bc2108b13,
737                0xccc649c4b9532bf3,
738                0xf8d295b2ded9dc
739            ])).unwrap(),
740            c1: Fq::from_repr(FqRepr([
741                0x228109103250c9d0,
742                0x8a411ad149045812,
743                0xa9109e8f3041427e,
744                0xb07e9bc405608611,
745                0xfcd559cbe77bd8b8,
746                0x18d400b280d93e62
747            ])).unwrap(),
748        }
749    );
750    a.frobenius_map(1);
751    assert_eq!(
752        a,
753        Fq2 {
754            c0: Fq::from_repr(FqRepr([
755                0x2d0078036923ffc7,
756                0x11e59ea221a3b6d2,
757                0x8b1a52e0a90f59ed,
758                0xb966ce3bc2108b13,
759                0xccc649c4b9532bf3,
760                0xf8d295b2ded9dc
761            ])).unwrap(),
762            c1: Fq::from_repr(FqRepr([
763                0x977df6efcdaee0db,
764                0x946ae52d684fa7ed,
765                0xbe203411c66fb3a5,
766                0xb3f8afc0ee248cad,
767                0x4e464dea5bcfd41e,
768                0x12d1137b8a6a837
769            ])).unwrap(),
770        }
771    );
772    a.frobenius_map(2);
773    assert_eq!(
774        a,
775        Fq2 {
776            c0: Fq::from_repr(FqRepr([
777                0x2d0078036923ffc7,
778                0x11e59ea221a3b6d2,
779                0x8b1a52e0a90f59ed,
780                0xb966ce3bc2108b13,
781                0xccc649c4b9532bf3,
782                0xf8d295b2ded9dc
783            ])).unwrap(),
784            c1: Fq::from_repr(FqRepr([
785                0x977df6efcdaee0db,
786                0x946ae52d684fa7ed,
787                0xbe203411c66fb3a5,
788                0xb3f8afc0ee248cad,
789                0x4e464dea5bcfd41e,
790                0x12d1137b8a6a837
791            ])).unwrap(),
792        }
793    );
794}
795
796#[test]
797fn test_fq2_sqrt() {
798    use super::fq::FqRepr;
799    use ff::PrimeField;
800
801    assert_eq!(
802        Fq2 {
803            c0: Fq::from_repr(FqRepr([
804                0x476b4c309720e227,
805                0x34c2d04faffdab6,
806                0xa57e6fc1bab51fd9,
807                0xdb4a116b5bf74aa1,
808                0x1e58b2159dfe10e2,
809                0x7ca7da1f13606ac
810            ])).unwrap(),
811            c1: Fq::from_repr(FqRepr([
812                0xfa8de88b7516d2c3,
813                0x371a75ed14f41629,
814                0x4cec2dca577a3eb6,
815                0x212611bca4e99121,
816                0x8ee5394d77afb3d,
817                0xec92336650e49d5
818            ])).unwrap(),
819        }.sqrt()
820            .unwrap(),
821        Fq2 {
822            c0: Fq::from_repr(FqRepr([
823                0x40b299b2704258c5,
824                0x6ef7de92e8c68b63,
825                0x6d2ddbe552203e82,
826                0x8d7f1f723d02c1d3,
827                0x881b3e01b611c070,
828                0x10f6963bbad2ebc5
829            ])).unwrap(),
830            c1: Fq::from_repr(FqRepr([
831                0xc099534fc209e752,
832                0x7670594665676447,
833                0x28a20faed211efe7,
834                0x6b852aeaf2afcb1b,
835                0xa4c93b08105d71a9,
836                0x8d7cfff94216330
837            ])).unwrap(),
838        }
839    );
840
841    assert_eq!(
842        Fq2 {
843            c0: Fq::from_repr(FqRepr([
844                0xb9f78429d1517a6b,
845                0x1eabfffeb153ffff,
846                0x6730d2a0f6b0f624,
847                0x64774b84f38512bf,
848                0x4b1ba7b6434bacd7,
849                0x1a0111ea397fe69a
850            ])).unwrap(),
851            c1: Fq::zero(),
852        }.sqrt()
853            .unwrap(),
854        Fq2 {
855            c0: Fq::zero(),
856            c1: Fq::from_repr(FqRepr([
857                0xb9fefffffd4357a3,
858                0x1eabfffeb153ffff,
859                0x6730d2a0f6b0f624,
860                0x64774b84f38512bf,
861                0x4b1ba7b6434bacd7,
862                0x1a0111ea397fe69a
863            ])).unwrap(),
864        }
865    );
866}
867
868#[test]
869fn test_fq2_legendre() {
870    use ff::LegendreSymbol::*;
871
872    assert_eq!(Zero, Fq2::zero().legendre());
873    // i^2 = -1
874    let mut m1 = Fq2::one();
875    m1.negate();
876    assert_eq!(QuadraticResidue, m1.legendre());
877    m1.mul_by_nonresidue();
878    assert_eq!(QuadraticNonResidue, m1.legendre());
879}
880
881#[cfg(test)]
882use rand::{SeedableRng, XorShiftRng};
883
884#[test]
885fn test_fq2_mul_nonresidue() {
886    let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
887
888    let nqr = Fq2 {
889        c0: Fq::one(),
890        c1: Fq::one(),
891    };
892
893    for _ in 0..1000 {
894        let mut a = Fq2::rand(&mut rng);
895        let mut b = a;
896        a.mul_by_nonresidue();
897        b.mul_assign(&nqr);
898
899        assert_eq!(a, b);
900    }
901}
902
903#[test]
904fn fq2_field_tests() {
905    use ff::PrimeField;
906
907    crate::tests::field::random_field_tests::<Fq2>();
908    crate::tests::field::random_sqrt_tests::<Fq2>();
909    crate::tests::field::random_frobenius_tests::<Fq2, _>(super::fq::Fq::char(), 13);
910}