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;
8pub mod dft_testing;
9pub mod extension_testing;
10pub mod from_integer_tests;
11pub mod packedfield_testing;
12
13use alloc::vec::Vec;
14use core::array;
15use core::iter::successors;
16
17pub use bench_func::*;
18pub use dft_testing::*;
19pub use extension_testing::*;
20use num_bigint::BigUint;
21use p3_field::coset::TwoAdicMultiplicativeCoset;
22use p3_field::{
23    ExtensionField, Field, PackedValue, PrimeCharacteristicRing, PrimeField32, PrimeField64,
24    TwoAdicField,
25};
26use p3_util::iter_array_chunks_padded;
27pub use packedfield_testing::*;
28use proptest::prelude::*;
29use rand::distr::{Distribution, StandardUniform};
30use rand::rngs::SmallRng;
31use rand::{RngExt, SeedableRng};
32use serde::Serialize;
33use serde::de::DeserializeOwned;
34
35/// Generate a random field element from a u64 seed, for use in proptest strategies.
36fn arb_field<F>() -> impl Strategy<Value = F>
37where
38    F: core::fmt::Debug + 'static,
39    StandardUniform: Distribution<F>,
40{
41    any::<u64>().prop_map(|seed| {
42        let mut rng = SmallRng::seed_from_u64(seed);
43        rng.random()
44    })
45}
46
47#[allow(clippy::eq_op)]
48pub fn test_ring_with_eq<R: PrimeCharacteristicRing + Copy + Eq>(zeros: &[R], ones: &[R])
49where
50    StandardUniform: Distribution<R> + Distribution<[R; 16]>,
51{
52    // zeros should be a vector containing different representatives of `R::ZERO`.
53    // ones should be a vector containing different representatives of `R::ONE`.
54    let mut rng = SmallRng::seed_from_u64(1);
55    let x = rng.random::<R>();
56    let y = rng.random::<R>();
57    let z = rng.random::<R>();
58    assert_eq!(R::ONE + R::NEG_ONE, R::ZERO, "Error 1 + (-1) =/= 0");
59    assert_eq!(R::NEG_ONE + R::TWO, R::ONE, "Error -1 + 2 =/= 1");
60    assert_eq!(x + (-x), R::ZERO, "Error x + (-x) =/= 0");
61    assert_eq!(R::ONE + R::ONE, R::TWO, "Error 1 + 1 =/= 2");
62    assert_eq!(-(-x), x, "Error when testing double negation");
63    assert_eq!(x + x, x * R::TWO, "Error when comparing x * 2 to x + x");
64    assert_eq!(
65        x * R::TWO,
66        x.double(),
67        "Error when comparing x.double() to x * 2"
68    );
69    assert_eq!(x, x.halve() * R::TWO, "Error when testing halve.");
70
71    // Check different representatives of Zero.
72    for zero in zeros.iter().copied() {
73        assert_eq!(zero, R::ZERO);
74        assert_eq!(x + zero, x, "Error when testing additive identity right.");
75        assert_eq!(zero + x, x, "Error when testing additive identity left.");
76        assert_eq!(x - zero, x, "Error when testing subtracting zero.");
77        assert_eq!(zero - x, -x, "Error when testing subtracting  from zero.");
78        assert_eq!(
79            x * zero,
80            zero,
81            "Error when testing right multiplication by 0."
82        );
83        assert_eq!(
84            zero * x,
85            zero,
86            "Error when testing left multiplication by 0."
87        );
88    }
89
90    // Check different representatives of One.
91    for one in ones.iter().copied() {
92        assert_eq!(one, R::ONE);
93        assert_eq!(one * one, one);
94        assert_eq!(
95            x * one,
96            x,
97            "Error when testing multiplicative identity right."
98        );
99        assert_eq!(
100            one * x,
101            x,
102            "Error when testing multiplicative identity left."
103        );
104    }
105
106    assert_eq!(
107        x * R::NEG_ONE,
108        -x,
109        "Error when testing right multiplication by -1."
110    );
111    assert_eq!(
112        R::NEG_ONE * x,
113        -x,
114        "Error when testing left multiplication by -1."
115    );
116    assert_eq!(x * x, x.square(), "Error when testing x * x = x.square()");
117    assert_eq!(
118        x * x * x,
119        x.cube(),
120        "Error when testing x * x * x = x.cube()"
121    );
122    assert_eq!(x + y, y + x, "Error when testing commutativity of addition");
123    assert_eq!(
124        (x - y),
125        -(y - x),
126        "Error when testing anticommutativity of sub."
127    );
128    assert_eq!(
129        x * y,
130        y * x,
131        "Error when testing commutativity of multiplication."
132    );
133    assert_eq!(
134        x + (y + z),
135        (x + y) + z,
136        "Error when testing associativity of addition"
137    );
138    assert_eq!(
139        x * (y * z),
140        (x * y) * z,
141        "Error when testing associativity of multiplication."
142    );
143    assert_eq!(
144        x - (y - z),
145        (x - y) + z,
146        "Error when testing subtraction and addition"
147    );
148    assert_eq!(
149        x - (y + z),
150        (x - y) - z,
151        "Error when testing subtraction and addition"
152    );
153    assert_eq!(
154        (x + y) - z,
155        x + (y - z),
156        "Error when testing subtraction and addition"
157    );
158    assert_eq!(
159        x * (-y),
160        -(x * y),
161        "Error when testing distributivity of mul and right neg."
162    );
163    assert_eq!(
164        (-x) * y,
165        -(x * y),
166        "Error when testing distributivity of mul and left neg."
167    );
168
169    assert_eq!(
170        x * (y + z),
171        x * y + x * z,
172        "Error when testing distributivity of add and left mul."
173    );
174    assert_eq!(
175        (x + y) * z,
176        x * z + y * z,
177        "Error when testing distributivity of add and right mul."
178    );
179    assert_eq!(
180        x * (y - z),
181        x * y - x * z,
182        "Error when testing distributivity of sub and left mul."
183    );
184    assert_eq!(
185        (x - y) * z,
186        x * z - y * z,
187        "Error when testing distributivity of sub and right mul."
188    );
189
190    let vec1: [R; 64] = rng.random();
191    let vec2: [R; 64] = rng.random();
192    test_sums(&vec1[..16].try_into().unwrap());
193    test_dot_product(&vec1, &vec2);
194
195    assert_eq!(
196        x.exp_const_u64::<0>(),
197        R::ONE,
198        "Error when comparing x.exp_const_u64::<0> to R::ONE."
199    );
200    assert_eq!(
201        x.exp_const_u64::<1>(),
202        x,
203        "Error when comparing x.exp_const_u64::<3> to x."
204    );
205    assert_eq!(
206        x.exp_const_u64::<2>(),
207        x * x,
208        "Error when comparing x.exp_const_u64::<3> to x*x."
209    );
210    assert_eq!(
211        x.exp_const_u64::<3>(),
212        x * x * x,
213        "Error when comparing x.exp_const_u64::<3> to x*x*x."
214    );
215    assert_eq!(
216        x.exp_const_u64::<4>(),
217        x * x * x * x,
218        "Error when comparing x.exp_const_u64::<3> to x*x*x*x."
219    );
220    assert_eq!(
221        x.exp_const_u64::<5>(),
222        x * x * x * x * x,
223        "Error when comparing x.exp_const_u64::<5> to x*x*x*x*x."
224    );
225    assert_eq!(
226        x.exp_const_u64::<6>(),
227        x * x * x * x * x * x,
228        "Error when comparing x.exp_const_u64::<7> to x*x*x*x*x*x."
229    );
230    assert_eq!(
231        x.exp_const_u64::<7>(),
232        x * x * x * x * x * x * x,
233        "Error when comparing x.exp_const_u64::<7> to x*x*x*x*x*x*x."
234    );
235
236    test_binary_ops(zeros, ones, x, y, z);
237
238    // Edge case tests with special values
239    for &a in &[R::ZERO, R::ONE, R::TWO, R::NEG_ONE] {
240        for &b in &[R::ZERO, R::ONE, R::TWO, R::NEG_ONE] {
241            assert_eq!(a + b, b + a, "commutativity with special values");
242            assert_eq!(a * b, b * a, "commutativity with special values");
243        }
244        assert_eq!(a * a, a.square(), "square with special value");
245        assert_eq!(a * a * a, a.cube(), "cube with special value");
246        assert_eq!(a.halve().double(), a, "halve/double with special value");
247    }
248
249    // Test that Product of empty iterator returns ONE (the multiplicative identity)
250    let empty: [R; 0] = [];
251    let product_result: R = empty.into_iter().product();
252    assert_eq!(
253        product_result,
254        R::ONE,
255        "Product of empty iterator should return ONE, not ZERO"
256    );
257}
258
259pub fn test_mul_2exp_u64<R: PrimeCharacteristicRing + Eq>()
260where
261    StandardUniform: Distribution<R>,
262{
263    let mut rng = SmallRng::seed_from_u64(1);
264    let x = rng.random::<R>();
265    assert_eq!(x.mul_2exp_u64(0), x);
266    assert_eq!(x.mul_2exp_u64(1), x.double());
267    for i in 0..128 {
268        assert_eq!(
269            x.clone().mul_2exp_u64(i),
270            x.clone() * R::from_u128(1_u128 << i)
271        );
272    }
273    // Goldilocks behaviour changes at 96, 192 so we want to test larger numbers than that.
274    for i in 128..256 {
275        assert_eq!(x.clone().mul_2exp_u64(i), x.clone() * R::TWO.exp_u64(i));
276    }
277}
278
279pub fn test_div_2exp_u64<R: PrimeCharacteristicRing + Eq>()
280where
281    StandardUniform: Distribution<R>,
282{
283    let mut rng = SmallRng::seed_from_u64(1);
284    let x = rng.random::<R>();
285    assert_eq!(x.div_2exp_u64(0), x);
286    assert_eq!(x.div_2exp_u64(1), x.halve());
287    for i in 0..128 {
288        assert_eq!(x.mul_2exp_u64(i).div_2exp_u64(i), x);
289        assert_eq!(
290            x.div_2exp_u64(i),
291            // Best to invert in the prime subfield in case F is an extension field.
292            x.clone() * R::from_prime_subfield(R::PrimeSubfield::from_u128(1_u128 << i).inverse())
293        );
294    }
295    // Goldilocks behaviour changes at 96, 192 so we want to test larger numbers than that.
296    for i in 128..256 {
297        assert_eq!(x.mul_2exp_u64(i).div_2exp_u64(i), x);
298        assert_eq!(
299            x.div_2exp_u64(i),
300            // Best to invert in the prime subfield in case F is an extension field.
301            x.clone() * R::from_prime_subfield(R::PrimeSubfield::TWO.inverse().exp_u64(i))
302        );
303    }
304}
305
306pub fn test_add_slice<F: Field>()
307where
308    StandardUniform: Distribution<F>,
309{
310    let mut rng = SmallRng::seed_from_u64(1);
311    let lengths = [
312        F::Packing::WIDTH - 1,
313        F::Packing::WIDTH,
314        (F::Packing::WIDTH - 1) + (F::Packing::WIDTH << 10),
315    ];
316    for len in lengths {
317        let mut slice_1: Vec<_> = (&mut rng).sample_iter(StandardUniform).take(len).collect();
318        let slice_1_copy = slice_1.clone();
319        let slice_2: Vec<_> = (&mut rng).sample_iter(StandardUniform).take(len).collect();
320
321        F::add_slices(&mut slice_1, &slice_2);
322        for i in 0..len {
323            assert_eq!(slice_1[i], slice_1_copy[i] + slice_2[i]);
324        }
325    }
326}
327
328pub fn test_inverse<F: Field>()
329where
330    StandardUniform: Distribution<F>,
331{
332    assert_eq!(None, F::ZERO.try_inverse());
333    assert_eq!(Some(F::ONE), F::ONE.try_inverse());
334    assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
335    let two_inv = F::TWO
336        .try_inverse()
337        .expect("2 must be invertible in this field (test_inverse assumes characteristic != 2)");
338    assert_eq!(two_inv, F::ONE.halve(), "inverse of 2 == halve(1)");
339    let mut rng = SmallRng::seed_from_u64(1);
340    for _ in 0..1000 {
341        let x = rng.random::<F>();
342        if !x.is_zero() && !x.is_one() {
343            let z = x.inverse();
344            assert_ne!(x, z);
345            assert_eq!(x * z, F::ONE);
346        }
347    }
348}
349
350/// Test JSON serialization and deserialization for a set of field values.
351///
352/// This function tests that:
353/// 1. Each value can be serialized and deserialized correctly
354/// 2. Double round-trip serialization is consistent
355pub fn test_field_json_serialization<F>(values: &[F])
356where
357    F: PrimeCharacteristicRing + Serialize + DeserializeOwned + Eq,
358{
359    for value in values {
360        // Single round-trip
361        let serialized = serde_json::to_string(value).expect("Failed to serialize field element");
362        let deserialized: F =
363            serde_json::from_str(&serialized).expect("Failed to deserialize field element");
364        assert_eq!(
365            *value, deserialized,
366            "Single round-trip serialization failed"
367        );
368
369        // Double round-trip to ensure consistency
370        let serialized_again = serde_json::to_string(&deserialized)
371            .expect("Failed to serialize field element (second time)");
372        let deserialized_again: F = serde_json::from_str(&serialized_again)
373            .expect("Failed to deserialize field element (second time)");
374        assert_eq!(
375            *value, deserialized_again,
376            "Double round-trip serialization failed"
377        );
378        assert_eq!(
379            deserialized, deserialized_again,
380            "Deserialized values should be equal"
381        );
382    }
383}
384
385/// Test JSON deserialization boundary behavior for 32-bit prime fields.
386///
387/// Most fields only accept values in `[0, ORDER_U32)`, while some fields (e.g. Mersenne31)
388/// have a redundant representation of zero and also accept `ORDER_U32`.
389pub fn test_prime_field_32_json_deserialization_boundaries<F>(accepts_order_repr: bool)
390where
391    F: PrimeField32 + Serialize + DeserializeOwned + Eq,
392{
393    let zero: F = serde_json::from_str("0").expect("Failed to deserialize zero");
394    assert_eq!(zero, F::ZERO, "Deserializing 0 should produce ZERO");
395
396    let original: F = serde_json::from_str("42").expect("Failed to deserialize test value");
397    let serialized = serde_json::to_string(&original).expect("Failed to serialize test value");
398    let deserialized: F =
399        serde_json::from_str(&serialized).expect("Failed to deserialize serialized test value");
400    assert_eq!(
401        deserialized, original,
402        "Round-trip serialization should preserve the value"
403    );
404
405    let max_valid = if accepts_order_repr {
406        F::ORDER_U32
407    } else {
408        F::ORDER_U32 - 1
409    };
410    let max_valid_json = serde_json::to_string(&max_valid).expect("Failed to encode max valid u32");
411    let max_valid_result: Result<F, _> = serde_json::from_str(&max_valid_json);
412    assert!(
413        max_valid_result.is_ok(),
414        "Expected max valid representation to deserialize successfully"
415    );
416
417    if let Some(first_invalid) = max_valid.checked_add(1) {
418        let first_invalid_json =
419            serde_json::to_string(&first_invalid).expect("Failed to encode first invalid value");
420        let first_invalid_result: Result<F, _> = serde_json::from_str(&first_invalid_json);
421        assert!(
422            first_invalid_result.is_err(),
423            "Expected first out-of-range representation to fail deserialization"
424        );
425    }
426
427    if max_valid != u32::MAX {
428        let max_u32_json = serde_json::to_string(&u32::MAX).expect("Failed to encode u32::MAX");
429        let max_u32_result: Result<F, _> = serde_json::from_str(&max_u32_json);
430        assert!(
431            max_u32_result.is_err(),
432            "Expected u32::MAX to fail deserialization"
433        );
434    }
435}
436
437pub fn test_dot_product<R: PrimeCharacteristicRing + Eq + Copy>(u: &[R; 64], v: &[R; 64]) {
438    let mut dot = R::ZERO;
439    assert_eq!(
440        dot,
441        R::dot_product::<0>(u[..0].try_into().unwrap(), v[..0].try_into().unwrap())
442    );
443    dot += u[0] * v[0];
444    assert_eq!(
445        dot,
446        R::dot_product::<1>(u[..1].try_into().unwrap(), v[..1].try_into().unwrap())
447    );
448    dot += u[1] * v[1];
449    assert_eq!(
450        dot,
451        R::dot_product::<2>(u[..2].try_into().unwrap(), v[..2].try_into().unwrap())
452    );
453    dot += u[2] * v[2];
454    assert_eq!(
455        dot,
456        R::dot_product::<3>(u[..3].try_into().unwrap(), v[..3].try_into().unwrap())
457    );
458    dot += u[3] * v[3];
459    assert_eq!(
460        dot,
461        R::dot_product::<4>(u[..4].try_into().unwrap(), v[..4].try_into().unwrap())
462    );
463    dot += u[4] * v[4];
464    assert_eq!(
465        dot,
466        R::dot_product::<5>(u[..5].try_into().unwrap(), v[..5].try_into().unwrap())
467    );
468    dot += u[5] * v[5];
469    assert_eq!(
470        dot,
471        R::dot_product::<6>(u[..6].try_into().unwrap(), v[..6].try_into().unwrap())
472    );
473    dot += u[6] * v[6];
474    assert_eq!(
475        dot,
476        R::dot_product::<7>(u[..7].try_into().unwrap(), v[..7].try_into().unwrap())
477    );
478    dot += u[7] * v[7];
479    assert_eq!(
480        dot,
481        R::dot_product::<8>(u[..8].try_into().unwrap(), v[..8].try_into().unwrap())
482    );
483    dot += u[8] * v[8];
484    assert_eq!(
485        dot,
486        R::dot_product::<9>(u[..9].try_into().unwrap(), v[..9].try_into().unwrap())
487    );
488    dot += u[9] * v[9];
489    assert_eq!(
490        dot,
491        R::dot_product::<10>(u[..10].try_into().unwrap(), v[..10].try_into().unwrap())
492    );
493    dot += u[10] * v[10];
494    assert_eq!(
495        dot,
496        R::dot_product::<11>(u[..11].try_into().unwrap(), v[..11].try_into().unwrap())
497    );
498    dot += u[11] * v[11];
499    assert_eq!(
500        dot,
501        R::dot_product::<12>(u[..12].try_into().unwrap(), v[..12].try_into().unwrap())
502    );
503    dot += u[12] * v[12];
504    assert_eq!(
505        dot,
506        R::dot_product::<13>(u[..13].try_into().unwrap(), v[..13].try_into().unwrap())
507    );
508    dot += u[13] * v[13];
509    assert_eq!(
510        dot,
511        R::dot_product::<14>(u[..14].try_into().unwrap(), v[..14].try_into().unwrap())
512    );
513    dot += u[14] * v[14];
514    assert_eq!(
515        dot,
516        R::dot_product::<15>(u[..15].try_into().unwrap(), v[..15].try_into().unwrap())
517    );
518    dot += u[15] * v[15];
519    assert_eq!(
520        dot,
521        R::dot_product::<16>(u[..16].try_into().unwrap(), v[..16].try_into().unwrap())
522    );
523
524    let dot_64: R = u
525        .iter()
526        .zip(v.iter())
527        .fold(R::ZERO, |acc, (&lhs, &rhs)| acc + (lhs * rhs));
528    assert_eq!(dot_64, R::dot_product::<64>(u, v));
529}
530
531pub fn test_sums<R: PrimeCharacteristicRing + Eq + Copy>(u: &[R; 16]) {
532    let mut sum = R::ZERO;
533    assert_eq!(sum, R::sum_array::<0>(u[..0].try_into().unwrap()));
534    assert_eq!(sum, u[..0].iter().copied().sum());
535    sum += u[0];
536    assert_eq!(sum, R::sum_array::<1>(u[..1].try_into().unwrap()));
537    assert_eq!(sum, u[..1].iter().copied().sum());
538    sum += u[1];
539    assert_eq!(sum, R::sum_array::<2>(u[..2].try_into().unwrap()));
540    assert_eq!(sum, u[..2].iter().copied().sum());
541    sum += u[2];
542    assert_eq!(sum, R::sum_array::<3>(u[..3].try_into().unwrap()));
543    assert_eq!(sum, u[..3].iter().copied().sum());
544    sum += u[3];
545    assert_eq!(sum, R::sum_array::<4>(u[..4].try_into().unwrap()));
546    assert_eq!(sum, u[..4].iter().copied().sum());
547    sum += u[4];
548    assert_eq!(sum, R::sum_array::<5>(u[..5].try_into().unwrap()));
549    assert_eq!(sum, u[..5].iter().copied().sum());
550    sum += u[5];
551    assert_eq!(sum, R::sum_array::<6>(u[..6].try_into().unwrap()));
552    assert_eq!(sum, u[..6].iter().copied().sum());
553    sum += u[6];
554    assert_eq!(sum, R::sum_array::<7>(u[..7].try_into().unwrap()));
555    assert_eq!(sum, u[..7].iter().copied().sum());
556    sum += u[7];
557    assert_eq!(sum, R::sum_array::<8>(u[..8].try_into().unwrap()));
558    assert_eq!(sum, u[..8].iter().copied().sum());
559    sum += u[8];
560    assert_eq!(sum, R::sum_array::<9>(u[..9].try_into().unwrap()));
561    assert_eq!(sum, u[..9].iter().copied().sum());
562    sum += u[9];
563    assert_eq!(sum, R::sum_array::<10>(u[..10].try_into().unwrap()));
564    assert_eq!(sum, u[..10].iter().copied().sum());
565    sum += u[10];
566    assert_eq!(sum, R::sum_array::<11>(u[..11].try_into().unwrap()));
567    assert_eq!(sum, u[..11].iter().copied().sum());
568    sum += u[11];
569    assert_eq!(sum, R::sum_array::<12>(u[..12].try_into().unwrap()));
570    assert_eq!(sum, u[..12].iter().copied().sum());
571    sum += u[12];
572    assert_eq!(sum, R::sum_array::<13>(u[..13].try_into().unwrap()));
573    assert_eq!(sum, u[..13].iter().copied().sum());
574    sum += u[13];
575    assert_eq!(sum, R::sum_array::<14>(u[..14].try_into().unwrap()));
576    assert_eq!(sum, u[..14].iter().copied().sum());
577    sum += u[14];
578    assert_eq!(sum, R::sum_array::<15>(u[..15].try_into().unwrap()));
579    assert_eq!(sum, u[..15].iter().copied().sum());
580    sum += u[15];
581    assert_eq!(sum, R::sum_array::<16>(u));
582    assert_eq!(sum, u.iter().copied().sum());
583}
584
585pub fn test_binary_ops<R: PrimeCharacteristicRing + Eq + Copy>(
586    zeros: &[R],
587    ones: &[R],
588    x: R,
589    y: R,
590    z: R,
591) {
592    for zero in zeros {
593        for one in ones {
594            assert_eq!(one.xor(one), R::ZERO, "Error when testing xor(1, 1) = 0.");
595            assert_eq!(zero.xor(one), R::ONE, "Error when testing xor(0, 1) = 1.");
596            assert_eq!(one.xor(zero), R::ONE, "Error when testing xor(1, 0) = 1.");
597            assert_eq!(zero.xor(zero), R::ZERO, "Error when testing xor(0, 0) = 0.");
598            assert_eq!(one.andn(one), R::ZERO, "Error when testing andn(1, 1) = 0.");
599            assert_eq!(zero.andn(one), R::ONE, "Error when testing andn(0, 1) = 1.");
600            assert_eq!(
601                one.andn(zero),
602                R::ZERO,
603                "Error when testing andn(1, 0) = 0."
604            );
605            assert_eq!(
606                zero.andn(zero),
607                R::ZERO,
608                "Error when testing andn(0, 0) = 0."
609            );
610            assert_eq!(
611                zero.bool_check(),
612                R::ZERO,
613                "Error when testing bool_check(0) = 0."
614            );
615            assert_eq!(
616                one.bool_check(),
617                R::ZERO,
618                "Error when testing bool_check(1) = 0."
619            );
620        }
621    }
622
623    assert_eq!(
624        R::ONE.xor(&R::NEG_ONE),
625        R::TWO,
626        "Error when testing xor(1, -1) = 2."
627    );
628    assert_eq!(
629        R::NEG_ONE.xor(&R::ONE),
630        R::TWO,
631        "Error when testing xor(-1, 1) = 2."
632    );
633    assert_eq!(
634        R::NEG_ONE.xor(&R::NEG_ONE),
635        R::from_i8(-4),
636        "Error when testing xor(-1, -1) = -4."
637    );
638    assert_eq!(
639        R::ONE.andn(&R::NEG_ONE),
640        R::ZERO,
641        "Error when testing andn(1, -1) = 0."
642    );
643    assert_eq!(
644        R::NEG_ONE.andn(&R::ONE),
645        R::TWO,
646        "Error when testing andn(-1, 1) = 2."
647    );
648    assert_eq!(
649        R::NEG_ONE.andn(&R::NEG_ONE),
650        -R::TWO,
651        "Error when testing andn(-1, -1) = -2."
652    );
653
654    assert_eq!(x.xor(&y), x + y - x * y.double(), "Error when testing xor.");
655
656    assert_eq!(x.andn(&y), (R::ONE - x) * y, "Error when testing andn.");
657
658    assert_eq!(
659        x.xor3(&y, &z),
660        x + y + z - (x * y + x * z + y * z).double() + x * y * z.double().double(),
661        "Error when testing xor3."
662    );
663}
664
665/// Tests the optimized implementation of `powers.take(n).collect()`
666pub fn test_powers_collect<F: Field>() {
667    // Small using serial implementation
668    let small_powers_serial = [0, 1, 2, 3, 4, 15];
669    // Small using packed implementation
670    let small_powers_packed = [16, 17];
671    // Large powers of two
672    let powers_of_two = [5, 6, 7, 8, 9, 10, 13];
673
674    let num_powers_tests: Vec<usize> = small_powers_serial
675        .into_iter()
676        .chain(small_powers_packed)
677        .chain(powers_of_two.iter().flat_map(|exp| {
678            // Check boundaries at power of 2
679            let n = 1 << exp;
680            [n - 1, n, n + 1]
681        }))
682        .collect();
683
684    let base = F::TWO;
685    let shift = F::GENERATOR;
686
687    // Manual implementation of `Powers`
688    let expected_iter = successors(Some(shift), |prev| Some(*prev * base));
689
690    for num_powers in num_powers_tests {
691        let expected: Vec<_> = expected_iter.clone().take(num_powers).collect();
692        let actual = base.shifted_powers(shift).collect_n(num_powers);
693        assert_eq!(
694            expected, actual,
695            "Got different powers when taking {num_powers}"
696        );
697    }
698}
699
700/// A function which extends the `exp_u64` code to handle `BigUints`.
701///
702/// This solution is slow (particularly when dealing with extension fields
703/// which should really be making use of the frobenius map) but should be
704/// fast enough for testing purposes.
705pub(crate) fn exp_biguint<F: Field>(x: F, exponent: &BigUint) -> F {
706    let digits = exponent.to_u64_digits();
707    let size = digits.len();
708
709    let mut power = F::ONE;
710
711    let bases = (0..size).map(|i| x.exp_power_of_2(64 * i));
712    digits
713        .iter()
714        .zip(bases)
715        .for_each(|(digit, base)| power *= base.exp_u64(*digit));
716    power
717}
718
719/// Given a list of the factors of the multiplicative group of a field, check
720/// that the defined generator is actually a generator of that group.
721pub fn test_generator<F: Field>(multiplicative_group_factors: &[(BigUint, u32)]) {
722    // First we check that the given factors multiply to the order of the
723    // multiplicative group (|F| - 1). Ideally this would also check that
724    // the given factors are prime but as factors can be large that check
725    // can end up being quite expensive so ignore that for now. As the factors
726    // are hardcoded and public, these prime checks can be easily done using
727    // sage or wolfram alpha.
728    let product: BigUint = multiplicative_group_factors
729        .iter()
730        .map(|(factor, exponent)| factor.pow(*exponent))
731        .product();
732    assert_eq!(product + BigUint::from(1u32), F::order());
733
734    // Given a prime factorization r = p1^e1 * p2^e2 * ... * pk^ek, an element g has order
735    // r if and only if g^r = 1 and g^(r/pi) != 1 for all pi in the prime factorization of r.
736    let mut partial_products: Vec<F> = (0..=multiplicative_group_factors.len())
737        .map(|i| {
738            let mut generator_power = F::GENERATOR;
739            multiplicative_group_factors
740                .iter()
741                .enumerate()
742                .for_each(|(j, (factor, exponent))| {
743                    let modified_exponent = if i == j { exponent - 1 } else { *exponent };
744                    for _ in 0..modified_exponent {
745                        generator_power = exp_biguint(generator_power, factor);
746                    }
747                });
748            generator_power
749        })
750        .collect();
751
752    assert_eq!(partial_products.pop().unwrap(), F::ONE);
753
754    for elem in partial_products.into_iter() {
755        assert_ne!(elem, F::ONE);
756    }
757}
758
759pub fn test_two_adic_generator_consistency<F: TwoAdicField>() {
760    let log_n = F::TWO_ADICITY;
761    let g = F::two_adic_generator(log_n);
762    for bits in 0..=log_n {
763        assert_eq!(g.exp_power_of_2(bits), F::two_adic_generator(log_n - bits));
764    }
765}
766
767pub fn test_two_adic_point_collection<F: TwoAdicField>() {
768    let log_n = F::TWO_ADICITY.min(15);
769    for bits in 0..=log_n {
770        let group = TwoAdicMultiplicativeCoset::new(F::ONE, bits).unwrap();
771        let points = group.iter().collect();
772        // Add `map` to avoid calling `BoundedPowers::collect()`
773        #[allow(clippy::map_identity)]
774        let points_expected = group.iter().map(|x| x).collect::<Vec<_>>();
775        assert_eq!(points, points_expected);
776    }
777}
778
779pub fn test_ef_two_adic_generator_consistency<
780    F: TwoAdicField,
781    EF: TwoAdicField + ExtensionField<F>,
782>() {
783    assert_eq!(
784        Into::<EF>::into(F::two_adic_generator(F::TWO_ADICITY)),
785        EF::two_adic_generator(F::TWO_ADICITY)
786    );
787}
788
789pub fn test_into_bytes_32<F: PrimeField32>(zeros: &[F], ones: &[F])
790where
791    StandardUniform: Distribution<F>,
792{
793    let mut rng = SmallRng::seed_from_u64(1);
794    let x = rng.random::<F>();
795
796    assert_eq!(
797        x.into_bytes().into_iter().collect::<Vec<_>>(),
798        x.to_unique_u32().to_le_bytes()
799    );
800    for one in ones {
801        assert_eq!(
802            one.into_bytes().into_iter().collect::<Vec<_>>(),
803            F::ONE.to_unique_u32().to_le_bytes()
804        );
805    }
806    for zero in zeros {
807        assert_eq!(zero.into_bytes().into_iter().collect::<Vec<_>>(), [0; 4]);
808    }
809}
810
811pub fn test_into_bytes_64<F: PrimeField64>(zeros: &[F], ones: &[F])
812where
813    StandardUniform: Distribution<F>,
814{
815    let mut rng = SmallRng::seed_from_u64(1);
816    let x = rng.random::<F>();
817
818    assert_eq!(
819        x.into_bytes().into_iter().collect::<Vec<_>>(),
820        x.to_unique_u64().to_le_bytes()
821    );
822    for one in ones {
823        assert_eq!(
824            one.into_bytes().into_iter().collect::<Vec<_>>(),
825            F::ONE.to_unique_u64().to_le_bytes()
826        );
827    }
828    for zero in zeros {
829        assert_eq!(zero.into_bytes().into_iter().collect::<Vec<_>>(), [0; 8]);
830    }
831}
832
833pub fn test_into_stream<F: Field>()
834where
835    StandardUniform: Distribution<[F; 16]>,
836{
837    let mut rng = SmallRng::seed_from_u64(1);
838    let xs: [F; 16] = rng.random();
839
840    let byte_vec = F::into_byte_stream(xs).into_iter().collect::<Vec<_>>();
841    let u32_vec = F::into_u32_stream(xs).into_iter().collect::<Vec<_>>();
842    let u64_vec = F::into_u64_stream(xs).into_iter().collect::<Vec<_>>();
843
844    let expected_bytes = xs
845        .into_iter()
846        .flat_map(|x| x.into_bytes())
847        .collect::<Vec<_>>();
848    let expected_u32s = iter_array_chunks_padded(byte_vec.iter().copied(), 0)
849        .map(u32::from_le_bytes)
850        .collect::<Vec<_>>();
851    let expected_u64s = iter_array_chunks_padded(byte_vec.iter().copied(), 0)
852        .map(u64::from_le_bytes)
853        .collect::<Vec<_>>();
854
855    assert_eq!(byte_vec, expected_bytes);
856    assert_eq!(u32_vec, expected_u32s);
857    assert_eq!(u64_vec, expected_u64s);
858
859    let ys: [F; 16] = rng.random();
860    let zs: [F; 16] = rng.random();
861
862    let combs: [[F; 3]; 16] = array::from_fn(|i| [xs[i], ys[i], zs[i]]);
863
864    let byte_vec_ys = F::into_byte_stream(ys).into_iter().collect::<Vec<_>>();
865    let byte_vec_zs = F::into_byte_stream(zs).into_iter().collect::<Vec<_>>();
866    let u32_vec_ys = F::into_u32_stream(ys).into_iter().collect::<Vec<_>>();
867    let u32_vec_zs = F::into_u32_stream(zs).into_iter().collect::<Vec<_>>();
868    let u64_vec_ys = F::into_u64_stream(ys).into_iter().collect::<Vec<_>>();
869    let u64_vec_zs = F::into_u64_stream(zs).into_iter().collect::<Vec<_>>();
870
871    let combined_bytes = F::into_parallel_byte_streams(combs)
872        .into_iter()
873        .collect::<Vec<_>>();
874    let combined_u32s = F::into_parallel_u32_streams(combs)
875        .into_iter()
876        .collect::<Vec<_>>();
877    let combined_u64s = F::into_parallel_u64_streams(combs)
878        .into_iter()
879        .collect::<Vec<_>>();
880
881    let expected_combined_bytes: Vec<[u8; 3]> = (0..byte_vec.len())
882        .map(|i| [byte_vec[i], byte_vec_ys[i], byte_vec_zs[i]])
883        .collect();
884    let expected_combined_u32s: Vec<[u32; 3]> = (0..u32_vec.len())
885        .map(|i| [u32_vec[i], u32_vec_ys[i], u32_vec_zs[i]])
886        .collect();
887    let expected_combined_u64s: Vec<[u64; 3]> = (0..u64_vec.len())
888        .map(|i| [u64_vec[i], u64_vec_ys[i], u64_vec_zs[i]])
889        .collect();
890
891    assert_eq!(combined_bytes, expected_combined_bytes);
892    assert_eq!(combined_u32s, expected_combined_u32s);
893    assert_eq!(combined_u64s, expected_combined_u64s);
894}
895
896/// Test ring axioms with 256 random (x, y, z) triplets via proptest.
897///
898/// Tests commutativity, associativity, distributivity, negation,
899/// subtraction identities, square/cube, double/halve, and
900/// multiplication by zero and negative one.
901pub fn test_ring_axioms_proptest<R>()
902where
903    R: PrimeCharacteristicRing + Copy + Eq + core::fmt::Debug + 'static,
904    StandardUniform: Distribution<R>,
905{
906    let config = ProptestConfig::with_cases(256);
907    proptest!(config, |(x in arb_field::<R>(), y in arb_field::<R>(), z in arb_field::<R>())| {
908        // Commutativity
909        prop_assert_eq!(x + y, y + x, "addition commutativity");
910        prop_assert_eq!(x * y, y * x, "multiplication commutativity");
911
912        // Associativity
913        prop_assert_eq!(x + (y + z), (x + y) + z, "addition associativity");
914        prop_assert_eq!(x * (y * z), (x * y) * z, "multiplication associativity");
915
916        // Distributivity
917        prop_assert_eq!(x * (y + z), x * y + x * z, "left distributivity");
918        prop_assert_eq!((x + y) * z, x * z + y * z, "right distributivity");
919
920        // Negation
921        prop_assert_eq!(x + (-x), R::ZERO, "additive inverse");
922        prop_assert_eq!(-(-x), x, "double negation");
923
924        // Subtraction identities
925        prop_assert_eq!(x - (y - z), (x - y) + z, "sub-sub identity");
926        prop_assert_eq!(x - (y + z), (x - y) - z, "sub-add identity");
927
928        // Square and cube
929        prop_assert_eq!(x * x, x.square(), "square");
930        prop_assert_eq!(x * x * x, x.cube(), "cube");
931
932        // Double and halve
933        prop_assert_eq!(x.double(), x + x, "double");
934        prop_assert_eq!(x.halve().double(), x, "halve roundtrip");
935
936        // Multiplication by zero and negative one
937        prop_assert_eq!(x * R::ZERO, R::ZERO, "x * 0 == 0");
938        prop_assert_eq!(R::NEG_ONE * x, -x, "-1 * x == -x");
939    });
940}
941
942/// Test field axioms (inverse, division) with deterministic edge cases
943/// and 256 random non-zero (x, y, z) triplets via proptest.
944pub fn test_field_axioms_proptest<F>()
945where
946    F: Field + core::fmt::Debug + 'static,
947    StandardUniform: Distribution<F>,
948{
949    // Deterministic edge cases
950    assert_eq!(F::TWO.inverse(), F::ONE.halve());
951    assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
952    assert_eq!(
953        F::GENERATOR.inverse() * F::GENERATOR,
954        F::ONE,
955        "generator inverse roundtrip"
956    );
957
958    // Proptest: 256 random triplets, all non-zero
959    let config = ProptestConfig::with_cases(256);
960    proptest!(config, |(x in arb_field::<F>(), y in arb_field::<F>(), z in arb_field::<F>())| {
961        // Skip if any element is zero
962        if x.is_zero() || y.is_zero() || z.is_zero() {
963            return Ok(());
964        }
965
966        // Inverse properties
967        prop_assert_eq!(x * x.inverse(), F::ONE, "x * x^-1 == 1");
968        prop_assert_eq!(x.inverse().inverse(), x, "double inverse");
969        prop_assert_eq!(x.square().inverse(), x.inverse().square(), "square-inverse commutativity");
970
971        // Division roundtrip
972        prop_assert_eq!((x / y) * y, x, "division roundtrip");
973
974        // Division associativity
975        prop_assert_eq!(x / (y * z), (x / y) / z, "division-multiplication associativity");
976        prop_assert_eq!((x * y) / z, x * (y / z), "multiplication-division associativity");
977    });
978}
979
980#[macro_export]
981macro_rules! test_ring_with_eq {
982    ($ring:ty, $zeros: expr, $ones: expr) => {
983        mod ring_tests {
984            use p3_field::PrimeCharacteristicRing;
985
986            #[test]
987            fn test_ring_with_eq() {
988                $crate::test_ring_with_eq::<$ring>($zeros, $ones);
989            }
990            #[test]
991            fn test_mul_2exp_u64() {
992                $crate::test_mul_2exp_u64::<$ring>();
993            }
994            #[test]
995            fn test_div_2exp_u64() {
996                $crate::test_div_2exp_u64::<$ring>();
997            }
998        }
999    };
1000}
1001
1002#[macro_export]
1003macro_rules! test_field {
1004    ($field:ty, $zeros: expr, $ones: expr, $factors: expr) => {
1005        $crate::test_ring_with_eq!($field, $zeros, $ones);
1006
1007        mod field_tests {
1008            #[test]
1009            fn test_inverse() {
1010                $crate::test_inverse::<$field>();
1011            }
1012            #[test]
1013            fn test_generator() {
1014                $crate::test_generator::<$field>($factors);
1015            }
1016            #[test]
1017            fn test_streaming() {
1018                $crate::test_into_stream::<$field>();
1019            }
1020            #[test]
1021            fn test_powers_collect() {
1022                $crate::test_powers_collect::<$field>();
1023            }
1024            #[test]
1025            fn test_ring_axioms_proptest() {
1026                $crate::test_ring_axioms_proptest::<$field>();
1027            }
1028            #[test]
1029            fn test_field_axioms_proptest() {
1030                $crate::test_field_axioms_proptest::<$field>();
1031            }
1032        }
1033
1034        // Looks a little strange but we also check that everything works
1035        // when the field is considered as a trivial extension of itself.
1036        mod trivial_extension_tests {
1037            #[test]
1038            fn test_to_from_trivial_extension() {
1039                $crate::test_to_from_extension_field::<$field, $field>();
1040            }
1041
1042            #[test]
1043            fn test_trivial_packed_extension() {
1044                $crate::test_packed_extension::<$field, $field>();
1045            }
1046        }
1047    };
1048}
1049
1050#[macro_export]
1051macro_rules! test_prime_field {
1052    ($field:ty) => {
1053        mod from_integer_small_tests {
1054            use p3_field::integers::QuotientMap;
1055            use p3_field::{Field, PrimeCharacteristicRing};
1056
1057            #[test]
1058            fn test_small_integer_conversions() {
1059                $crate::generate_from_small_int_tests!(
1060                    $field,
1061                    [
1062                        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1063                    ]
1064                );
1065            }
1066
1067            #[test]
1068            fn test_small_signed_integer_conversions() {
1069                $crate::generate_from_small_neg_int_tests!(
1070                    $field,
1071                    [i8, i16, i32, i64, i128, isize]
1072                );
1073            }
1074        }
1075    };
1076}
1077
1078#[macro_export]
1079macro_rules! test_prime_field_64 {
1080    ($field:ty, $zeros: expr, $ones: expr) => {
1081        mod from_integer_tests_prime_field_64 {
1082            use p3_field::integers::QuotientMap;
1083            use p3_field::{Field, PrimeCharacteristicRing, PrimeField64, RawDataSerializable};
1084            use rand::rngs::SmallRng;
1085            use rand::{RngExt, SeedableRng};
1086
1087            #[test]
1088            fn test_as_canonical_u64() {
1089                let mut rng = SmallRng::seed_from_u64(1);
1090                let x: u64 = rng.random();
1091                let x_mod_order = x % <$field>::ORDER_U64;
1092
1093                assert_eq!(<$field>::ZERO.as_canonical_u64(), 0);
1094                assert_eq!(<$field>::ONE.as_canonical_u64(), 1);
1095                assert_eq!(<$field>::TWO.as_canonical_u64(), 2 % <$field>::ORDER_U64);
1096                assert_eq!(
1097                    <$field>::NEG_ONE.as_canonical_u64(),
1098                    <$field>::ORDER_U64 - 1
1099                );
1100
1101                assert_eq!(
1102                    <$field>::from_int(<$field>::ORDER_U64).as_canonical_u64(),
1103                    0
1104                );
1105                assert_eq!(<$field>::from_int(x).as_canonical_u64(), x_mod_order);
1106                assert_eq!(
1107                    unsafe { <$field>::from_canonical_unchecked(x_mod_order).as_canonical_u64() },
1108                    x_mod_order
1109                );
1110            }
1111
1112            #[test]
1113            fn test_as_unique_u64() {
1114                assert_ne!(
1115                    <$field>::ZERO.to_unique_u64(),
1116                    <$field>::ONE.to_unique_u64()
1117                );
1118                assert_ne!(
1119                    <$field>::ZERO.to_unique_u64(),
1120                    <$field>::NEG_ONE.to_unique_u64()
1121                );
1122                assert_eq!(
1123                    <$field>::from_int(<$field>::ORDER_U64).to_unique_u64(),
1124                    <$field>::ZERO.to_unique_u64()
1125                );
1126            }
1127
1128            #[test]
1129            fn test_large_unsigned_integer_conversions() {
1130                $crate::generate_from_large_u_int_tests!($field, <$field>::ORDER_U64, [u64, u128]);
1131            }
1132
1133            #[test]
1134            fn test_large_signed_integer_conversions() {
1135                $crate::generate_from_large_i_int_tests!($field, <$field>::ORDER_U64, [i64, i128]);
1136            }
1137
1138            #[test]
1139            fn test_raw_data_serializable() {
1140                // Only do the 64-bit test if the field is 64 bits.
1141                // This will error if tested on smaller fields.
1142                if <$field>::NUM_BYTES == 8 {
1143                    $crate::test_into_bytes_64::<$field>($zeros, $ones);
1144                }
1145            }
1146        }
1147    };
1148}
1149
1150#[macro_export]
1151macro_rules! test_prime_field_32 {
1152    ($field:ty, $zeros: expr, $ones: expr) => {
1153        mod from_integer_tests_prime_field_32 {
1154            use p3_field::integers::QuotientMap;
1155            use p3_field::{Field, PrimeCharacteristicRing, PrimeField32, PrimeField64};
1156            use rand::rngs::SmallRng;
1157            use rand::{RngExt, SeedableRng};
1158
1159            #[test]
1160            fn test_as_canonical_u32() {
1161                let mut rng = SmallRng::seed_from_u64(1);
1162                let x: u32 = rng.random();
1163                let x_mod_order = x % <$field>::ORDER_U32;
1164
1165                for zero in $zeros {
1166                    assert_eq!(zero.as_canonical_u32(), 0);
1167                    assert_eq!(zero.to_unique_u32() as u64, zero.to_unique_u64());
1168                }
1169                for one in $ones {
1170                    assert_eq!(one.as_canonical_u32(), 1);
1171                    assert_eq!(one.to_unique_u32() as u64, one.to_unique_u64());
1172                }
1173                assert_eq!(<$field>::TWO.as_canonical_u32(), 2 % <$field>::ORDER_U32);
1174                assert_eq!(
1175                    <$field>::NEG_ONE.as_canonical_u32(),
1176                    <$field>::ORDER_U32 - 1
1177                );
1178                assert_eq!(
1179                    <$field>::from_int(<$field>::ORDER_U32).as_canonical_u32(),
1180                    0
1181                );
1182                assert_eq!(<$field>::from_int(x).as_canonical_u32(), x_mod_order);
1183                assert_eq!(
1184                    <$field>::from_int(x).to_unique_u32() as u64,
1185                    <$field>::from_int(x).to_unique_u64()
1186                );
1187                assert_eq!(
1188                    unsafe { <$field>::from_canonical_unchecked(x_mod_order).as_canonical_u32() },
1189                    x_mod_order
1190                );
1191            }
1192
1193            #[test]
1194            fn test_as_unique_u32() {
1195                assert_ne!(
1196                    <$field>::ZERO.to_unique_u32(),
1197                    <$field>::ONE.to_unique_u32()
1198                );
1199                assert_ne!(
1200                    <$field>::ZERO.to_unique_u32(),
1201                    <$field>::NEG_ONE.to_unique_u32()
1202                );
1203                assert_eq!(
1204                    <$field>::from_int(<$field>::ORDER_U32).to_unique_u32(),
1205                    <$field>::ZERO.to_unique_u32()
1206                );
1207            }
1208
1209            #[test]
1210            fn test_large_unsigned_integer_conversions() {
1211                $crate::generate_from_large_u_int_tests!(
1212                    $field,
1213                    <$field>::ORDER_U32,
1214                    [u32, u64, u128]
1215                );
1216            }
1217
1218            #[test]
1219            fn test_large_signed_integer_conversions() {
1220                $crate::generate_from_large_i_int_tests!(
1221                    $field,
1222                    <$field>::ORDER_U32,
1223                    [i32, i64, i128]
1224                );
1225            }
1226
1227            #[test]
1228            fn test_raw_data_serializable() {
1229                $crate::test_into_bytes_32::<$field>($zeros, $ones);
1230            }
1231
1232            #[test]
1233            fn test_json_deserialization_boundaries() {
1234                let accepts_order_repr = $zeros.len() > 1;
1235                $crate::test_prime_field_32_json_deserialization_boundaries::<$field>(
1236                    accepts_order_repr,
1237                );
1238            }
1239        }
1240    };
1241}
1242
1243#[macro_export]
1244macro_rules! test_two_adic_field {
1245    ($field:ty) => {
1246        mod two_adic_field_tests {
1247            #[test]
1248            fn test_two_adic_consistency() {
1249                $crate::test_two_adic_generator_consistency::<$field>();
1250                $crate::test_two_adic_point_collection::<$field>();
1251            }
1252
1253            // Looks a little strange but we also check that everything works
1254            // when the field is considered as a trivial extension of itself.
1255            #[test]
1256            fn test_two_adic_generator_consistency_as_trivial_extension() {
1257                $crate::test_ef_two_adic_generator_consistency::<$field, $field>();
1258            }
1259        }
1260    };
1261}
1262
1263#[macro_export]
1264macro_rules! test_extension_field {
1265    ($field:ty, $ef:ty) => {
1266        mod extension_field_tests {
1267            #[test]
1268            fn test_to_from_extension() {
1269                $crate::test_to_from_extension_field::<$field, $ef>();
1270            }
1271
1272            #[test]
1273            fn test_galois_extension() {
1274                $crate::test_galois_extension::<$field, $ef>();
1275            }
1276
1277            #[test]
1278            fn test_packed_extension() {
1279                $crate::test_packed_extension::<$field, $ef>();
1280            }
1281        }
1282    };
1283}
1284
1285#[macro_export]
1286macro_rules! test_two_adic_extension_field {
1287    ($field:ty, $ef:ty) => {
1288        use $crate::test_two_adic_field;
1289
1290        test_two_adic_field!($ef);
1291
1292        mod two_adic_extension_field_tests {
1293
1294            #[test]
1295            fn test_ef_two_adic_generator_consistency() {
1296                $crate::test_ef_two_adic_generator_consistency::<$field, $ef>();
1297            }
1298        }
1299    };
1300}
1301
1302#[macro_export]
1303macro_rules! test_frobenius {
1304    ($field:ty, $ef:ty) => {
1305        mod frobenius_tests {
1306            #[test]
1307            fn test_frobenius_fixes_base_field() {
1308                $crate::test_frobenius_fixes_base_field::<$field, $ef>();
1309            }
1310
1311            #[test]
1312            fn test_frobenius_proptest() {
1313                $crate::test_frobenius_proptest::<$field, $ef>();
1314            }
1315        }
1316    };
1317}