Skip to main content

p3_field_testing/
lib.rs

1//! Utilities for testing field implementations.
2
3#![no_std]
4
5extern crate alloc;
6
7#[cfg(not(target_arch = "wasm32"))]
8pub mod bench_func;
9pub mod dft_testing;
10pub mod extension_testing;
11pub mod from_integer_tests;
12pub mod packedfield_testing;
13
14use alloc::vec::Vec;
15use core::array;
16use core::iter::successors;
17
18#[cfg(not(target_arch = "wasm32"))]
19pub use bench_func::*;
20pub use dft_testing::*;
21pub use extension_testing::*;
22use num_bigint::BigUint;
23use p3_field::coset::TwoAdicMultiplicativeCoset;
24use p3_field::{
25    ExtensionField, Field, PackedValue, PrimeCharacteristicRing, PrimeField32, PrimeField64,
26    TwoAdicField, batch_multiplicative_inverse,
27};
28use p3_util::iter_array_chunks_padded;
29pub use packedfield_testing::*;
30use proptest::prelude::*;
31use rand::distr::{Distribution, StandardUniform};
32use rand::rngs::SmallRng;
33use rand::{RngExt, SeedableRng};
34use serde::Serialize;
35use serde::de::DeserializeOwned;
36
37/// Generate a random field element from a u64 seed, for use in proptest strategies.
38fn arb_field<F>() -> impl Strategy<Value = F>
39where
40    F: core::fmt::Debug + 'static,
41    StandardUniform: Distribution<F>,
42{
43    any::<u64>().prop_map(|seed| {
44        let mut rng = SmallRng::seed_from_u64(seed);
45        rng.random()
46    })
47}
48
49#[allow(clippy::eq_op)]
50pub fn test_ring_with_eq<R: PrimeCharacteristicRing + Copy + Eq>(zeros: &[R], ones: &[R])
51where
52    StandardUniform: Distribution<R> + Distribution<[R; 16]>,
53{
54    // zeros should be a vector containing different representatives of `R::ZERO`.
55    // ones should be a vector containing different representatives of `R::ONE`.
56    let mut rng = SmallRng::seed_from_u64(1);
57    let x = rng.random::<R>();
58    let y = rng.random::<R>();
59    let z = rng.random::<R>();
60    assert_eq!(R::ONE + R::NEG_ONE, R::ZERO, "Error 1 + (-1) =/= 0");
61    assert_eq!(R::NEG_ONE + R::TWO, R::ONE, "Error -1 + 2 =/= 1");
62    assert_eq!(x + (-x), R::ZERO, "Error x + (-x) =/= 0");
63    assert_eq!(R::ONE + R::ONE, R::TWO, "Error 1 + 1 =/= 2");
64    assert_eq!(-(-x), x, "Error when testing double negation");
65    assert_eq!(x + x, x * R::TWO, "Error when comparing x * 2 to x + x");
66    assert_eq!(
67        x * R::TWO,
68        x.double(),
69        "Error when comparing x.double() to x * 2"
70    );
71    assert_eq!(x, x.halve() * R::TWO, "Error when testing halve.");
72
73    // Check different representatives of Zero.
74    for zero in zeros.iter().copied() {
75        assert_eq!(zero, R::ZERO);
76        assert_eq!(x + zero, x, "Error when testing additive identity right.");
77        assert_eq!(zero + x, x, "Error when testing additive identity left.");
78        assert_eq!(x - zero, x, "Error when testing subtracting zero.");
79        assert_eq!(zero - x, -x, "Error when testing subtracting  from zero.");
80        assert_eq!(
81            x * zero,
82            zero,
83            "Error when testing right multiplication by 0."
84        );
85        assert_eq!(
86            zero * x,
87            zero,
88            "Error when testing left multiplication by 0."
89        );
90    }
91
92    // Check different representatives of One.
93    for one in ones.iter().copied() {
94        assert_eq!(one, R::ONE);
95        assert_eq!(one * one, one);
96        assert_eq!(
97            x * one,
98            x,
99            "Error when testing multiplicative identity right."
100        );
101        assert_eq!(
102            one * x,
103            x,
104            "Error when testing multiplicative identity left."
105        );
106    }
107
108    assert_eq!(
109        x * R::NEG_ONE,
110        -x,
111        "Error when testing right multiplication by -1."
112    );
113    assert_eq!(
114        R::NEG_ONE * x,
115        -x,
116        "Error when testing left multiplication by -1."
117    );
118    assert_eq!(x * x, x.square(), "Error when testing x * x = x.square()");
119    assert_eq!(
120        x * x * x,
121        x.cube(),
122        "Error when testing x * x * x = x.cube()"
123    );
124    assert_eq!(x + y, y + x, "Error when testing commutativity of addition");
125    assert_eq!(
126        (x - y),
127        -(y - x),
128        "Error when testing anticommutativity of sub."
129    );
130    assert_eq!(
131        x * y,
132        y * x,
133        "Error when testing commutativity of multiplication."
134    );
135    assert_eq!(
136        x + (y + z),
137        (x + y) + z,
138        "Error when testing associativity of addition"
139    );
140    assert_eq!(
141        x * (y * z),
142        (x * y) * z,
143        "Error when testing associativity of multiplication."
144    );
145    assert_eq!(
146        x - (y - z),
147        (x - y) + z,
148        "Error when testing subtraction and addition"
149    );
150    assert_eq!(
151        x - (y + z),
152        (x - y) - z,
153        "Error when testing subtraction and addition"
154    );
155    assert_eq!(
156        (x + y) - z,
157        x + (y - z),
158        "Error when testing subtraction and addition"
159    );
160    assert_eq!(
161        x * (-y),
162        -(x * y),
163        "Error when testing distributivity of mul and right neg."
164    );
165    assert_eq!(
166        (-x) * y,
167        -(x * y),
168        "Error when testing distributivity of mul and left neg."
169    );
170
171    assert_eq!(
172        x * (y + z),
173        x * y + x * z,
174        "Error when testing distributivity of add and left mul."
175    );
176    assert_eq!(
177        (x + y) * z,
178        x * z + y * z,
179        "Error when testing distributivity of add and right mul."
180    );
181    assert_eq!(
182        x * (y - z),
183        x * y - x * z,
184        "Error when testing distributivity of sub and left mul."
185    );
186    assert_eq!(
187        (x - y) * z,
188        x * z - y * z,
189        "Error when testing distributivity of sub and right mul."
190    );
191
192    let vec1: [R; 64] = rng.random();
193    let vec2: [R; 64] = rng.random();
194    test_sums(&vec1[..16].try_into().unwrap());
195    test_dot_product(&vec1, &vec2);
196
197    assert_eq!(
198        x.exp_const_u64::<0>(),
199        R::ONE,
200        "Error when comparing x.exp_const_u64::<0> to R::ONE."
201    );
202    assert_eq!(
203        x.exp_const_u64::<1>(),
204        x,
205        "Error when comparing x.exp_const_u64::<3> to x."
206    );
207    assert_eq!(
208        x.exp_const_u64::<2>(),
209        x * x,
210        "Error when comparing x.exp_const_u64::<3> to x*x."
211    );
212    assert_eq!(
213        x.exp_const_u64::<3>(),
214        x * x * x,
215        "Error when comparing x.exp_const_u64::<3> to x*x*x."
216    );
217    assert_eq!(
218        x.exp_const_u64::<4>(),
219        x * x * x * x,
220        "Error when comparing x.exp_const_u64::<3> to x*x*x*x."
221    );
222    assert_eq!(
223        x.exp_const_u64::<5>(),
224        x * x * x * x * x,
225        "Error when comparing x.exp_const_u64::<5> to x*x*x*x*x."
226    );
227    assert_eq!(
228        x.exp_const_u64::<6>(),
229        x * x * x * x * x * x,
230        "Error when comparing x.exp_const_u64::<7> to x*x*x*x*x*x."
231    );
232    assert_eq!(
233        x.exp_const_u64::<7>(),
234        x * x * x * x * x * x * x,
235        "Error when comparing x.exp_const_u64::<7> to x*x*x*x*x*x*x."
236    );
237
238    test_binary_ops(zeros, ones, x, y, z);
239
240    // Edge case tests with special values
241    for &a in &[R::ZERO, R::ONE, R::TWO, R::NEG_ONE] {
242        for &b in &[R::ZERO, R::ONE, R::TWO, R::NEG_ONE] {
243            assert_eq!(a + b, b + a, "commutativity with special values");
244            assert_eq!(a * b, b * a, "commutativity with special values");
245        }
246        assert_eq!(a * a, a.square(), "square with special value");
247        assert_eq!(a * a * a, a.cube(), "cube with special value");
248        assert_eq!(a.halve().double(), a, "halve/double with special value");
249    }
250
251    // Test that Product of empty iterator returns ONE (the multiplicative identity)
252    let empty: [R; 0] = [];
253    let product_result: R = empty.into_iter().product();
254    assert_eq!(
255        product_result,
256        R::ONE,
257        "Product of empty iterator should return ONE, not ZERO"
258    );
259}
260
261/// Identical to [`test_ring_with_eq()`], except it omits the `halve` identities, which
262/// [`PrimeCharacteristicRing::halve`] does not support in characteristic 2.
263#[allow(clippy::eq_op)]
264pub fn test_ring_with_eq_char2<R: PrimeCharacteristicRing + Copy + Eq>(zeros: &[R], ones: &[R])
265where
266    StandardUniform: Distribution<R> + Distribution<[R; 16]>,
267{
268    // zeros should be a vector containing different representatives of `R::ZERO`.
269    // ones should be a vector containing different representatives of `R::ONE`.
270    let mut rng = SmallRng::seed_from_u64(1);
271    let x = rng.random::<R>();
272    let y = rng.random::<R>();
273    let z = rng.random::<R>();
274    assert_eq!(R::ONE + R::NEG_ONE, R::ZERO, "Error 1 + (-1) =/= 0");
275    assert_eq!(R::NEG_ONE + R::TWO, R::ONE, "Error -1 + 2 =/= 1");
276    assert_eq!(x + (-x), R::ZERO, "Error x + (-x) =/= 0");
277    assert_eq!(R::ONE + R::ONE, R::TWO, "Error 1 + 1 =/= 2");
278    assert_eq!(-(-x), x, "Error when testing double negation");
279    assert_eq!(x + x, x * R::TWO, "Error when comparing x * 2 to x + x");
280    assert_eq!(
281        x * R::TWO,
282        x.double(),
283        "Error when comparing x.double() to x * 2"
284    );
285
286    // Check different representatives of Zero.
287    for zero in zeros.iter().copied() {
288        assert_eq!(zero, R::ZERO);
289        assert_eq!(x + zero, x, "Error when testing additive identity right.");
290        assert_eq!(zero + x, x, "Error when testing additive identity left.");
291        assert_eq!(x - zero, x, "Error when testing subtracting zero.");
292        assert_eq!(zero - x, -x, "Error when testing subtracting  from zero.");
293        assert_eq!(
294            x * zero,
295            zero,
296            "Error when testing right multiplication by 0."
297        );
298        assert_eq!(
299            zero * x,
300            zero,
301            "Error when testing left multiplication by 0."
302        );
303    }
304
305    // Check different representatives of One.
306    for one in ones.iter().copied() {
307        assert_eq!(one, R::ONE);
308        assert_eq!(one * one, one);
309        assert_eq!(
310            x * one,
311            x,
312            "Error when testing multiplicative identity right."
313        );
314        assert_eq!(
315            one * x,
316            x,
317            "Error when testing multiplicative identity left."
318        );
319    }
320
321    assert_eq!(
322        x * R::NEG_ONE,
323        -x,
324        "Error when testing right multiplication by -1."
325    );
326    assert_eq!(
327        R::NEG_ONE * x,
328        -x,
329        "Error when testing left multiplication by -1."
330    );
331    assert_eq!(x * x, x.square(), "Error when testing x * x = x.square()");
332    assert_eq!(
333        x * x * x,
334        x.cube(),
335        "Error when testing x * x * x = x.cube()"
336    );
337    assert_eq!(x + y, y + x, "Error when testing commutativity of addition");
338    assert_eq!(
339        (x - y),
340        -(y - x),
341        "Error when testing anticommutativity of sub."
342    );
343    assert_eq!(
344        x * y,
345        y * x,
346        "Error when testing commutativity of multiplication."
347    );
348    assert_eq!(
349        x + (y + z),
350        (x + y) + z,
351        "Error when testing associativity of addition"
352    );
353    assert_eq!(
354        x * (y * z),
355        (x * y) * z,
356        "Error when testing associativity of multiplication."
357    );
358    assert_eq!(
359        x - (y - z),
360        (x - y) + z,
361        "Error when testing subtraction and addition"
362    );
363    assert_eq!(
364        x - (y + z),
365        (x - y) - z,
366        "Error when testing subtraction and addition"
367    );
368    assert_eq!(
369        (x + y) - z,
370        x + (y - z),
371        "Error when testing subtraction and addition"
372    );
373    assert_eq!(
374        x * (-y),
375        -(x * y),
376        "Error when testing distributivity of mul and right neg."
377    );
378    assert_eq!(
379        (-x) * y,
380        -(x * y),
381        "Error when testing distributivity of mul and left neg."
382    );
383
384    assert_eq!(
385        x * (y + z),
386        x * y + x * z,
387        "Error when testing distributivity of add and left mul."
388    );
389    assert_eq!(
390        (x + y) * z,
391        x * z + y * z,
392        "Error when testing distributivity of add and right mul."
393    );
394    assert_eq!(
395        x * (y - z),
396        x * y - x * z,
397        "Error when testing distributivity of sub and left mul."
398    );
399    assert_eq!(
400        (x - y) * z,
401        x * z - y * z,
402        "Error when testing distributivity of sub and right mul."
403    );
404
405    let vec1: [R; 64] = rng.random();
406    let vec2: [R; 64] = rng.random();
407    test_sums(&vec1[..16].try_into().unwrap());
408    test_dot_product(&vec1, &vec2);
409
410    assert_eq!(
411        x.exp_const_u64::<0>(),
412        R::ONE,
413        "Error when comparing x.exp_const_u64::<0> to R::ONE."
414    );
415    assert_eq!(
416        x.exp_const_u64::<1>(),
417        x,
418        "Error when comparing x.exp_const_u64::<3> to x."
419    );
420    assert_eq!(
421        x.exp_const_u64::<2>(),
422        x * x,
423        "Error when comparing x.exp_const_u64::<3> to x*x."
424    );
425    assert_eq!(
426        x.exp_const_u64::<3>(),
427        x * x * x,
428        "Error when comparing x.exp_const_u64::<3> to x*x*x."
429    );
430    assert_eq!(
431        x.exp_const_u64::<4>(),
432        x * x * x * x,
433        "Error when comparing x.exp_const_u64::<3> to x*x*x*x."
434    );
435    assert_eq!(
436        x.exp_const_u64::<5>(),
437        x * x * x * x * x,
438        "Error when comparing x.exp_const_u64::<5> to x*x*x*x*x."
439    );
440    assert_eq!(
441        x.exp_const_u64::<6>(),
442        x * x * x * x * x * x,
443        "Error when comparing x.exp_const_u64::<7> to x*x*x*x*x*x."
444    );
445    assert_eq!(
446        x.exp_const_u64::<7>(),
447        x * x * x * x * x * x * x,
448        "Error when comparing x.exp_const_u64::<7> to x*x*x*x*x*x*x."
449    );
450
451    test_binary_ops(zeros, ones, x, y, z);
452
453    // Edge case tests with special values
454    for &a in &[R::ZERO, R::ONE, R::TWO, R::NEG_ONE] {
455        for &b in &[R::ZERO, R::ONE, R::TWO, R::NEG_ONE] {
456            assert_eq!(a + b, b + a, "commutativity with special values");
457            assert_eq!(a * b, b * a, "commutativity with special values");
458        }
459        assert_eq!(a * a, a.square(), "square with special value");
460        assert_eq!(a * a * a, a.cube(), "cube with special value");
461    }
462
463    // Test that Product of empty iterator returns ONE (the multiplicative identity)
464    let empty: [R; 0] = [];
465    let product_result: R = empty.into_iter().product();
466    assert_eq!(
467        product_result,
468        R::ONE,
469        "Product of empty iterator should return ONE, not ZERO"
470    );
471}
472
473pub fn test_mul_2exp_u64<R: PrimeCharacteristicRing + Eq>()
474where
475    StandardUniform: Distribution<R>,
476{
477    let mut rng = SmallRng::seed_from_u64(1);
478    let x = rng.random::<R>();
479    assert_eq!(x.mul_2exp_u64(0), x);
480    assert_eq!(x.mul_2exp_u64(1), x.double());
481    for i in 0..128 {
482        assert_eq!(
483            x.clone().mul_2exp_u64(i),
484            x.clone() * R::from_u128(1_u128 << i)
485        );
486    }
487    // Goldilocks behaviour changes at 96, 192 so we want to test larger numbers than that.
488    for i in 128..256 {
489        assert_eq!(x.clone().mul_2exp_u64(i), x.clone() * R::TWO.exp_u64(i));
490    }
491}
492
493/// In characteristic 2, `2 == 0`, so `mul_2exp_u64(e)` collapses to `ZERO` for every
494/// `e >= 1` (and is the identity at `e == 0`). Replaces [`test_mul_2exp_u64`], which
495/// compares against multiplication by `2^e` computed as if `2` were nonzero.
496pub fn test_mul_2exp_u64_is_zero_above_e0<R: PrimeCharacteristicRing + Eq>()
497where
498    StandardUniform: Distribution<R>,
499{
500    let mut rng = SmallRng::seed_from_u64(1);
501    let x = rng.random::<R>();
502    // Small exponents plus values straddling the 64- and 128-bit boundaries, where an
503    // implementation computing `2^e` as a fixed-width shift would overflow rather than
504    // collapse to `ZERO`.
505    const EXPONENTS: [u64; 9] = [1, 2, 7, 8, 63, 64, 127, 128, 255];
506    for sample in [R::ZERO, R::ONE, x] {
507        assert_eq!(
508            sample.mul_2exp_u64(0),
509            sample,
510            "mul_2exp_u64(0) must be the identity"
511        );
512        for e in EXPONENTS {
513            assert_eq!(
514                sample.mul_2exp_u64(e),
515                R::ZERO,
516                "mul_2exp_u64({e}) must be ZERO in characteristic 2"
517            );
518        }
519    }
520}
521
522/// [`PrimeCharacteristicRing::halve`] is documented to panic in characteristic 2.
523///
524/// Must be invoked from a `#[should_panic]` test.
525pub fn test_halve_panics_char2<R: PrimeCharacteristicRing>() {
526    let _halved = R::ONE.halve();
527}
528
529/// [`PrimeCharacteristicRing::div_2exp_u64`] is documented to panic in characteristic 2.
530///
531/// Must be invoked from a `#[should_panic]` test.
532pub fn test_div_2exp_u64_panics_char2<R: PrimeCharacteristicRing>() {
533    let _divided = R::ONE.div_2exp_u64(1);
534}
535
536pub fn test_div_2exp_u64<R: PrimeCharacteristicRing + Eq>()
537where
538    StandardUniform: Distribution<R>,
539{
540    let mut rng = SmallRng::seed_from_u64(1);
541    let x = rng.random::<R>();
542    assert_eq!(x.div_2exp_u64(0), x);
543    assert_eq!(x.div_2exp_u64(1), x.halve());
544    for i in 0..128 {
545        assert_eq!(x.mul_2exp_u64(i).div_2exp_u64(i), x);
546        assert_eq!(
547            x.div_2exp_u64(i),
548            // Best to invert in the prime subfield in case F is an extension field.
549            x.clone() * R::from_prime_subfield(R::PrimeSubfield::from_u128(1_u128 << i).inverse())
550        );
551    }
552    // Goldilocks behaviour changes at 96, 192 so we want to test larger numbers than that.
553    for i in 128..256 {
554        assert_eq!(x.mul_2exp_u64(i).div_2exp_u64(i), x);
555        assert_eq!(
556            x.div_2exp_u64(i),
557            // Best to invert in the prime subfield in case F is an extension field.
558            x.clone() * R::from_prime_subfield(R::PrimeSubfield::TWO.inverse().exp_u64(i))
559        );
560    }
561}
562
563pub fn test_add_slice<F: Field>()
564where
565    StandardUniform: Distribution<F>,
566{
567    let mut rng = SmallRng::seed_from_u64(1);
568    let lengths = [
569        F::Packing::WIDTH - 1,
570        F::Packing::WIDTH,
571        (F::Packing::WIDTH - 1) + (F::Packing::WIDTH << 10),
572    ];
573    for len in lengths {
574        let mut slice_1: Vec<_> = (&mut rng).sample_iter(StandardUniform).take(len).collect();
575        let slice_1_copy = slice_1.clone();
576        let slice_2: Vec<_> = (&mut rng).sample_iter(StandardUniform).take(len).collect();
577
578        F::add_slices(&mut slice_1, &slice_2);
579        for i in 0..len {
580            assert_eq!(slice_1[i], slice_1_copy[i] + slice_2[i]);
581        }
582    }
583}
584
585pub fn test_inverse<F: Field>()
586where
587    StandardUniform: Distribution<F>,
588{
589    assert_eq!(None, F::ZERO.try_inverse());
590    assert_eq!(Some(F::ONE), F::ONE.try_inverse());
591    assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
592    let two_inv = F::TWO
593        .try_inverse()
594        .expect("2 must be invertible in this field (test_inverse assumes characteristic != 2)");
595    assert_eq!(two_inv, F::ONE.halve(), "inverse of 2 == halve(1)");
596    let mut rng = SmallRng::seed_from_u64(1);
597    for _ in 0..1000 {
598        let x = rng.random::<F>();
599        if !x.is_zero() && !x.is_one() {
600            let z = x.inverse();
601            assert_ne!(x, z);
602            assert_eq!(x * z, F::ONE);
603        }
604    }
605}
606
607/// Identical to [`test_inverse`], except it omits the `2.inverse() == 1.halve()` check,
608/// since `2 == 0` is not invertible in characteristic 2.
609pub fn test_inverse_char2<F: Field>()
610where
611    StandardUniform: Distribution<F>,
612{
613    assert_eq!(None, F::ZERO.try_inverse());
614    assert_eq!(Some(F::ONE), F::ONE.try_inverse());
615    assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
616    let mut rng = SmallRng::seed_from_u64(1);
617    for _ in 0..1000 {
618        let x = rng.random::<F>();
619        if !x.is_zero() && !x.is_one() {
620            let z = x.inverse();
621            assert_ne!(x, z);
622            assert_eq!(x * z, F::ONE);
623        }
624    }
625}
626
627/// Test that [`Field::try_sqrt`] agrees with squaring.
628///
629/// Assumes the field has characteristic `!= 2`, so that roughly half of all
630/// elements are quadratic non-residues.
631pub fn test_sqrt<F: Field>()
632where
633    StandardUniform: Distribution<F>,
634{
635    // `0` is its own square root and `1` is always a square.
636    assert_eq!(F::ZERO.try_sqrt(), Some(F::ZERO));
637    assert_eq!(
638        F::ONE.try_sqrt().map(|r| r.square()),
639        Some(F::ONE),
640        "1 must be a square"
641    );
642
643    let mut rng = SmallRng::seed_from_u64(0x59A7);
644    let mut residues = 0;
645    let mut non_residues = 0;
646    for _ in 0..1000 {
647        let x = rng.random::<F>();
648
649        // The square of any element is a quadratic residue, and any returned
650        // root must square back to it.
651        let square = x.square();
652        let root = square.try_sqrt().expect("x^2 is always a square");
653        assert_eq!(root.square(), square, "sqrt(x^2)^2 == x^2");
654
655        // A random element is a residue iff `try_sqrt` succeeds; when it does,
656        // the result must be a genuine square root.
657        match x.try_sqrt() {
658            Some(r) => {
659                assert_eq!(r.square(), x, "try_sqrt(x)^2 == x");
660                residues += 1;
661            }
662            None => non_residues += 1,
663        }
664    }
665
666    // With 1000 samples both branches are hit with overwhelming probability.
667    assert!(residues > 0, "expected to sample a quadratic residue");
668    assert!(
669        non_residues > 0,
670        "expected to sample a quadratic non-residue"
671    );
672}
673
674/// Test that [`Field::try_sqrt`] agrees with squaring, in characteristic 2.
675///
676/// Every finite field of characteristic 2 is perfect, so the Frobenius endomorphism
677/// `x -> x^2` is a bijection and every element has a (unique) square root. Unlike
678/// [`test_sqrt`], this does not expect to find any quadratic non-residues.
679pub fn test_sqrt_char2<F: Field>()
680where
681    StandardUniform: Distribution<F>,
682{
683    assert_eq!(F::ZERO.try_sqrt(), Some(F::ZERO));
684    assert_eq!(
685        F::ONE.try_sqrt().map(|r| r.square()),
686        Some(F::ONE),
687        "1 must be a square"
688    );
689
690    let mut rng = SmallRng::seed_from_u64(0x59A7);
691    for _ in 0..1000 {
692        let x = rng.random::<F>();
693
694        // The square of any element is a quadratic residue, and any returned
695        // root must square back to it.
696        let square = x.square();
697        let root = square.try_sqrt().expect("x^2 is always a square");
698        assert_eq!(root.square(), square, "sqrt(x^2)^2 == x^2");
699
700        // Every element of a characteristic-2 field is itself a square.
701        let r = x
702            .try_sqrt()
703            .expect("every element is a square in characteristic 2");
704        assert_eq!(r.square(), x, "try_sqrt(x)^2 == x");
705    }
706}
707
708/// Verify [`batch_multiplicative_inverse`] against the naive per-element inverse
709/// across a range of input lengths.
710///
711/// Sizes are chosen to exercise:
712/// - the empty input,
713/// - lengths below the packing width (tail-only path),
714/// - lengths whose remainder mod the packing width is 1, 2, or 3
715///   (mixed prefix-packed + tail-serial path),
716/// - lengths that straddle the internal `par_chunks` boundary (1024)
717///   so the trailing chunk receives a non-aligned tail.
718pub fn test_batch_multiplicative_inverse<F: Field>()
719where
720    StandardUniform: Distribution<F>,
721{
722    let mut rng = SmallRng::seed_from_u64(0xBA7C);
723
724    let lengths = [
725        0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 17, 63, 64, 65, 1023, 1024, 1025, 1027, 2049, 4099,
726    ];
727
728    for &n in &lengths {
729        let xs: Vec<F> = (0..n)
730            .map(|_| {
731                // Reject zero so every input is invertible.
732                let mut x = rng.random::<F>();
733                while x.is_zero() {
734                    x = rng.random::<F>();
735                }
736                x
737            })
738            .collect();
739
740        let got = batch_multiplicative_inverse(&xs);
741        assert_eq!(got.len(), n, "result length mismatch for n = {n}");
742
743        for (i, (x, inv)) in xs.iter().zip(&got).enumerate() {
744            assert_eq!(
745                *x * *inv,
746                F::ONE,
747                "x[{i}] * inv[{i}] != 1 for input length {n}"
748            );
749        }
750    }
751}
752
753/// Test JSON serialization and deserialization for a set of field values.
754///
755/// This function tests that:
756/// 1. Each value can be serialized and deserialized correctly
757/// 2. Double round-trip serialization is consistent
758pub fn test_field_json_serialization<F>(values: &[F])
759where
760    F: PrimeCharacteristicRing + Serialize + DeserializeOwned + Eq,
761{
762    for value in values {
763        // Single round-trip
764        let serialized = serde_json::to_string(value).expect("Failed to serialize field element");
765        let deserialized: F =
766            serde_json::from_str(&serialized).expect("Failed to deserialize field element");
767        assert_eq!(
768            *value, deserialized,
769            "Single round-trip serialization failed"
770        );
771
772        // Double round-trip to ensure consistency
773        let serialized_again = serde_json::to_string(&deserialized)
774            .expect("Failed to serialize field element (second time)");
775        let deserialized_again: F = serde_json::from_str(&serialized_again)
776            .expect("Failed to deserialize field element (second time)");
777        assert_eq!(
778            *value, deserialized_again,
779            "Double round-trip serialization failed"
780        );
781        assert_eq!(
782            deserialized, deserialized_again,
783            "Deserialized values should be equal"
784        );
785    }
786}
787
788/// Test JSON deserialization boundary behavior for 32-bit prime fields.
789///
790/// The serde encoding is canonical: only values in `[0, ORDER_U32)` deserialize.
791pub fn test_prime_field_32_json_deserialization_boundaries<F>()
792where
793    F: PrimeField32 + Serialize + DeserializeOwned + Eq,
794{
795    let zero: F = serde_json::from_str("0").expect("Failed to deserialize zero");
796    assert_eq!(zero, F::ZERO, "Deserializing 0 should produce ZERO");
797
798    let original: F = serde_json::from_str("42").expect("Failed to deserialize test value");
799    let serialized = serde_json::to_string(&original).expect("Failed to serialize test value");
800    let deserialized: F =
801        serde_json::from_str(&serialized).expect("Failed to deserialize serialized test value");
802    assert_eq!(
803        deserialized, original,
804        "Round-trip serialization should preserve the value"
805    );
806
807    let max_valid = F::ORDER_U32 - 1;
808    let max_valid_json = serde_json::to_string(&max_valid).expect("Failed to encode max valid u32");
809    let max_valid_result: Result<F, _> = serde_json::from_str(&max_valid_json);
810    assert!(
811        max_valid_result.is_ok(),
812        "Expected max valid representation to deserialize successfully"
813    );
814
815    if let Some(first_invalid) = max_valid.checked_add(1) {
816        let first_invalid_json =
817            serde_json::to_string(&first_invalid).expect("Failed to encode first invalid value");
818        let first_invalid_result: Result<F, _> = serde_json::from_str(&first_invalid_json);
819        assert!(
820            first_invalid_result.is_err(),
821            "Expected first out-of-range representation to fail deserialization"
822        );
823    }
824
825    if max_valid != u32::MAX {
826        let max_u32_json = serde_json::to_string(&u32::MAX).expect("Failed to encode u32::MAX");
827        let max_u32_result: Result<F, _> = serde_json::from_str(&max_u32_json);
828        assert!(
829            max_u32_result.is_err(),
830            "Expected u32::MAX to fail deserialization"
831        );
832    }
833}
834
835pub fn test_dot_product<R: PrimeCharacteristicRing + Eq + Copy>(u: &[R; 64], v: &[R; 64]) {
836    let mut dot = R::ZERO;
837    assert_eq!(
838        dot,
839        R::dot_product::<0>(u[..0].try_into().unwrap(), v[..0].try_into().unwrap())
840    );
841    dot += u[0] * v[0];
842    assert_eq!(
843        dot,
844        R::dot_product::<1>(u[..1].try_into().unwrap(), v[..1].try_into().unwrap())
845    );
846    dot += u[1] * v[1];
847    assert_eq!(
848        dot,
849        R::dot_product::<2>(u[..2].try_into().unwrap(), v[..2].try_into().unwrap())
850    );
851    dot += u[2] * v[2];
852    assert_eq!(
853        dot,
854        R::dot_product::<3>(u[..3].try_into().unwrap(), v[..3].try_into().unwrap())
855    );
856    dot += u[3] * v[3];
857    assert_eq!(
858        dot,
859        R::dot_product::<4>(u[..4].try_into().unwrap(), v[..4].try_into().unwrap())
860    );
861    dot += u[4] * v[4];
862    assert_eq!(
863        dot,
864        R::dot_product::<5>(u[..5].try_into().unwrap(), v[..5].try_into().unwrap())
865    );
866    dot += u[5] * v[5];
867    assert_eq!(
868        dot,
869        R::dot_product::<6>(u[..6].try_into().unwrap(), v[..6].try_into().unwrap())
870    );
871    dot += u[6] * v[6];
872    assert_eq!(
873        dot,
874        R::dot_product::<7>(u[..7].try_into().unwrap(), v[..7].try_into().unwrap())
875    );
876    dot += u[7] * v[7];
877    assert_eq!(
878        dot,
879        R::dot_product::<8>(u[..8].try_into().unwrap(), v[..8].try_into().unwrap())
880    );
881    dot += u[8] * v[8];
882    assert_eq!(
883        dot,
884        R::dot_product::<9>(u[..9].try_into().unwrap(), v[..9].try_into().unwrap())
885    );
886    dot += u[9] * v[9];
887    assert_eq!(
888        dot,
889        R::dot_product::<10>(u[..10].try_into().unwrap(), v[..10].try_into().unwrap())
890    );
891    dot += u[10] * v[10];
892    assert_eq!(
893        dot,
894        R::dot_product::<11>(u[..11].try_into().unwrap(), v[..11].try_into().unwrap())
895    );
896    dot += u[11] * v[11];
897    assert_eq!(
898        dot,
899        R::dot_product::<12>(u[..12].try_into().unwrap(), v[..12].try_into().unwrap())
900    );
901    dot += u[12] * v[12];
902    assert_eq!(
903        dot,
904        R::dot_product::<13>(u[..13].try_into().unwrap(), v[..13].try_into().unwrap())
905    );
906    dot += u[13] * v[13];
907    assert_eq!(
908        dot,
909        R::dot_product::<14>(u[..14].try_into().unwrap(), v[..14].try_into().unwrap())
910    );
911    dot += u[14] * v[14];
912    assert_eq!(
913        dot,
914        R::dot_product::<15>(u[..15].try_into().unwrap(), v[..15].try_into().unwrap())
915    );
916    dot += u[15] * v[15];
917    assert_eq!(
918        dot,
919        R::dot_product::<16>(u[..16].try_into().unwrap(), v[..16].try_into().unwrap())
920    );
921
922    let dot_64: R = u
923        .iter()
924        .zip(v.iter())
925        .fold(R::ZERO, |acc, (&lhs, &rhs)| acc + (lhs * rhs));
926    assert_eq!(dot_64, R::dot_product::<64>(u, v));
927}
928
929pub fn test_sums<R: PrimeCharacteristicRing + Eq + Copy>(u: &[R; 16]) {
930    let mut sum = R::ZERO;
931    assert_eq!(sum, R::sum_array::<0>(u[..0].try_into().unwrap()));
932    assert_eq!(sum, u[..0].iter().copied().sum());
933    sum += u[0];
934    assert_eq!(sum, R::sum_array::<1>(u[..1].try_into().unwrap()));
935    assert_eq!(sum, u[..1].iter().copied().sum());
936    sum += u[1];
937    assert_eq!(sum, R::sum_array::<2>(u[..2].try_into().unwrap()));
938    assert_eq!(sum, u[..2].iter().copied().sum());
939    sum += u[2];
940    assert_eq!(sum, R::sum_array::<3>(u[..3].try_into().unwrap()));
941    assert_eq!(sum, u[..3].iter().copied().sum());
942    sum += u[3];
943    assert_eq!(sum, R::sum_array::<4>(u[..4].try_into().unwrap()));
944    assert_eq!(sum, u[..4].iter().copied().sum());
945    sum += u[4];
946    assert_eq!(sum, R::sum_array::<5>(u[..5].try_into().unwrap()));
947    assert_eq!(sum, u[..5].iter().copied().sum());
948    sum += u[5];
949    assert_eq!(sum, R::sum_array::<6>(u[..6].try_into().unwrap()));
950    assert_eq!(sum, u[..6].iter().copied().sum());
951    sum += u[6];
952    assert_eq!(sum, R::sum_array::<7>(u[..7].try_into().unwrap()));
953    assert_eq!(sum, u[..7].iter().copied().sum());
954    sum += u[7];
955    assert_eq!(sum, R::sum_array::<8>(u[..8].try_into().unwrap()));
956    assert_eq!(sum, u[..8].iter().copied().sum());
957    sum += u[8];
958    assert_eq!(sum, R::sum_array::<9>(u[..9].try_into().unwrap()));
959    assert_eq!(sum, u[..9].iter().copied().sum());
960    sum += u[9];
961    assert_eq!(sum, R::sum_array::<10>(u[..10].try_into().unwrap()));
962    assert_eq!(sum, u[..10].iter().copied().sum());
963    sum += u[10];
964    assert_eq!(sum, R::sum_array::<11>(u[..11].try_into().unwrap()));
965    assert_eq!(sum, u[..11].iter().copied().sum());
966    sum += u[11];
967    assert_eq!(sum, R::sum_array::<12>(u[..12].try_into().unwrap()));
968    assert_eq!(sum, u[..12].iter().copied().sum());
969    sum += u[12];
970    assert_eq!(sum, R::sum_array::<13>(u[..13].try_into().unwrap()));
971    assert_eq!(sum, u[..13].iter().copied().sum());
972    sum += u[13];
973    assert_eq!(sum, R::sum_array::<14>(u[..14].try_into().unwrap()));
974    assert_eq!(sum, u[..14].iter().copied().sum());
975    sum += u[14];
976    assert_eq!(sum, R::sum_array::<15>(u[..15].try_into().unwrap()));
977    assert_eq!(sum, u[..15].iter().copied().sum());
978    sum += u[15];
979    assert_eq!(sum, R::sum_array::<16>(u));
980    assert_eq!(sum, u.iter().copied().sum());
981}
982
983pub fn test_binary_ops<R: PrimeCharacteristicRing + Eq + Copy>(
984    zeros: &[R],
985    ones: &[R],
986    x: R,
987    y: R,
988    z: R,
989) {
990    for zero in zeros {
991        for one in ones {
992            assert_eq!(one.xor(one), R::ZERO, "Error when testing xor(1, 1) = 0.");
993            assert_eq!(zero.xor(one), R::ONE, "Error when testing xor(0, 1) = 1.");
994            assert_eq!(one.xor(zero), R::ONE, "Error when testing xor(1, 0) = 1.");
995            assert_eq!(zero.xor(zero), R::ZERO, "Error when testing xor(0, 0) = 0.");
996            assert_eq!(one.andn(one), R::ZERO, "Error when testing andn(1, 1) = 0.");
997            assert_eq!(zero.andn(one), R::ONE, "Error when testing andn(0, 1) = 1.");
998            assert_eq!(
999                one.andn(zero),
1000                R::ZERO,
1001                "Error when testing andn(1, 0) = 0."
1002            );
1003            assert_eq!(
1004                zero.andn(zero),
1005                R::ZERO,
1006                "Error when testing andn(0, 0) = 0."
1007            );
1008            assert_eq!(
1009                zero.bool_check(),
1010                R::ZERO,
1011                "Error when testing bool_check(0) = 0."
1012            );
1013            assert_eq!(
1014                one.bool_check(),
1015                R::ZERO,
1016                "Error when testing bool_check(1) = 0."
1017            );
1018        }
1019    }
1020
1021    assert_eq!(
1022        R::ONE.xor(&R::NEG_ONE),
1023        R::TWO,
1024        "Error when testing xor(1, -1) = 2."
1025    );
1026    assert_eq!(
1027        R::NEG_ONE.xor(&R::ONE),
1028        R::TWO,
1029        "Error when testing xor(-1, 1) = 2."
1030    );
1031    assert_eq!(
1032        R::NEG_ONE.xor(&R::NEG_ONE),
1033        R::from_i8(-4),
1034        "Error when testing xor(-1, -1) = -4."
1035    );
1036    assert_eq!(
1037        R::ONE.andn(&R::NEG_ONE),
1038        R::ZERO,
1039        "Error when testing andn(1, -1) = 0."
1040    );
1041    assert_eq!(
1042        R::NEG_ONE.andn(&R::ONE),
1043        R::TWO,
1044        "Error when testing andn(-1, 1) = 2."
1045    );
1046    assert_eq!(
1047        R::NEG_ONE.andn(&R::NEG_ONE),
1048        -R::TWO,
1049        "Error when testing andn(-1, -1) = -2."
1050    );
1051
1052    assert_eq!(x.xor(&y), x + y - x * y.double(), "Error when testing xor.");
1053
1054    assert_eq!(x.andn(&y), (R::ONE - x) * y, "Error when testing andn.");
1055
1056    assert_eq!(
1057        x.xor3(&y, &z),
1058        x + y + z - (x * y + x * z + y * z).double() + x * y * z.double().double(),
1059        "Error when testing xor3."
1060    );
1061}
1062
1063/// Checks the fixed enumeration used for interpolation nodes.
1064///
1065/// `0..64` is the tested range, capped by the size of the field: a field with fewer than 64
1066/// elements cannot enumerate 64 distinct ones, and injectivity is only ever asked for on the
1067/// indices a protocol can reach.
1068pub fn test_interpolation_nodes<F: Field>() {
1069    assert_eq!(F::interpolation_node(0), F::ZERO);
1070    assert_eq!(F::interpolation_node(1), F::ONE);
1071    let count = usize::try_from(F::order()).unwrap_or(usize::MAX).min(64);
1072    let nodes: Vec<F> = (0..count).map(F::interpolation_node).collect();
1073    for (i, a) in nodes.iter().enumerate() {
1074        for b in &nodes[..i] {
1075            assert_ne!(a, b, "interpolation nodes must be pairwise distinct");
1076        }
1077    }
1078}
1079
1080/// Tests the optimized implementation of `powers.take(n).collect()`
1081pub fn test_powers_collect<F: Field>() {
1082    // Small using serial implementation
1083    let small_powers_serial = [0, 1, 2, 3, 4, 15];
1084    // Small using packed implementation
1085    let small_powers_packed = [16, 17];
1086    // Large powers of two
1087    let powers_of_two = [5, 6, 7, 8, 9, 10, 13];
1088
1089    let num_powers_tests: Vec<usize> = small_powers_serial
1090        .into_iter()
1091        .chain(small_powers_packed)
1092        .chain(powers_of_two.iter().flat_map(|exp| {
1093            // Check boundaries at power of 2
1094            let n = 1 << exp;
1095            [n - 1, n, n + 1]
1096        }))
1097        .collect();
1098
1099    let base = F::TWO;
1100    let shift = F::GENERATOR;
1101
1102    // Manual implementation of `Powers`
1103    let expected_iter = successors(Some(shift), |prev| Some(*prev * base));
1104
1105    for num_powers in num_powers_tests {
1106        let expected: Vec<_> = expected_iter.clone().take(num_powers).collect();
1107        let actual = base.shifted_powers(shift).collect_n(num_powers);
1108        assert_eq!(
1109            expected, actual,
1110            "Got different powers when taking {num_powers}"
1111        );
1112    }
1113}
1114
1115/// Identical to [`test_powers_collect`], except it uses `F::GENERATOR` (nonzero, and not
1116/// `ONE`) as the base instead of `F::TWO`. In characteristic 2, `TWO == ZERO`, so
1117/// `test_powers_collect`'s sequence of powers degenerates to `[shift, ZERO, ZERO, ...]` for
1118/// every tested length: both the optimized `collect_n` path and the reference `successors`
1119/// chain hit that same degenerate case identically, so the test would pass while exercising
1120/// essentially none of the packed/serial `collect_n` machinery it exists to cover.
1121pub fn test_powers_collect_char2<F: Field>() {
1122    // Small using serial implementation
1123    let small_powers_serial = [0, 1, 2, 3, 4, 15];
1124    // Small using packed implementation
1125    let small_powers_packed = [16, 17];
1126    // Large powers of two
1127    let powers_of_two = [5, 6, 7, 8, 9, 10, 13];
1128
1129    let num_powers_tests: Vec<usize> = small_powers_serial
1130        .into_iter()
1131        .chain(small_powers_packed)
1132        .chain(powers_of_two.iter().flat_map(|exp| {
1133            // Check boundaries at power of 2
1134            let n = 1 << exp;
1135            [n - 1, n, n + 1]
1136        }))
1137        .collect();
1138
1139    let base = F::GENERATOR;
1140    let shift = F::GENERATOR;
1141
1142    // Manual implementation of `Powers`
1143    let expected_iter = successors(Some(shift), |prev| Some(*prev * base));
1144
1145    for num_powers in num_powers_tests {
1146        let expected: Vec<_> = expected_iter.clone().take(num_powers).collect();
1147        let actual = base.shifted_powers(shift).collect_n(num_powers);
1148        assert_eq!(
1149            expected, actual,
1150            "Got different powers when taking {num_powers}"
1151        );
1152    }
1153}
1154
1155/// A function which extends the `exp_u64` code to handle `BigUints`.
1156///
1157/// This solution is slow (particularly when dealing with extension fields
1158/// which should really be making use of the frobenius map) but should be
1159/// fast enough for testing purposes.
1160pub(crate) fn exp_biguint<F: Field>(x: F, exponent: &BigUint) -> F {
1161    let digits = exponent.to_u64_digits();
1162    let size = digits.len();
1163
1164    let mut power = F::ONE;
1165
1166    let bases = (0..size).map(|i| x.exp_power_of_2(64 * i));
1167    digits
1168        .iter()
1169        .zip(bases)
1170        .for_each(|(digit, base)| power *= base.exp_u64(*digit));
1171    power
1172}
1173
1174/// Given a list of the factors of the multiplicative group of a field, check
1175/// that the defined generator is actually a generator of that group.
1176pub fn test_generator<F: Field>(multiplicative_group_factors: &[(BigUint, u32)]) {
1177    // First we check that the given factors multiply to the order of the
1178    // multiplicative group (|F| - 1). Ideally this would also check that
1179    // the given factors are prime but as factors can be large that check
1180    // can end up being quite expensive so ignore that for now. As the factors
1181    // are hardcoded and public, these prime checks can be easily done using
1182    // sage or wolfram alpha.
1183    let product: BigUint = multiplicative_group_factors
1184        .iter()
1185        .map(|(factor, exponent)| factor.pow(*exponent))
1186        .product();
1187    assert_eq!(product + BigUint::from(1u32), F::order());
1188
1189    // Given a prime factorization r = p1^e1 * p2^e2 * ... * pk^ek, an element g has order
1190    // r if and only if g^r = 1 and g^(r/pi) != 1 for all pi in the prime factorization of r.
1191    let mut partial_products: Vec<F> = (0..=multiplicative_group_factors.len())
1192        .map(|i| {
1193            let mut generator_power = F::GENERATOR;
1194            multiplicative_group_factors
1195                .iter()
1196                .enumerate()
1197                .for_each(|(j, (factor, exponent))| {
1198                    let modified_exponent = if i == j { exponent - 1 } else { *exponent };
1199                    for _ in 0..modified_exponent {
1200                        generator_power = exp_biguint(generator_power, factor);
1201                    }
1202                });
1203            generator_power
1204        })
1205        .collect();
1206
1207    assert_eq!(partial_products.pop().unwrap(), F::ONE);
1208
1209    for elem in partial_products.into_iter() {
1210        assert_ne!(elem, F::ONE);
1211    }
1212}
1213
1214pub fn test_two_adic_generator_consistency<F: TwoAdicField>() {
1215    let log_n = F::TWO_ADICITY;
1216    let g = F::two_adic_generator(log_n);
1217    for bits in 0..=log_n {
1218        assert_eq!(g.exp_power_of_2(bits), F::two_adic_generator(log_n - bits));
1219    }
1220}
1221
1222pub fn test_two_adic_point_collection<F: TwoAdicField>() {
1223    let log_n = F::TWO_ADICITY.min(15);
1224    for bits in 0..=log_n {
1225        let group = TwoAdicMultiplicativeCoset::new(F::ONE, bits).unwrap();
1226        let points = group.iter().collect();
1227        // Add `map` to avoid calling `BoundedPowers::collect()`
1228        #[allow(clippy::map_identity)]
1229        let points_expected = group.iter().map(|x| x).collect::<Vec<_>>();
1230        assert_eq!(points, points_expected);
1231    }
1232}
1233
1234pub fn test_ef_two_adic_generator_consistency<
1235    F: TwoAdicField,
1236    EF: TwoAdicField + ExtensionField<F>,
1237>() {
1238    assert_eq!(
1239        Into::<EF>::into(F::two_adic_generator(F::TWO_ADICITY)),
1240        EF::two_adic_generator(F::TWO_ADICITY)
1241    );
1242}
1243
1244pub fn test_into_bytes_32<F: PrimeField32>(zeros: &[F], ones: &[F])
1245where
1246    StandardUniform: Distribution<F>,
1247{
1248    let mut rng = SmallRng::seed_from_u64(1);
1249    let x = rng.random::<F>();
1250
1251    assert_eq!(
1252        x.into_bytes().into_iter().collect::<Vec<_>>(),
1253        x.to_unique_u32().to_le_bytes()
1254    );
1255    for one in ones {
1256        assert_eq!(
1257            one.into_bytes().into_iter().collect::<Vec<_>>(),
1258            F::ONE.to_unique_u32().to_le_bytes()
1259        );
1260    }
1261    for zero in zeros {
1262        assert_eq!(zero.into_bytes().into_iter().collect::<Vec<_>>(), [0; 4]);
1263    }
1264}
1265
1266pub fn test_into_bytes_64<F: PrimeField64>(zeros: &[F], ones: &[F])
1267where
1268    StandardUniform: Distribution<F>,
1269{
1270    let mut rng = SmallRng::seed_from_u64(1);
1271    let x = rng.random::<F>();
1272
1273    assert_eq!(
1274        x.into_bytes().into_iter().collect::<Vec<_>>(),
1275        x.to_unique_u64().to_le_bytes()
1276    );
1277    for one in ones {
1278        assert_eq!(
1279            one.into_bytes().into_iter().collect::<Vec<_>>(),
1280            F::ONE.to_unique_u64().to_le_bytes()
1281        );
1282    }
1283    for zero in zeros {
1284        assert_eq!(zero.into_bytes().into_iter().collect::<Vec<_>>(), [0; 8]);
1285    }
1286}
1287
1288pub fn test_into_stream<F: Field>()
1289where
1290    StandardUniform: Distribution<[F; 16]>,
1291{
1292    let mut rng = SmallRng::seed_from_u64(1);
1293    let xs: [F; 16] = rng.random();
1294
1295    let byte_vec = F::into_byte_stream(xs).into_iter().collect::<Vec<_>>();
1296    let u32_vec = F::into_u32_stream(xs).into_iter().collect::<Vec<_>>();
1297    let u64_vec = F::into_u64_stream(xs).into_iter().collect::<Vec<_>>();
1298
1299    let expected_bytes = xs
1300        .into_iter()
1301        .flat_map(|x| x.into_bytes())
1302        .collect::<Vec<_>>();
1303    let expected_u32s = iter_array_chunks_padded(byte_vec.iter().copied(), 0)
1304        .map(u32::from_le_bytes)
1305        .collect::<Vec<_>>();
1306    let expected_u64s = iter_array_chunks_padded(byte_vec.iter().copied(), 0)
1307        .map(u64::from_le_bytes)
1308        .collect::<Vec<_>>();
1309
1310    assert_eq!(byte_vec, expected_bytes);
1311    assert_eq!(u32_vec, expected_u32s);
1312    assert_eq!(u64_vec, expected_u64s);
1313
1314    let ys: [F; 16] = rng.random();
1315    let zs: [F; 16] = rng.random();
1316
1317    let combs: [[F; 3]; 16] = array::from_fn(|i| [xs[i], ys[i], zs[i]]);
1318
1319    let byte_vec_ys = F::into_byte_stream(ys).into_iter().collect::<Vec<_>>();
1320    let byte_vec_zs = F::into_byte_stream(zs).into_iter().collect::<Vec<_>>();
1321    let u32_vec_ys = F::into_u32_stream(ys).into_iter().collect::<Vec<_>>();
1322    let u32_vec_zs = F::into_u32_stream(zs).into_iter().collect::<Vec<_>>();
1323    let u64_vec_ys = F::into_u64_stream(ys).into_iter().collect::<Vec<_>>();
1324    let u64_vec_zs = F::into_u64_stream(zs).into_iter().collect::<Vec<_>>();
1325
1326    let combined_bytes = F::into_parallel_byte_streams(combs)
1327        .into_iter()
1328        .collect::<Vec<_>>();
1329    let combined_u32s = F::into_parallel_u32_streams(combs)
1330        .into_iter()
1331        .collect::<Vec<_>>();
1332    let combined_u64s = F::into_parallel_u64_streams(combs)
1333        .into_iter()
1334        .collect::<Vec<_>>();
1335
1336    let expected_combined_bytes: Vec<[u8; 3]> = (0..byte_vec.len())
1337        .map(|i| [byte_vec[i], byte_vec_ys[i], byte_vec_zs[i]])
1338        .collect();
1339    let expected_combined_u32s: Vec<[u32; 3]> = (0..u32_vec.len())
1340        .map(|i| [u32_vec[i], u32_vec_ys[i], u32_vec_zs[i]])
1341        .collect();
1342    let expected_combined_u64s: Vec<[u64; 3]> = (0..u64_vec.len())
1343        .map(|i| [u64_vec[i], u64_vec_ys[i], u64_vec_zs[i]])
1344        .collect();
1345
1346    assert_eq!(combined_bytes, expected_combined_bytes);
1347    assert_eq!(combined_u32s, expected_combined_u32s);
1348    assert_eq!(combined_u64s, expected_combined_u64s);
1349}
1350
1351/// Test ring axioms with 256 random (x, y, z) triplets via proptest.
1352///
1353/// Tests commutativity, associativity, distributivity, negation,
1354/// subtraction identities, square/cube, double/halve, and
1355/// multiplication by zero and negative one.
1356pub fn test_ring_axioms_proptest<R>()
1357where
1358    R: PrimeCharacteristicRing + Copy + Eq + core::fmt::Debug + 'static,
1359    StandardUniform: Distribution<R>,
1360{
1361    let config = ProptestConfig::with_cases(256);
1362    proptest!(config, |(x in arb_field::<R>(), y in arb_field::<R>(), z in arb_field::<R>())| {
1363        // Commutativity
1364        prop_assert_eq!(x + y, y + x, "addition commutativity");
1365        prop_assert_eq!(x * y, y * x, "multiplication commutativity");
1366
1367        // Associativity
1368        prop_assert_eq!(x + (y + z), (x + y) + z, "addition associativity");
1369        prop_assert_eq!(x * (y * z), (x * y) * z, "multiplication associativity");
1370
1371        // Distributivity
1372        prop_assert_eq!(x * (y + z), x * y + x * z, "left distributivity");
1373        prop_assert_eq!((x + y) * z, x * z + y * z, "right distributivity");
1374
1375        // Negation
1376        prop_assert_eq!(x + (-x), R::ZERO, "additive inverse");
1377        prop_assert_eq!(-(-x), x, "double negation");
1378
1379        // Subtraction identities
1380        prop_assert_eq!(x - (y - z), (x - y) + z, "sub-sub identity");
1381        prop_assert_eq!(x - (y + z), (x - y) - z, "sub-add identity");
1382
1383        // Square and cube
1384        prop_assert_eq!(x * x, x.square(), "square");
1385        prop_assert_eq!(x * x * x, x.cube(), "cube");
1386
1387        // Double and halve
1388        prop_assert_eq!(x.double(), x + x, "double");
1389        prop_assert_eq!(x.halve().double(), x, "halve roundtrip");
1390
1391        // Multiplication by zero and negative one
1392        prop_assert_eq!(x * R::ZERO, R::ZERO, "x * 0 == 0");
1393        prop_assert_eq!(R::NEG_ONE * x, -x, "-1 * x == -x");
1394    });
1395}
1396
1397/// Identical to [`test_ring_axioms_proptest`], except it omits the `halve` roundtrip
1398/// check, which [`PrimeCharacteristicRing::halve`] does not support in characteristic 2.
1399pub fn test_ring_axioms_proptest_char2<R>()
1400where
1401    R: PrimeCharacteristicRing + Copy + Eq + core::fmt::Debug + 'static,
1402    StandardUniform: Distribution<R>,
1403{
1404    let config = ProptestConfig::with_cases(256);
1405    proptest!(config, |(x in arb_field::<R>(), y in arb_field::<R>(), z in arb_field::<R>())| {
1406        // Commutativity
1407        prop_assert_eq!(x + y, y + x, "addition commutativity");
1408        prop_assert_eq!(x * y, y * x, "multiplication commutativity");
1409
1410        // Associativity
1411        prop_assert_eq!(x + (y + z), (x + y) + z, "addition associativity");
1412        prop_assert_eq!(x * (y * z), (x * y) * z, "multiplication associativity");
1413
1414        // Distributivity
1415        prop_assert_eq!(x * (y + z), x * y + x * z, "left distributivity");
1416        prop_assert_eq!((x + y) * z, x * z + y * z, "right distributivity");
1417
1418        // Negation
1419        prop_assert_eq!(x + (-x), R::ZERO, "additive inverse");
1420        prop_assert_eq!(-(-x), x, "double negation");
1421
1422        // Subtraction identities
1423        prop_assert_eq!(x - (y - z), (x - y) + z, "sub-sub identity");
1424        prop_assert_eq!(x - (y + z), (x - y) - z, "sub-add identity");
1425
1426        // Square and cube
1427        prop_assert_eq!(x * x, x.square(), "square");
1428        prop_assert_eq!(x * x * x, x.cube(), "cube");
1429
1430        // Double
1431        prop_assert_eq!(x.double(), x + x, "double");
1432
1433        // Multiplication by zero and negative one
1434        prop_assert_eq!(x * R::ZERO, R::ZERO, "x * 0 == 0");
1435        prop_assert_eq!(R::NEG_ONE * x, -x, "-1 * x == -x");
1436    });
1437}
1438
1439/// Test field axioms (inverse, division) with deterministic edge cases
1440/// and 256 random non-zero (x, y, z) triplets via proptest.
1441pub fn test_field_axioms_proptest<F>()
1442where
1443    F: Field + core::fmt::Debug + 'static,
1444    StandardUniform: Distribution<F>,
1445{
1446    // Deterministic edge cases
1447    assert_eq!(F::TWO.inverse(), F::ONE.halve());
1448    assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
1449    assert_eq!(
1450        F::GENERATOR.inverse() * F::GENERATOR,
1451        F::ONE,
1452        "generator inverse roundtrip"
1453    );
1454
1455    // Proptest: 256 random triplets, all non-zero
1456    let config = ProptestConfig::with_cases(256);
1457    proptest!(config, |(x in arb_field::<F>(), y in arb_field::<F>(), z in arb_field::<F>())| {
1458        // Skip if any element is zero
1459        if x.is_zero() || y.is_zero() || z.is_zero() {
1460            return Ok(());
1461        }
1462
1463        // Inverse properties
1464        prop_assert_eq!(x * x.inverse(), F::ONE, "x * x^-1 == 1");
1465        prop_assert_eq!(x.inverse().inverse(), x, "double inverse");
1466        prop_assert_eq!(x.square().inverse(), x.inverse().square(), "square-inverse commutativity");
1467
1468        // Division roundtrip
1469        prop_assert_eq!((x / y) * y, x, "division roundtrip");
1470
1471        // Division associativity
1472        prop_assert_eq!(x / (y * z), (x / y) / z, "division-multiplication associativity");
1473        prop_assert_eq!((x * y) / z, x * (y / z), "multiplication-division associativity");
1474    });
1475}
1476
1477/// Identical to [`test_field_axioms_proptest`], except it omits the
1478/// `2.inverse() == 1.halve()` edge case, since `2 == 0` is not invertible in
1479/// characteristic 2.
1480pub fn test_field_axioms_proptest_char2<F>()
1481where
1482    F: Field + core::fmt::Debug + 'static,
1483    StandardUniform: Distribution<F>,
1484{
1485    // Deterministic edge cases
1486    assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
1487    assert_eq!(
1488        F::GENERATOR.inverse() * F::GENERATOR,
1489        F::ONE,
1490        "generator inverse roundtrip"
1491    );
1492
1493    // Proptest: 256 random triplets, all non-zero
1494    let config = ProptestConfig::with_cases(256);
1495    proptest!(config, |(x in arb_field::<F>(), y in arb_field::<F>(), z in arb_field::<F>())| {
1496        // Skip if any element is zero
1497        if x.is_zero() || y.is_zero() || z.is_zero() {
1498            return Ok(());
1499        }
1500
1501        // Inverse properties
1502        prop_assert_eq!(x * x.inverse(), F::ONE, "x * x^-1 == 1");
1503        prop_assert_eq!(x.inverse().inverse(), x, "double inverse");
1504        prop_assert_eq!(x.square().inverse(), x.inverse().square(), "square-inverse commutativity");
1505
1506        // Division roundtrip
1507        prop_assert_eq!((x / y) * y, x, "division roundtrip");
1508
1509        // Division associativity
1510        prop_assert_eq!(x / (y * z), (x / y) / z, "division-multiplication associativity");
1511        prop_assert_eq!((x * y) / z, x * (y / z), "multiplication-division associativity");
1512    });
1513}
1514
1515#[macro_export]
1516macro_rules! test_ring_with_eq {
1517    ($ring:ty, $zeros: expr, $ones: expr) => {
1518        mod ring_tests {
1519            use p3_field::PrimeCharacteristicRing;
1520
1521            #[test]
1522            fn test_ring_with_eq() {
1523                $crate::test_ring_with_eq::<$ring>($zeros, $ones);
1524            }
1525            #[test]
1526            fn test_mul_2exp_u64() {
1527                $crate::test_mul_2exp_u64::<$ring>();
1528            }
1529            #[test]
1530            fn test_div_2exp_u64() {
1531                $crate::test_div_2exp_u64::<$ring>();
1532            }
1533        }
1534    };
1535}
1536
1537#[macro_export]
1538macro_rules! test_field {
1539    ($field:ty, $zeros: expr, $ones: expr, $factors: expr) => {
1540        $crate::test_ring_with_eq!($field, $zeros, $ones);
1541
1542        mod field_tests {
1543            #[test]
1544            fn test_inverse() {
1545                $crate::test_inverse::<$field>();
1546            }
1547            #[test]
1548            fn test_batch_multiplicative_inverse() {
1549                $crate::test_batch_multiplicative_inverse::<$field>();
1550            }
1551            #[test]
1552            fn test_sqrt() {
1553                $crate::test_sqrt::<$field>();
1554            }
1555            #[test]
1556            fn test_generator() {
1557                $crate::test_generator::<$field>($factors);
1558            }
1559            #[test]
1560            fn test_streaming() {
1561                $crate::test_into_stream::<$field>();
1562            }
1563            #[test]
1564            fn test_powers_collect() {
1565                $crate::test_powers_collect::<$field>();
1566            }
1567            #[test]
1568            fn test_interpolation_nodes() {
1569                $crate::test_interpolation_nodes::<$field>();
1570            }
1571            #[test]
1572            fn test_ring_axioms_proptest() {
1573                $crate::test_ring_axioms_proptest::<$field>();
1574            }
1575            #[test]
1576            fn test_field_axioms_proptest() {
1577                $crate::test_field_axioms_proptest::<$field>();
1578            }
1579        }
1580
1581        // Looks a little strange but we also check that everything works
1582        // when the field is considered as a trivial extension of itself.
1583        mod trivial_extension_tests {
1584            #[test]
1585            fn test_to_from_trivial_extension() {
1586                $crate::test_to_from_extension_field::<$field, $field>();
1587            }
1588
1589            #[test]
1590            fn test_trivial_packed_extension() {
1591                $crate::test_packed_extension::<$field, $field>();
1592            }
1593        }
1594    };
1595}
1596
1597/// A [`test_field!`]-equivalent suite for fields of characteristic 2.
1598///
1599/// `PrimeCharacteristicRing::{halve, div_2exp_u64}` are documented to panic
1600/// unconditionally in characteristic 2, so this replaces [`test_div_2exp_u64`] with
1601/// [`test_halve_panics_char2`] and [`test_div_2exp_u64_panics_char2`], which pin that
1602/// panic, and swaps every other halve-dependent (or otherwise characteristic-2-degenerate)
1603/// check for a characteristic-2-safe sibling (`test_ring_with_eq_char2`,
1604/// `test_mul_2exp_u64_is_zero_above_e0`, `test_inverse_char2`, `test_sqrt_char2`,
1605/// `test_powers_collect_char2`, `test_ring_axioms_proptest_char2`,
1606/// `test_field_axioms_proptest_char2`).
1607#[macro_export]
1608macro_rules! test_binary_field {
1609    ($field:ty, $zeros: expr, $ones: expr, $factors: expr) => {
1610        mod ring_tests {
1611            use p3_field::PrimeCharacteristicRing;
1612
1613            #[test]
1614            fn test_ring_with_eq() {
1615                $crate::test_ring_with_eq_char2::<$field>($zeros, $ones);
1616            }
1617            #[test]
1618            fn test_mul_2exp_u64() {
1619                $crate::test_mul_2exp_u64_is_zero_above_e0::<$field>();
1620            }
1621            #[test]
1622            #[should_panic]
1623            fn test_halve_panics() {
1624                $crate::test_halve_panics_char2::<$field>();
1625            }
1626            #[test]
1627            #[should_panic]
1628            fn test_div_2exp_u64_panics() {
1629                $crate::test_div_2exp_u64_panics_char2::<$field>();
1630            }
1631        }
1632
1633        mod field_tests {
1634            #[test]
1635            fn test_inverse() {
1636                $crate::test_inverse_char2::<$field>();
1637            }
1638            #[test]
1639            fn test_batch_multiplicative_inverse() {
1640                $crate::test_batch_multiplicative_inverse::<$field>();
1641            }
1642            #[test]
1643            fn test_sqrt() {
1644                $crate::test_sqrt_char2::<$field>();
1645            }
1646            #[test]
1647            fn test_generator() {
1648                $crate::test_generator::<$field>($factors);
1649            }
1650            #[test]
1651            fn test_streaming() {
1652                $crate::test_into_stream::<$field>();
1653            }
1654            #[test]
1655            fn test_powers_collect() {
1656                $crate::test_powers_collect_char2::<$field>();
1657            }
1658            #[test]
1659            fn test_interpolation_nodes() {
1660                $crate::test_interpolation_nodes::<$field>();
1661            }
1662            #[test]
1663            fn test_ring_axioms_proptest() {
1664                $crate::test_ring_axioms_proptest_char2::<$field>();
1665            }
1666            #[test]
1667            fn test_field_axioms_proptest() {
1668                $crate::test_field_axioms_proptest_char2::<$field>();
1669            }
1670        }
1671
1672        // Looks a little strange but we also check that everything works
1673        // when the field is considered as a trivial extension of itself.
1674        mod trivial_extension_tests {
1675            #[test]
1676            fn test_to_from_trivial_extension() {
1677                $crate::test_to_from_extension_field::<$field, $field>();
1678            }
1679
1680            #[test]
1681            fn test_trivial_packed_extension() {
1682                $crate::test_packed_extension::<$field, $field>();
1683            }
1684        }
1685    };
1686}
1687
1688#[macro_export]
1689macro_rules! test_prime_field {
1690    ($field:ty) => {
1691        mod from_integer_small_tests {
1692            use p3_field::integers::QuotientMap;
1693            use p3_field::{Field, PrimeCharacteristicRing};
1694
1695            #[test]
1696            fn test_small_integer_conversions() {
1697                $crate::generate_from_small_int_tests!(
1698                    $field,
1699                    [
1700                        u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1701                    ]
1702                );
1703            }
1704
1705            #[test]
1706            fn test_small_signed_integer_conversions() {
1707                $crate::generate_from_small_neg_int_tests!(
1708                    $field,
1709                    [i8, i16, i32, i64, i128, isize]
1710                );
1711            }
1712        }
1713    };
1714}
1715
1716#[macro_export]
1717macro_rules! test_prime_field_64 {
1718    ($field:ty, $zeros: expr, $ones: expr) => {
1719        mod from_integer_tests_prime_field_64 {
1720            use p3_field::integers::QuotientMap;
1721            use p3_field::{Field, PrimeCharacteristicRing, PrimeField64, RawDataSerializable};
1722            use rand::rngs::SmallRng;
1723            use rand::{RngExt, SeedableRng};
1724
1725            #[test]
1726            fn test_as_canonical_u64() {
1727                let mut rng = SmallRng::seed_from_u64(1);
1728                let x: u64 = rng.random();
1729                let x_mod_order = x % <$field>::ORDER_U64;
1730
1731                assert_eq!(<$field>::ZERO.as_canonical_u64(), 0);
1732                assert_eq!(<$field>::ONE.as_canonical_u64(), 1);
1733                assert_eq!(<$field>::TWO.as_canonical_u64(), 2 % <$field>::ORDER_U64);
1734                assert_eq!(
1735                    <$field>::NEG_ONE.as_canonical_u64(),
1736                    <$field>::ORDER_U64 - 1
1737                );
1738
1739                assert_eq!(
1740                    <$field>::from_int(<$field>::ORDER_U64).as_canonical_u64(),
1741                    0
1742                );
1743                assert_eq!(<$field>::from_int(x).as_canonical_u64(), x_mod_order);
1744                assert_eq!(
1745                    unsafe { <$field>::from_canonical_unchecked(x_mod_order).as_canonical_u64() },
1746                    x_mod_order
1747                );
1748            }
1749
1750            #[test]
1751            fn test_as_unique_u64() {
1752                assert_ne!(
1753                    <$field>::ZERO.to_unique_u64(),
1754                    <$field>::ONE.to_unique_u64()
1755                );
1756                assert_ne!(
1757                    <$field>::ZERO.to_unique_u64(),
1758                    <$field>::NEG_ONE.to_unique_u64()
1759                );
1760                assert_eq!(
1761                    <$field>::from_int(<$field>::ORDER_U64).to_unique_u64(),
1762                    <$field>::ZERO.to_unique_u64()
1763                );
1764            }
1765
1766            #[test]
1767            fn test_large_unsigned_integer_conversions() {
1768                $crate::generate_from_large_u_int_tests!($field, <$field>::ORDER_U64, [u64, u128]);
1769            }
1770
1771            #[test]
1772            fn test_large_signed_integer_conversions() {
1773                $crate::generate_from_large_i_int_tests!($field, <$field>::ORDER_U64, [i64, i128]);
1774            }
1775
1776            #[test]
1777            fn test_raw_data_serializable() {
1778                // Only do the 64-bit test if the field is 64 bits.
1779                // This will error if tested on smaller fields.
1780                if <$field>::NUM_BYTES == 8 {
1781                    $crate::test_into_bytes_64::<$field>($zeros, $ones);
1782                }
1783            }
1784        }
1785    };
1786}
1787
1788#[macro_export]
1789macro_rules! test_prime_field_32 {
1790    ($field:ty, $zeros: expr, $ones: expr) => {
1791        mod from_integer_tests_prime_field_32 {
1792            use p3_field::integers::QuotientMap;
1793            use p3_field::{Field, PrimeCharacteristicRing, PrimeField32, PrimeField64};
1794            use rand::rngs::SmallRng;
1795            use rand::{RngExt, SeedableRng};
1796
1797            #[test]
1798            fn test_as_canonical_u32() {
1799                let mut rng = SmallRng::seed_from_u64(1);
1800                let x: u32 = rng.random();
1801                let x_mod_order = x % <$field>::ORDER_U32;
1802
1803                for zero in $zeros {
1804                    assert_eq!(zero.as_canonical_u32(), 0);
1805                    assert_eq!(zero.to_unique_u32() as u64, zero.to_unique_u64());
1806                }
1807                for one in $ones {
1808                    assert_eq!(one.as_canonical_u32(), 1);
1809                    assert_eq!(one.to_unique_u32() as u64, one.to_unique_u64());
1810                }
1811                assert_eq!(<$field>::TWO.as_canonical_u32(), 2 % <$field>::ORDER_U32);
1812                assert_eq!(
1813                    <$field>::NEG_ONE.as_canonical_u32(),
1814                    <$field>::ORDER_U32 - 1
1815                );
1816                assert_eq!(
1817                    <$field>::from_int(<$field>::ORDER_U32).as_canonical_u32(),
1818                    0
1819                );
1820                assert_eq!(<$field>::from_int(x).as_canonical_u32(), x_mod_order);
1821                assert_eq!(
1822                    <$field>::from_int(x).to_unique_u32() as u64,
1823                    <$field>::from_int(x).to_unique_u64()
1824                );
1825                assert_eq!(
1826                    unsafe { <$field>::from_canonical_unchecked(x_mod_order).as_canonical_u32() },
1827                    x_mod_order
1828                );
1829            }
1830
1831            #[test]
1832            fn test_as_unique_u32() {
1833                assert_ne!(
1834                    <$field>::ZERO.to_unique_u32(),
1835                    <$field>::ONE.to_unique_u32()
1836                );
1837                assert_ne!(
1838                    <$field>::ZERO.to_unique_u32(),
1839                    <$field>::NEG_ONE.to_unique_u32()
1840                );
1841                assert_eq!(
1842                    <$field>::from_int(<$field>::ORDER_U32).to_unique_u32(),
1843                    <$field>::ZERO.to_unique_u32()
1844                );
1845            }
1846
1847            #[test]
1848            fn test_large_unsigned_integer_conversions() {
1849                $crate::generate_from_large_u_int_tests!(
1850                    $field,
1851                    <$field>::ORDER_U32,
1852                    [u32, u64, u128]
1853                );
1854            }
1855
1856            #[test]
1857            fn test_large_signed_integer_conversions() {
1858                $crate::generate_from_large_i_int_tests!(
1859                    $field,
1860                    <$field>::ORDER_U32,
1861                    [i32, i64, i128]
1862                );
1863            }
1864
1865            #[test]
1866            fn test_raw_data_serializable() {
1867                $crate::test_into_bytes_32::<$field>($zeros, $ones);
1868            }
1869
1870            #[test]
1871            fn test_json_deserialization_boundaries() {
1872                $crate::test_prime_field_32_json_deserialization_boundaries::<$field>();
1873            }
1874        }
1875    };
1876}
1877
1878#[macro_export]
1879macro_rules! test_two_adic_field {
1880    ($field:ty) => {
1881        mod two_adic_field_tests {
1882            #[test]
1883            fn test_two_adic_consistency() {
1884                $crate::test_two_adic_generator_consistency::<$field>();
1885                $crate::test_two_adic_point_collection::<$field>();
1886            }
1887
1888            // Looks a little strange but we also check that everything works
1889            // when the field is considered as a trivial extension of itself.
1890            #[test]
1891            fn test_two_adic_generator_consistency_as_trivial_extension() {
1892                $crate::test_ef_two_adic_generator_consistency::<$field, $field>();
1893            }
1894        }
1895    };
1896}
1897
1898#[macro_export]
1899macro_rules! test_extension_field {
1900    ($field:ty, $ef:ty) => {
1901        mod extension_field_tests {
1902            #[test]
1903            fn test_to_from_extension() {
1904                $crate::test_to_from_extension_field::<$field, $ef>();
1905            }
1906
1907            #[test]
1908            fn test_galois_extension() {
1909                $crate::test_galois_extension::<$field, $ef>();
1910            }
1911
1912            #[test]
1913            fn test_packed_extension() {
1914                $crate::test_packed_extension::<$field, $ef>();
1915            }
1916        }
1917    };
1918}
1919
1920#[macro_export]
1921macro_rules! test_two_adic_extension_field {
1922    ($field:ty, $ef:ty) => {
1923        use $crate::test_two_adic_field;
1924
1925        test_two_adic_field!($ef);
1926
1927        mod two_adic_extension_field_tests {
1928
1929            #[test]
1930            fn test_ef_two_adic_generator_consistency() {
1931                $crate::test_ef_two_adic_generator_consistency::<$field, $ef>();
1932            }
1933        }
1934    };
1935}
1936
1937#[macro_export]
1938macro_rules! test_frobenius {
1939    ($field:ty, $ef:ty) => {
1940        mod frobenius_tests {
1941            #[test]
1942            fn test_frobenius_fixes_base_field() {
1943                $crate::test_frobenius_fixes_base_field::<$field, $ef>();
1944            }
1945
1946            #[test]
1947            fn test_frobenius_proptest() {
1948                $crate::test_frobenius_proptest::<$field, $ef>();
1949            }
1950        }
1951    };
1952}