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