1#![allow(clippy::assign_op_pattern, clippy::op_ref)]
4
5use cfg_if::cfg_if;
6
7cfg_if! {
8 if #[cfg(target_pointer_width = "32")] {
9 mod field_10x26;
10 } else if #[cfg(target_pointer_width = "64")] {
11 mod field_5x52;
12 } else {
13 compile_error!("unsupported target word size (i.e. target_pointer_width)");
14 }
15}
16
17cfg_if! {
18 if #[cfg(debug_assertions)] {
19 mod field_impl;
20 use field_impl::FieldElementImpl;
21 } else {
22 cfg_if! {
23 if #[cfg(target_pointer_width = "32")] {
24 use field_10x26::FieldElement10x26 as FieldElementImpl;
25 } else if #[cfg(target_pointer_width = "64")] {
26 use field_5x52::FieldElement5x52 as FieldElementImpl;
27 } else {
28 compile_error!("unsupported target word size (i.e. target_pointer_width)");
29 }
30 }
31 }
32}
33
34use crate::FieldBytes;
35use core::{
36 iter::{Product, Sum},
37 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
38};
39use elliptic_curve::{
40 ff::{self, Field, PrimeField},
41 ops::Invert,
42 rand_core::RngCore,
43 subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
44 zeroize::DefaultIsZeroes,
45};
46
47#[cfg(test)]
48use num_bigint::{BigUint, ToBigUint};
49
50#[derive(Clone, Copy, Debug)]
52pub struct FieldElement(FieldElementImpl);
53
54impl FieldElement {
55 pub const ZERO: Self = Self(FieldElementImpl::ZERO);
57
58 pub const ONE: Self = Self(FieldElementImpl::ONE);
60
61 pub fn is_zero(&self) -> Choice {
67 self.0.is_zero()
68 }
69
70 pub fn is_even(&self) -> Choice {
76 !self.0.is_odd()
77 }
78
79 pub fn is_odd(&self) -> Choice {
85 self.0.is_odd()
86 }
87
88 pub(crate) const fn from_bytes_unchecked(bytes: &[u8; 32]) -> Self {
91 Self(FieldElementImpl::from_bytes_unchecked(bytes))
92 }
93
94 pub fn from_bytes(bytes: &FieldBytes) -> CtOption<Self> {
99 FieldElementImpl::from_bytes(bytes).map(Self)
100 }
101
102 pub const fn from_u64(w: u64) -> Self {
104 Self(FieldElementImpl::from_u64(w))
105 }
106
107 pub fn to_bytes(self) -> FieldBytes {
109 self.0.normalize().to_bytes()
110 }
111
112 pub fn negate(&self, magnitude: u32) -> Self {
115 Self(self.0.negate(magnitude))
116 }
117
118 pub fn normalize(&self) -> Self {
121 Self(self.0.normalize())
122 }
123
124 pub fn normalize_weak(&self) -> Self {
127 Self(self.0.normalize_weak())
128 }
129
130 pub fn normalizes_to_zero(&self) -> Choice {
132 self.0.normalizes_to_zero()
133 }
134
135 pub fn mul_single(&self, rhs: u32) -> Self {
138 Self(self.0.mul_single(rhs))
139 }
140
141 pub fn double(&self) -> Self {
144 Self(self.0.add(&(self.0)))
145 }
146
147 pub fn mul(&self, rhs: &Self) -> Self {
151 Self(self.0.mul(&(rhs.0)))
152 }
153
154 pub fn square(&self) -> Self {
159 Self(self.0.square())
160 }
161
162 fn pow2k(&self, k: usize) -> Self {
164 let mut x = *self;
165 for _j in 0..k {
166 x = x.square();
167 }
168 x
169 }
170
171 pub fn invert(&self) -> CtOption<Self> {
174 let x2 = self.pow2k(1).mul(self);
179 let x3 = x2.pow2k(1).mul(self);
180 let x6 = x3.pow2k(3).mul(&x3);
181 let x9 = x6.pow2k(3).mul(&x3);
182 let x11 = x9.pow2k(2).mul(&x2);
183 let x22 = x11.pow2k(11).mul(&x11);
184 let x44 = x22.pow2k(22).mul(&x22);
185 let x88 = x44.pow2k(44).mul(&x44);
186 let x176 = x88.pow2k(88).mul(&x88);
187 let x220 = x176.pow2k(44).mul(&x44);
188 let x223 = x220.pow2k(3).mul(&x3);
189
190 let res = x223
192 .pow2k(23)
193 .mul(&x22)
194 .pow2k(5)
195 .mul(self)
196 .pow2k(3)
197 .mul(&x2)
198 .pow2k(2)
199 .mul(self);
200
201 CtOption::new(res, !self.normalizes_to_zero())
202 }
203
204 pub fn sqrt(&self) -> CtOption<Self> {
207 let x2 = self.pow2k(1).mul(self);
223 let x3 = x2.pow2k(1).mul(self);
224 let x6 = x3.pow2k(3).mul(&x3);
225 let x9 = x6.pow2k(3).mul(&x3);
226 let x11 = x9.pow2k(2).mul(&x2);
227 let x22 = x11.pow2k(11).mul(&x11);
228 let x44 = x22.pow2k(22).mul(&x22);
229 let x88 = x44.pow2k(44).mul(&x44);
230 let x176 = x88.pow2k(88).mul(&x88);
231 let x220 = x176.pow2k(44).mul(&x44);
232 let x223 = x220.pow2k(3).mul(&x3);
233
234 let res = x223.pow2k(23).mul(&x22).pow2k(6).mul(&x2).pow2k(2);
236
237 let is_root = (res.mul(&res).negate(1) + self).normalizes_to_zero();
238
239 CtOption::new(res, is_root)
241 }
242
243 #[cfg(test)]
244 pub fn modulus_as_biguint() -> BigUint {
245 Self::ONE.negate(1).to_biguint().unwrap() + 1.to_biguint().unwrap()
246 }
247}
248
249impl Invert for FieldElement {
250 type Output = CtOption<Self>;
251
252 fn invert(&self) -> CtOption<Self> {
253 self.invert()
254 }
255}
256
257impl Field for FieldElement {
258 const ZERO: Self = Self::ZERO;
259 const ONE: Self = Self::ONE;
260
261 fn random(mut rng: impl RngCore) -> Self {
262 let mut bytes = FieldBytes::default();
263
264 loop {
265 rng.fill_bytes(&mut bytes);
266 if let Some(fe) = Self::from_bytes(&bytes).into() {
267 return fe;
268 }
269 }
270 }
271
272 #[must_use]
273 fn square(&self) -> Self {
274 self.square()
275 }
276
277 #[must_use]
278 fn double(&self) -> Self {
279 self.double()
280 }
281
282 fn invert(&self) -> CtOption<Self> {
283 self.invert()
284 }
285
286 fn sqrt(&self) -> CtOption<Self> {
287 self.sqrt()
288 }
289
290 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
291 ff::helpers::sqrt_ratio_generic(num, div)
292 }
293}
294
295impl PrimeField for FieldElement {
296 type Repr = FieldBytes;
297
298 const MODULUS: &'static str =
299 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f";
300 const NUM_BITS: u32 = 256;
301 const CAPACITY: u32 = 255;
302 const TWO_INV: Self = Self(FieldElementImpl::from_bytes_unchecked(&[
303 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
304 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff,
305 0xfe, 0x18,
306 ]));
307 const MULTIPLICATIVE_GENERATOR: Self = Self::from_u64(3);
308 const S: u32 = 1;
309 const ROOT_OF_UNITY: Self = Self(FieldElementImpl::from_bytes_unchecked(&[
310 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
311 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
312 0xfc, 0x2e,
313 ]));
314 const ROOT_OF_UNITY_INV: Self = Self(FieldElementImpl::from_bytes_unchecked(&[
315 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
316 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
317 0xfc, 0x2e,
318 ]));
319 const DELTA: Self = Self::from_u64(9);
320
321 fn from_repr(repr: Self::Repr) -> CtOption<Self> {
322 Self::from_bytes(&repr)
323 }
324
325 fn to_repr(&self) -> Self::Repr {
326 self.to_bytes()
327 }
328
329 fn is_odd(&self) -> Choice {
330 self.is_odd()
331 }
332}
333
334impl ConditionallySelectable for FieldElement {
335 #[inline(always)]
336 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
337 Self(FieldElementImpl::conditional_select(&(a.0), &(b.0), choice))
338 }
339}
340
341impl ConstantTimeEq for FieldElement {
342 fn ct_eq(&self, other: &Self) -> Choice {
343 self.0.ct_eq(&(other.0))
344 }
345}
346
347impl Default for FieldElement {
348 fn default() -> Self {
349 Self::ZERO
350 }
351}
352
353impl DefaultIsZeroes for FieldElement {}
354
355impl Eq for FieldElement {}
356
357impl From<u64> for FieldElement {
358 fn from(k: u64) -> Self {
359 Self(FieldElementImpl::from_u64(k))
360 }
361}
362
363impl PartialEq for FieldElement {
364 fn eq(&self, other: &Self) -> bool {
365 self.0.ct_eq(&(other.0)).into()
366 }
367}
368
369impl Add<FieldElement> for FieldElement {
370 type Output = FieldElement;
371
372 fn add(self, other: FieldElement) -> FieldElement {
373 FieldElement(self.0.add(&(other.0)))
374 }
375}
376
377impl Add<&FieldElement> for FieldElement {
378 type Output = FieldElement;
379
380 fn add(self, other: &FieldElement) -> FieldElement {
381 FieldElement(self.0.add(&(other.0)))
382 }
383}
384
385impl Add<&FieldElement> for &FieldElement {
386 type Output = FieldElement;
387
388 fn add(self, other: &FieldElement) -> FieldElement {
389 FieldElement(self.0.add(&(other.0)))
390 }
391}
392
393impl AddAssign<FieldElement> for FieldElement {
394 fn add_assign(&mut self, other: FieldElement) {
395 *self = *self + &other;
396 }
397}
398
399impl AddAssign<&FieldElement> for FieldElement {
400 fn add_assign(&mut self, other: &FieldElement) {
401 *self = *self + other;
402 }
403}
404
405impl Sub<FieldElement> for FieldElement {
406 type Output = FieldElement;
407
408 fn sub(self, other: FieldElement) -> FieldElement {
409 self + -other
410 }
411}
412
413impl Sub<&FieldElement> for FieldElement {
414 type Output = FieldElement;
415
416 fn sub(self, other: &FieldElement) -> FieldElement {
417 self + -other
418 }
419}
420
421impl SubAssign<FieldElement> for FieldElement {
422 fn sub_assign(&mut self, other: FieldElement) {
423 *self = *self + -other;
424 }
425}
426
427impl SubAssign<&FieldElement> for FieldElement {
428 fn sub_assign(&mut self, other: &FieldElement) {
429 *self = *self + -other;
430 }
431}
432
433impl Mul<FieldElement> for FieldElement {
434 type Output = FieldElement;
435
436 fn mul(self, other: FieldElement) -> FieldElement {
437 FieldElement(self.0.mul(&(other.0)))
438 }
439}
440
441impl Mul<&FieldElement> for FieldElement {
442 type Output = FieldElement;
443
444 #[inline(always)]
445 fn mul(self, other: &FieldElement) -> FieldElement {
446 FieldElement(self.0.mul(&(other.0)))
447 }
448}
449
450impl Mul<&FieldElement> for &FieldElement {
451 type Output = FieldElement;
452
453 fn mul(self, other: &FieldElement) -> FieldElement {
454 FieldElement(self.0.mul(&(other.0)))
455 }
456}
457
458impl MulAssign<FieldElement> for FieldElement {
459 fn mul_assign(&mut self, rhs: FieldElement) {
460 *self = *self * &rhs;
461 }
462}
463
464impl MulAssign<&FieldElement> for FieldElement {
465 fn mul_assign(&mut self, rhs: &FieldElement) {
466 *self = *self * rhs;
467 }
468}
469
470impl Neg for FieldElement {
471 type Output = FieldElement;
472
473 fn neg(self) -> FieldElement {
474 self.negate(1)
475 }
476}
477
478impl Neg for &FieldElement {
479 type Output = FieldElement;
480
481 fn neg(self) -> FieldElement {
482 self.negate(1)
483 }
484}
485
486impl Sum for FieldElement {
487 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
488 iter.reduce(core::ops::Add::add).unwrap_or(Self::ZERO)
489 }
490}
491
492impl<'a> Sum<&'a FieldElement> for FieldElement {
493 #[inline]
494 fn sum<I: Iterator<Item = &'a FieldElement>>(iter: I) -> Self {
495 iter.copied().sum()
496 }
497}
498
499impl Product for FieldElement {
500 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
501 iter.reduce(core::ops::Mul::mul).unwrap_or(Self::ONE)
502 }
503}
504
505impl<'a> Product<&'a FieldElement> for FieldElement {
506 fn product<I: Iterator<Item = &'a FieldElement>>(iter: I) -> Self {
507 iter.copied().product()
508 }
509}
510
511#[cfg(test)]
512mod tests {
513 use elliptic_curve::ff::{Field, PrimeField};
514 use elliptic_curve::ops::BatchInvert;
515 use num_bigint::{BigUint, ToBigUint};
516 use proptest::prelude::*;
517 use rand_core::OsRng;
518
519 use super::FieldElement;
520 use crate::{
521 arithmetic::dev::{biguint_to_bytes, bytes_to_biguint},
522 test_vectors::field::DBL_TEST_VECTORS,
523 FieldBytes,
524 };
525
526 #[cfg(feature = "alloc")]
527 use alloc::vec::Vec;
528
529 impl From<&BigUint> for FieldElement {
530 fn from(x: &BigUint) -> Self {
531 let bytes = biguint_to_bytes(x);
532 Self::from_bytes(&bytes.into()).unwrap()
533 }
534 }
535
536 impl ToBigUint for FieldElement {
537 fn to_biguint(&self) -> Option<BigUint> {
538 Some(bytes_to_biguint(self.to_bytes().as_ref()))
539 }
540 }
541
542 const T: [u64; 4] = [
544 0xffffffff7ffffe17,
545 0xffffffffffffffff,
546 0xffffffffffffffff,
547 0x7fffffffffffffff,
548 ];
549
550 #[test]
551 fn two_inv_constant() {
552 assert_eq!(
553 (FieldElement::from(2u64) * FieldElement::TWO_INV).normalize(),
554 FieldElement::ONE
555 );
556 }
557
558 #[test]
559 fn root_of_unity_constant() {
560 assert_eq!(
562 FieldElement::ROOT_OF_UNITY
563 .pow_vartime(&[1u64 << FieldElement::S, 0, 0, 0])
564 .normalize(),
565 FieldElement::ONE
566 );
567
568 assert_eq!(
570 FieldElement::MULTIPLICATIVE_GENERATOR
571 .pow_vartime(&T)
572 .normalize(),
573 FieldElement::ROOT_OF_UNITY
574 )
575 }
576
577 #[test]
578 fn root_of_unity_inv_constant() {
579 assert_eq!(
580 (FieldElement::ROOT_OF_UNITY * FieldElement::ROOT_OF_UNITY_INV).normalize(),
581 FieldElement::ONE
582 );
583 }
584
585 #[test]
586 fn delta_constant() {
587 assert_eq!(
589 FieldElement::DELTA.pow_vartime(&T).normalize(),
590 FieldElement::ONE
591 );
592 }
593
594 #[test]
595 fn zero_is_additive_identity() {
596 let zero = FieldElement::ZERO;
597 let one = FieldElement::ONE;
598 assert_eq!((zero + &zero).normalize(), zero);
599 assert_eq!((one + &zero).normalize(), one);
600 }
601
602 #[test]
603 fn one_is_multiplicative_identity() {
604 let one = FieldElement::ONE;
605 assert_eq!((one * &one).normalize(), one);
606 }
607
608 #[test]
609 fn from_bytes() {
610 assert_eq!(
611 FieldElement::from_bytes(&FieldBytes::default()).unwrap(),
612 FieldElement::ZERO
613 );
614 assert_eq!(
615 FieldElement::from_bytes(
616 &[
617 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
618 0, 0, 0, 0, 0, 1
619 ]
620 .into()
621 )
622 .unwrap(),
623 FieldElement::ONE
624 );
625 assert!(bool::from(
626 FieldElement::from_bytes(&[0xff; 32].into()).is_none()
627 ));
628 }
629
630 #[test]
631 fn to_bytes() {
632 assert_eq!(FieldElement::ZERO.to_bytes(), [0; 32].into());
633 assert_eq!(
634 FieldElement::ONE.to_bytes(),
635 [
636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
637 0, 0, 0, 1
638 ]
639 .into()
640 );
641 }
642
643 #[test]
644 fn repeated_add() {
645 let mut r = FieldElement::ONE;
646 for i in 0..DBL_TEST_VECTORS.len() {
647 assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into());
648 r = (r + &r).normalize();
649 }
650 }
651
652 #[test]
653 fn repeated_double() {
654 let mut r = FieldElement::ONE;
655 for i in 0..DBL_TEST_VECTORS.len() {
656 assert_eq!(r.to_bytes(), DBL_TEST_VECTORS[i].into());
657 r = r.double().normalize();
658 }
659 }
660
661 #[test]
662 fn repeated_mul() {
663 let mut r = FieldElement::ONE;
664 let two = r + &r;
665 for i in 0..DBL_TEST_VECTORS.len() {
666 assert_eq!(r.normalize().to_bytes(), DBL_TEST_VECTORS[i].into());
667 r = r * &two;
668 }
669 }
670
671 #[test]
672 fn negation() {
673 let two = FieldElement::ONE.double();
674 let neg_two = two.negate(2);
675 assert_eq!((two + &neg_two).normalize(), FieldElement::ZERO);
676 assert_eq!(neg_two.negate(3).normalize(), two.normalize());
677 }
678
679 #[test]
680 fn invert() {
681 assert!(bool::from(FieldElement::ZERO.invert().is_none()));
682
683 let one = FieldElement::ONE;
684 assert_eq!(one.invert().unwrap().normalize(), one);
685
686 let two = one + &one;
687 let inv_two = two.invert().unwrap();
688 assert_eq!((two * &inv_two).normalize(), one);
689 }
690
691 #[test]
692 fn batch_invert_array() {
693 let k: FieldElement = FieldElement::random(&mut OsRng);
694 let l: FieldElement = FieldElement::random(&mut OsRng);
695
696 let expected = [k.invert().unwrap(), l.invert().unwrap()];
697 assert_eq!(
698 <FieldElement as BatchInvert<_>>::batch_invert(&[k, l]).unwrap(),
699 expected
700 );
701 }
702
703 #[test]
704 #[cfg(feature = "alloc")]
705 fn batch_invert() {
706 let k: FieldElement = FieldElement::random(&mut OsRng);
707 let l: FieldElement = FieldElement::random(&mut OsRng);
708
709 let expected = vec![k.invert().unwrap(), l.invert().unwrap()];
710 let field_elements = vec![k, l];
711 let res: Vec<_> =
712 <FieldElement as BatchInvert<_>>::batch_invert(field_elements.as_slice()).unwrap();
713 assert_eq!(res, expected);
714 }
715
716 #[test]
717 fn sqrt() {
718 let one = FieldElement::ONE;
719 let two = one + &one;
720 let four = two.square();
721 assert_eq!(four.sqrt().unwrap().normalize(), two.normalize());
722 }
723
724 #[test]
725 #[cfg_attr(
726 debug_assertions,
727 should_panic(expected = "assertion failed: self.normalized")
728 )]
729 fn unnormalized_is_odd() {
730 let x = FieldElement::from_bytes_unchecked(&[
737 61, 128, 156, 189, 241, 12, 174, 4, 80, 52, 238, 78, 188, 251, 9, 188, 95, 115, 38, 6,
738 212, 168, 175, 174, 211, 232, 208, 14, 182, 45, 59, 122,
739 ]);
740 let y = x.sqrt().unwrap();
743
744 assert!(y.normalize().is_odd().unwrap_u8() == 0);
746
747 let _result = y.is_odd();
749 }
750
751 prop_compose! {
752 fn field_element()(bytes in any::<[u8; 32]>()) -> FieldElement {
753 let mut res = bytes_to_biguint(&bytes);
754 let m = FieldElement::modulus_as_biguint();
755 if res >= m {
758 res -= m;
759 }
760 FieldElement::from(&res)
761 }
762 }
763
764 proptest! {
765
766 #[test]
767 fn fuzzy_add(
768 a in field_element(),
769 b in field_element()
770 ) {
771 let a_bi = a.to_biguint().unwrap();
772 let b_bi = b.to_biguint().unwrap();
773 let res_bi = (&a_bi + &b_bi) % FieldElement::modulus_as_biguint();
774 let res_ref = FieldElement::from(&res_bi);
775 let res_test = (&a + &b).normalize();
776 assert_eq!(res_test, res_ref);
777 }
778
779 #[test]
780 fn fuzzy_mul(
781 a in field_element(),
782 b in field_element()
783 ) {
784 let a_bi = a.to_biguint().unwrap();
785 let b_bi = b.to_biguint().unwrap();
786 let res_bi = (&a_bi * &b_bi) % FieldElement::modulus_as_biguint();
787 let res_ref = FieldElement::from(&res_bi);
788 let res_test = (&a * &b).normalize();
789 assert_eq!(res_test, res_ref);
790 }
791
792 #[test]
793 fn fuzzy_square(
794 a in field_element()
795 ) {
796 let a_bi = a.to_biguint().unwrap();
797 let res_bi = (&a_bi * &a_bi) % FieldElement::modulus_as_biguint();
798 let res_ref = FieldElement::from(&res_bi);
799 let res_test = a.square().normalize();
800 assert_eq!(res_test, res_ref);
801 }
802
803 #[test]
804 fn fuzzy_negate(
805 a in field_element()
806 ) {
807 let m = FieldElement::modulus_as_biguint();
808 let a_bi = a.to_biguint().unwrap();
809 let res_bi = (&m - &a_bi) % &m;
810 let res_ref = FieldElement::from(&res_bi);
811 let res_test = a.negate(1).normalize();
812 assert_eq!(res_test, res_ref);
813 }
814
815 #[test]
816 fn fuzzy_sqrt(
817 a in field_element()
818 ) {
819 let m = FieldElement::modulus_as_biguint();
820 let a_bi = a.to_biguint().unwrap();
821 let sqr_bi = (&a_bi * &a_bi) % &m;
822 let sqr = FieldElement::from(&sqr_bi);
823
824 let res_ref1 = a;
825 let possible_sqrt = (&m - &a_bi) % &m;
826 let res_ref2 = FieldElement::from(&possible_sqrt);
827 let res_test = sqr.sqrt().unwrap().normalize();
828 assert!(res_test == res_ref1 || res_test == res_ref2);
830 }
831
832 #[test]
833 fn fuzzy_invert(
834 a in field_element()
835 ) {
836 let a = if bool::from(a.is_zero()) { FieldElement::ONE } else { a };
837 let a_bi = a.to_biguint().unwrap();
838 let inv = a.invert().unwrap().normalize();
839 let inv_bi = inv.to_biguint().unwrap();
840 let m = FieldElement::modulus_as_biguint();
841 assert_eq!((&inv_bi * &a_bi) % &m, 1.to_biguint().unwrap());
842 }
843 }
844}