1use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
2use digest::generic_array::{
3 typenum::{U128, U64},
4 GenericArray,
5};
6use ff::{Field, SqrtField};
7use hash_to_field::{BaseFromRO, FromRO};
8use signum::{Sgn0Result, Signum0};
9use std::cmp::Ordering;
10
11#[derive(Copy, Clone, Debug, Eq, PartialEq, Zeroize)]
13pub struct Fq2 {
14 pub c0: Fq,
15 pub c1: Fq,
16}
17
18impl ::std::fmt::Display for Fq2 {
19 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
20 write!(f, "Fq2({} + {} * u)", self.c0, self.c1)
21 }
22}
23
24impl Ord for Fq2 {
26 #[inline(always)]
27 fn cmp(&self, other: &Fq2) -> Ordering {
28 match self.c1.cmp(&other.c1) {
29 Ordering::Greater => Ordering::Greater,
30 Ordering::Less => Ordering::Less,
31 Ordering::Equal => self.c0.cmp(&other.c0),
32 }
33 }
34}
35
36impl PartialOrd for Fq2 {
37 #[inline(always)]
38 fn partial_cmp(&self, other: &Fq2) -> Option<Ordering> {
39 Some(self.cmp(other))
40 }
41}
42
43impl Fq2 {
44 pub fn mul_by_nonresidue(&mut self) {
46 let t0 = self.c0;
47 self.c0.sub_assign(&self.c1);
48 self.c1.add_assign(&t0);
49 }
50
51 pub fn norm(&self) -> Fq {
53 let mut t0 = self.c0;
54 let mut t1 = self.c1;
55 t0.square();
56 t1.square();
57 t1.add_assign(&t0);
58
59 t1
60 }
61}
62
63impl Field for Fq2 {
64 fn random<R: rand_core::RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
65 Fq2 {
66 c0: Fq::random(rng),
67 c1: Fq::random(rng),
68 }
69 }
70 fn zero() -> Self {
71 Fq2 {
72 c0: Fq::zero(),
73 c1: Fq::zero(),
74 }
75 }
76
77 fn one() -> Self {
78 Fq2 {
79 c0: Fq::one(),
80 c1: Fq::zero(),
81 }
82 }
83
84 fn is_zero(&self) -> bool {
85 self.c0.is_zero() && self.c1.is_zero()
86 }
87
88 fn square(&mut self) {
89 let mut ab = self.c0;
90 ab.mul_assign(&self.c1);
91 let mut c0c1 = self.c0;
92 c0c1.add_assign(&self.c1);
93 let mut c0 = self.c1;
94 c0.negate();
95 c0.add_assign(&self.c0);
96 c0.mul_assign(&c0c1);
97 c0.sub_assign(&ab);
98 self.c1 = ab;
99 self.c1.add_assign(&ab);
100 c0.add_assign(&ab);
101 self.c0 = c0;
102 }
103
104 fn double(&mut self) {
105 self.c0.double();
106 self.c1.double();
107 }
108
109 fn negate(&mut self) {
110 self.c0.negate();
111 self.c1.negate();
112 }
113
114 fn add_assign(&mut self, other: &Self) {
115 self.c0.add_assign(&other.c0);
116 self.c1.add_assign(&other.c1);
117 }
118
119 fn sub_assign(&mut self, other: &Self) {
120 self.c0.sub_assign(&other.c0);
121 self.c1.sub_assign(&other.c1);
122 }
123
124 fn mul_assign(&mut self, other: &Self) {
125 let mut aa = self.c0;
126 aa.mul_assign(&other.c0);
127 let mut bb = self.c1;
128 bb.mul_assign(&other.c1);
129 let mut o = other.c0;
130 o.add_assign(&other.c1);
131 self.c1.add_assign(&self.c0);
132 self.c1.mul_assign(&o);
133 self.c1.sub_assign(&aa);
134 self.c1.sub_assign(&bb);
135 self.c0 = aa;
136 self.c0.sub_assign(&bb);
137 }
138
139 fn inverse(&self) -> Option<Self> {
140 let mut t1 = self.c1;
141 t1.square();
142 let mut t0 = self.c0;
143 t0.square();
144 t0.add_assign(&t1);
145 t0.inverse().map(|t| {
146 let mut tmp = Fq2 {
147 c0: self.c0,
148 c1: self.c1,
149 };
150 tmp.c0.mul_assign(&t);
151 tmp.c1.mul_assign(&t);
152 tmp.c1.negate();
153
154 tmp
155 })
156 }
157
158 fn frobenius_map(&mut self, power: usize) {
159 self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]);
160 }
161}
162
163impl SqrtField for Fq2 {
164 fn legendre(&self) -> ::ff::LegendreSymbol {
165 self.norm().legendre()
166 }
167
168 fn sqrt(&self) -> Option<Self> {
169 if self.is_zero() {
172 Some(Self::zero())
173 } else {
174 let mut a1 = self.pow([
176 0xee7fbfffffffeaaa,
177 0x7aaffffac54ffff,
178 0xd9cc34a83dac3d89,
179 0xd91dd2e13ce144af,
180 0x92c6e9ed90d2eb35,
181 0x680447a8e5ff9a6,
182 ]);
183 let mut alpha = a1;
184 alpha.square();
185 alpha.mul_assign(self);
186 let mut a0 = alpha;
187 a0.frobenius_map(1);
188 a0.mul_assign(&alpha);
189
190 let neg1 = Fq2 {
191 c0: NEGATIVE_ONE,
192 c1: Fq::zero(),
193 };
194
195 if a0 == neg1 {
196 None
197 } else {
198 a1.mul_assign(self);
199
200 if alpha == neg1 {
201 a1.mul_assign(&Fq2 {
202 c0: Fq::zero(),
203 c1: Fq::one(),
204 });
205 } else {
206 alpha.add_assign(&Fq2::one());
207 alpha = alpha.pow([
209 0xdcff7fffffffd555,
210 0xf55ffff58a9ffff,
211 0xb39869507b587b12,
212 0xb23ba5c279c2895f,
213 0x258dd3db21a5d66b,
214 0xd0088f51cbff34d,
215 ]);
216 a1.mul_assign(&alpha);
217 }
218
219 Some(a1)
220 }
221 }
222 }
223}
224
225impl FromRO for Fq2 {
227 type Length = U128;
228
229 fn from_ro(okm: &GenericArray<u8, U128>) -> Fq2 {
230 let c0 = Fq::from_okm(GenericArray::<u8, U64>::from_slice(&okm[..64]));
231 let c1 = Fq::from_okm(GenericArray::<u8, U64>::from_slice(&okm[64..]));
232 Fq2 { c0, c1 }
233 }
234}
235
236impl Signum0 for Fq2 {
237 fn sgn0(&self) -> Sgn0Result {
238 let Fq2 { c0, c1 } = self;
239 if c1.is_zero() {
240 c0.sgn0()
241 } else {
242 c1.sgn0()
243 }
244 }
245}
246
247#[test]
248fn test_fq2_ordering() {
249 let mut a = Fq2 {
250 c0: Fq::zero(),
251 c1: Fq::zero(),
252 };
253
254 let mut b = a;
255
256 assert!(a.cmp(&b) == Ordering::Equal);
257 b.c0.add_assign(&Fq::one());
258 assert!(a.cmp(&b) == Ordering::Less);
259 a.c0.add_assign(&Fq::one());
260 assert!(a.cmp(&b) == Ordering::Equal);
261 b.c1.add_assign(&Fq::one());
262 assert!(a.cmp(&b) == Ordering::Less);
263 a.c0.add_assign(&Fq::one());
264 assert!(a.cmp(&b) == Ordering::Less);
265 a.c1.add_assign(&Fq::one());
266 assert!(a.cmp(&b) == Ordering::Greater);
267 b.c0.add_assign(&Fq::one());
268 assert!(a.cmp(&b) == Ordering::Equal);
269}
270
271#[test]
272fn test_fq2_basics() {
273 assert_eq!(
274 Fq2 {
275 c0: Fq::zero(),
276 c1: Fq::zero(),
277 },
278 Fq2::zero()
279 );
280 assert_eq!(
281 Fq2 {
282 c0: Fq::one(),
283 c1: Fq::zero(),
284 },
285 Fq2::one()
286 );
287 assert!(Fq2::zero().is_zero());
288 assert!(!Fq2::one().is_zero());
289 assert!(!Fq2 {
290 c0: Fq::zero(),
291 c1: Fq::one(),
292 }
293 .is_zero());
294}
295
296#[test]
297fn test_fq2_squaring() {
298 use super::fq::FqRepr;
299 use ff::PrimeField;
300
301 let mut a = Fq2 {
302 c0: Fq::one(),
303 c1: Fq::one(),
304 }; a.square();
306 assert_eq!(
307 a,
308 Fq2 {
309 c0: Fq::zero(),
310 c1: Fq::from_repr(FqRepr::from(2)).unwrap(),
311 }
312 ); let mut a = Fq2 {
315 c0: Fq::zero(),
316 c1: Fq::one(),
317 }; a.square();
319 assert_eq!(a, {
320 let mut neg1 = Fq::one();
321 neg1.negate();
322 Fq2 {
323 c0: neg1,
324 c1: Fq::zero(),
325 }
326 }); let mut a = Fq2 {
329 c0: Fq::from_repr(FqRepr([
330 0x9c2c6309bbf8b598,
331 0x4eef5c946536f602,
332 0x90e34aab6fb6a6bd,
333 0xf7f295a94e58ae7c,
334 0x41b76dcc1c3fbe5e,
335 0x7080c5fa1d8e042,
336 ]))
337 .unwrap(),
338 c1: Fq::from_repr(FqRepr([
339 0x38f473b3c870a4ab,
340 0x6ad3291177c8c7e5,
341 0xdac5a4c911a4353e,
342 0xbfb99020604137a0,
343 0xfc58a7b7be815407,
344 0x10d1615e75250a21,
345 ]))
346 .unwrap(),
347 };
348 a.square();
349 assert_eq!(
350 a,
351 Fq2 {
352 c0: Fq::from_repr(FqRepr([
353 0xf262c28c538bcf68,
354 0xb9f2a66eae1073ba,
355 0xdc46ab8fad67ae0,
356 0xcb674157618da176,
357 0x4cf17b5893c3d327,
358 0x7eac81369c43361
359 ]))
360 .unwrap(),
361 c1: Fq::from_repr(FqRepr([
362 0xc1579cf58e980cf8,
363 0xa23eb7e12dd54d98,
364 0xe75138bce4cec7aa,
365 0x38d0d7275a9689e1,
366 0x739c983042779a65,
367 0x1542a61c8a8db994
368 ]))
369 .unwrap(),
370 }
371 );
372}
373
374#[test]
375fn test_fq2_mul() {
376 use super::fq::FqRepr;
377 use ff::PrimeField;
378
379 let mut a = Fq2 {
380 c0: Fq::from_repr(FqRepr([
381 0x85c9f989e1461f03,
382 0xa2e33c333449a1d6,
383 0x41e461154a7354a3,
384 0x9ee53e7e84d7532e,
385 0x1c202d8ed97afb45,
386 0x51d3f9253e2516f,
387 ]))
388 .unwrap(),
389 c1: Fq::from_repr(FqRepr([
390 0xa7348a8b511aedcf,
391 0x143c215d8176b319,
392 0x4cc48081c09b8903,
393 0x9533e4a9a5158be,
394 0x7a5e1ecb676d65f9,
395 0x180c3ee46656b008,
396 ]))
397 .unwrap(),
398 };
399 a.mul_assign(&Fq2 {
400 c0: Fq::from_repr(FqRepr([
401 0xe21f9169805f537e,
402 0xfc87e62e179c285d,
403 0x27ece175be07a531,
404 0xcd460f9f0c23e430,
405 0x6c9110292bfa409,
406 0x2c93a72eb8af83e,
407 ]))
408 .unwrap(),
409 c1: Fq::from_repr(FqRepr([
410 0x4b1c3f936d8992d4,
411 0x1d2a72916dba4c8a,
412 0x8871c508658d1e5f,
413 0x57a06d3135a752ae,
414 0x634cd3c6c565096d,
415 0x19e17334d4e93558,
416 ]))
417 .unwrap(),
418 });
419 assert_eq!(
420 a,
421 Fq2 {
422 c0: Fq::from_repr(FqRepr([
423 0x95b5127e6360c7e4,
424 0xde29c31a19a6937e,
425 0xf61a96dacf5a39bc,
426 0x5511fe4d84ee5f78,
427 0x5310a202d92f9963,
428 0x1751afbe166e5399
429 ]))
430 .unwrap(),
431 c1: Fq::from_repr(FqRepr([
432 0x84af0e1bd630117a,
433 0x6c63cd4da2c2aa7,
434 0x5ba6e5430e883d40,
435 0xc975106579c275ee,
436 0x33a9ac82ce4c5083,
437 0x1ef1a36c201589d
438 ]))
439 .unwrap(),
440 }
441 );
442}
443
444#[test]
445fn test_fq2_inverse() {
446 use super::fq::FqRepr;
447 use ff::PrimeField;
448
449 assert!(Fq2::zero().inverse().is_none());
450
451 let a = Fq2 {
452 c0: Fq::from_repr(FqRepr([
453 0x85c9f989e1461f03,
454 0xa2e33c333449a1d6,
455 0x41e461154a7354a3,
456 0x9ee53e7e84d7532e,
457 0x1c202d8ed97afb45,
458 0x51d3f9253e2516f,
459 ]))
460 .unwrap(),
461 c1: Fq::from_repr(FqRepr([
462 0xa7348a8b511aedcf,
463 0x143c215d8176b319,
464 0x4cc48081c09b8903,
465 0x9533e4a9a5158be,
466 0x7a5e1ecb676d65f9,
467 0x180c3ee46656b008,
468 ]))
469 .unwrap(),
470 };
471 let a = a.inverse().unwrap();
472 assert_eq!(
473 a,
474 Fq2 {
475 c0: Fq::from_repr(FqRepr([
476 0x70300f9bcb9e594,
477 0xe5ecda5fdafddbb2,
478 0x64bef617d2915a8f,
479 0xdfba703293941c30,
480 0xa6c3d8f9586f2636,
481 0x1351ef01941b70c4
482 ]))
483 .unwrap(),
484 c1: Fq::from_repr(FqRepr([
485 0x8c39fd76a8312cb4,
486 0x15d7b6b95defbff0,
487 0x947143f89faedee9,
488 0xcbf651a0f367afb2,
489 0xdf4e54f0d3ef15a6,
490 0x103bdf241afb0019
491 ]))
492 .unwrap(),
493 }
494 );
495}
496
497#[test]
498fn test_fq2_addition() {
499 use super::fq::FqRepr;
500 use ff::PrimeField;
501
502 let mut a = Fq2 {
503 c0: Fq::from_repr(FqRepr([
504 0x2d0078036923ffc7,
505 0x11e59ea221a3b6d2,
506 0x8b1a52e0a90f59ed,
507 0xb966ce3bc2108b13,
508 0xccc649c4b9532bf3,
509 0xf8d295b2ded9dc,
510 ]))
511 .unwrap(),
512 c1: Fq::from_repr(FqRepr([
513 0x977df6efcdaee0db,
514 0x946ae52d684fa7ed,
515 0xbe203411c66fb3a5,
516 0xb3f8afc0ee248cad,
517 0x4e464dea5bcfd41e,
518 0x12d1137b8a6a837,
519 ]))
520 .unwrap(),
521 };
522 a.add_assign(&Fq2 {
523 c0: Fq::from_repr(FqRepr([
524 0x619a02d78dc70ef2,
525 0xb93adfc9119e33e8,
526 0x4bf0b99a9f0dca12,
527 0x3b88899a42a6318f,
528 0x986a4a62fa82a49d,
529 0x13ce433fa26027f5,
530 ]))
531 .unwrap(),
532 c1: Fq::from_repr(FqRepr([
533 0x66323bf80b58b9b9,
534 0xa1379b6facf6e596,
535 0x402aef1fb797e32f,
536 0x2236f55246d0d44d,
537 0x4c8c1800eb104566,
538 0x11d6e20e986c2085,
539 ]))
540 .unwrap(),
541 });
542 assert_eq!(
543 a,
544 Fq2 {
545 c0: Fq::from_repr(FqRepr([
546 0x8e9a7adaf6eb0eb9,
547 0xcb207e6b3341eaba,
548 0xd70b0c7b481d23ff,
549 0xf4ef57d604b6bca2,
550 0x65309427b3d5d090,
551 0x14c715d5553f01d2
552 ]))
553 .unwrap(),
554 c1: Fq::from_repr(FqRepr([
555 0xfdb032e7d9079a94,
556 0x35a2809d15468d83,
557 0xfe4b23317e0796d5,
558 0xd62fa51334f560fa,
559 0x9ad265eb46e01984,
560 0x1303f3465112c8bc
561 ]))
562 .unwrap(),
563 }
564 );
565}
566
567#[test]
568fn test_fq2_subtraction() {
569 use super::fq::FqRepr;
570 use ff::PrimeField;
571
572 let mut a = Fq2 {
573 c0: Fq::from_repr(FqRepr([
574 0x2d0078036923ffc7,
575 0x11e59ea221a3b6d2,
576 0x8b1a52e0a90f59ed,
577 0xb966ce3bc2108b13,
578 0xccc649c4b9532bf3,
579 0xf8d295b2ded9dc,
580 ]))
581 .unwrap(),
582 c1: Fq::from_repr(FqRepr([
583 0x977df6efcdaee0db,
584 0x946ae52d684fa7ed,
585 0xbe203411c66fb3a5,
586 0xb3f8afc0ee248cad,
587 0x4e464dea5bcfd41e,
588 0x12d1137b8a6a837,
589 ]))
590 .unwrap(),
591 };
592 a.sub_assign(&Fq2 {
593 c0: Fq::from_repr(FqRepr([
594 0x619a02d78dc70ef2,
595 0xb93adfc9119e33e8,
596 0x4bf0b99a9f0dca12,
597 0x3b88899a42a6318f,
598 0x986a4a62fa82a49d,
599 0x13ce433fa26027f5,
600 ]))
601 .unwrap(),
602 c1: Fq::from_repr(FqRepr([
603 0x66323bf80b58b9b9,
604 0xa1379b6facf6e596,
605 0x402aef1fb797e32f,
606 0x2236f55246d0d44d,
607 0x4c8c1800eb104566,
608 0x11d6e20e986c2085,
609 ]))
610 .unwrap(),
611 });
612 assert_eq!(
613 a,
614 Fq2 {
615 c0: Fq::from_repr(FqRepr([
616 0x8565752bdb5c9b80,
617 0x7756bed7c15982e9,
618 0xa65a6be700b285fe,
619 0xe255902672ef6c43,
620 0x7f77a718021c342d,
621 0x72ba14049fe9881
622 ]))
623 .unwrap(),
624 c1: Fq::from_repr(FqRepr([
625 0xeb4abaf7c255d1cd,
626 0x11df49bc6cacc256,
627 0xe52617930588c69a,
628 0xf63905f39ad8cb1f,
629 0x4cd5dd9fb40b3b8f,
630 0x957411359ba6e4c
631 ]))
632 .unwrap(),
633 }
634 );
635}
636
637#[test]
638fn test_fq2_negation() {
639 use super::fq::FqRepr;
640 use ff::PrimeField;
641
642 let mut a = Fq2 {
643 c0: Fq::from_repr(FqRepr([
644 0x2d0078036923ffc7,
645 0x11e59ea221a3b6d2,
646 0x8b1a52e0a90f59ed,
647 0xb966ce3bc2108b13,
648 0xccc649c4b9532bf3,
649 0xf8d295b2ded9dc,
650 ]))
651 .unwrap(),
652 c1: Fq::from_repr(FqRepr([
653 0x977df6efcdaee0db,
654 0x946ae52d684fa7ed,
655 0xbe203411c66fb3a5,
656 0xb3f8afc0ee248cad,
657 0x4e464dea5bcfd41e,
658 0x12d1137b8a6a837,
659 ]))
660 .unwrap(),
661 };
662 a.negate();
663 assert_eq!(
664 a,
665 Fq2 {
666 c0: Fq::from_repr(FqRepr([
667 0x8cfe87fc96dbaae4,
668 0xcc6615c8fb0492d,
669 0xdc167fc04da19c37,
670 0xab107d49317487ab,
671 0x7e555df189f880e3,
672 0x19083f5486a10cbd
673 ]))
674 .unwrap(),
675 c1: Fq::from_repr(FqRepr([
676 0x228109103250c9d0,
677 0x8a411ad149045812,
678 0xa9109e8f3041427e,
679 0xb07e9bc405608611,
680 0xfcd559cbe77bd8b8,
681 0x18d400b280d93e62
682 ]))
683 .unwrap(),
684 }
685 );
686}
687
688#[test]
689fn test_fq2_doubling() {
690 use super::fq::FqRepr;
691 use ff::PrimeField;
692
693 let mut a = Fq2 {
694 c0: Fq::from_repr(FqRepr([
695 0x2d0078036923ffc7,
696 0x11e59ea221a3b6d2,
697 0x8b1a52e0a90f59ed,
698 0xb966ce3bc2108b13,
699 0xccc649c4b9532bf3,
700 0xf8d295b2ded9dc,
701 ]))
702 .unwrap(),
703 c1: Fq::from_repr(FqRepr([
704 0x977df6efcdaee0db,
705 0x946ae52d684fa7ed,
706 0xbe203411c66fb3a5,
707 0xb3f8afc0ee248cad,
708 0x4e464dea5bcfd41e,
709 0x12d1137b8a6a837,
710 ]))
711 .unwrap(),
712 };
713 a.double();
714 assert_eq!(
715 a,
716 Fq2 {
717 c0: Fq::from_repr(FqRepr([
718 0x5a00f006d247ff8e,
719 0x23cb3d4443476da4,
720 0x1634a5c1521eb3da,
721 0x72cd9c7784211627,
722 0x998c938972a657e7,
723 0x1f1a52b65bdb3b9
724 ]))
725 .unwrap(),
726 c1: Fq::from_repr(FqRepr([
727 0x2efbeddf9b5dc1b6,
728 0x28d5ca5ad09f4fdb,
729 0x7c4068238cdf674b,
730 0x67f15f81dc49195b,
731 0x9c8c9bd4b79fa83d,
732 0x25a226f714d506e
733 ]))
734 .unwrap(),
735 }
736 );
737}
738
739#[test]
740fn test_fq2_frobenius_map() {
741 use super::fq::FqRepr;
742 use ff::PrimeField;
743
744 let mut a = Fq2 {
745 c0: Fq::from_repr(FqRepr([
746 0x2d0078036923ffc7,
747 0x11e59ea221a3b6d2,
748 0x8b1a52e0a90f59ed,
749 0xb966ce3bc2108b13,
750 0xccc649c4b9532bf3,
751 0xf8d295b2ded9dc,
752 ]))
753 .unwrap(),
754 c1: Fq::from_repr(FqRepr([
755 0x977df6efcdaee0db,
756 0x946ae52d684fa7ed,
757 0xbe203411c66fb3a5,
758 0xb3f8afc0ee248cad,
759 0x4e464dea5bcfd41e,
760 0x12d1137b8a6a837,
761 ]))
762 .unwrap(),
763 };
764 a.frobenius_map(0);
765 assert_eq!(
766 a,
767 Fq2 {
768 c0: Fq::from_repr(FqRepr([
769 0x2d0078036923ffc7,
770 0x11e59ea221a3b6d2,
771 0x8b1a52e0a90f59ed,
772 0xb966ce3bc2108b13,
773 0xccc649c4b9532bf3,
774 0xf8d295b2ded9dc
775 ]))
776 .unwrap(),
777 c1: Fq::from_repr(FqRepr([
778 0x977df6efcdaee0db,
779 0x946ae52d684fa7ed,
780 0xbe203411c66fb3a5,
781 0xb3f8afc0ee248cad,
782 0x4e464dea5bcfd41e,
783 0x12d1137b8a6a837
784 ]))
785 .unwrap(),
786 }
787 );
788 a.frobenius_map(1);
789 assert_eq!(
790 a,
791 Fq2 {
792 c0: Fq::from_repr(FqRepr([
793 0x2d0078036923ffc7,
794 0x11e59ea221a3b6d2,
795 0x8b1a52e0a90f59ed,
796 0xb966ce3bc2108b13,
797 0xccc649c4b9532bf3,
798 0xf8d295b2ded9dc
799 ]))
800 .unwrap(),
801 c1: Fq::from_repr(FqRepr([
802 0x228109103250c9d0,
803 0x8a411ad149045812,
804 0xa9109e8f3041427e,
805 0xb07e9bc405608611,
806 0xfcd559cbe77bd8b8,
807 0x18d400b280d93e62
808 ]))
809 .unwrap(),
810 }
811 );
812 a.frobenius_map(1);
813 assert_eq!(
814 a,
815 Fq2 {
816 c0: Fq::from_repr(FqRepr([
817 0x2d0078036923ffc7,
818 0x11e59ea221a3b6d2,
819 0x8b1a52e0a90f59ed,
820 0xb966ce3bc2108b13,
821 0xccc649c4b9532bf3,
822 0xf8d295b2ded9dc
823 ]))
824 .unwrap(),
825 c1: Fq::from_repr(FqRepr([
826 0x977df6efcdaee0db,
827 0x946ae52d684fa7ed,
828 0xbe203411c66fb3a5,
829 0xb3f8afc0ee248cad,
830 0x4e464dea5bcfd41e,
831 0x12d1137b8a6a837
832 ]))
833 .unwrap(),
834 }
835 );
836 a.frobenius_map(2);
837 assert_eq!(
838 a,
839 Fq2 {
840 c0: Fq::from_repr(FqRepr([
841 0x2d0078036923ffc7,
842 0x11e59ea221a3b6d2,
843 0x8b1a52e0a90f59ed,
844 0xb966ce3bc2108b13,
845 0xccc649c4b9532bf3,
846 0xf8d295b2ded9dc
847 ]))
848 .unwrap(),
849 c1: Fq::from_repr(FqRepr([
850 0x977df6efcdaee0db,
851 0x946ae52d684fa7ed,
852 0xbe203411c66fb3a5,
853 0xb3f8afc0ee248cad,
854 0x4e464dea5bcfd41e,
855 0x12d1137b8a6a837
856 ]))
857 .unwrap(),
858 }
859 );
860}
861
862#[test]
863fn test_fq2_sqrt() {
864 use super::fq::FqRepr;
865 use ff::PrimeField;
866
867 assert_eq!(
868 Fq2 {
869 c0: Fq::from_repr(FqRepr([
870 0x476b4c309720e227,
871 0x34c2d04faffdab6,
872 0xa57e6fc1bab51fd9,
873 0xdb4a116b5bf74aa1,
874 0x1e58b2159dfe10e2,
875 0x7ca7da1f13606ac
876 ]))
877 .unwrap(),
878 c1: Fq::from_repr(FqRepr([
879 0xfa8de88b7516d2c3,
880 0x371a75ed14f41629,
881 0x4cec2dca577a3eb6,
882 0x212611bca4e99121,
883 0x8ee5394d77afb3d,
884 0xec92336650e49d5
885 ]))
886 .unwrap(),
887 }
888 .sqrt()
889 .unwrap(),
890 Fq2 {
891 c0: Fq::from_repr(FqRepr([
892 0x40b299b2704258c5,
893 0x6ef7de92e8c68b63,
894 0x6d2ddbe552203e82,
895 0x8d7f1f723d02c1d3,
896 0x881b3e01b611c070,
897 0x10f6963bbad2ebc5
898 ]))
899 .unwrap(),
900 c1: Fq::from_repr(FqRepr([
901 0xc099534fc209e752,
902 0x7670594665676447,
903 0x28a20faed211efe7,
904 0x6b852aeaf2afcb1b,
905 0xa4c93b08105d71a9,
906 0x8d7cfff94216330
907 ]))
908 .unwrap(),
909 }
910 );
911
912 assert_eq!(
913 Fq2 {
914 c0: Fq::from_repr(FqRepr([
915 0xb9f78429d1517a6b,
916 0x1eabfffeb153ffff,
917 0x6730d2a0f6b0f624,
918 0x64774b84f38512bf,
919 0x4b1ba7b6434bacd7,
920 0x1a0111ea397fe69a
921 ]))
922 .unwrap(),
923 c1: Fq::zero(),
924 }
925 .sqrt()
926 .unwrap(),
927 Fq2 {
928 c0: Fq::zero(),
929 c1: Fq::from_repr(FqRepr([
930 0xb9fefffffd4357a3,
931 0x1eabfffeb153ffff,
932 0x6730d2a0f6b0f624,
933 0x64774b84f38512bf,
934 0x4b1ba7b6434bacd7,
935 0x1a0111ea397fe69a
936 ]))
937 .unwrap(),
938 }
939 );
940}
941
942#[test]
943fn test_fq2_legendre() {
944 use ff::LegendreSymbol::*;
945
946 assert_eq!(Zero, Fq2::zero().legendre());
947 let mut m1 = Fq2::one();
949 m1.negate();
950 assert_eq!(QuadraticResidue, m1.legendre());
951 m1.mul_by_nonresidue();
952 assert_eq!(QuadraticNonResidue, m1.legendre());
953}
954
955#[cfg(test)]
956use rand_core::SeedableRng;
957#[test]
960fn test_fq2_mul_nonresidue() {
961 let mut rng = rand_xorshift::XorShiftRng::from_seed([
962 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
963 0xe5,
964 ]);
965 let nqr = Fq2 {
966 c0: Fq::one(),
967 c1: Fq::one(),
968 };
969
970 for _ in 0..1000 {
971 let mut a = Fq2::random(&mut rng);
972 let mut b = a;
973 a.mul_by_nonresidue();
974 b.mul_assign(&nqr);
975
976 assert_eq!(a, b);
977 }
978}
979
980#[test]
981fn fq2_field_tests() {
982 use ff::PrimeField;
983
984 ::tests::field::random_field_tests::<Fq2>();
985 ::tests::field::random_sqrt_tests::<Fq2>();
986 ::tests::field::random_frobenius_tests::<Fq2, _>(super::fq::Fq::char(), 13);
987}
988
989#[test]
990fn test_fq2_hash_to_field_xof_shake128() {
991 use super::fq::FqRepr;
992 use ff::PrimeField;
993 use hash_to_field::{hash_to_field, ExpandMsgXof};
994 use sha3::Shake128;
995
996 let u = hash_to_field::<Fq2, ExpandMsgXof<Shake128>>(b"hello world", b"asdfqwerzxcv", 5);
997 let c0 = FqRepr([
998 0x83b44bd21d9176f9u64,
999 0x500e57bed444b495u64,
1000 0x99e7981c634e8dau64,
1001 0x534d01b15f9dfc5bu64,
1002 0xc28fdd7ba924fc24u64,
1003 0x149b57b053aba2f1u64,
1004 ]);
1005 let c1 = FqRepr([
1006 0x52a9e519f8d670u64,
1007 0x80836391c697e0f3u64,
1008 0xdef4327ec50c9e2fu64,
1009 0xfe1bd6918af282a6u64,
1010 0xdca9b63feb10ef5au64,
1011 0x2fe35c636602fc3u64,
1012 ]);
1013 let expect = Fq2 {
1014 c0: Fq::from_repr(c0).unwrap(),
1015 c1: Fq::from_repr(c1).unwrap(),
1016 };
1017 assert_eq!(u[0], expect);
1018 let c0 = FqRepr([
1019 0xc67cf203a4d5a146u64,
1020 0x71aa5c4048396b4u64,
1021 0x161a0f70a89fe76du64,
1022 0x480fc40ff5eb8cbau64,
1023 0xd137a2af45f88a31u64,
1024 0x18feaaf129abfb5cu64,
1025 ]);
1026 let c1 = FqRepr([
1027 0x5d269239a15f0beeu64,
1028 0x16515524243a806du64,
1029 0xaaf873bc4664cdf2u64,
1030 0xf31ca30fdde1a7dau64,
1031 0xbbc54a41017a7cd6u64,
1032 0x4774c213e3a6a7du64,
1033 ]);
1034 let expect = Fq2 {
1035 c0: Fq::from_repr(c0).unwrap(),
1036 c1: Fq::from_repr(c1).unwrap(),
1037 };
1038 assert_eq!(u[1], expect);
1039 let c0 = FqRepr([
1040 0xab6e3121ad020c5cu64,
1041 0x914a2813c62a0174u64,
1042 0x191f045dda39ef40u64,
1043 0x703fb6dd5708c2b7u64,
1044 0xf3b7e2d9c65aeb48u64,
1045 0x9a18b8b5a11e2beu64,
1046 ]);
1047 let c1 = FqRepr([
1048 0x99e3b69a05559fd3u64,
1049 0x5d634f8ea80270b1u64,
1050 0xcddc741e008d6f48u64,
1051 0xdc7cef61f00c12b1u64,
1052 0xc882bc3f8fa43794u64,
1053 0xdfe8ec63832446cu64,
1054 ]);
1055 let expect = Fq2 {
1056 c0: Fq::from_repr(c0).unwrap(),
1057 c1: Fq::from_repr(c1).unwrap(),
1058 };
1059 assert_eq!(u[2], expect);
1060 let c0 = FqRepr([
1061 0xbac4c5dd6b1e6cffu64,
1062 0x22a18330d743265eu64,
1063 0xd6e76b24b45ce456u64,
1064 0x5ddbe250869b02d9u64,
1065 0x70ba43cb49fa664cu64,
1066 0x11d12bfd064a9c07u64,
1067 ]);
1068 let c1 = FqRepr([
1069 0x46ab0b9ca2a026a8u64,
1070 0xe7c542debb3e8863u64,
1071 0x5beb58e25a0fba93u64,
1072 0xaac9366a1e124881u64,
1073 0xa17db74df34c6629u64,
1074 0x17d114628ff83e09u64,
1075 ]);
1076 let expect = Fq2 {
1077 c0: Fq::from_repr(c0).unwrap(),
1078 c1: Fq::from_repr(c1).unwrap(),
1079 };
1080 assert_eq!(u[3], expect);
1081 let c0 = FqRepr([
1082 0x4a02b77af5981d89u64,
1083 0x4691dce449e5475du64,
1084 0xf77a0e8e3982aaa6u64,
1085 0x2845134c4ca09dfbu64,
1086 0x28eb49d2df16aca4u64,
1087 0x117cfe69c07adc28u64,
1088 ]);
1089 let c1 = FqRepr([
1090 0x3f20eb109b30d170u64,
1091 0xf9db62febb5f6430u64,
1092 0xa8f532675eabfe7au64,
1093 0x553b99a8f101d00bu64,
1094 0x6707e210f918ccfbu64,
1095 0x17b968ebb357f7efu64,
1096 ]);
1097 let expect = Fq2 {
1098 c0: Fq::from_repr(c0).unwrap(),
1099 c1: Fq::from_repr(c1).unwrap(),
1100 };
1101 assert_eq!(u[4], expect);
1102}
1103
1104#[test]
1105fn test_fq2_hash_to_field_xmd_sha256() {
1106 use super::fq::FqRepr;
1107 use ff::PrimeField;
1108 use hash_to_field::{hash_to_field, ExpandMsgXmd};
1109 use sha2::Sha256;
1110
1111 let u = hash_to_field::<Fq2, ExpandMsgXmd<Sha256>>(b"hello world", b"asdfqwerzxcv", 5);
1112 let c0 = FqRepr([
1113 0x8013b8de1c730ccdu64,
1114 0xd19df445418e9f11u64,
1115 0xfae296c27ed04aceu64,
1116 0x1615a7c2e5dc8be4u64,
1117 0x69bc8b813ad8a2eeu64,
1118 0x621a916a3dd4ce7u64,
1119 ]);
1120 let c1 = FqRepr([
1121 0x2f21543bb7e13c15u64,
1122 0x79a2713c2a7471fbu64,
1123 0xccf4be18d3320ad2u64,
1124 0x63ff7b3318ee22a6u64,
1125 0x3a966c650ea0de7au64,
1126 0x6e92928bd785218u64,
1127 ]);
1128 let expect = Fq2 {
1129 c0: Fq::from_repr(c0).unwrap(),
1130 c1: Fq::from_repr(c1).unwrap(),
1131 };
1132 assert_eq!(u[0], expect);
1133 let c0 = FqRepr([
1134 0x4af5da7a38284cb9u64,
1135 0x49bdeb3e2d8c55a1u64,
1136 0x3cd8d0502207ae3du64,
1137 0x78b015530955cd51u64,
1138 0x1fdfd411fa9df1acu64,
1139 0x12b47d2dbfb8b7adu64,
1140 ]);
1141 let c1 = FqRepr([
1142 0xf0610ab9d30ace85u64,
1143 0x3cba524826095c26u64,
1144 0x2cca88714bd91543u64,
1145 0xb7809e759c9d0b96u64,
1146 0xb14c45e3c57e384u64,
1147 0x97bd219ee74f234u64,
1148 ]);
1149 let expect = Fq2 {
1150 c0: Fq::from_repr(c0).unwrap(),
1151 c1: Fq::from_repr(c1).unwrap(),
1152 };
1153 assert_eq!(u[1], expect);
1154 let c0 = FqRepr([
1155 0x1c9e390ec0ccfbd7u64,
1156 0xf9df7e6f2907332au64,
1157 0x135b4bcdbfc9b7bbu64,
1158 0x3aa60e647cc96fc8u64,
1159 0xa4c312e21e72f56cu64,
1160 0x145307a104618b9cu64,
1161 ]);
1162 let c1 = FqRepr([
1163 0x71e6f415f440a8ffu64,
1164 0x2e9636615390a691u64,
1165 0x3777508fadfae164u64,
1166 0x5bacbcfb0ee19ce3u64,
1167 0x203c81bd6ed27200u64,
1168 0xbc7bf3ad0854416u64,
1169 ]);
1170 let expect = Fq2 {
1171 c0: Fq::from_repr(c0).unwrap(),
1172 c1: Fq::from_repr(c1).unwrap(),
1173 };
1174 assert_eq!(u[2], expect);
1175 let c0 = FqRepr([
1176 0x4085662818b318fcu64,
1177 0xee1d6563dfc486b7u64,
1178 0x3f9294a50d8c8015u64,
1179 0xd4cbb000d6289d89u64,
1180 0x4fa081a472f02ddbu64,
1181 0x13f591c4a737afc2u64,
1182 ]);
1183 let c1 = FqRepr([
1184 0xb109a8ddbda9cdf7u64,
1185 0x4b37831e7daab6f2u64,
1186 0xec6dd9fe4bafa1f0u64,
1187 0x43d5ac76277b7584u64,
1188 0x17f548d1cd113567u64,
1189 0x12a35bed47708d4eu64,
1190 ]);
1191 let expect = Fq2 {
1192 c0: Fq::from_repr(c0).unwrap(),
1193 c1: Fq::from_repr(c1).unwrap(),
1194 };
1195 assert_eq!(u[3], expect);
1196 let c0 = FqRepr([
1197 0xa9c3b37df4203321u64,
1198 0x63a17215811a2de1u64,
1199 0xec72143f15671003u64,
1200 0x9f1e7c13ce8af1b9u64,
1201 0x1c164a2698a93988u64,
1202 0x160a417e29e70d97u64,
1203 ]);
1204 let c1 = FqRepr([
1205 0x3cd586733e0bab94u64,
1206 0xa335c8696e6af945u64,
1207 0xf9ab253161bc54e3u64,
1208 0xa53863e80553ccb8u64,
1209 0x43dca822001a0642u64,
1210 0x10b0a85bd661e512u64,
1211 ]);
1212 let expect = Fq2 {
1213 c0: Fq::from_repr(c0).unwrap(),
1214 c1: Fq::from_repr(c1).unwrap(),
1215 };
1216 assert_eq!(u[4], expect);
1217}
1218
1219#[test]
1220fn test_fq2_sgn0() {
1221 use super::fq::P_M1_OVER2;
1222
1223 assert_eq!(Fq2::zero().sgn0(), Sgn0Result::NonNegative);
1224 assert_eq!(Fq2::one().sgn0(), Sgn0Result::NonNegative);
1225 assert_eq!(
1226 Fq2 {
1227 c0: P_M1_OVER2,
1228 c1: Fq::zero()
1229 }
1230 .sgn0(),
1231 Sgn0Result::NonNegative
1232 );
1233 assert_eq!(
1234 Fq2 {
1235 c0: P_M1_OVER2,
1236 c1: Fq::one()
1237 }
1238 .sgn0(),
1239 Sgn0Result::NonNegative
1240 );
1241
1242 let p_p1_over2 = {
1243 let mut tmp = P_M1_OVER2;
1244 tmp.add_assign(&Fq::one());
1245 tmp
1246 };
1247 assert_eq!(
1248 Fq2 {
1249 c0: p_p1_over2,
1250 c1: Fq::zero()
1251 }
1252 .sgn0(),
1253 Sgn0Result::Negative
1254 );
1255 assert_eq!(
1256 Fq2 {
1257 c0: p_p1_over2,
1258 c1: Fq::one()
1259 }
1260 .sgn0(),
1261 Sgn0Result::NonNegative
1262 );
1263
1264 let m1 = {
1265 let mut tmp = Fq::one();
1266 tmp.negate();
1267 tmp
1268 };
1269 assert_eq!(
1270 Fq2 {
1271 c0: P_M1_OVER2,
1272 c1: m1
1273 }
1274 .sgn0(),
1275 Sgn0Result::Negative
1276 );
1277 assert_eq!(
1278 Fq2 {
1279 c0: p_p1_over2,
1280 c1: m1
1281 }
1282 .sgn0(),
1283 Sgn0Result::Negative
1284 );
1285 assert_eq!(
1286 Fq2 {
1287 c0: Fq::zero(),
1288 c1: m1
1289 }
1290 .sgn0(),
1291 Sgn0Result::Negative
1292 );
1293 assert_eq!(
1294 Fq2 {
1295 c0: P_M1_OVER2,
1296 c1: p_p1_over2
1297 }
1298 .sgn0(),
1299 Sgn0Result::Negative
1300 );
1301 assert_eq!(
1302 Fq2 {
1303 c0: p_p1_over2,
1304 c1: P_M1_OVER2
1305 }
1306 .sgn0(),
1307 Sgn0Result::NonNegative
1308 );
1309}