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