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