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#[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
20impl 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 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 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 if self.is_zero() {
171 Some(Self::zero())
172 } else {
173 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.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 }; a.square();
284 assert_eq!(
285 a,
286 Fq2 {
287 c0: Fq::zero(),
288 c1: Fq::from_repr(FqRepr::from(2)).unwrap(),
289 }
290 ); let mut a = Fq2 {
293 c0: Fq::zero(),
294 c1: Fq::one(),
295 }; 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 }); 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 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}