Skip to main content

p3_field_testing/
lib.rs

1//! Utilities for testing field implementations.
2
3#![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        // (x - 1)(x - 2) = x^2 - 3x + 2
201        assert_eq!(
202            binomial_expand(&[F::one(), F::two()]),
203            vec![F::two(), -F::from_canonical_usize(3), F::one()]
204        );
205    }
206}