p3_field_testing/
lib.rs

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