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