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