1use crate::{
2 fields::{Field, PrimeField},
3 AdditiveGroup, FftField, LegendreSymbol, One, SqrtPrecomputation, ToConstraintField,
4 UniformRand, Zero,
5};
6use ark_serialize::{
7 CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
8 CanonicalSerializeWithFlags, Compress, EmptyFlags, Flags, SerializationError, Valid, Validate,
9};
10use ark_std::{
11 cmp::*,
12 fmt,
13 io::{Read, Write},
14 iter::*,
15 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
16 rand::{
17 distributions::{Distribution, Standard},
18 Rng,
19 },
20 vec::*,
21};
22use zeroize::Zeroize;
23
24pub trait CubicExtConfig: 'static + Send + Sync + Sized {
26 type BasePrimeField: PrimeField;
28 type BaseField: Field<BasePrimeField = Self::BasePrimeField>;
34 type FrobCoeff: Field;
37
38 const SQRT_PRECOMP: Option<SqrtPrecomputation<CubicExtField<Self>>>;
40
41 const DEGREE_OVER_BASE_PRIME_FIELD: usize;
43
44 const NONRESIDUE: Self::BaseField;
46
47 const FROBENIUS_COEFF_C1: &'static [Self::FrobCoeff];
49 const FROBENIUS_COEFF_C2: &'static [Self::FrobCoeff];
50
51 #[inline(always)]
54 fn mul_base_field_by_nonresidue_in_place(fe: &mut Self::BaseField) -> &mut Self::BaseField {
55 *fe *= &Self::NONRESIDUE;
56 fe
57 }
58
59 #[inline(always)]
62 fn mul_base_field_by_nonresidue(mut fe: Self::BaseField) -> Self::BaseField {
63 Self::mul_base_field_by_nonresidue_in_place(&mut fe);
64 fe
65 }
66
67 fn mul_base_field_by_frob_coeff(
70 c1: &mut Self::BaseField,
71 c2: &mut Self::BaseField,
72 power: usize,
73 );
74}
75
76#[derive(Educe)]
79#[educe(Default, Hash, Clone, Copy, Debug, PartialEq, Eq)]
80pub struct CubicExtField<P: CubicExtConfig> {
81 pub c0: P::BaseField,
82 pub c1: P::BaseField,
83 pub c2: P::BaseField,
84}
85
86impl<P: CubicExtConfig> CubicExtField<P> {
87 pub const fn new(c0: P::BaseField, c1: P::BaseField, c2: P::BaseField) -> Self {
108 Self { c0, c1, c2 }
109 }
110
111 pub fn mul_assign_by_base_field(&mut self, value: &P::BaseField) {
112 self.c0.mul_assign(value);
113 self.c1.mul_assign(value);
114 self.c2.mul_assign(value);
115 }
116
117 pub fn norm(&self) -> P::BaseField {
122 let index_multiplier = P::BaseField::extension_degree() as usize;
126 let mut self_to_p = *self;
127 self_to_p.frobenius_map_in_place(index_multiplier);
128 let mut self_to_p2 = *self;
129 self_to_p2.frobenius_map_in_place(2 * index_multiplier);
130 self_to_p *= &(self_to_p2 * self);
131 assert!(self_to_p.c1.is_zero() && self_to_p.c2.is_zero());
132 self_to_p.c0
133 }
134}
135
136impl<P: CubicExtConfig> Zero for CubicExtField<P> {
137 fn zero() -> Self {
138 Self::new(P::BaseField::ZERO, P::BaseField::ZERO, P::BaseField::ZERO)
139 }
140
141 fn is_zero(&self) -> bool {
142 self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
143 }
144}
145
146impl<P: CubicExtConfig> One for CubicExtField<P> {
147 fn one() -> Self {
148 Self::new(P::BaseField::ONE, P::BaseField::ZERO, P::BaseField::ZERO)
149 }
150
151 fn is_one(&self) -> bool {
152 self.c0.is_one() && self.c1.is_zero() && self.c2.is_zero()
153 }
154}
155
156impl<P: CubicExtConfig> AdditiveGroup for CubicExtField<P> {
157 type Scalar = Self;
158
159 const ZERO: Self = Self::new(P::BaseField::ZERO, P::BaseField::ZERO, P::BaseField::ZERO);
160
161 fn double(&self) -> Self {
162 let mut result = *self;
163 result.double_in_place();
164 result
165 }
166
167 fn double_in_place(&mut self) -> &mut Self {
168 self.c0.double_in_place();
169 self.c1.double_in_place();
170 self.c2.double_in_place();
171 self
172 }
173
174 fn neg_in_place(&mut self) -> &mut Self {
175 self.c0.neg_in_place();
176 self.c1.neg_in_place();
177 self.c2.neg_in_place();
178 self
179 }
180}
181
182impl<P: CubicExtConfig> Field for CubicExtField<P> {
183 type BasePrimeField = P::BasePrimeField;
184
185 const SQRT_PRECOMP: Option<SqrtPrecomputation<Self>> = P::SQRT_PRECOMP;
186
187 const ONE: Self = Self::new(P::BaseField::ONE, P::BaseField::ZERO, P::BaseField::ZERO);
188
189 fn extension_degree() -> u64 {
190 3 * P::BaseField::extension_degree()
191 }
192
193 fn from_base_prime_field(elem: Self::BasePrimeField) -> Self {
194 let fe = P::BaseField::from_base_prime_field(elem);
195 Self::new(fe, P::BaseField::ZERO, P::BaseField::ZERO)
196 }
197
198 fn to_base_prime_field_elements(&self) -> impl Iterator<Item = Self::BasePrimeField> {
199 self.c0
200 .to_base_prime_field_elements()
201 .chain(self.c1.to_base_prime_field_elements())
202 .chain(self.c2.to_base_prime_field_elements())
203 }
204
205 fn from_base_prime_field_elems(
206 elems: impl IntoIterator<Item = Self::BasePrimeField>,
207 ) -> Option<Self> {
208 let mut elems = elems.into_iter();
209 let elems = elems.by_ref();
210 let base_ext_deg = P::BaseField::extension_degree() as usize;
211 let element = Some(Self::new(
212 P::BaseField::from_base_prime_field_elems(elems.take(base_ext_deg))?,
213 P::BaseField::from_base_prime_field_elems(elems.take(base_ext_deg))?,
214 P::BaseField::from_base_prime_field_elems(elems.take(base_ext_deg))?,
215 ));
216 if elems.next().is_some() {
217 None
218 } else {
219 element
220 }
221 }
222
223 #[inline]
224 fn from_random_bytes_with_flags<F: Flags>(bytes: &[u8]) -> Option<(Self, F)> {
225 let split_at = bytes.len() / 3;
226 if let Some(c0) = P::BaseField::from_random_bytes(&bytes[..split_at]) {
227 if let Some(c1) = P::BaseField::from_random_bytes(&bytes[split_at..2 * split_at]) {
228 if let Some((c2, flags)) =
229 P::BaseField::from_random_bytes_with_flags(&bytes[2 * split_at..])
230 {
231 return Some((CubicExtField::new(c0, c1, c2), flags));
232 }
233 }
234 }
235 None
236 }
237
238 #[inline]
239 fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
240 Self::from_random_bytes_with_flags::<EmptyFlags>(bytes).map(|f| f.0)
241 }
242
243 fn square(&self) -> Self {
244 let mut result = *self;
245 result.square_in_place();
246 result
247 }
248
249 fn square_in_place(&mut self) -> &mut Self {
250 let a = self.c0;
254 let b = self.c1;
255 let c = self.c2;
256
257 let s0 = a.square();
258 let ab = a * &b;
259 let s1 = ab.double();
260 let s2 = (a - &b + &c).square();
261 let bc = b * &c;
262 let s3 = bc.double();
263 let s4 = c.square();
264
265 self.c0 = s3;
267 P::mul_base_field_by_nonresidue_in_place(&mut self.c0);
268 self.c0 += &s0;
269
270 self.c1 = s4;
272 P::mul_base_field_by_nonresidue_in_place(&mut self.c1);
273 self.c1 += &s1;
274
275 self.c2 = s1 + &s2 + &s3 - &s0 - &s4;
276 self
277 }
278
279 fn legendre(&self) -> LegendreSymbol {
281 self.norm().legendre()
282 }
283
284 fn inverse(&self) -> Option<Self> {
285 if self.is_zero() {
286 None
287 } else {
288 let t0 = self.c0.square();
292 let t1 = self.c1.square();
293 let t2 = self.c2.square();
294 let t3 = self.c0 * &self.c1;
295 let t4 = self.c0 * &self.c2;
296 let t5 = self.c1 * &self.c2;
297 let n5 = P::mul_base_field_by_nonresidue(t5);
298
299 let s0 = t0 - &n5;
300 let s1 = P::mul_base_field_by_nonresidue(t2) - &t3;
301 let s2 = t1 - &t4; let a1 = self.c2 * &s1;
304 let a2 = self.c1 * &s2;
305 let mut a3 = a1 + &a2;
306 a3 = P::mul_base_field_by_nonresidue(a3);
307 let t6 = (self.c0 * &s0 + &a3).inverse().unwrap();
308
309 let c0 = t6 * &s0;
310 let c1 = t6 * &s1;
311 let c2 = t6 * &s2;
312
313 Some(Self::new(c0, c1, c2))
314 }
315 }
316
317 fn inverse_in_place(&mut self) -> Option<&mut Self> {
318 if let Some(inverse) = self.inverse() {
319 *self = inverse;
320 Some(self)
321 } else {
322 None
323 }
324 }
325
326 fn frobenius_map_in_place(&mut self, power: usize) {
327 self.c0.frobenius_map_in_place(power);
328 self.c1.frobenius_map_in_place(power);
329 self.c2.frobenius_map_in_place(power);
330
331 P::mul_base_field_by_frob_coeff(&mut self.c1, &mut self.c2, power);
332 }
333
334 fn mul_by_base_prime_field(&self, elem: &Self::BasePrimeField) -> Self {
335 let mut result = *self;
336 result.c0 = result.c0.mul_by_base_prime_field(elem);
337 result.c1 = result.c1.mul_by_base_prime_field(elem);
338 result.c2 = result.c2.mul_by_base_prime_field(elem);
339 result
340 }
341}
342
343impl<P: CubicExtConfig> Ord for CubicExtField<P> {
345 #[inline(always)]
346 fn cmp(&self, other: &Self) -> Ordering {
347 let c2_cmp = self.c2.cmp(&other.c2);
348 let c1_cmp = self.c1.cmp(&other.c1);
349 let c0_cmp = self.c0.cmp(&other.c0);
350 if c2_cmp == Ordering::Equal {
351 if c1_cmp == Ordering::Equal {
352 c0_cmp
353 } else {
354 c1_cmp
355 }
356 } else {
357 c2_cmp
358 }
359 }
360}
361
362impl<P: CubicExtConfig> PartialOrd for CubicExtField<P> {
363 #[inline(always)]
364 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
365 Some(self.cmp(other))
366 }
367}
368
369impl<P: CubicExtConfig> Zeroize for CubicExtField<P> {
370 fn zeroize(&mut self) {
373 self.c0.zeroize();
374 self.c1.zeroize();
375 self.c2.zeroize();
376 }
377}
378
379impl<P: CubicExtConfig> From<u128> for CubicExtField<P> {
380 fn from(other: u128) -> Self {
381 let fe: P::BaseField = other.into();
382 Self::new(fe, P::BaseField::ZERO, P::BaseField::ZERO)
383 }
384}
385
386impl<P: CubicExtConfig> From<i128> for CubicExtField<P> {
387 #[inline]
388 fn from(val: i128) -> Self {
389 let abs = Self::from(val.unsigned_abs());
390 if val.is_positive() {
391 abs
392 } else {
393 -abs
394 }
395 }
396}
397
398impl<P: CubicExtConfig> From<u64> for CubicExtField<P> {
399 fn from(other: u64) -> Self {
400 let fe: P::BaseField = other.into();
401 Self::new(fe, P::BaseField::ZERO, P::BaseField::ZERO)
402 }
403}
404
405impl<P: CubicExtConfig> From<i64> for CubicExtField<P> {
406 #[inline]
407 fn from(val: i64) -> Self {
408 let abs = Self::from(val.unsigned_abs());
409 if val.is_positive() {
410 abs
411 } else {
412 -abs
413 }
414 }
415}
416
417impl<P: CubicExtConfig> From<u32> for CubicExtField<P> {
418 fn from(other: u32) -> Self {
419 let fe: P::BaseField = other.into();
420 Self::new(fe, P::BaseField::ZERO, P::BaseField::ZERO)
421 }
422}
423
424impl<P: CubicExtConfig> From<i32> for CubicExtField<P> {
425 #[inline]
426 fn from(val: i32) -> Self {
427 let abs = Self::from(val.unsigned_abs());
428 if val.is_positive() {
429 abs
430 } else {
431 -abs
432 }
433 }
434}
435
436impl<P: CubicExtConfig> From<u16> for CubicExtField<P> {
437 fn from(other: u16) -> Self {
438 let fe: P::BaseField = other.into();
439 Self::new(fe, P::BaseField::ZERO, P::BaseField::ZERO)
440 }
441}
442
443impl<P: CubicExtConfig> From<i16> for CubicExtField<P> {
444 #[inline]
445 fn from(val: i16) -> Self {
446 let abs = Self::from(val.unsigned_abs());
447 if val.is_positive() {
448 abs
449 } else {
450 -abs
451 }
452 }
453}
454
455impl<P: CubicExtConfig> From<u8> for CubicExtField<P> {
456 fn from(other: u8) -> Self {
457 let fe: P::BaseField = other.into();
458 Self::new(fe, P::BaseField::ZERO, P::BaseField::ZERO)
459 }
460}
461
462impl<P: CubicExtConfig> From<i8> for CubicExtField<P> {
463 #[inline]
464 fn from(val: i8) -> Self {
465 let abs = Self::from(val.unsigned_abs());
466 if val.is_positive() {
467 abs
468 } else {
469 -abs
470 }
471 }
472}
473
474impl<P: CubicExtConfig> From<bool> for CubicExtField<P> {
475 fn from(other: bool) -> Self {
476 Self::new(
477 u8::from(other).into(),
478 P::BaseField::ZERO,
479 P::BaseField::ZERO,
480 )
481 }
482}
483
484impl<P: CubicExtConfig> Neg for CubicExtField<P> {
485 type Output = Self;
486 #[inline]
487 fn neg(mut self) -> Self {
488 self.c0.neg_in_place();
489 self.c1.neg_in_place();
490 self.c2.neg_in_place();
491 self
492 }
493}
494
495impl<P: CubicExtConfig> Distribution<CubicExtField<P>> for Standard {
496 #[inline]
497 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> CubicExtField<P> {
498 CubicExtField::new(
499 UniformRand::rand(rng),
500 UniformRand::rand(rng),
501 UniformRand::rand(rng),
502 )
503 }
504}
505
506impl<'a, P: CubicExtConfig> Add<&'a CubicExtField<P>> for CubicExtField<P> {
507 type Output = Self;
508
509 #[inline]
510 fn add(mut self, other: &Self) -> Self {
511 self.add_assign(other);
512 self
513 }
514}
515
516impl<'a, P: CubicExtConfig> Sub<&'a CubicExtField<P>> for CubicExtField<P> {
517 type Output = Self;
518
519 #[inline]
520 fn sub(mut self, other: &Self) -> Self {
521 self.sub_assign(other);
522 self
523 }
524}
525
526impl<'a, P: CubicExtConfig> Mul<&'a CubicExtField<P>> for CubicExtField<P> {
527 type Output = Self;
528
529 #[inline]
530 fn mul(mut self, other: &Self) -> Self {
531 self.mul_assign(other);
532 self
533 }
534}
535
536impl<'a, P: CubicExtConfig> Div<&'a CubicExtField<P>> for CubicExtField<P> {
537 type Output = Self;
538
539 #[inline]
540 fn div(mut self, other: &Self) -> Self {
541 self.mul_assign(&other.inverse().unwrap());
542 self
543 }
544}
545
546impl_additive_ops_from_ref!(CubicExtField, CubicExtConfig);
547impl_multiplicative_ops_from_ref!(CubicExtField, CubicExtConfig);
548impl<'a, P: CubicExtConfig> AddAssign<&'a Self> for CubicExtField<P> {
549 #[inline]
550 fn add_assign(&mut self, other: &Self) {
551 self.c0.add_assign(&other.c0);
552 self.c1.add_assign(&other.c1);
553 self.c2.add_assign(&other.c2);
554 }
555}
556
557impl<'a, P: CubicExtConfig> SubAssign<&'a Self> for CubicExtField<P> {
558 #[inline]
559 fn sub_assign(&mut self, other: &Self) {
560 self.c0.sub_assign(&other.c0);
561 self.c1.sub_assign(&other.c1);
562 self.c2.sub_assign(&other.c2);
563 }
564}
565
566impl<'a, P: CubicExtConfig> MulAssign<&'a Self> for CubicExtField<P> {
567 #[inline]
568 #[allow(clippy::many_single_char_names)]
569 fn mul_assign(&mut self, other: &Self) {
570 let a = other.c0;
575 let b = other.c1;
576 let c = other.c2;
577
578 let d = self.c0;
579 let e = self.c1;
580 let f = self.c2;
581
582 let ad = d * &a;
583 let be = e * &b;
584 let cf = f * &c;
585
586 let x = (e + &f) * &(b + &c) - &be - &cf;
587 let y = (d + &e) * &(a + &b) - &ad - &be;
588 let z = (d + &f) * &(a + &c) - &ad + &be - &cf;
589
590 self.c0 = ad + &P::mul_base_field_by_nonresidue(x);
591 self.c1 = y + &P::mul_base_field_by_nonresidue(cf);
592 self.c2 = z;
593 }
594}
595
596impl<'a, P: CubicExtConfig> DivAssign<&'a Self> for CubicExtField<P> {
597 #[inline]
598 fn div_assign(&mut self, other: &Self) {
599 self.mul_assign(&other.inverse().unwrap());
600 }
601}
602
603impl<P: CubicExtConfig> fmt::Display for CubicExtField<P> {
604 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605 write!(f, "CubicExtField({}, {}, {})", self.c0, self.c1, self.c2)
606 }
607}
608
609impl<P: CubicExtConfig> CanonicalSerializeWithFlags for CubicExtField<P> {
610 #[inline]
611 fn serialize_with_flags<W: Write, F: Flags>(
612 &self,
613 mut writer: W,
614 flags: F,
615 ) -> Result<(), SerializationError> {
616 self.c0.serialize_compressed(&mut writer)?;
617 self.c1.serialize_compressed(&mut writer)?;
618 self.c2.serialize_with_flags(&mut writer, flags)?;
619 Ok(())
620 }
621
622 #[inline]
623 fn serialized_size_with_flags<F: Flags>(&self) -> usize {
624 self.c0.compressed_size()
625 + self.c1.compressed_size()
626 + self.c2.serialized_size_with_flags::<F>()
627 }
628}
629
630impl<P: CubicExtConfig> CanonicalSerialize for CubicExtField<P> {
631 #[inline]
632 fn serialize_with_mode<W: Write>(
633 &self,
634 writer: W,
635 _compress: Compress,
636 ) -> Result<(), SerializationError> {
637 self.serialize_with_flags(writer, EmptyFlags)
638 }
639
640 #[inline]
641 fn serialized_size(&self, _compress: Compress) -> usize {
642 self.serialized_size_with_flags::<EmptyFlags>()
643 }
644}
645
646impl<P: CubicExtConfig> CanonicalDeserializeWithFlags for CubicExtField<P> {
647 #[inline]
648 fn deserialize_with_flags<R: Read, F: Flags>(
649 mut reader: R,
650 ) -> Result<(Self, F), SerializationError> {
651 let c0 = CanonicalDeserialize::deserialize_compressed(&mut reader)?;
652 let c1 = CanonicalDeserialize::deserialize_compressed(&mut reader)?;
653 let (c2, flags) = CanonicalDeserializeWithFlags::deserialize_with_flags(&mut reader)?;
654 Ok((CubicExtField::new(c0, c1, c2), flags))
655 }
656}
657
658impl<P: CubicExtConfig> Valid for CubicExtField<P> {
659 fn check(&self) -> Result<(), SerializationError> {
660 self.c0.check()?;
661 self.c1.check()?;
662 self.c2.check()
663 }
664}
665
666impl<P: CubicExtConfig> CanonicalDeserialize for CubicExtField<P> {
667 #[inline]
668 fn deserialize_with_mode<R: Read>(
669 mut reader: R,
670 compress: Compress,
671 validate: Validate,
672 ) -> Result<Self, SerializationError> {
673 let c0: P::BaseField =
674 CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
675 let c1: P::BaseField =
676 CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
677 let c2: P::BaseField =
678 CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
679 Ok(CubicExtField::new(c0, c1, c2))
680 }
681}
682
683impl<P: CubicExtConfig> ToConstraintField<P::BasePrimeField> for CubicExtField<P>
684where
685 P::BaseField: ToConstraintField<P::BasePrimeField>,
686{
687 fn to_field_elements(&self) -> Option<Vec<P::BasePrimeField>> {
688 let mut res = Vec::new();
689 let mut c0_elems = self.c0.to_field_elements()?;
690 let mut c1_elems = self.c1.to_field_elements()?;
691 let mut c2_elems = self.c2.to_field_elements()?;
692
693 res.append(&mut c0_elems);
694 res.append(&mut c1_elems);
695 res.append(&mut c2_elems);
696
697 Some(res)
698 }
699}
700
701#[cfg(test)]
702mod cube_ext_tests {
703 use super::*;
704 use ark_std::test_rng;
705 use ark_test_curves::{
706 ark_ff::Field,
707 bls12_381::{Fq, Fq2, Fq6},
708 mnt6_753::Fq3,
709 };
710
711 #[test]
712 fn test_norm_for_towers() {
713 let mut rng = test_rng();
715 let a: Fq3 = rng.gen();
716 let _ = a.norm();
717
718 let a: Fq6 = rng.gen();
720 let _ = a.norm();
721 }
722
723 #[test]
724 fn test_from_base_prime_field_elements() {
725 let ext_degree = Fq6::extension_degree() as usize;
726 let max_num_elems_to_test = 10;
728 for d in 0..max_num_elems_to_test {
729 if d == ext_degree {
730 continue;
731 }
732 let mut random_coeffs = Vec::<Fq>::new();
733 for _ in 0..d {
734 random_coeffs.push(Fq::rand(&mut test_rng()));
735 }
736 let res = Fq6::from_base_prime_field_elems(random_coeffs);
737 assert_eq!(res, None);
738 }
739 let number_of_tests = 10;
742 for _ in 0..number_of_tests {
743 let mut random_coeffs = Vec::<Fq>::new();
744 for _ in 0..ext_degree {
745 random_coeffs.push(Fq::rand(&mut test_rng()));
746 }
747
748 let expected_0 = Fq2::new(random_coeffs[0], random_coeffs[1]);
749 let expected_1 = Fq2::new(random_coeffs[2], random_coeffs[3]);
750 let expected_2 = Fq2::new(random_coeffs[3], random_coeffs[4]);
751 let expected = Fq6::new(expected_0, expected_1, expected_2);
752
753 let actual = Fq6::from_base_prime_field_elems(random_coeffs).unwrap();
754 assert_eq!(actual, expected);
755 }
756 }
757
758 #[test]
759 fn test_from_base_prime_field_element() {
760 let ext_degree = Fq6::extension_degree() as usize;
761 let max_num_elems_to_test = 10;
762 for _ in 0..max_num_elems_to_test {
763 let mut random_coeffs = vec![Fq::zero(); ext_degree];
764 let random_coeff = Fq::rand(&mut test_rng());
765 let res = Fq6::from_base_prime_field(random_coeff);
766 random_coeffs[0] = random_coeff;
767 assert_eq!(
768 res,
769 Fq6::from_base_prime_field_elems(random_coeffs).unwrap()
770 );
771 }
772 }
773}
774
775impl<P: CubicExtConfig> FftField for CubicExtField<P>
776where
777 P::BaseField: FftField,
778{
779 const GENERATOR: Self = Self::new(
780 P::BaseField::GENERATOR,
781 P::BaseField::ZERO,
782 P::BaseField::ZERO,
783 );
784 const TWO_ADICITY: u32 = P::BaseField::TWO_ADICITY;
785 const TWO_ADIC_ROOT_OF_UNITY: Self = Self::new(
786 P::BaseField::TWO_ADIC_ROOT_OF_UNITY,
787 P::BaseField::ZERO,
788 P::BaseField::ZERO,
789 );
790 const SMALL_SUBGROUP_BASE: Option<u32> = P::BaseField::SMALL_SUBGROUP_BASE;
791 const SMALL_SUBGROUP_BASE_ADICITY: Option<u32> = P::BaseField::SMALL_SUBGROUP_BASE_ADICITY;
792 const LARGE_SUBGROUP_ROOT_OF_UNITY: Option<Self> =
793 if let Some(x) = P::BaseField::LARGE_SUBGROUP_ROOT_OF_UNITY {
794 Some(Self::new(x, P::BaseField::ZERO, P::BaseField::ZERO))
795 } else {
796 None
797 };
798}