1use alloc::string::ToString;
17use core::{
18 cmp::Ordering,
19 fmt::{Debug, Display, Formatter},
20 iter::{Product, Sum},
21 marker::PhantomData,
22 ops::{
23 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
24 },
25};
26
27use educe::Educe;
28use num_traits::{One, Zero};
29
30use crate::{
31 arithmetic::{
32 limb,
33 uint::{Uint, WideUint},
34 BigInteger,
35 },
36 const_for, const_for_unroll6,
37 field::{group::AdditiveGroup, prime::PrimeField, Field},
38};
39
40pub trait FpParams<const N: usize>: Send + Sync + 'static + Sized {
43 const MODULUS: Uint<N>;
45
46 const GENERATOR: Fp<Self, N>;
50
51 const HAS_MODULUS_SPARE_BIT: bool = Self::MODULUS.limbs[N - 1] >> 63 == 0;
53
54 const INV: u64 = inv::<Self, N>();
56
57 const R: Uint<N> = WideUint::new(Uint::<N>::MAX, Uint::<N>::ZERO)
62 .rem(&Self::MODULUS)
63 .wrapping_add(&Uint::ONE);
64
65 const R2: Uint<N> = WideUint::new(Uint::<N>::MAX, Uint::<N>::MAX)
68 .rem(&Self::MODULUS)
69 .wrapping_add(&Uint::ONE);
70
71 #[inline(always)]
73 fn add_assign(a: &mut Fp<Self, N>, b: &Fp<Self, N>) {
74 let c = a.montgomery_form.checked_add_assign(&b.montgomery_form);
76 if Self::HAS_MODULUS_SPARE_BIT {
78 *a = a.subtract_modulus();
79 } else {
80 *a = a.carrying_sub_modulus(c);
81 }
82 }
83
84 #[inline(always)]
86 fn sub_assign(a: &mut Fp<Self, N>, b: &Fp<Self, N>) {
87 if b.montgomery_form > a.montgomery_form {
89 a.montgomery_form.checked_add_assign(&Self::MODULUS);
90 }
91 a.montgomery_form.checked_sub_assign(&b.montgomery_form);
92 }
93
94 #[inline(always)]
96 fn double_in_place(a: &mut Fp<Self, N>) {
97 let c = a.montgomery_form.checked_mul2_assign();
99 if Self::HAS_MODULUS_SPARE_BIT {
101 *a = a.subtract_modulus();
102 } else {
103 *a = a.carrying_sub_modulus(c);
104 }
105 }
106
107 #[inline(always)]
109 fn neg_in_place(a: &mut Fp<Self, N>) {
110 if !a.is_zero() {
111 let mut tmp = Self::MODULUS;
112 tmp.checked_sub_assign(&a.montgomery_form);
113 a.montgomery_form = tmp;
114 }
115 }
116
117 #[inline(always)]
122 fn mul_assign(a: &mut Fp<Self, N>, b: &Fp<Self, N>) {
123 *a = Fp::<Self, N>::mul(a, b);
124 }
125
126 #[inline(always)]
128 fn square_in_place(a: &mut Fp<Self, N>) {
129 *a = Fp::<Self, N>::mul(a, a);
130 }
131
132 #[must_use]
141 #[inline(always)]
142 fn inverse(a: &Fp<Self, N>) -> Option<Fp<Self, N>> {
143 if a.is_zero() {
144 return None;
145 }
146
147 let one = Uint::ONE;
148
149 let mut u = a.montgomery_form;
150 let mut v = Self::MODULUS;
151 let mut b = Fp::new_unchecked(Self::R2); let mut c = Fp::zero();
153
154 while u != one && v != one {
155 while u.is_even() {
156 u.div2_assign();
157
158 if b.montgomery_form.is_even() {
159 b.montgomery_form.div2_assign();
160 } else {
161 let carry =
162 b.montgomery_form.checked_add_assign(&Self::MODULUS);
163 b.montgomery_form.div2_assign();
164 if !Self::HAS_MODULUS_SPARE_BIT && carry {
165 b.montgomery_form.limbs[N - 1] |= 1 << 63;
166 }
167 }
168 }
169
170 while v.is_even() {
171 v.div2_assign();
172
173 if c.montgomery_form.is_even() {
174 c.montgomery_form.div2_assign();
175 } else {
176 let carry =
177 c.montgomery_form.checked_add_assign(&Self::MODULUS);
178 c.montgomery_form.div2_assign();
179 if !Self::HAS_MODULUS_SPARE_BIT && carry {
180 c.montgomery_form.limbs[N - 1] |= 1 << 63;
181 }
182 }
183 }
184
185 if v < u {
186 u.checked_sub_assign(&v);
187 b -= &c;
188 } else {
189 v.checked_sub_assign(&u);
190 c -= &b;
191 }
192 }
193
194 if u == one {
195 Some(b)
196 } else {
197 Some(c)
198 }
199 }
200
201 #[must_use]
205 #[inline(always)]
206 fn from_bigint(num: Uint<N>) -> Fp<Self, N> {
207 Fp::<Self, N>::from_bigint(num)
208 }
209
210 #[must_use]
212 #[inline(always)]
213 fn into_bigint(elem: Fp<Self, N>) -> Uint<N> {
214 elem.into_bigint()
215 }
216}
217
218#[must_use]
220pub const fn inv<T: FpParams<N>, const N: usize>() -> u64 {
221 let mut inv = 1u64;
231 const_for!((_i in 0..63) {
232 inv = inv.wrapping_mul(inv);
234 inv = inv.wrapping_mul(T::MODULUS.limbs[0]);
236 });
237 inv.wrapping_neg()
238}
239
240#[derive(Educe)]
244#[educe(Default, Clone, Copy, PartialEq, Eq, Hash)]
245pub struct Fp<P: FpParams<N>, const N: usize> {
246 montgomery_form: Uint<N>,
250 #[doc(hidden)]
251 phantom: PhantomData<P>,
252}
253
254macro_rules! declare_fp {
256 ($fp:ident, $limbs:ident, $bits:expr) => {
257 #[doc = "Finite field with max"]
258 #[doc = stringify!($bits)]
259 #[doc = "bits size element."]
260 pub type $fp<P> = $crate::field::fp::Fp<
261 P,
262 {
263 usize::div_ceil(
264 $bits,
265 $crate::arithmetic::limb::Limb::BITS as usize,
266 )
267 },
268 >;
269
270 #[doc = "Number of limbs in the field with"]
271 #[doc = stringify!($bits)]
272 #[doc = "bits size element."]
273 pub const $limbs: usize = usize::div_ceil(
274 $bits,
275 $crate::arithmetic::limb::Limb::BITS as usize,
276 );
277 };
278}
279
280declare_fp!(Fp64, LIMBS_64, 64);
281declare_fp!(Fp128, LIMBS_128, 128);
282declare_fp!(Fp192, LIMBS_192, 192);
283declare_fp!(Fp256, LIMBS_256, 256);
284declare_fp!(Fp320, LIMBS_320, 320);
285declare_fp!(Fp384, LIMBS_384, 384);
286declare_fp!(Fp448, LIMBS_448, 448);
287declare_fp!(Fp512, LIMBS_512, 512);
288declare_fp!(Fp576, LIMBS_576, 576);
289declare_fp!(Fp640, LIMBS_640, 640);
290declare_fp!(Fp704, LIMBS_704, 704);
291declare_fp!(Fp768, LIMBS_768, 768);
292declare_fp!(Fp832, LIMBS_832, 832);
293
294impl<P: FpParams<N>, const N: usize> Fp<P, N> {
295 pub const GENERATOR: Fp<P, N> = P::GENERATOR;
301 pub const ONE: Fp<P, N> = Fp::new_unchecked(P::R);
304 pub const ZERO: Fp<P, N> = Fp::new_unchecked(Uint { limbs: [0; N] });
307
308 #[must_use]
314 #[inline(always)]
315 pub const fn new_unchecked(element: Uint<N>) -> Self {
316 Self { montgomery_form: element, phantom: PhantomData }
317 }
318
319 #[doc(hidden)]
320 #[inline(always)]
321 #[must_use]
322 pub const fn is_ge_modulus(&self) -> bool {
323 self.montgomery_form.ge(&P::MODULUS)
324 }
325
326 #[inline(always)]
327 const fn subtract_modulus(mut self) -> Self {
328 if self.is_ge_modulus() {
329 self.montgomery_form =
330 self.montgomery_form.wrapping_sub(&P::MODULUS);
331 }
332 self
333 }
334
335 #[inline]
338 #[must_use]
339 pub const fn new(element: Uint<N>) -> Self {
340 let r = Self { montgomery_form: element, phantom: PhantomData };
341 if r.is_zero() {
342 r
343 } else {
344 Fp::<P, N>::mul(
345 &r,
346 &Fp { montgomery_form: P::R2, phantom: PhantomData },
347 )
348 }
349 }
350
351 #[inline(always)]
357 #[must_use]
358 pub const fn mul(&self, rhs: &Self) -> Self {
359 let (carry, result) = self.mul_without_cond_subtract(rhs);
360 if P::HAS_MODULUS_SPARE_BIT {
361 result.subtract_modulus()
362 } else {
363 result.carrying_sub_modulus(carry)
364 }
365 }
366
367 #[inline(always)]
369 #[must_use]
370 pub const fn neg(self) -> Self {
371 if self.is_zero() {
372 return self;
373 }
374
375 let (res, _) = Self::MODULUS.checked_sub(&self.montgomery_form);
377 Fp::new_unchecked(res)
378 }
379
380 #[must_use]
382 pub const fn is_zero(&self) -> bool {
383 self.montgomery_form.is_zero()
384 }
385
386 #[inline(always)]
388 const fn carrying_sub_modulus(mut self, carry: bool) -> Self {
389 if carry || self.is_ge_modulus() {
390 self.montgomery_form =
391 self.montgomery_form.wrapping_sub(&P::MODULUS);
392 }
393 self
394 }
395
396 #[inline(always)]
397 const fn mul_without_cond_subtract(&self, other: &Self) -> (bool, Self) {
398 let (lo, hi) =
399 self.montgomery_form.widening_mul(&other.montgomery_form);
400
401 let (carry, res) = Self::widening_montgomery_reduction(lo, hi);
402 (carry, Self::new_unchecked(res))
403 }
404
405 #[inline(always)]
413 const fn widening_montgomery_reduction(
414 mut lo: Uint<N>,
415 mut hi: Uint<N>,
416 ) -> (bool, Uint<N>) {
417 let mut carry2 = false;
418 const_for_unroll6!((i in 0..N) {
419 let tmp = lo.limbs[i].wrapping_mul(P::INV);
420
421 let (_, mut carry) = limb::mac(lo.limbs[i], tmp, P::MODULUS.limbs[0]);
422
423 const_for_unroll6!((j in 1..N) {
424 let k = i + j;
425 if k >= N {
426 (hi.limbs[k - N], carry) = limb::carrying_mac(
427 hi.limbs[k - N],
428 tmp,
429 P::MODULUS.limbs[j],
430 carry
431 );
432 } else {
433 (lo.limbs[k], carry) = limb::carrying_mac(
434 lo.limbs[k],
435 tmp,
436 P::MODULUS.limbs[j],
437 carry
438 );
439 }
440 });
441 (hi.limbs[i], carry2) = limb::adc(hi.limbs[i], carry, carry2);
442 });
443
444 (carry2, hi)
445 }
446
447 #[inline(always)]
457 const fn montgomery_reduction(self) -> Uint<N> {
458 let mut limbs = self.montgomery_form.limbs;
459 const_for!((i in 0..N) {
460 let k = limbs[i].wrapping_mul(P::INV);
461
462 let (_, mut carry) = limb::mac(limbs[i], k, Self::MODULUS.limbs[0]);
463 const_for!((j in 1..N) {
464 (limbs[(j + i) % N], carry) = limb::carrying_mac(
465 limbs[(j + i) % N],
466 k,
467 Self::MODULUS.limbs[j],
468 carry,
469 );
470 });
471 limbs[i % N] = carry;
472 });
473 Uint::new(limbs)
474 }
475
476 #[must_use]
483 pub const fn from_fp<P2: FpParams<N2>, const N2: usize>(
484 value: Fp<P2, N2>,
485 ) -> Self {
486 let value = value.into_bigint();
487 let uint = Uint::<N>::from_uint(value);
488 Self::from_bigint(uint)
489 }
490
491 #[must_use]
495 #[inline(always)]
496 pub const fn from_bigint(num: Uint<N>) -> Self {
497 let elem = Fp::new_unchecked(num);
498 if elem.is_zero() {
499 elem
500 } else {
501 Fp::<P, N>::mul(&elem, &Fp::new_unchecked(P::R2))
502 }
503 }
504
505 #[must_use]
508 #[inline(always)]
509 pub const fn into_bigint(self) -> Uint<N> {
510 self.montgomery_reduction()
511 }
512}
513
514impl<P: FpParams<N>, const N: usize> Debug for Fp<P, N> {
515 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
516 Debug::fmt(&self.into_bigint(), f)
517 }
518}
519
520impl<P: FpParams<N>, const N: usize> Zero for Fp<P, N> {
521 #[inline]
522 fn zero() -> Self {
523 Self::ZERO
524 }
525
526 #[inline]
527 fn is_zero(&self) -> bool {
528 *self == Self::ZERO
529 }
530}
531
532impl<P: FpParams<N>, const N: usize> One for Fp<P, N> {
533 #[inline]
534 fn one() -> Self {
535 Self::ONE
536 }
537
538 #[inline]
539 fn is_one(&self) -> bool {
540 *self == Self::ONE
541 }
542}
543
544impl<P: FpParams<N>, const N: usize> AdditiveGroup for Fp<P, N> {
545 type Scalar = Self;
546
547 const ZERO: Self = Self::ZERO;
548
549 #[inline]
550 fn double(&self) -> Self {
551 let mut temp = *self;
552 temp.double_in_place();
553 temp
554 }
555
556 #[inline]
557 fn double_in_place(&mut self) -> &mut Self {
558 P::double_in_place(self);
559 self
560 }
561
562 #[inline]
563 fn neg_in_place(&mut self) -> &mut Self {
564 P::neg_in_place(self);
565 self
566 }
567}
568
569impl<P: FpParams<N>, const N: usize> Field for Fp<P, N> {
570 const ONE: Self = Fp::new_unchecked(P::R);
571
572 fn extension_degree() -> usize {
573 1
574 }
575
576 #[inline]
577 fn square(&self) -> Self {
578 let mut temp = *self;
579 temp.square_in_place();
580 temp
581 }
582
583 #[inline]
584 fn square_in_place(&mut self) -> &mut Self {
585 P::square_in_place(self);
586 self
587 }
588
589 #[inline]
590 fn inverse(&self) -> Option<Self> {
591 P::inverse(self)
592 }
593
594 fn inverse_in_place(&mut self) -> Option<&mut Self> {
595 if let Some(inverse) = self.inverse() {
596 *self = inverse;
597 Some(self)
598 } else {
599 None
600 }
601 }
602}
603
604impl<P: FpParams<N>, const N: usize> PrimeField for Fp<P, N> {
605 type BigInt = Uint<N>;
606
607 const HAS_MODULUS_SPARE_BIT: bool = P::HAS_MODULUS_SPARE_BIT;
608 const MODULUS: Self::BigInt = P::MODULUS;
609 const MODULUS_BIT_SIZE: usize = <Uint<N> as BigInteger>::BITS;
610
611 #[inline]
612 fn from_bigint(repr: Self::BigInt) -> Self {
613 P::from_bigint(repr)
614 }
615
616 #[inline]
617 fn into_bigint(self) -> Uint<N> {
618 P::into_bigint(self)
619 }
620}
621
622impl<P: FpParams<N>, const N: usize> Ord for Fp<P, N> {
623 fn cmp(&self, other: &Self) -> Ordering {
624 self.into_bigint().cmp(&other.into_bigint())
625 }
626}
627
628impl<P: FpParams<N>, const N: usize> PartialOrd for Fp<P, N> {
629 #[inline]
630 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
631 Some(self.cmp(other))
632 }
633}
634
635macro_rules! impl_fp_from_unsigned_int {
637 ($int:ty) => {
638 impl<P: FpParams<N>, const N: usize> From<$int> for Fp<P, N> {
639 fn from(other: $int) -> Self {
640 Fp::from_bigint(Uint::from(other))
641 }
642 }
643 };
644}
645
646macro_rules! impl_fp_from_signed_int {
648 ($int:ty) => {
649 impl<P: FpParams<N>, const N: usize> From<$int> for Fp<P, N> {
650 fn from(other: $int) -> Self {
651 let abs = other.unsigned_abs().into();
652 if other.is_positive() {
653 abs
654 } else {
655 -abs
656 }
657 }
658 }
659 };
660}
661
662impl_fp_from_unsigned_int!(u128);
663impl_fp_from_unsigned_int!(u64);
664impl_fp_from_unsigned_int!(u32);
665impl_fp_from_unsigned_int!(u16);
666impl_fp_from_unsigned_int!(u8);
667
668impl_fp_from_signed_int!(i128);
669impl_fp_from_signed_int!(i64);
670impl_fp_from_signed_int!(i32);
671impl_fp_from_signed_int!(i16);
672impl_fp_from_signed_int!(i8);
673
674impl<P: FpParams<N>, const N: usize> From<bool> for Fp<P, N> {
675 fn from(other: bool) -> Self {
676 u8::from(other).into()
677 }
678}
679
680macro_rules! impl_int_from_fp {
685 ($int:ty) => {
686 impl<P: FpParams<1>> From<Fp<P, 1>> for $int {
687 fn from(other: Fp<P, 1>) -> Self {
688 let uint = other.into_bigint();
689 let words = uint.as_limbs();
690 <$int>::try_from(words[0]).unwrap_or_else(|_| {
691 panic!("should convert to {}", stringify!($int))
692 })
693 }
694 }
695 };
696}
697
698impl_int_from_fp!(u128);
699impl_int_from_fp!(u64);
700impl_int_from_fp!(u32);
701impl_int_from_fp!(u16);
702impl_int_from_fp!(u8);
703impl_int_from_fp!(i128);
704impl_int_from_fp!(i64);
705impl_int_from_fp!(i32);
706impl_int_from_fp!(i16);
707impl_int_from_fp!(i8);
708
709impl<P: FpParams<N>, const N: usize> Display for Fp<P, N> {
712 #[inline]
713 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
714 let str = self.into_bigint().to_string();
715 write!(f, "{str}")
716 }
717}
718
719impl<P: FpParams<N>, const N: usize> Neg for Fp<P, N> {
720 type Output = Self;
721
722 #[inline]
723 fn neg(mut self) -> Self {
724 P::neg_in_place(&mut self);
725 self
726 }
727}
728
729impl<P: FpParams<N>, const N: usize> Add<&Fp<P, N>> for Fp<P, N> {
730 type Output = Self;
731
732 #[inline]
733 fn add(mut self, other: &Self) -> Self {
734 self.add_assign(other);
735 self
736 }
737}
738
739impl<P: FpParams<N>, const N: usize> Sub<&Fp<P, N>> for Fp<P, N> {
740 type Output = Self;
741
742 #[inline]
743 fn sub(mut self, other: &Self) -> Self {
744 self.sub_assign(other);
745 self
746 }
747}
748
749impl<P: FpParams<N>, const N: usize> Mul<&Fp<P, N>> for Fp<P, N> {
750 type Output = Self;
751
752 #[inline]
753 fn mul(mut self, other: &Self) -> Self {
754 self.mul_assign(other);
755 self
756 }
757}
758
759impl<P: FpParams<N>, const N: usize> Div<&Fp<P, N>> for Fp<P, N> {
760 type Output = Self;
761
762 #[inline]
763 fn div(mut self, other: &Self) -> Self {
764 self.mul_assign(&other.inverse().expect("should not divide by zero"));
767 self
768 }
769}
770
771impl<P: FpParams<N>, const N: usize> Add<&Fp<P, N>> for &Fp<P, N> {
772 type Output = Fp<P, N>;
773
774 #[inline]
775 fn add(self, other: &Fp<P, N>) -> Fp<P, N> {
776 let mut result = *self;
777 result.add_assign(other);
778 result
779 }
780}
781
782impl<P: FpParams<N>, const N: usize> Sub<&Fp<P, N>> for &Fp<P, N> {
783 type Output = Fp<P, N>;
784
785 #[inline]
786 fn sub(self, other: &Fp<P, N>) -> Fp<P, N> {
787 let mut result = *self;
788 result.sub_assign(other);
789 result
790 }
791}
792
793impl<P: FpParams<N>, const N: usize> Mul<&Fp<P, N>> for &Fp<P, N> {
794 type Output = Fp<P, N>;
795
796 #[inline]
797 fn mul(self, other: &Fp<P, N>) -> Fp<P, N> {
798 let mut result = *self;
799 result.mul_assign(other);
800 result
801 }
802}
803
804impl<P: FpParams<N>, const N: usize> Div<&Fp<P, N>> for &Fp<P, N> {
805 type Output = Fp<P, N>;
806
807 #[inline]
808 fn div(self, other: &Fp<P, N>) -> Fp<P, N> {
809 let mut result = *self;
810 result.div_assign(other);
811 result
812 }
813}
814
815impl<P: FpParams<N>, const N: usize> AddAssign<&Self> for Fp<P, N> {
816 #[inline]
817 fn add_assign(&mut self, other: &Self) {
818 P::add_assign(self, other);
819 }
820}
821
822impl<P: FpParams<N>, const N: usize> SubAssign<&Self> for Fp<P, N> {
823 #[inline]
824 fn sub_assign(&mut self, other: &Self) {
825 P::sub_assign(self, other);
826 }
827}
828
829impl<P: FpParams<N>, const N: usize> Add<Self> for Fp<P, N> {
830 type Output = Self;
831
832 #[inline]
833 fn add(mut self, other: Self) -> Self {
834 self.add_assign(&other);
835 self
836 }
837}
838
839impl<P: FpParams<N>, const N: usize> Add<&mut Self> for Fp<P, N> {
840 type Output = Self;
841
842 #[inline]
843 fn add(mut self, other: &mut Self) -> Self {
844 self.add_assign(&*other);
845 self
846 }
847}
848
849impl<P: FpParams<N>, const N: usize> Sub<Self> for Fp<P, N> {
850 type Output = Self;
851
852 #[inline]
853 fn sub(mut self, other: Self) -> Self {
854 self.sub_assign(&other);
855 self
856 }
857}
858
859impl<P: FpParams<N>, const N: usize> Sub<&mut Self> for Fp<P, N> {
860 type Output = Self;
861
862 #[inline]
863 fn sub(mut self, other: &mut Self) -> Self {
864 self.sub_assign(&*other);
865 self
866 }
867}
868
869impl<P: FpParams<N>, const N: usize> Sum<Self> for Fp<P, N> {
870 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
871 iter.fold(Self::zero(), Add::add)
872 }
873}
874
875impl<'a, P: FpParams<N>, const N: usize> Sum<&'a Self> for Fp<P, N> {
876 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
877 iter.fold(Self::zero(), Add::add)
878 }
879}
880
881impl<P: FpParams<N>, const N: usize> AddAssign<Self> for Fp<P, N> {
882 #[inline]
883 fn add_assign(&mut self, other: Self) {
884 self.add_assign(&other);
885 }
886}
887
888impl<P: FpParams<N>, const N: usize> SubAssign<Self> for Fp<P, N> {
889 #[inline]
890 fn sub_assign(&mut self, other: Self) {
891 self.sub_assign(&other);
892 }
893}
894
895impl<P: FpParams<N>, const N: usize> AddAssign<&mut Self> for Fp<P, N> {
896 #[inline]
897 fn add_assign(&mut self, other: &mut Self) {
898 self.add_assign(&*other);
899 }
900}
901
902impl<P: FpParams<N>, const N: usize> SubAssign<&mut Self> for Fp<P, N> {
903 #[inline]
904 fn sub_assign(&mut self, other: &mut Self) {
905 self.sub_assign(&*other);
906 }
907}
908
909impl<P: FpParams<N>, const N: usize> MulAssign<&Self> for Fp<P, N> {
910 #[inline]
911 fn mul_assign(&mut self, other: &Self) {
912 P::mul_assign(self, other);
913 }
914}
915
916impl<P: FpParams<N>, const N: usize> DivAssign<&Self> for Fp<P, N> {
917 #[inline]
918 fn div_assign(&mut self, other: &Self) {
919 self.mul_assign(&other.inverse().expect("should not divide by zero"));
922 }
923}
924
925impl<P: FpParams<N>, const N: usize> Mul<Self> for Fp<P, N> {
926 type Output = Self;
927
928 #[inline]
929 fn mul(mut self, other: Self) -> Self {
930 self.mul_assign(&other);
931 self
932 }
933}
934
935impl<P: FpParams<N>, const N: usize> Div<Self> for Fp<P, N> {
936 type Output = Self;
937
938 #[inline]
939 fn div(mut self, other: Self) -> Self {
940 use DivAssign;
941 self.div_assign(&other);
942 self
943 }
944}
945
946impl<P: FpParams<N>, const N: usize> Mul<&mut Self> for Fp<P, N> {
947 type Output = Self;
948
949 #[inline]
950 fn mul(mut self, other: &mut Self) -> Self {
951 self.mul_assign(&*other);
952 self
953 }
954}
955
956impl<P: FpParams<N>, const N: usize> Div<&mut Self> for Fp<P, N> {
957 type Output = Self;
958
959 #[inline]
960 fn div(mut self, other: &mut Self) -> Self {
961 self.div_assign(&*other);
962 self
963 }
964}
965
966impl<P: FpParams<N>, const N: usize> Product<Self> for Fp<P, N> {
967 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
968 iter.fold(Self::one(), Mul::mul)
969 }
970}
971
972impl<'a, P: FpParams<N>, const N: usize> Product<&'a Self> for Fp<P, N> {
973 fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
974 iter.fold(Self::one(), Mul::mul)
975 }
976}
977
978impl<P: FpParams<N>, const N: usize> MulAssign<Self> for Fp<P, N> {
979 #[inline]
980 fn mul_assign(&mut self, other: Self) {
981 self.mul_assign(&other);
982 }
983}
984
985impl<P: FpParams<N>, const N: usize> DivAssign<&mut Self> for Fp<P, N> {
986 #[inline]
987 fn div_assign(&mut self, other: &mut Self) {
988 self.div_assign(&*other);
989 }
990}
991
992impl<P: FpParams<N>, const N: usize> MulAssign<&mut Self> for Fp<P, N> {
993 #[inline]
994 fn mul_assign(&mut self, other: &mut Self) {
995 self.mul_assign(&*other);
996 }
997}
998
999impl<P: FpParams<N>, const N: usize> DivAssign<Self> for Fp<P, N> {
1000 #[inline]
1001 fn div_assign(&mut self, other: Self) {
1002 self.div_assign(&other);
1003 }
1004}
1005
1006impl<P: FpParams<N>, const N: usize> zeroize::Zeroize for Fp<P, N> {
1007 fn zeroize(&mut self) {
1010 self.montgomery_form.zeroize();
1011 }
1012}
1013
1014impl<P: FpParams<N>, const N: usize> From<Fp<P, N>> for Uint<N> {
1015 #[inline]
1016 fn from(fp: Fp<P, N>) -> Self {
1017 fp.into_bigint()
1018 }
1019}
1020
1021impl<P: FpParams<N>, const N: usize> From<Uint<N>> for Fp<P, N> {
1022 #[inline]
1023 fn from(int: Uint<N>) -> Self {
1024 Self::from_bigint(int)
1025 }
1026}
1027
1028#[macro_export]
1030macro_rules! fp_from_num {
1031 ($num:literal) => {
1032 $crate::field::fp::Fp::new($crate::arithmetic::uint::from_str_radix(
1033 $num, 10,
1034 ))
1035 };
1036}
1037
1038#[macro_export]
1040macro_rules! fp_from_hex {
1041 ($num:literal) => {{
1042 $crate::field::fp::Fp::new($crate::arithmetic::uint::from_str_hex($num))
1043 }};
1044}
1045
1046#[cfg(test)]
1047mod tests {
1048 use proptest::prelude::*;
1049
1050 use super::*;
1051 use crate::{
1052 arithmetic::uint::{U256, U512, U64},
1053 field::{
1054 fp::{Fp64, FpParams, LIMBS_64},
1055 group::AdditiveGroup,
1056 },
1057 fp_from_num, from_num,
1058 };
1059
1060 type Field64 = Fp64<Fp64Param>;
1061 struct Fp64Param;
1062 impl FpParams<LIMBS_64> for Fp64Param {
1063 const GENERATOR: Fp64<Fp64Param> = fp_from_num!("3");
1064 const MODULUS: U64 = from_num!("1000003"); }
1066
1067 const MODULUS: i128 = 1000003; #[test]
1070 fn add() {
1071 proptest!(|(a: i64, b: i64)| {
1072 let res = Field64::from(a) + Field64::from(b);
1073 let res: i128 = res.into();
1074 let a = i128::from(a);
1075 let b = i128::from(b);
1076 prop_assert_eq!(res, (a + b).rem_euclid(MODULUS));
1077 });
1078 }
1079
1080 #[test]
1081 fn double() {
1082 proptest!(|(a: i64)| {
1083 let res = Field64::from(a).double();
1084 let res: i128 = res.into();
1085 let a = i128::from(a);
1086 prop_assert_eq!(res, (a + a).rem_euclid(MODULUS));
1087 });
1088 }
1089
1090 #[test]
1091 fn sub() {
1092 proptest!(|(a: i64, b: i64)| {
1093 let res = Field64::from(a) - Field64::from(b);
1094 let res: i128 = res.into();
1095 let a = i128::from(a);
1096 let b = i128::from(b);
1097 prop_assert_eq!(res, (a - b).rem_euclid(MODULUS));
1098 });
1099 }
1100
1101 #[test]
1102 fn mul() {
1103 proptest!(|(a: i64, b: i64)| {
1104 let res = Field64::from(a) * Field64::from(b);
1105 let res: i128 = res.into();
1106 let a = i128::from(a);
1107 let b = i128::from(b);
1108 prop_assert_eq!(res, (a * b).rem_euclid(MODULUS));
1109 });
1110 }
1111
1112 #[test]
1113 fn square() {
1114 proptest!(|(a: i64)| {
1115 let res = Field64::from(a).square();
1116 let res: i128 = res.into();
1117 let a = i128::from(a);
1118 prop_assert_eq!(res, (a * a).rem_euclid(MODULUS));
1119 });
1120 }
1121
1122 prop_compose! {
1123 fn non_zero_modulo_i64()(
1124 b in 1..i64::MAX
1125 ) -> i64 {
1126 if i128::from(b) % MODULUS == 0 {
1127 b + 1
1128 } else {
1129 b
1130 }
1131 }
1132 }
1133
1134 #[test]
1135 fn div() {
1136 proptest!(|(a: i64, b in non_zero_modulo_i64())| {
1137 let res = Field64::from(a) / Field64::from(b);
1138 let res: i128 = res.into();
1139 let a = i128::from(a);
1140 let b = i128::from(b);
1141 prop_assert_eq!((res * b).rem_euclid(MODULUS), a.rem_euclid(MODULUS));
1143 });
1144 }
1145
1146 fn dumb_pow(a: i128, b: i128) -> i128 {
1148 (0..b).fold(1, |acc, _| (acc * a).rem_euclid(MODULUS))
1149 }
1150
1151 #[test]
1152 fn pow() {
1153 proptest!(|(a: i64, b in 0_u32..1000)| {
1154 let res = Field64::from(a).pow(b);
1155 let res: i128 = res.into();
1156 let a = i128::from(a);
1157 let b = i128::from(b);
1158 prop_assert_eq!(res, dumb_pow(a, b));
1159 });
1160 }
1161
1162 #[test]
1163 fn neg() {
1164 proptest!(|(a: i64)| {
1165 let res = -Field64::from(a);
1166 let res: i128 = res.into();
1167 let a = i128::from(a);
1168 prop_assert_eq!(res, (-a).rem_euclid(MODULUS));
1169 });
1170 }
1171
1172 #[test]
1173 fn one() {
1174 proptest!(|(a: i64)| {
1175 let res = Field64::one();
1176 let res: i128 = res.into();
1177 prop_assert_eq!(res, 1);
1178
1179 let res = Field64::one() * Field64::from(a);
1180 let res: i128 = res.into();
1181 let a: i128 = a.into();
1182 prop_assert_eq!(res, a.rem_euclid(MODULUS));
1183 });
1184 }
1185
1186 #[test]
1187 fn zero() {
1188 proptest!(|(a: i64)| {
1189 let res = Field64::zero();
1190 let res: i128 = res.into();
1191 prop_assert_eq!(res, 0);
1192
1193 let res = Field64::zero() + Field64::from(a);
1194 let res: i128 = res.into();
1195 let a: i128 = a.into();
1196 prop_assert_eq!(res, a.rem_euclid(MODULUS));
1197 });
1198 }
1199
1200 #[test]
1201 fn from_fp() {
1202 pub(crate) type Scalar = Fp256<Fp256Param>;
1204
1205 pub(crate) struct Fp256Param;
1206 impl FpParams<LIMBS_256> for Fp256Param {
1207 const GENERATOR: Fp256<Self> = fp_from_num!("2");
1208 const MODULUS: U256 = from_num!("7237005577332262213973186563042994240857116359379907606001950938285454250989");
1209 }
1210
1211 pub(crate) type WideScalar = Fp512<Fp512Param>;
1213
1214 pub(crate) struct Fp512Param;
1215 impl FpParams<LIMBS_512> for Fp512Param {
1216 const GENERATOR: Fp512<Self> = fp_from_num!("2");
1217 const MODULUS: U512 = from_num!("7237005577332262213973186563042994240857116359379907606001950938285454250989");
1218 }
1219
1220 proptest!(|(limbs: [u64; 4])|{
1223 let number = U256::new(limbs);
1224 let expected_scalar = Scalar::from(number);
1225 let wide_scalar = WideScalar::from_fp(expected_scalar);
1226 let scalar = Scalar::from_fp(wide_scalar);
1227
1228 assert_eq!(scalar, expected_scalar);
1229 });
1230 }
1231}