Skip to main content

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