halo2curves_axiom/bls12_381/
fp12.rs

1//! Source: <https://github.com/privacy-scaling-explorations/bls12_381>
2
3use crate::{
4    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
5    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
6};
7
8use super::fp::*;
9use super::fp2::*;
10use super::fp6::*;
11
12use core::fmt;
13use core::ops::{Add, Mul, Neg, Sub};
14use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
15
16use rand_core::RngCore;
17
18/// This represents an element $c_0 + c_1 w$ of $\mathbb{F}_{p^12} = \mathbb{F}_{p^6}\[w\] / (w^2 - v)$.
19pub struct Fp12 {
20    pub c0: Fp6,
21    pub c1: Fp6,
22}
23
24impl From<Fp> for Fp12 {
25    fn from(f: Fp) -> Fp12 {
26        Fp12 {
27            c0: Fp6::from(f),
28            c1: Fp6::zero(),
29        }
30    }
31}
32
33impl From<Fp2> for Fp12 {
34    fn from(f: Fp2) -> Fp12 {
35        Fp12 {
36            c0: Fp6::from(f),
37            c1: Fp6::zero(),
38        }
39    }
40}
41
42impl From<Fp6> for Fp12 {
43    fn from(f: Fp6) -> Fp12 {
44        Fp12 {
45            c0: f,
46            c1: Fp6::zero(),
47        }
48    }
49}
50
51impl Eq for Fp12 {}
52impl PartialEq for Fp12 {
53    fn eq(&self, other: &Fp12) -> bool {
54        self.ct_eq(other).into()
55    }
56}
57
58impl Copy for Fp12 {}
59impl Clone for Fp12 {
60    #[inline]
61    fn clone(&self) -> Self {
62        *self
63    }
64}
65
66impl Default for Fp12 {
67    fn default() -> Self {
68        Fp12::zero()
69    }
70}
71
72#[cfg(feature = "zeroize")]
73impl zeroize::DefaultIsZeroes for Fp12 {}
74
75impl fmt::Debug for Fp12 {
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        write!(f, "{:?} + ({:?})*w", self.c0, self.c1)
78    }
79}
80
81impl ConditionallySelectable for Fp12 {
82    #[inline(always)]
83    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
84        Fp12 {
85            c0: Fp6::conditional_select(&a.c0, &b.c0, choice),
86            c1: Fp6::conditional_select(&a.c1, &b.c1, choice),
87        }
88    }
89}
90
91impl ConstantTimeEq for Fp12 {
92    #[inline(always)]
93    fn ct_eq(&self, other: &Self) -> Choice {
94        self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1)
95    }
96}
97
98impl Fp12 {
99    #[inline]
100    pub const fn zero() -> Self {
101        Fp12 {
102            c0: Fp6::zero(),
103            c1: Fp6::zero(),
104        }
105    }
106
107    #[inline]
108    pub const fn one() -> Self {
109        Fp12 {
110            c0: Fp6::one(),
111            c1: Fp6::zero(),
112        }
113    }
114
115    pub(crate) fn random(mut rng: impl RngCore) -> Self {
116        Fp12 {
117            c0: Fp6::random(&mut rng),
118            c1: Fp6::random(&mut rng),
119        }
120    }
121
122    pub fn double(&self) -> Self {
123        Self {
124            c0: self.c0.double(),
125            c1: self.c1.double(),
126        }
127    }
128
129    pub fn mul_by_014(&self, c0: &Fp2, c1: &Fp2, c4: &Fp2) -> Fp12 {
130        let aa = self.c0.mul_by_01(c0, c1);
131        let bb = self.c1.mul_by_1(c4);
132        let o = c1 + c4;
133        let c1 = self.c1 + self.c0;
134        let c1 = c1.mul_by_01(c0, &o);
135        let c1 = c1 - aa - bb;
136        let c0 = bb;
137        let c0 = c0.mul_by_nonresidue();
138        let c0 = c0 + aa;
139
140        Fp12 { c0, c1 }
141    }
142
143    #[inline(always)]
144    pub fn is_zero(&self) -> Choice {
145        self.c0.is_zero() & self.c1.is_zero()
146    }
147
148    #[inline(always)]
149    pub fn conjugate(&self) -> Self {
150        Fp12 {
151            c0: self.c0,
152            c1: -self.c1,
153        }
154    }
155
156    /// Raises this element to p.
157    #[inline(always)]
158    pub fn frobenius_map(&self) -> Self {
159        let c0 = self.c0.frobenius_map();
160        let c1 = self.c1.frobenius_map();
161
162        // c1 = c1 * (u + 1)^((p - 1) / 6)
163        let c1 = c1
164            * Fp6::from(Fp2 {
165                c0: Fp::from_raw_unchecked([
166                    0x0708_9552_b319_d465,
167                    0xc669_5f92_b50a_8313,
168                    0x97e8_3ccc_d117_228f,
169                    0xa35b_aeca_b2dc_29ee,
170                    0x1ce3_93ea_5daa_ce4d,
171                    0x08f2_220f_b0fb_66eb,
172                ]),
173                c1: Fp::from_raw_unchecked([
174                    0xb2f6_6aad_4ce5_d646,
175                    0x5842_a06b_fc49_7cec,
176                    0xcf48_95d4_2599_d394,
177                    0xc11b_9cba_40a8_e8d0,
178                    0x2e38_13cb_e5a0_de89,
179                    0x110e_efda_8884_7faf,
180                ]),
181            });
182
183        Fp12 { c0, c1 }
184    }
185
186    #[inline]
187    pub fn square(&self) -> Self {
188        let ab = self.c0 * self.c1;
189        let c0c1 = self.c0 + self.c1;
190        let c0 = self.c1.mul_by_nonresidue();
191        let c0 = c0 + self.c0;
192        let c0 = c0 * c0c1;
193        let c0 = c0 - ab;
194        let c1 = ab + ab;
195        let c0 = c0 - ab.mul_by_nonresidue();
196
197        Fp12 { c0, c1 }
198    }
199
200    pub fn invert(&self) -> CtOption<Self> {
201        (self.c0.square() - self.c1.square().mul_by_nonresidue())
202            .invert()
203            .map(|t| Fp12 {
204                c0: self.c0 * t,
205                c1: self.c1 * -t,
206            })
207    }
208}
209
210impl ff::Field for Fp12 {
211    const ZERO: Self = Self::zero();
212
213    const ONE: Self = Self::one();
214
215    fn random(mut rng: impl RngCore) -> Self {
216        Fp12 {
217            c0: Fp6::random(&mut rng),
218            c1: Fp6::random(&mut rng),
219        }
220    }
221
222    fn is_zero(&self) -> Choice {
223        self.c0.is_zero() & self.c1.is_zero()
224    }
225
226    fn square(&self) -> Self {
227        self.square()
228    }
229
230    fn double(&self) -> Self {
231        self.double()
232    }
233
234    fn sqrt(&self) -> CtOption<Self> {
235        unimplemented!()
236    }
237
238    fn invert(&self) -> CtOption<Self> {
239        self.invert()
240    }
241
242    fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) {
243        unimplemented!()
244    }
245}
246
247impl<'a, 'b> Mul<&'b Fp12> for &'a Fp12 {
248    type Output = Fp12;
249
250    #[inline]
251    fn mul(self, other: &'b Fp12) -> Self::Output {
252        let aa = self.c0 * other.c0;
253        let bb = self.c1 * other.c1;
254        let o = other.c0 + other.c1;
255        let c1 = self.c1 + self.c0;
256        let c1 = c1 * o;
257        let c1 = c1 - aa;
258        let c1 = c1 - bb;
259        let c0 = bb.mul_by_nonresidue();
260        let c0 = c0 + aa;
261
262        Fp12 { c0, c1 }
263    }
264}
265
266impl<'a, 'b> Add<&'b Fp12> for &'a Fp12 {
267    type Output = Fp12;
268
269    #[inline]
270    fn add(self, rhs: &'b Fp12) -> Self::Output {
271        Fp12 {
272            c0: self.c0 + rhs.c0,
273            c1: self.c1 + rhs.c1,
274        }
275    }
276}
277
278impl<'a> Neg for &'a Fp12 {
279    type Output = Fp12;
280
281    #[inline]
282    fn neg(self) -> Self::Output {
283        Fp12 {
284            c0: -self.c0,
285            c1: -self.c1,
286        }
287    }
288}
289
290impl Neg for Fp12 {
291    type Output = Fp12;
292
293    #[inline]
294    fn neg(self) -> Self::Output {
295        -&self
296    }
297}
298
299impl<'a, 'b> Sub<&'b Fp12> for &'a Fp12 {
300    type Output = Fp12;
301
302    #[inline]
303    fn sub(self, rhs: &'b Fp12) -> Self::Output {
304        Fp12 {
305            c0: self.c0 - rhs.c0,
306            c1: self.c1 - rhs.c1,
307        }
308    }
309}
310
311impl_binops_additive!(Fp12, Fp12);
312impl_binops_multiplicative!(Fp12, Fp12);
313crate::impl_sum_prod!(Fp12);
314
315// non_residue^((modulus^i-1)/6) for i=0,...,11
316pub const FROBENIUS_COEFF_FQ12_C1: [Fp2; 12] = [
317    // Fp2(u + 1)**(((q^0) - 1) / 6)
318    Fp2 {
319        c0: Fp([
320            0x760900000002fffd,
321            0xebf4000bc40c0002,
322            0x5f48985753c758ba,
323            0x77ce585370525745,
324            0x5c071a97a256ec6d,
325            0x15f65ec3fa80e493,
326        ]),
327        c1: Fp([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
328    },
329    // Fp2(u + 1)**(((q^1) - 1) / 6)
330    Fp2 {
331        c0: Fp([
332            0x7089552b319d465,
333            0xc6695f92b50a8313,
334            0x97e83cccd117228f,
335            0xa35baecab2dc29ee,
336            0x1ce393ea5daace4d,
337            0x8f2220fb0fb66eb,
338        ]),
339        c1: Fp([
340            0xb2f66aad4ce5d646,
341            0x5842a06bfc497cec,
342            0xcf4895d42599d394,
343            0xc11b9cba40a8e8d0,
344            0x2e3813cbe5a0de89,
345            0x110eefda88847faf,
346        ]),
347    },
348    // Fp2(u + 1)**(((q^2) - 1) / 6)
349    Fp2 {
350        c0: Fp([
351            0xecfb361b798dba3a,
352            0xc100ddb891865a2c,
353            0xec08ff1232bda8e,
354            0xd5c13cc6f1ca4721,
355            0x47222a47bf7b5c04,
356            0x110f184e51c5f59,
357        ]),
358        c1: Fp([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
359    },
360    // Fp2(u + 1)**(((q^3) - 1) / 6)
361    Fp2 {
362        c0: Fp([
363            0x3e2f585da55c9ad1,
364            0x4294213d86c18183,
365            0x382844c88b623732,
366            0x92ad2afd19103e18,
367            0x1d794e4fac7cf0b9,
368            0xbd592fc7d825ec8,
369        ]),
370        c1: Fp([
371            0x7bcfa7a25aa30fda,
372            0xdc17dec12a927e7c,
373            0x2f088dd86b4ebef1,
374            0xd1ca2087da74d4a7,
375            0x2da2596696cebc1d,
376            0xe2b7eedbbfd87d2,
377        ]),
378    },
379    // Fp2(u + 1)**(((q^4) - 1) / 6)
380    Fp2 {
381        c0: Fp([
382            0x30f1361b798a64e8,
383            0xf3b8ddab7ece5a2a,
384            0x16a8ca3ac61577f7,
385            0xc26a2ff874fd029b,
386            0x3636b76660701c6e,
387            0x51ba4ab241b6160,
388        ]),
389        c1: Fp([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
390    },
391    // Fp2(u + 1)**(((q^5) - 1) / 6)
392    Fp2 {
393        c0: Fp([
394            0x3726c30af242c66c,
395            0x7c2ac1aad1b6fe70,
396            0xa04007fbba4b14a2,
397            0xef517c3266341429,
398            0x95ba654ed2226b,
399            0x2e370eccc86f7dd,
400        ]),
401        c1: Fp([
402            0x82d83cf50dbce43f,
403            0xa2813e53df9d018f,
404            0xc6f0caa53c65e181,
405            0x7525cf528d50fe95,
406            0x4a85ed50f4798a6b,
407            0x171da0fd6cf8eebd,
408        ]),
409    },
410    // Fp2(u + 1)**(((q^6) - 1) / 6)
411    Fp2 {
412        c0: Fp([
413            0x43f5fffffffcaaae,
414            0x32b7fff2ed47fffd,
415            0x7e83a49a2e99d69,
416            0xeca8f3318332bb7a,
417            0xef148d1ea0f4c069,
418            0x40ab3263eff0206,
419        ]),
420        c1: Fp([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
421    },
422    // Fp2(u + 1)**(((q^7) - 1) / 6)
423    Fp2 {
424        c0: Fp([
425            0xb2f66aad4ce5d646,
426            0x5842a06bfc497cec,
427            0xcf4895d42599d394,
428            0xc11b9cba40a8e8d0,
429            0x2e3813cbe5a0de89,
430            0x110eefda88847faf,
431        ]),
432        c1: Fp([
433            0x7089552b319d465,
434            0xc6695f92b50a8313,
435            0x97e83cccd117228f,
436            0xa35baecab2dc29ee,
437            0x1ce393ea5daace4d,
438            0x8f2220fb0fb66eb,
439        ]),
440    },
441    // Fp2(u + 1)**(((q^8) - 1) / 6)
442    Fp2 {
443        c0: Fp([
444            0xcd03c9e48671f071,
445            0x5dab22461fcda5d2,
446            0x587042afd3851b95,
447            0x8eb60ebe01bacb9e,
448            0x3f97d6e83d050d2,
449            0x18f0206554638741,
450        ]),
451        c1: Fp([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
452    },
453    // Fp2(u + 1)**(((q^9) - 1) / 6)
454    Fp2 {
455        c0: Fp([
456            0x7bcfa7a25aa30fda,
457            0xdc17dec12a927e7c,
458            0x2f088dd86b4ebef1,
459            0xd1ca2087da74d4a7,
460            0x2da2596696cebc1d,
461            0xe2b7eedbbfd87d2,
462        ]),
463        c1: Fp([
464            0x3e2f585da55c9ad1,
465            0x4294213d86c18183,
466            0x382844c88b623732,
467            0x92ad2afd19103e18,
468            0x1d794e4fac7cf0b9,
469            0xbd592fc7d825ec8,
470        ]),
471    },
472    // Fp2(u + 1)**(((q^10) - 1) / 6)
473    Fp2 {
474        c0: Fp([
475            0x890dc9e4867545c3,
476            0x2af322533285a5d5,
477            0x50880866309b7e2c,
478            0xa20d1b8c7e881024,
479            0x14e4f04fe2db9068,
480            0x14e56d3f1564853a,
481        ]),
482        c1: Fp([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
483    },
484    // Fp2(u + 1)**(((q^11) - 1) / 6)
485    Fp2 {
486        c0: Fp([
487            0x82d83cf50dbce43f,
488            0xa2813e53df9d018f,
489            0xc6f0caa53c65e181,
490            0x7525cf528d50fe95,
491            0x4a85ed50f4798a6b,
492            0x171da0fd6cf8eebd,
493        ]),
494        c1: Fp([
495            0x3726c30af242c66c,
496            0x7c2ac1aad1b6fe70,
497            0xa04007fbba4b14a2,
498            0xef517c3266341429,
499            0x95ba654ed2226b,
500            0x2e370eccc86f7dd,
501        ]),
502    },
503];
504
505#[test]
506fn test_arithmetic() {
507    use super::fp::*;
508    use super::fp2::*;
509
510    let a = Fp12 {
511        c0: Fp6 {
512            c0: Fp2 {
513                c0: Fp::from_raw_unchecked([
514                    0x47f9_cb98_b1b8_2d58,
515                    0x5fe9_11eb_a3aa_1d9d,
516                    0x96bf_1b5f_4dd8_1db3,
517                    0x8100_d27c_c925_9f5b,
518                    0xafa2_0b96_7464_0eab,
519                    0x09bb_cea7_d8d9_497d,
520                ]),
521                c1: Fp::from_raw_unchecked([
522                    0x0303_cb98_b166_2daa,
523                    0xd931_10aa_0a62_1d5a,
524                    0xbfa9_820c_5be4_a468,
525                    0x0ba3_643e_cb05_a348,
526                    0xdc35_34bb_1f1c_25a6,
527                    0x06c3_05bb_19c0_e1c1,
528                ]),
529            },
530            c1: Fp2 {
531                c0: Fp::from_raw_unchecked([
532                    0x46f9_cb98_b162_d858,
533                    0x0be9_109c_f7aa_1d57,
534                    0xc791_bc55_fece_41d2,
535                    0xf84c_5770_4e38_5ec2,
536                    0xcb49_c1d9_c010_e60f,
537                    0x0acd_b8e1_58bf_e3c8,
538                ]),
539                c1: Fp::from_raw_unchecked([
540                    0x8aef_cb98_b15f_8306,
541                    0x3ea1_108f_e4f2_1d54,
542                    0xcf79_f69f_a1b7_df3b,
543                    0xe4f5_4aa1_d16b_1a3c,
544                    0xba5e_4ef8_6105_a679,
545                    0x0ed8_6c07_97be_e5cf,
546                ]),
547            },
548            c2: Fp2 {
549                c0: Fp::from_raw_unchecked([
550                    0xcee5_cb98_b15c_2db4,
551                    0x7159_1082_d23a_1d51,
552                    0xd762_30e9_44a1_7ca4,
553                    0xd19e_3dd3_549d_d5b6,
554                    0xa972_dc17_01fa_66e3,
555                    0x12e3_1f2d_d6bd_e7d6,
556                ]),
557                c1: Fp::from_raw_unchecked([
558                    0xad2a_cb98_b173_2d9d,
559                    0x2cfd_10dd_0696_1d64,
560                    0x0739_6b86_c6ef_24e8,
561                    0xbd76_e2fd_b1bf_c820,
562                    0x6afe_a7f6_de94_d0d5,
563                    0x1099_4b0c_5744_c040,
564                ]),
565            },
566        },
567        c1: Fp6 {
568            c0: Fp2 {
569                c0: Fp::from_raw_unchecked([
570                    0x47f9_cb98_b1b8_2d58,
571                    0x5fe9_11eb_a3aa_1d9d,
572                    0x96bf_1b5f_4dd8_1db3,
573                    0x8100_d27c_c925_9f5b,
574                    0xafa2_0b96_7464_0eab,
575                    0x09bb_cea7_d8d9_497d,
576                ]),
577                c1: Fp::from_raw_unchecked([
578                    0x0303_cb98_b166_2daa,
579                    0xd931_10aa_0a62_1d5a,
580                    0xbfa9_820c_5be4_a468,
581                    0x0ba3_643e_cb05_a348,
582                    0xdc35_34bb_1f1c_25a6,
583                    0x06c3_05bb_19c0_e1c1,
584                ]),
585            },
586            c1: Fp2 {
587                c0: Fp::from_raw_unchecked([
588                    0x46f9_cb98_b162_d858,
589                    0x0be9_109c_f7aa_1d57,
590                    0xc791_bc55_fece_41d2,
591                    0xf84c_5770_4e38_5ec2,
592                    0xcb49_c1d9_c010_e60f,
593                    0x0acd_b8e1_58bf_e3c8,
594                ]),
595                c1: Fp::from_raw_unchecked([
596                    0x8aef_cb98_b15f_8306,
597                    0x3ea1_108f_e4f2_1d54,
598                    0xcf79_f69f_a1b7_df3b,
599                    0xe4f5_4aa1_d16b_1a3c,
600                    0xba5e_4ef8_6105_a679,
601                    0x0ed8_6c07_97be_e5cf,
602                ]),
603            },
604            c2: Fp2 {
605                c0: Fp::from_raw_unchecked([
606                    0xcee5_cb98_b15c_2db4,
607                    0x7159_1082_d23a_1d51,
608                    0xd762_30e9_44a1_7ca4,
609                    0xd19e_3dd3_549d_d5b6,
610                    0xa972_dc17_01fa_66e3,
611                    0x12e3_1f2d_d6bd_e7d6,
612                ]),
613                c1: Fp::from_raw_unchecked([
614                    0xad2a_cb98_b173_2d9d,
615                    0x2cfd_10dd_0696_1d64,
616                    0x0739_6b86_c6ef_24e8,
617                    0xbd76_e2fd_b1bf_c820,
618                    0x6afe_a7f6_de94_d0d5,
619                    0x1099_4b0c_5744_c040,
620                ]),
621            },
622        },
623    };
624
625    let b = Fp12 {
626        c0: Fp6 {
627            c0: Fp2 {
628                c0: Fp::from_raw_unchecked([
629                    0x47f9_cb98_b1b8_2d58,
630                    0x5fe9_11eb_a3aa_1d9d,
631                    0x96bf_1b5f_4dd8_1db3,
632                    0x8100_d272_c925_9f5b,
633                    0xafa2_0b96_7464_0eab,
634                    0x09bb_cea7_d8d9_497d,
635                ]),
636                c1: Fp::from_raw_unchecked([
637                    0x0303_cb98_b166_2daa,
638                    0xd931_10aa_0a62_1d5a,
639                    0xbfa9_820c_5be4_a468,
640                    0x0ba3_643e_cb05_a348,
641                    0xdc35_34bb_1f1c_25a6,
642                    0x06c3_05bb_19c0_e1c1,
643                ]),
644            },
645            c1: Fp2 {
646                c0: Fp::from_raw_unchecked([
647                    0x46f9_cb98_b162_d858,
648                    0x0be9_109c_f7aa_1d57,
649                    0xc791_bc55_fece_41d2,
650                    0xf84c_5770_4e38_5ec2,
651                    0xcb49_c1d9_c010_e60f,
652                    0x0acd_b8e1_58bf_e348,
653                ]),
654                c1: Fp::from_raw_unchecked([
655                    0x8aef_cb98_b15f_8306,
656                    0x3ea1_108f_e4f2_1d54,
657                    0xcf79_f69f_a1b7_df3b,
658                    0xe4f5_4aa1_d16b_1a3c,
659                    0xba5e_4ef8_6105_a679,
660                    0x0ed8_6c07_97be_e5cf,
661                ]),
662            },
663            c2: Fp2 {
664                c0: Fp::from_raw_unchecked([
665                    0xcee5_cb98_b15c_2db4,
666                    0x7159_1082_d23a_1d51,
667                    0xd762_30e9_44a1_7ca4,
668                    0xd19e_3dd3_549d_d5b6,
669                    0xa972_dc17_01fa_66e3,
670                    0x12e3_1f2d_d6bd_e7d6,
671                ]),
672                c1: Fp::from_raw_unchecked([
673                    0xad2a_cb98_b173_2d9d,
674                    0x2cfd_10dd_0696_1d64,
675                    0x0739_6b86_c6ef_24e8,
676                    0xbd76_e2fd_b1bf_c820,
677                    0x6afe_a7f6_de94_d0d5,
678                    0x1099_4b0c_5744_c040,
679                ]),
680            },
681        },
682        c1: Fp6 {
683            c0: Fp2 {
684                c0: Fp::from_raw_unchecked([
685                    0x47f9_cb98_b1b8_2d58,
686                    0x5fe9_11eb_a3aa_1d9d,
687                    0x96bf_1b5f_4dd2_1db3,
688                    0x8100_d27c_c925_9f5b,
689                    0xafa2_0b96_7464_0eab,
690                    0x09bb_cea7_d8d9_497d,
691                ]),
692                c1: Fp::from_raw_unchecked([
693                    0x0303_cb98_b166_2daa,
694                    0xd931_10aa_0a62_1d5a,
695                    0xbfa9_820c_5be4_a468,
696                    0x0ba3_643e_cb05_a348,
697                    0xdc35_34bb_1f1c_25a6,
698                    0x06c3_05bb_19c0_e1c1,
699                ]),
700            },
701            c1: Fp2 {
702                c0: Fp::from_raw_unchecked([
703                    0x46f9_cb98_b162_d858,
704                    0x0be9_109c_f7aa_1d57,
705                    0xc791_bc55_fece_41d2,
706                    0xf84c_5770_4e38_5ec2,
707                    0xcb49_c1d9_c010_e60f,
708                    0x0acd_b8e1_58bf_e3c8,
709                ]),
710                c1: Fp::from_raw_unchecked([
711                    0x8aef_cb98_b15f_8306,
712                    0x3ea1_108f_e4f2_1d54,
713                    0xcf79_f69f_a117_df3b,
714                    0xe4f5_4aa1_d16b_1a3c,
715                    0xba5e_4ef8_6105_a679,
716                    0x0ed8_6c07_97be_e5cf,
717                ]),
718            },
719            c2: Fp2 {
720                c0: Fp::from_raw_unchecked([
721                    0xcee5_cb98_b15c_2db4,
722                    0x7159_1082_d23a_1d51,
723                    0xd762_30e9_44a1_7ca4,
724                    0xd19e_3dd3_549d_d5b6,
725                    0xa972_dc17_01fa_66e3,
726                    0x12e3_1f2d_d6bd_e7d6,
727                ]),
728                c1: Fp::from_raw_unchecked([
729                    0xad2a_cb98_b173_2d9d,
730                    0x2cfd_10dd_0696_1d64,
731                    0x0739_6b86_c6ef_24e8,
732                    0xbd76_e2fd_b1bf_c820,
733                    0x6afe_a7f6_de94_d0d5,
734                    0x1099_4b0c_5744_c040,
735                ]),
736            },
737        },
738    };
739
740    let c = Fp12 {
741        c0: Fp6 {
742            c0: Fp2 {
743                c0: Fp::from_raw_unchecked([
744                    0x47f9_cb98_71b8_2d58,
745                    0x5fe9_11eb_a3aa_1d9d,
746                    0x96bf_1b5f_4dd8_1db3,
747                    0x8100_d27c_c925_9f5b,
748                    0xafa2_0b96_7464_0eab,
749                    0x09bb_cea7_d8d9_497d,
750                ]),
751                c1: Fp::from_raw_unchecked([
752                    0x0303_cb98_b166_2daa,
753                    0xd931_10aa_0a62_1d5a,
754                    0xbfa9_820c_5be4_a468,
755                    0x0ba3_643e_cb05_a348,
756                    0xdc35_34bb_1f1c_25a6,
757                    0x06c3_05bb_19c0_e1c1,
758                ]),
759            },
760            c1: Fp2 {
761                c0: Fp::from_raw_unchecked([
762                    0x46f9_cb98_b162_d858,
763                    0x0be9_109c_f7aa_1d57,
764                    0x7791_bc55_fece_41d2,
765                    0xf84c_5770_4e38_5ec2,
766                    0xcb49_c1d9_c010_e60f,
767                    0x0acd_b8e1_58bf_e3c8,
768                ]),
769                c1: Fp::from_raw_unchecked([
770                    0x8aef_cb98_b15f_8306,
771                    0x3ea1_108f_e4f2_1d54,
772                    0xcf79_f69f_a1b7_df3b,
773                    0xe4f5_4aa1_d16b_133c,
774                    0xba5e_4ef8_6105_a679,
775                    0x0ed8_6c07_97be_e5cf,
776                ]),
777            },
778            c2: Fp2 {
779                c0: Fp::from_raw_unchecked([
780                    0xcee5_cb98_b15c_2db4,
781                    0x7159_1082_d23a_1d51,
782                    0xd762_40e9_44a1_7ca4,
783                    0xd19e_3dd3_549d_d5b6,
784                    0xa972_dc17_01fa_66e3,
785                    0x12e3_1f2d_d6bd_e7d6,
786                ]),
787                c1: Fp::from_raw_unchecked([
788                    0xad2a_cb98_b173_2d9d,
789                    0x2cfd_10dd_0696_1d64,
790                    0x0739_6b86_c6ef_24e8,
791                    0xbd76_e2fd_b1bf_c820,
792                    0x6afe_a7f6_de94_d0d5,
793                    0x1099_4b0c_1744_c040,
794                ]),
795            },
796        },
797        c1: Fp6 {
798            c0: Fp2 {
799                c0: Fp::from_raw_unchecked([
800                    0x47f9_cb98_b1b8_2d58,
801                    0x5fe9_11eb_a3aa_1d9d,
802                    0x96bf_1b5f_4dd8_1db3,
803                    0x8100_d27c_c925_9f5b,
804                    0xafa2_0b96_7464_0eab,
805                    0x09bb_cea7_d8d9_497d,
806                ]),
807                c1: Fp::from_raw_unchecked([
808                    0x0303_cb98_b166_2daa,
809                    0xd931_10aa_0a62_1d5a,
810                    0xbfa9_820c_5be4_a468,
811                    0x0ba3_643e_cb05_a348,
812                    0xdc35_34bb_1f1c_25a6,
813                    0x06c3_05bb_19c0_e1c1,
814                ]),
815            },
816            c1: Fp2 {
817                c0: Fp::from_raw_unchecked([
818                    0x46f9_cb98_b162_d858,
819                    0x0be9_109c_f7aa_1d57,
820                    0xc791_bc55_fece_41d2,
821                    0xf84c_5770_4e38_5ec2,
822                    0xcb49_c1d3_c010_e60f,
823                    0x0acd_b8e1_58bf_e3c8,
824                ]),
825                c1: Fp::from_raw_unchecked([
826                    0x8aef_cb98_b15f_8306,
827                    0x3ea1_108f_e4f2_1d54,
828                    0xcf79_f69f_a1b7_df3b,
829                    0xe4f5_4aa1_d16b_1a3c,
830                    0xba5e_4ef8_6105_a679,
831                    0x0ed8_6c07_97be_e5cf,
832                ]),
833            },
834            c2: Fp2 {
835                c0: Fp::from_raw_unchecked([
836                    0xcee5_cb98_b15c_2db4,
837                    0x7159_1082_d23a_1d51,
838                    0xd762_30e9_44a1_7ca4,
839                    0xd19e_3dd3_549d_d5b6,
840                    0xa972_dc17_01fa_66e3,
841                    0x12e3_1f2d_d6bd_e7d6,
842                ]),
843                c1: Fp::from_raw_unchecked([
844                    0xad2a_cb98_b173_2d9d,
845                    0x2cfd_10dd_0696_1d64,
846                    0x0739_6b86_c6ef_24e8,
847                    0xbd76_e2fd_b1bf_c820,
848                    0x6afe_a7f6_de94_d0d5,
849                    0x1099_4b0c_5744_1040,
850                ]),
851            },
852        },
853    };
854
855    // because a and b and c are similar to each other and
856    // I was lazy, this is just some arbitrary way to make
857    // them a little more different
858    let a = a.square().invert().unwrap().square() + c;
859    let b = b.square().invert().unwrap().square() + a;
860    let c = c.square().invert().unwrap().square() + b;
861
862    assert_eq!(a.square(), a * a);
863    assert_eq!(b.square(), b * b);
864    assert_eq!(c.square(), c * c);
865
866    assert_eq!((a + b) * c.square(), (c * c * a) + (c * c * b));
867
868    assert_eq!(
869        a.invert().unwrap() * b.invert().unwrap(),
870        (a * b).invert().unwrap()
871    );
872    assert_eq!(a.invert().unwrap() * a, Fp12::one());
873
874    assert!(a != a.frobenius_map());
875    assert_eq!(
876        a,
877        a.frobenius_map()
878            .frobenius_map()
879            .frobenius_map()
880            .frobenius_map()
881            .frobenius_map()
882            .frobenius_map()
883            .frobenius_map()
884            .frobenius_map()
885            .frobenius_map()
886            .frobenius_map()
887            .frobenius_map()
888            .frobenius_map()
889    );
890}
891
892#[cfg(feature = "zeroize")]
893#[test]
894fn test_zeroize() {
895    use zeroize::Zeroize;
896
897    let mut a = Fp12::one();
898    a.zeroize();
899    assert!(bool::from(a.is_zero()));
900}