1#![no_std]
4
5extern crate alloc;
6
7pub mod bench_func;
8pub mod packedfield_testing;
9
10pub use bench_func::*;
11use num_bigint::BigUint;
12use num_traits::identities::One;
13use p3_field::{
14 cyclic_subgroup_coset_known_order, cyclic_subgroup_known_order, two_adic_coset_zerofier,
15 two_adic_subgroup_zerofier, ExtensionField, Field, TwoAdicField,
16};
17pub use packedfield_testing::*;
18use rand::distributions::{Distribution, Standard};
19use rand::Rng;
20
21#[allow(clippy::eq_op)]
22pub fn test_add_neg_sub_mul<F: Field>()
23where
24 Standard: Distribution<F>,
25{
26 let mut rng = rand::thread_rng();
27 let x = rng.gen::<F>();
28 let y = rng.gen::<F>();
29 let z = rng.gen::<F>();
30 assert_eq!(x + (-x), F::zero());
31 assert_eq!(-x, F::zero() - x);
32 assert_eq!(x + x, x * F::two());
33 assert_eq!(x, x.halve() * F::two());
34 assert_eq!(x * (-x), -x.square());
35 assert_eq!(x + y, y + x);
36 assert_eq!(x * y, y * x);
37 assert_eq!(x * (y * z), (x * y) * z);
38 assert_eq!(x - (y + z), (x - y) - z);
39 assert_eq!((x + y) - z, x + (y - z));
40 assert_eq!(x * (y + z), x * y + x * z);
41 assert_eq!(
42 x + y + z + x + y + z,
43 [x, x, y, y, z, z].iter().cloned().sum()
44 );
45}
46
47pub fn test_inv_div<F: Field>()
48where
49 Standard: Distribution<F>,
50{
51 let mut rng = rand::thread_rng();
52 let x = rng.gen::<F>();
53 let y = rng.gen::<F>();
54 let z = rng.gen::<F>();
55 assert_eq!(x * x.inverse(), F::one());
56 assert_eq!(x.inverse() * x, F::one());
57 assert_eq!(x.square().inverse(), x.inverse().square());
58 assert_eq!((x / y) * y, x);
59 assert_eq!(x / (y * z), (x / y) / z);
60 assert_eq!((x * y) / z, x * (y / z));
61}
62
63pub fn test_inverse<F: Field>()
64where
65 Standard: Distribution<F>,
66{
67 assert_eq!(None, F::zero().try_inverse());
68
69 assert_eq!(Some(F::one()), F::one().try_inverse());
70
71 let mut rng = rand::thread_rng();
72 for _ in 0..1000 {
73 let x = rng.gen::<F>();
74 if !x.is_zero() && !x.is_one() {
75 let z = x.inverse();
76 assert_ne!(x, z);
77 assert_eq!(x * z, F::one());
78 }
79 }
80}
81
82pub fn test_multiplicative_group_factors<F: Field>() {
83 let product: BigUint = F::multiplicative_group_factors()
84 .into_iter()
85 .map(|(factor, exponent)| factor.pow(exponent as u32))
86 .product();
87 assert_eq!(product + BigUint::one(), F::order());
88}
89
90pub fn test_two_adic_subgroup_zerofier<F: TwoAdicField>() {
91 for log_n in 0..5 {
92 let g = F::two_adic_generator(log_n);
93 for x in cyclic_subgroup_known_order(g, 1 << log_n) {
94 let zerofier_eval = two_adic_subgroup_zerofier(log_n, x);
95 assert_eq!(zerofier_eval, F::zero());
96 }
97 }
98}
99
100pub fn test_two_adic_coset_zerofier<F: TwoAdicField>() {
101 for log_n in 0..5 {
102 let g = F::two_adic_generator(log_n);
103 let shift = F::generator();
104 for x in cyclic_subgroup_coset_known_order(g, shift, 1 << log_n) {
105 let zerofier_eval = two_adic_coset_zerofier(log_n, shift, x);
106 assert_eq!(zerofier_eval, F::zero());
107 }
108 }
109}
110
111pub fn test_two_adic_generator_consistency<F: TwoAdicField>() {
112 let log_n = F::TWO_ADICITY;
113 let g = F::two_adic_generator(log_n);
114 for bits in 0..=log_n {
115 assert_eq!(g.exp_power_of_2(bits), F::two_adic_generator(log_n - bits));
116 }
117}
118
119pub fn test_ef_two_adic_generator_consistency<
120 F: TwoAdicField,
121 EF: TwoAdicField + ExtensionField<F>,
122>() {
123 assert_eq!(
124 EF::from_base(F::two_adic_generator(F::TWO_ADICITY)),
125 EF::two_adic_generator(F::TWO_ADICITY)
126 );
127}
128
129#[macro_export]
130macro_rules! test_field {
131 ($field:ty) => {
132 mod field_tests {
133 #[test]
134 fn test_add_neg_sub_mul() {
135 $crate::test_add_neg_sub_mul::<$field>();
136 }
137 #[test]
138 fn test_inv_div() {
139 $crate::test_inv_div::<$field>();
140 }
141 #[test]
142 fn test_inverse() {
143 $crate::test_inverse::<$field>();
144 }
145 #[test]
146 fn test_multiplicative_group_factors() {
147 $crate::test_multiplicative_group_factors::<$field>();
148 }
149 }
150 };
151}
152
153#[macro_export]
154macro_rules! test_two_adic_field {
155 ($field:ty) => {
156 mod two_adic_field_tests {
157 #[test]
158 fn test_two_adic_field_subgroup_zerofier() {
159 $crate::test_two_adic_subgroup_zerofier::<$field>();
160 }
161 #[test]
162 fn test_two_adic_coset_zerofier() {
163 $crate::test_two_adic_coset_zerofier::<$field>();
164 }
165 #[test]
166 fn test_two_adic_consisitency() {
167 $crate::test_two_adic_generator_consistency::<$field>();
168 }
169 }
170 };
171}
172
173#[macro_export]
174macro_rules! test_two_adic_extension_field {
175 ($field:ty, $ef:ty) => {
176 use $crate::test_two_adic_field;
177
178 test_two_adic_field!($ef);
179
180 mod two_adic_extension_field_tests {
181
182 #[test]
183 fn test_ef_two_adic_generator_consistency() {
184 $crate::test_ef_two_adic_generator_consistency::<$field, $ef>();
185 }
186 }
187 };
188}
189
190#[cfg(test)]
191mod tests {
192 use alloc::vec;
193 use alloc::vec::Vec;
194
195 use p3_baby_bear::BabyBear;
196 use p3_field::extension::{BinomialExtensionField, HasFrobenius};
197 use p3_field::{binomial_expand, eval_poly, AbstractExtensionField, AbstractField};
198 use rand::random;
199
200 use super::*;
201
202 #[test]
203 fn test_minimal_poly() {
204 type F = BabyBear;
205 type EF = BinomialExtensionField<F, 4>;
206 for _ in 0..1024 {
207 let x: EF = random();
208 let m: Vec<EF> = x.minimal_poly().into_iter().map(EF::from_base).collect();
209 assert!(eval_poly(&m, x).is_zero());
210 }
211 }
212
213 #[test]
214 fn test_binomial_expand() {
215 type F = BabyBear;
216 assert_eq!(
218 binomial_expand(&[F::one(), F::two()]),
219 vec![F::two(), -F::from_canonical_usize(3), F::one()]
220 );
221 }
222}