1#![doc = include_str!("../readme.md")]
2#![no_std]
3
4use core::{
5 fmt::{Debug, Display, Write},
6 marker::PhantomData,
7 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
8};
9
10use packet::Packet;
11
12mod numerics;
13mod packet;
14
15pub trait PolySettings<const SIZE: usize, const LOG2: usize>: Sized {
22 const MODULO: u64;
27
28 const DEGREE: usize;
33
34 const OVERFLOW: FinitePoly<Self, SIZE, LOG2>;
47}
48
49pub struct FinitePoly<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> {
84 pub(crate) internal: [Packet<LOG2>; SIZE],
85 pub(crate) _phantom: PhantomData<T>,
86}
87
88impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Eq
89 for FinitePoly<T, SIZE, LOG2>
90{
91}
92
93impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> PartialEq
94 for FinitePoly<T, SIZE, LOG2>
95{
96 fn eq(&self, other: &Self) -> bool {
97 Self::eq(*self, *other)
98 }
99}
100
101impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> PartialEq<u64>
102 for FinitePoly<T, SIZE, LOG2>
103{
104 fn eq(&self, other: &u64) -> bool {
105 self.degree() == 0 && (self.get_nth_coeff(0) % T::MODULO) == *other
106 }
107}
108
109impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Copy
110 for FinitePoly<T, SIZE, LOG2>
111{
112}
113
114impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Clone
115 for FinitePoly<T, SIZE, LOG2>
116{
117 fn clone(&self) -> Self {
118 *self
119 }
120}
121
122impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> FinitePoly<T, SIZE, LOG2> {
129 pub const ZERO: Self = Self {
131 internal: [Packet::<LOG2>::new(); SIZE],
132 _phantom: PhantomData,
133 };
134
135 const FALSE_ZERO: Packet<LOG2> = Packet::splat(T::MODULO as u64 % (1u64 << LOG2));
136 const OVERFLOW: Packet<LOG2> = Packet::splat((1u64 << LOG2) % T::MODULO as u64);
137 const DEGREE_OVERFLOW_BIT: usize = T::DEGREE - 1 - Self::DEGREE_OVERFLOW_U64 * 64;
138 const DEGREE_OVERFLOW_U64: usize = (T::DEGREE - 1) / 64;
139 const FILTER_EXCESS_BITS: u64 =
140 (1 << Self::DEGREE_OVERFLOW_BIT) | ((1 << Self::DEGREE_OVERFLOW_BIT) - 1);
141
142 pub const ONE: Self = Self::from_int(1);
144
145 pub const fn splat(value: u64) -> Self {
156 Self {
157 internal: [Packet::splat(value); SIZE],
158 _phantom: PhantomData,
159 }
160 }
161
162 pub const fn from_int(value: u64) -> Self {
179 let mut me = Self::ZERO;
180 me.internal[0] = Packet::from_int(value % T::MODULO);
181
182 me
183 }
184
185 const fn remove_false_zeros(mut self) -> Self {
200 let mut done = 0;
201
202 while done < SIZE {
203 let temp = self.internal[done];
204
205 let zeros_detect = temp.xor(Self::FALSE_ZERO).or_reduce();
210
211 self.internal[done] = temp.and_u64(zeros_detect);
214
215 done += 1;
216 }
217
218 self
219 }
220
221 pub const fn degree(mut self) -> usize {
238 self = self.remove_false_zeros();
239
240 let mut done = 1;
241
242 while done <= SIZE {
243 let mut to_detect = self.internal[SIZE - done];
244
245 if done == SIZE {
246 to_detect = to_detect.and_u64(Self::FILTER_EXCESS_BITS);
247 }
248
249 let leading = to_detect.leading_zeros();
250 let first_one_idx = 64 - leading;
251
252 if first_one_idx != 0 {
253 let degree_total = first_one_idx + (SIZE - done) as u64 * 64;
254
255 return degree_total as usize - 1;
256 }
257
258 done += 1;
259 }
260
261 0
262 }
263
264 pub const fn eq(self, other: Self) -> bool {
278 let diff = self.sub(other);
279
280 diff.is_zero()
281 }
282
283 pub const fn is_zero(mut self) -> bool {
297 self = self.remove_false_zeros();
298 let mut done = 0;
299
300 while done < SIZE - 1 {
301 if self.internal[done].or_reduce() != 0 {
302 return false;
303 }
304
305 done += 1;
306 }
307
308 if self.internal[SIZE - 1].or_reduce() << (64 - T::DEGREE % 64) != 0 {
309 return false;
310 }
311
312 true
313 }
314
315 const fn add_within(n: Packet<LOG2>, m: Packet<LOG2>) -> Packet<LOG2> {
319 let mut result = n;
320 let mut carry = m;
321 let mut overflow_carry = Packet::new();
322
323 while !carry.is_zero() || !overflow_carry.is_zero() {
324 let add = result.xor(carry).xor(overflow_carry);
325 let new_carry = result
328 .and(carry.or(overflow_carry))
329 .or(carry.and(overflow_carry));
330
331 let (bumped, new_carry) = new_carry.left_shift_horizontal();
332
333 let new_overflow = Self::OVERFLOW.and_u64(bumped);
334
335 result = add;
336 carry = new_carry;
337 overflow_carry = new_overflow;
338 }
339
340 result
341 }
342
343 pub const fn add(mut self, other: Self) -> Self {
359 let mut i = 0;
360 while i < SIZE {
361 self.internal[i] = Self::add_within(self.internal[i], other.internal[i]);
362 i += 1;
363 }
364
365 self
366 }
367
368 const fn sub_within(n: Packet<LOG2>, m: Packet<LOG2>) -> Packet<LOG2> {
371 let mut result = n;
372 let mut carry = m;
373 let mut underflow_carry = Packet::new();
374
375 while !carry.is_zero() || !underflow_carry.is_zero() {
376 let sub = result.xor(carry).xor(underflow_carry);
377
378 let new_carry = result
379 .not()
380 .and(carry.or(underflow_carry))
381 .or(carry.and(underflow_carry));
382
383 let (bumped, new_carry) = new_carry.left_shift_horizontal();
384
385 let new_underflow = Self::OVERFLOW.and_u64(bumped);
386
387 result = sub;
388 carry = new_carry;
389 underflow_carry = new_underflow;
390 }
391
392 result
393 }
394
395 pub const fn sub(mut self, other: Self) -> Self {
411 let mut i = 0;
412 while i < SIZE {
413 self.internal[i] = Self::sub_within(self.internal[i], other.internal[i]);
414 i += 1;
415 }
416
417 self
418 }
419
420 const fn neg_within(n: Packet<LOG2>) -> Packet<LOG2> {
423 let mut result = n;
424 let mut carry = n;
425 let bumped;
426
427 (bumped, carry) = carry.left_shift_horizontal();
428
429 let mut underflow_carry = Self::OVERFLOW.and_u64(bumped);
430
431 while !carry.is_zero() || !underflow_carry.is_zero() {
432 let sub = result.xor(carry).xor(underflow_carry);
433
434 let new_carry = result
435 .not()
436 .and(carry.or(underflow_carry))
437 .or(carry.and(underflow_carry));
438
439 let (bumped, new_carry) = new_carry.left_shift_horizontal();
440
441 let new_underflow = Self::OVERFLOW.and_u64(bumped);
442
443 result = sub;
444 carry = new_carry;
445 underflow_carry = new_underflow;
446 }
447
448 result
449 }
450
451 pub const fn neg(mut self) -> Self {
468 let mut i = 0;
469
470 while i < SIZE {
471 self.internal[i] = Self::neg_within(self.internal[i]);
472
473 i += 1;
474 }
475
476 self
477 }
478
479 pub const fn mul_modulo(self, by: u64) -> Self {
500 let mut by = by % T::MODULO as u64;
501
502 let mut acc = Self::ZERO;
503 let mut power_2 = self;
504
505 while by != 0 {
506 if by & 1 == 1 {
507 acc = acc.add(power_2);
508 }
509
510 by >>= 1;
511 power_2 = power_2.add(power_2);
512 }
513
514 acc
515 }
516
517 pub const fn mul_x(mut self) -> Self {
530 let extracted_overflow =
531 self.internal[Self::DEGREE_OVERFLOW_U64].extract_coefficient(Self::DEGREE_OVERFLOW_BIT);
532
533 let overflow = T::OVERFLOW.mul_modulo(extracted_overflow);
534
535 self = self.unchecked_mulx(1);
536
537 self.add(overflow)
538 }
539
540 pub const fn unchecked_mulx(mut self, power: usize) -> Self {
551 if power == 0 {
552 return self;
553 }
554 let mut done = 0;
555
556 let mut carry = Packet::new();
557
558 while done != SIZE {
559 let new_carry = self.internal[done].rsh(64 - power);
560 self.internal[done] = self.internal[done].lsh(power).or(carry);
561
562 carry = new_carry;
563 done += 1;
564 }
565
566 self
567 }
568
569 pub const fn get_nth_coeff(self, coeff: usize) -> u64 {
582 if coeff >= T::DEGREE {
583 return 0;
584 }
585
586 let u64_idx = coeff / 64;
587 let within_u64_idx = coeff % 64;
588
589 self.internal[u64_idx].extract_coefficient(within_u64_idx)
590 }
591
592 #[must_use = "Since this method is const and cannot take &mut, you must assign it to a new variable."]
605 pub const fn set_coeff(mut self, idx: usize, coeff: u64) -> Self {
606 if idx >= T::DEGREE {
607 return self;
608 }
609
610 let u64_idx = idx / 64;
611 let within_u64_idx = idx % 64;
612
613 self.internal[u64_idx] = self.internal[u64_idx].set_coeff(within_u64_idx, coeff);
614
615 self
616 }
617
618 pub const fn mul(self, other: Self) -> Self {
634 let mut acc = Self::ZERO;
635 let mut power_x = self;
636
637 let mut powers_done = 0;
638
639 while powers_done < T::DEGREE {
640 let coeff = other.get_nth_coeff(powers_done);
641
642 if coeff != 0 {
643 if coeff == 1 {
644 acc = acc.add(power_x);
645 } else {
646 acc = acc.add(power_x.mul_modulo(coeff));
647 }
648 }
649
650 power_x = power_x.mul_x();
651
652 powers_done += 1;
653 }
654
655 acc
656 }
657
658 pub const fn divide_remainder(self, other: Self) -> Option<(Self, Self)> {
677 let other_degree = other.degree();
678
679 let mut quotient = Self::ZERO;
680 let mut remainder = self;
681
682 let mut remainder_degree = remainder.degree();
683
684 while other_degree <= remainder_degree && !remainder.is_zero() {
685 let difference_in_degree = remainder_degree - other_degree;
686 let my_coeff = remainder.get_nth_coeff(remainder_degree);
688 let other_coeff = other.get_nth_coeff(other_degree);
689
690 let Some(inverse) = numerics::divide_modulo(T::MODULO, my_coeff, other_coeff) else {
691 return None;
692 };
693
694 let division = Self::from_int(inverse).unchecked_mulx(difference_in_degree);
695 quotient = quotient.add(division);
696
697 let product = other
698 .mul_modulo(inverse)
699 .unchecked_mulx(difference_in_degree);
700
701 remainder = remainder.sub(product);
702
703 remainder_degree = remainder.degree();
704 }
705
706 Some((quotient, remainder))
707 }
708
709 pub const fn divide_quotient_poly_by_self(self) -> Option<(Self, Self)> {
730 let my_degree = T::DEGREE;
731 let other_degree = self.degree();
732
733 let difference_in_degree = my_degree - other_degree;
734 let other_coeff = self.get_nth_coeff(other_degree);
735
736 let Some(inverse) = numerics::invert_in_modulo(T::MODULO, other_coeff) else {
737 return None;
738 };
739
740 let division = if difference_in_degree == T::DEGREE {
741 return Some((Self::ZERO.sub(T::OVERFLOW).mul_modulo(inverse), Self::ZERO));
742 } else {
743 Self::from_int(inverse).unchecked_mulx(difference_in_degree)
744 };
745
746 let to_remove = self.set_coeff(other_degree, 0);
747
748 let product = to_remove.mul(division);
749
750 let remainder = Self::ZERO.sub(T::OVERFLOW).sub(product);
751
752 let Some((new_division, remainder)) = remainder.divide_remainder(self) else {
753 return None;
754 };
755
756 Some((division.add(new_division), remainder))
757 }
758
759 pub const fn invert(self) -> Option<Self> {
782 let mut t = Self::ZERO;
783 let mut r;
784 let mut new_t = Self::ONE;
785 let mut new_r = self;
786
787 let Some((quotient, remainder)) = self.divide_quotient_poly_by_self() else {
792 return None;
793 };
794
795 (r, new_r) = (new_r, remainder);
796 (t, new_t) = (new_t, t.sub(quotient.mul(new_t)));
797
798 while !new_r.is_zero() {
799 let Some((quotient, remainder)) = Self::divide_remainder(r, new_r) else {
800 return None;
801 };
802
803 (r, new_r) = (new_r, remainder);
804 (t, new_t) = (new_t, t.sub(quotient.mul(new_t)));
805 }
806
807 if r.degree() > 0 {
808 return None;
809 }
810
811 let r_as_integer = r.get_nth_coeff(0);
812 let Some(inverse) = numerics::invert_in_modulo(T::MODULO, r_as_integer) else {
813 return None;
814 };
815
816 Some(t.mul_modulo(inverse))
817 }
818
819 pub const fn from_coeffs(mut coeffs: &[u64]) -> Self {
830 let to_do = if coeffs.len() > T::DEGREE {
831 T::DEGREE
832 } else {
833 coeffs.len()
834 };
835
836 (_, coeffs) = coeffs.split_at(coeffs.len() - to_do);
837
838 let last_block_length = coeffs.len() % 64;
839
840 let (last_block, mut coeffs) = coeffs.split_at(last_block_length);
841
842 let last_block = Packet::from_coeffs(last_block);
843
844 let mut acc = Self::ZERO;
845
846 let mut insertion_idx = 0;
847
848 while coeffs.len() != 0 {
849 let (rest, last) = coeffs.split_at(coeffs.len() - 64);
850
851 coeffs = rest;
852
853 acc.internal[insertion_idx] = Packet::from_coeffs(last);
854
855 insertion_idx += 1;
856 }
857
858 acc.internal[insertion_idx] = last_block;
859
860 acc
861 }
862
863 pub fn format_full(self, mut w: impl Write) -> core::fmt::Result {
865 for i in (1..T::DEGREE).rev() {
866 let coeff = self.get_nth_coeff(i) % T::MODULO as u64;
867
868 write!(w, "{coeff}x^{i} + ")?;
869 }
870
871 write!(w, "{}", self.get_nth_coeff(0) % T::MODULO as u64)
872 }
873
874 pub fn format_filtered(self, mut w: impl Write) -> core::fmt::Result {
876 if self == Self::ZERO {
877 return write!(w, "0");
878 }
879
880 let mut seen_first = false;
881
882 for i in (1..T::DEGREE).rev() {
883 let coeff = self.get_nth_coeff(i) % T::MODULO as u64;
884
885 if coeff != 0 {
886 if seen_first {
887 write!(w, " + ")?;
888 } else {
889 seen_first = true;
890 }
891
892 if coeff != 1 {
893 write!(w, "{coeff}")?;
894 }
895
896 write!(w, "x")?;
897
898 if i != 1 {
899 write!(w, "^{i}")?;
900 }
901 }
902 }
903
904 let zeroth = self.get_nth_coeff(0) % T::MODULO as u64;
905
906 if zeroth != 0 {
907 if seen_first {
908 write!(w, " + {zeroth}")?;
909 } else {
910 write!(w, "{zeroth}")?;
911 }
912 }
913
914 Ok(())
915 }
916
917 pub fn iter() -> FinitePolyIterator<T, SIZE, LOG2> {
919 FinitePolyIterator {
920 coeffs: Some(Self::ZERO),
921 _item: PhantomData,
922 }
923 }
924}
925
926impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Debug
927 for FinitePoly<T, SIZE, LOG2>
928{
929 fn fmt(&self, mut f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
930 self.format_full(&mut f)?;
931 write!(f, " [")?;
932 for val in self.internal[1..].iter().rev() {
933 write!(f, "{val}, ")?;
934 }
935 write!(f, "{}", self.internal[0])?;
936 write!(f, "]")
937 }
938}
939
940impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Display
941 for FinitePoly<T, SIZE, LOG2>
942{
943 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
944 self.format_filtered(f)
945 }
946}
947
948impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Mul<Self>
949 for FinitePoly<T, SIZE, LOG2>
950{
951 type Output = Self;
952
953 fn mul(self, rhs: Self) -> Self {
954 self.mul(rhs)
955 }
956}
957
958impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Mul<u64>
959 for FinitePoly<T, SIZE, LOG2>
960{
961 type Output = Self;
962
963 fn mul(self, rhs: u64) -> Self {
964 self.mul_modulo(rhs)
965 }
966}
967
968impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Div<Self>
969 for FinitePoly<T, SIZE, LOG2>
970{
971 type Output = Self;
972
973 fn div(self, rhs: Self) -> Self {
974 self * rhs.invert().unwrap()
975 }
976}
977
978impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Div<u64>
979 for FinitePoly<T, SIZE, LOG2>
980{
981 type Output = Self;
982
983 fn div(self, rhs: u64) -> Self {
984 self * Self::from_int(rhs).invert().unwrap()
985 }
986}
987
988impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Add<Self>
989 for FinitePoly<T, SIZE, LOG2>
990{
991 type Output = Self;
992
993 fn add(self, rhs: Self) -> Self {
994 self.add(rhs)
995 }
996}
997
998impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Add<u64>
999 for FinitePoly<T, SIZE, LOG2>
1000{
1001 type Output = Self;
1002
1003 fn add(self, rhs: u64) -> Self {
1004 self.add(Self::from_int(rhs))
1005 }
1006}
1007
1008impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Neg
1009 for FinitePoly<T, SIZE, LOG2>
1010{
1011 type Output = Self;
1012
1013 fn neg(self) -> Self {
1014 self.neg()
1015 }
1016}
1017
1018impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Sub<Self>
1019 for FinitePoly<T, SIZE, LOG2>
1020{
1021 type Output = Self;
1022
1023 fn sub(self, rhs: Self) -> Self {
1024 self.sub(rhs)
1025 }
1026}
1027
1028impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Sub<u64>
1029 for FinitePoly<T, SIZE, LOG2>
1030{
1031 type Output = Self;
1032
1033 fn sub(self, rhs: u64) -> Self {
1034 self.sub(Self::from_int(rhs))
1035 }
1036}
1037
1038impl<T: PolySettings<SIZE, LOG2>, U, const SIZE: usize, const LOG2: usize> AddAssign<U>
1039 for FinitePoly<T, SIZE, LOG2>
1040where
1041 Self: Add<U, Output = Self>,
1042{
1043 fn add_assign(&mut self, rhs: U) {
1044 *self = *self + rhs;
1045 }
1046}
1047
1048impl<T: PolySettings<SIZE, LOG2>, U, const SIZE: usize, const LOG2: usize> SubAssign<U>
1049 for FinitePoly<T, SIZE, LOG2>
1050where
1051 Self: Sub<U, Output = Self>,
1052{
1053 fn sub_assign(&mut self, rhs: U) {
1054 *self = *self - rhs;
1055 }
1056}
1057
1058impl<T: PolySettings<SIZE, LOG2>, U, const SIZE: usize, const LOG2: usize> MulAssign<U>
1059 for FinitePoly<T, SIZE, LOG2>
1060where
1061 Self: Mul<U, Output = Self>,
1062{
1063 fn mul_assign(&mut self, rhs: U) {
1064 *self = *self * rhs;
1065 }
1066}
1067
1068impl<T: PolySettings<SIZE, LOG2>, U, const SIZE: usize, const LOG2: usize> DivAssign<U>
1069 for FinitePoly<T, SIZE, LOG2>
1070where
1071 Self: Div<U, Output = Self>,
1072{
1073 fn div_assign(&mut self, rhs: U) {
1074 *self = *self / rhs;
1075 }
1076}
1077
1078pub struct FinitePolyIterator<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> {
1082 coeffs: Option<FinitePoly<T, SIZE, LOG2>>,
1083 _item: PhantomData<FinitePoly<T, SIZE, LOG2>>,
1084}
1085
1086impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> Iterator
1087 for FinitePolyIterator<T, SIZE, LOG2>
1088{
1089 type Item = FinitePoly<T, SIZE, LOG2>;
1090
1091 fn next(&mut self) -> Option<Self::Item> {
1092 let coeffs = self.coeffs?;
1093 let mut new_coeffs = coeffs;
1094
1095 let mut is_zero = true;
1096
1097 for i in 0..T::DEGREE {
1098 let elem = new_coeffs.get_nth_coeff(i);
1099
1100 let mut new_val = elem + 1;
1101
1102 let carry = new_val / T::MODULO as u64;
1103 new_val -= carry * T::MODULO as u64;
1104
1105 new_coeffs = new_coeffs.set_coeff(i, new_val);
1106
1107 is_zero &= new_val == 0;
1108
1109 if carry == 0 {
1110 break;
1111 }
1112 }
1113
1114 if is_zero {
1115 self.coeffs = None;
1116 } else {
1117 self.coeffs = Some(new_coeffs);
1118 }
1119
1120 Some(coeffs)
1121 }
1122}
1123
1124impl<T: PolySettings<SIZE, LOG2>, const SIZE: usize, const LOG2: usize> From<u64>
1125 for FinitePoly<T, SIZE, LOG2>
1126{
1127 fn from(value: u64) -> Self {
1128 Self::from_int(value)
1129 }
1130}
1131
1132const fn log2(x: u64) -> usize {
1133 (64 - (x - 1).leading_zeros()) as _
1134}
1135
1136pub const fn get_size<T: PolySettings<0, 0>>() -> usize {
1139 T::DEGREE.div_ceil(64)
1140}
1141
1142pub const fn get_log2<T: PolySettings<0, 0>>() -> usize {
1145 log2(T::MODULO)
1146}
1147
1148#[doc(hidden)]
1149#[macro_export]
1150#[allow(unused_macros)]
1151macro_rules! forward_const {
1152 (
1153 $view:vis, ($t:ty) :
1154 $(
1155 fn $name:ident($($param_name:ident $(* $idx:literal)? $(: $param_ty:ty)?),*) -> $ret_ty:ident$(<$generics:ident>)?;
1156 )*
1157 ) => {
1158 $(
1159 #[allow(dead_code)]
1160 $view const fn $name($($param_name $(: $param_ty)?),*) -> $ret_ty$(<$generics>)? {
1161 $crate::forward_const!(@result : ($ret_ty) : (<$t>::$name($($crate::forward_const!(@param: $param_name $(* $idx)?)),*)))
1162 }
1163 )*
1164 };
1165
1166 (@param: $n:ident * $idx:literal) => {$n.0};
1167 (@param: $($t:tt)*) => {$($t)*};
1168 (@result: (Self) : ($($t:tt)*)) => {Self($($t)*)};
1169 (@result: (Option) : ($($t:tt)*)) => {match $($t)* { Some(x) => Some(Self(x)), None => None }};
1170 (@result: ($($t0:tt)*) : ($($t:tt)*)) => {$($t)*};
1171}
1172
1173#[doc(hidden)]
1174#[macro_export]
1175#[allow(unused_macros)]
1176macro_rules! forward_op_impl {
1177 (@basic: $on:ty: $($name:ident -- $method:ident ($op:tt) $other:ident $(*$lit:literal)?),*) => {
1178
$(
1179
$crate::forward_op_impl!{@basic_inner: $on ; $name ; $method ; ($op) ; $other $(*$lit)?}
1180
)*
1181 };
1182 (@basic_inner: $on:ty ; $name:ident ; $method:ident ; ($op:tt) ; $other:ident $(* $lit:literal)?) => {
1183 impl ::core::ops::$name<$other> for $on {
1184 type Output = Self;
1185
1186 fn $method(self, other: $other) -> Self {
1187 Self(self.0 $op $crate::forward_const!(@param: other $(* $lit)?))
1188 }
1189 }
1190 };
1191
1192 (@assign: $on:ty: $($name:ident -- $method:ident $other:ident $(*$lit:literal)?),*) => {
1193 $(
1194 $crate::forward_op_impl!{@assign_inner: $on ; $name ; $method ; $other $(*$lit)?}
1195 )*
1196 };
1197 (@assign_inner: $on:ty ; $name:ident ; $method:ident ; $other:ident $(* $lit:literal)?) => {
1198 impl ::core::ops::$name<$other> for $on {
1199 fn $method(&mut self, other: $other) {
1200 self.0.$method($crate::forward_const!(@param: other $(* $lit)?))
1201 }
1202 }
1203 };
1204}
1205
1206#[allow(unused_macros)]
1223#[macro_export]
1224macro_rules! make_ring {
1225 ($($(#[$at:meta])* $view:vis $name:ident = { Z % $modulo:literal, x^ $degree:literal = [$($coefficients:literal),+] };)+) => {$(
1226 $(#[$at])*
1227 #[derive(PartialEq, Copy, Clone)]
1228 $view struct $name($crate::FinitePoly<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>);
1229
1230 impl<const SIZE: usize, const LOG2: usize> $crate::PolySettings<SIZE, LOG2> for $name {
1231 const DEGREE: usize = $degree;
1232 const MODULO: u64 = $modulo;
1233
1234 const OVERFLOW: $crate::FinitePoly<Self, SIZE, LOG2> = $crate::FinitePoly::<Self, SIZE, LOG2>::from_coeffs(&[$($coefficients),+]);
1235 }
1236
1237 impl $name {
1238 #[allow(dead_code)]
1239 $view const LOG2: usize = $crate::get_size::<Self>();
1240 #[allow(dead_code)]
1241 $view const SIZE: usize = $crate::get_log2::<Self>();
1242 #[allow(dead_code)]
1243 $view const OVERFLOW: Self = Self(<Self as $crate::PolySettings<{Self::LOG2}, {Self::SIZE}>>::OVERFLOW);
1244
1245 $view const ZERO: Self = Self($crate::FinitePoly::<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>::ZERO);
1246 $view const ONE: Self = Self($crate::FinitePoly::<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>::ONE);
1247
1248 $crate::forward_const! {
1249 $view, ($crate::FinitePoly<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>) :
1250 fn splat(value: u64) -> Self;
1251 fn from_int(value: u64) -> Self;
1252 fn degree(self*0) -> usize;
1253 fn eq(self*0, other*0: Self) -> bool;
1254 fn is_zero(self*0) -> bool;
1255 fn add(self*0, other*0: Self) -> Self;
1256 fn sub(self*0, other*0: Self) -> Self;
1257 fn mul(self*0, other*0: Self) -> Self;
1258 fn neg(self*0) -> Self;
1259 fn mul_modulo(self*0, by: u64) -> Self;
1260 fn mul_x(self*0) -> Self;
1261 fn unchecked_mulx(self*0, power: usize) -> Self;
1262 fn get_nth_coeff(self*0, coeff: usize) -> u64;
1263 fn set_coeff(self*0, idx: usize, coeff: u64) -> Self;
1264 fn invert(self*0) -> Option<Self>;
1265 fn from_coeffs(coeffs: &[u64]) -> Self;
1266 }
1267
1268 #[allow(dead_code)]
1269 $view const fn divide_remainder(self, other: Self) -> Option<(Self, Self)> {
1270 match self.0.divide_remainder(other.0) {
1271 Some((x, y)) => Some((Self(x), Self(y))),
1272 None => None
1273 }
1274 }
1275
1276 #[allow(dead_code)]
1277 $view const fn divide_quotient_poly_by_self(self) -> Option<(Self, Self)> {
1278 match self.0.divide_quotient_poly_by_self() {
1279 Some((x, y)) => Some((Self(x), Self(y))),
1280 None => None
1281 }
1282 }
1283
1284 $view fn iter() -> impl Iterator<Item = Self> {
1285 $crate::FinitePoly::<Self, {$crate::get_size::<Self>()}, {$crate::get_log2::<Self>()}>::iter().map(|x| Self(x))
1286 }
1287 }
1288
1289 const _: () = {
1290 type Poly = $crate::FinitePoly<$name, {$crate::get_size::<$name>()}, {$crate::get_log2::<$name>()}>;
1291 impl From<$name> for Poly {
1292 fn from(other: $name) -> Self {
1293 other.0
1294 }
1295 }
1296
1297 impl From<Poly> for $name {
1298 fn from(other: Poly) -> Self {
1299 Self(other)
1300 }
1301 }
1302
1303 impl ::core::fmt::Debug for $name {
1304 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
1305 <Poly as ::core::fmt::Debug>::fmt(&self.0, f)
1306 }
1307 }
1308
1309 impl ::core::fmt::Display for $name {
1310 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
1311 <Poly as ::core::fmt::Display>::fmt(&self.0, f)
1312 }
1313 }
1314
1315 impl ::core::cmp::Eq for $name {}
1316
1317 impl<T> ::core::cmp::PartialEq<T> for $name
1318 where Poly: PartialEq<T> {
1319 fn eq(&self, other: &T) -> bool {
1320 self.0 == *other
1321 }
1322 }
1323
1324 $crate::forward_op_impl! {
1325 @basic: $name:
1326 Add -- add (+) u64,
1327 Add -- add (+) Poly,
1328 Add -- add (+) $name * 0,
1329 Sub -- sub (-) u64,
1330 Sub -- sub (-) Poly,
1331 Sub -- sub (-) $name * 0,
1332 Mul -- mul (*) u64,
1333 Mul -- mul (*) Poly,
1334 Mul -- mul (*) $name * 0,
1335 Div -- div (/) u64,
1336 Div -- div (/) Poly,
1337 Div -- div (/) $name * 0
1338 }
1339
1340 $crate::forward_op_impl! {
1341 @assign: $name:
1342 AddAssign -- add_assign u64,
1343 AddAssign -- add_assign Poly,
1344 AddAssign -- add_assign $name * 0,
1345 SubAssign -- sub_assign u64,
1346 SubAssign -- sub_assign Poly,
1347 SubAssign -- sub_assign $name * 0,
1348 MulAssign -- mul_assign u64,
1349 MulAssign -- mul_assign Poly,
1350 MulAssign -- mul_assign $name * 0,
1351 DivAssign -- div_assign u64,
1352 DivAssign -- div_assign Poly,
1353 DivAssign -- div_assign $name * 0
1354 }
1355 };
1356 )+};
1357}
1358
1359#[cfg(test)]
1360mod tests {
1361 macro_rules! make_ring_tests {
1362 ($name:ident, $coeffs:literal, $modulo:literal) => {
1363 #[test]
1364 fn integer_to_poly() {
1365 let one_const = $name::ONE;
1366 let one_phi = $name::from_int(1);
1367
1368 assert_eq!(one_const, one_phi);
1369
1370 for i in 0..20 {
1371 let pre_reduced = i % $modulo;
1372
1373 let value_1 = $name::from_int(i);
1374 let value_2 = $name::from_int(pre_reduced);
1375 let mut value_3 = $name::ZERO;
1376
1377 for _ in 0..i {
1378 value_3 = value_3 + $name::ONE;
1379 }
1380
1381 let mut value_4 = $name::ZERO;
1382
1383 for _ in 0..pre_reduced {
1384 value_4 = value_4 + $name::ONE;
1385 }
1386
1387 assert_eq!(value_1, value_2);
1388 assert_eq!(value_2, value_3);
1389 assert_eq!(value_3, value_4);
1390 }
1391 }
1392
1393 #[test]
1394 fn coeff_equality() {
1395 for lhs in $name::iter() {
1396 for rhs in $name::iter() {
1397 let mut equal = true;
1398 for power in 0..$coeffs {
1399 let coeff_left = lhs.get_nth_coeff(power) % $modulo;
1400 let coeff_right = rhs.get_nth_coeff(power) % $modulo;
1401
1402 equal &= coeff_left == coeff_right;
1403 }
1404
1405 assert_eq!(equal, lhs == rhs, "Lhs: {lhs}, Rhs: {rhs}");
1406 }
1407 }
1408 }
1409
1410 #[test]
1411 fn equality_is_equality() {
1412 for x in $name::iter() {
1419 assert_eq!(x, x);
1420 }
1421
1422 for x in $name::iter() {
1424 for y in $name::iter() {
1425 assert_eq!(x == y, y == x);
1426 }
1427 }
1428
1429 for x in $name::iter() {
1431 for y in $name::iter() {
1432 for z in $name::iter() {
1433 if x == y && y == z {
1434 assert_eq!(x, z);
1435 }
1436 }
1437 }
1438 }
1439 }
1440
1441 #[test]
1459 fn addition_commutes() {
1460 for x in $name::iter() {
1461 for y in $name::iter() {
1462 assert_eq!(x + y, y + x);
1463 }
1464 }
1465 }
1466
1467 #[test]
1468 fn multiplication_commutes() {
1469 for x in $name::iter() {
1470 for y in $name::iter() {
1471 assert_eq!(x * y, y * x);
1472 }
1473 }
1474 }
1475
1476 #[test]
1477 fn addition_associates() {
1478 for x in $name::iter() {
1479 for y in $name::iter() {
1480 for z in $name::iter() {
1481 assert_eq!(x + (y + z), (x + y) + z);
1482 }
1483 }
1484 }
1485 }
1486
1487 #[test]
1488 fn multiplication_associates() {
1489 for x in $name::iter() {
1490 for y in $name::iter() {
1491 for z in $name::iter() {
1492 assert_eq!(x * (y * z), (x * y) * z);
1493 }
1494 }
1495 }
1496 }
1497
1498 #[test]
1499 fn zero_is_zero() {
1500 for x in $name::iter() {
1501 assert_eq!(x + $name::ZERO, x);
1502 }
1503 }
1504
1505 #[test]
1506 fn one_is_one() {
1507 for x in $name::iter() {
1508 assert_eq!(x * $name::ONE, x);
1509 }
1510 }
1511
1512 #[test]
1513 fn multiplication_distributes() {
1514 for x in $name::iter() {
1515 for y in $name::iter() {
1516 for z in $name::iter() {
1517 assert_eq!(x * (y + z), (x * y) + (x * z));
1518 }
1519 }
1520 }
1521 }
1522
1523 #[test]
1524 fn additive_inverses() {
1525 'a: for x in $name::iter() {
1526 for y in $name::iter() {
1527 if x + y == $name::ZERO {
1528 continue 'a;
1529 }
1530 }
1531
1532 panic!("Additive inverse for {x} not found!");
1533 }
1534 }
1535
1536 #[test]
1537 fn zero_is_not_one() {
1538 assert_ne!($name::ZERO, $name::ONE);
1539 }
1540 };
1541 }
1542
1543 make_ring! {
1544 F125 = { Z % 5, x^3 = [2, 2] };
1545 BadRingSmall = { Z % 6, x^1 = [0] };
1546 BadRing = { Z % 6, x^2 = [3, 2] };
1547 BadPoly = { Z % 5, x^2 = [4] };
1548 }
1549
1550 mod field {
1551 use super::F125;
1552 make_ring_tests! {F125, 3, 5}
1553
1554 #[test]
1555 fn multiplicative_inverse() {
1556 for x in F125::iter() {
1557 let computed_inverse = x.invert();
1558
1559 let mut found_inverse = None;
1560 for y in F125::iter() {
1561 if x * y == F125::ONE {
1562 found_inverse = Some(y);
1563 break;
1564 }
1565 }
1566
1567 assert_eq!(computed_inverse, found_inverse, "Poly: {x}");
1568
1569 if !x.is_zero() && computed_inverse.is_none() {
1570 panic!("Multiplicative inverse for {x} not found!");
1571 }
1572 }
1573 }
1574 }
1575
1576 mod integers_bad {
1577 use super::BadRingSmall;
1578 make_ring_tests! {BadRingSmall, 1, 6}
1579
1580 #[test]
1581 fn integers_mod_bad() {
1582 for (i, val) in BadRingSmall::iter().enumerate() {
1583 assert_eq!(val, BadRingSmall::from_int(i as u64));
1584 }
1585 }
1586 }
1587
1588 mod integers_bad_poly_bad {
1589 use super::BadRing;
1590 make_ring_tests! {BadRing, 2, 6}
1591 }
1592
1593 mod poly_bad {
1594 use super::BadPoly;
1595 make_ring_tests! {BadPoly, 2, 5}
1596 }
1597}