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