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
261pub fn test_mul_2exp_u64<R: PrimeCharacteristicRing + Eq>()
262where
263 StandardUniform: Distribution<R>,
264{
265 let mut rng = SmallRng::seed_from_u64(1);
266 let x = rng.random::<R>();
267 assert_eq!(x.mul_2exp_u64(0), x);
268 assert_eq!(x.mul_2exp_u64(1), x.double());
269 for i in 0..128 {
270 assert_eq!(
271 x.clone().mul_2exp_u64(i),
272 x.clone() * R::from_u128(1_u128 << i)
273 );
274 }
275 for i in 128..256 {
277 assert_eq!(x.clone().mul_2exp_u64(i), x.clone() * R::TWO.exp_u64(i));
278 }
279}
280
281pub fn test_div_2exp_u64<R: PrimeCharacteristicRing + Eq>()
282where
283 StandardUniform: Distribution<R>,
284{
285 let mut rng = SmallRng::seed_from_u64(1);
286 let x = rng.random::<R>();
287 assert_eq!(x.div_2exp_u64(0), x);
288 assert_eq!(x.div_2exp_u64(1), x.halve());
289 for i in 0..128 {
290 assert_eq!(x.mul_2exp_u64(i).div_2exp_u64(i), x);
291 assert_eq!(
292 x.div_2exp_u64(i),
293 x.clone() * R::from_prime_subfield(R::PrimeSubfield::from_u128(1_u128 << i).inverse())
295 );
296 }
297 for i in 128..256 {
299 assert_eq!(x.mul_2exp_u64(i).div_2exp_u64(i), x);
300 assert_eq!(
301 x.div_2exp_u64(i),
302 x.clone() * R::from_prime_subfield(R::PrimeSubfield::TWO.inverse().exp_u64(i))
304 );
305 }
306}
307
308pub fn test_add_slice<F: Field>()
309where
310 StandardUniform: Distribution<F>,
311{
312 let mut rng = SmallRng::seed_from_u64(1);
313 let lengths = [
314 F::Packing::WIDTH - 1,
315 F::Packing::WIDTH,
316 (F::Packing::WIDTH - 1) + (F::Packing::WIDTH << 10),
317 ];
318 for len in lengths {
319 let mut slice_1: Vec<_> = (&mut rng).sample_iter(StandardUniform).take(len).collect();
320 let slice_1_copy = slice_1.clone();
321 let slice_2: Vec<_> = (&mut rng).sample_iter(StandardUniform).take(len).collect();
322
323 F::add_slices(&mut slice_1, &slice_2);
324 for i in 0..len {
325 assert_eq!(slice_1[i], slice_1_copy[i] + slice_2[i]);
326 }
327 }
328}
329
330pub fn test_inverse<F: Field>()
331where
332 StandardUniform: Distribution<F>,
333{
334 assert_eq!(None, F::ZERO.try_inverse());
335 assert_eq!(Some(F::ONE), F::ONE.try_inverse());
336 assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
337 let two_inv = F::TWO
338 .try_inverse()
339 .expect("2 must be invertible in this field (test_inverse assumes characteristic != 2)");
340 assert_eq!(two_inv, F::ONE.halve(), "inverse of 2 == halve(1)");
341 let mut rng = SmallRng::seed_from_u64(1);
342 for _ in 0..1000 {
343 let x = rng.random::<F>();
344 if !x.is_zero() && !x.is_one() {
345 let z = x.inverse();
346 assert_ne!(x, z);
347 assert_eq!(x * z, F::ONE);
348 }
349 }
350}
351
352pub fn test_batch_multiplicative_inverse<F: Field>()
363where
364 StandardUniform: Distribution<F>,
365{
366 let mut rng = SmallRng::seed_from_u64(0xBA7C);
367
368 let lengths = [
369 0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 17, 63, 64, 65, 1023, 1024, 1025, 1027, 2049, 4099,
370 ];
371
372 for &n in &lengths {
373 let xs: Vec<F> = (0..n)
374 .map(|_| {
375 let mut x = rng.random::<F>();
377 while x.is_zero() {
378 x = rng.random::<F>();
379 }
380 x
381 })
382 .collect();
383
384 let got = batch_multiplicative_inverse(&xs);
385 assert_eq!(got.len(), n, "result length mismatch for n = {n}");
386
387 for (i, (x, inv)) in xs.iter().zip(&got).enumerate() {
388 assert_eq!(
389 *x * *inv,
390 F::ONE,
391 "x[{i}] * inv[{i}] != 1 for input length {n}"
392 );
393 }
394 }
395}
396
397pub fn test_field_json_serialization<F>(values: &[F])
403where
404 F: PrimeCharacteristicRing + Serialize + DeserializeOwned + Eq,
405{
406 for value in values {
407 let serialized = serde_json::to_string(value).expect("Failed to serialize field element");
409 let deserialized: F =
410 serde_json::from_str(&serialized).expect("Failed to deserialize field element");
411 assert_eq!(
412 *value, deserialized,
413 "Single round-trip serialization failed"
414 );
415
416 let serialized_again = serde_json::to_string(&deserialized)
418 .expect("Failed to serialize field element (second time)");
419 let deserialized_again: F = serde_json::from_str(&serialized_again)
420 .expect("Failed to deserialize field element (second time)");
421 assert_eq!(
422 *value, deserialized_again,
423 "Double round-trip serialization failed"
424 );
425 assert_eq!(
426 deserialized, deserialized_again,
427 "Deserialized values should be equal"
428 );
429 }
430}
431
432pub fn test_prime_field_32_json_deserialization_boundaries<F>()
436where
437 F: PrimeField32 + Serialize + DeserializeOwned + Eq,
438{
439 let zero: F = serde_json::from_str("0").expect("Failed to deserialize zero");
440 assert_eq!(zero, F::ZERO, "Deserializing 0 should produce ZERO");
441
442 let original: F = serde_json::from_str("42").expect("Failed to deserialize test value");
443 let serialized = serde_json::to_string(&original).expect("Failed to serialize test value");
444 let deserialized: F =
445 serde_json::from_str(&serialized).expect("Failed to deserialize serialized test value");
446 assert_eq!(
447 deserialized, original,
448 "Round-trip serialization should preserve the value"
449 );
450
451 let max_valid = F::ORDER_U32 - 1;
452 let max_valid_json = serde_json::to_string(&max_valid).expect("Failed to encode max valid u32");
453 let max_valid_result: Result<F, _> = serde_json::from_str(&max_valid_json);
454 assert!(
455 max_valid_result.is_ok(),
456 "Expected max valid representation to deserialize successfully"
457 );
458
459 if let Some(first_invalid) = max_valid.checked_add(1) {
460 let first_invalid_json =
461 serde_json::to_string(&first_invalid).expect("Failed to encode first invalid value");
462 let first_invalid_result: Result<F, _> = serde_json::from_str(&first_invalid_json);
463 assert!(
464 first_invalid_result.is_err(),
465 "Expected first out-of-range representation to fail deserialization"
466 );
467 }
468
469 if max_valid != u32::MAX {
470 let max_u32_json = serde_json::to_string(&u32::MAX).expect("Failed to encode u32::MAX");
471 let max_u32_result: Result<F, _> = serde_json::from_str(&max_u32_json);
472 assert!(
473 max_u32_result.is_err(),
474 "Expected u32::MAX to fail deserialization"
475 );
476 }
477}
478
479pub fn test_dot_product<R: PrimeCharacteristicRing + Eq + Copy>(u: &[R; 64], v: &[R; 64]) {
480 let mut dot = R::ZERO;
481 assert_eq!(
482 dot,
483 R::dot_product::<0>(u[..0].try_into().unwrap(), v[..0].try_into().unwrap())
484 );
485 dot += u[0] * v[0];
486 assert_eq!(
487 dot,
488 R::dot_product::<1>(u[..1].try_into().unwrap(), v[..1].try_into().unwrap())
489 );
490 dot += u[1] * v[1];
491 assert_eq!(
492 dot,
493 R::dot_product::<2>(u[..2].try_into().unwrap(), v[..2].try_into().unwrap())
494 );
495 dot += u[2] * v[2];
496 assert_eq!(
497 dot,
498 R::dot_product::<3>(u[..3].try_into().unwrap(), v[..3].try_into().unwrap())
499 );
500 dot += u[3] * v[3];
501 assert_eq!(
502 dot,
503 R::dot_product::<4>(u[..4].try_into().unwrap(), v[..4].try_into().unwrap())
504 );
505 dot += u[4] * v[4];
506 assert_eq!(
507 dot,
508 R::dot_product::<5>(u[..5].try_into().unwrap(), v[..5].try_into().unwrap())
509 );
510 dot += u[5] * v[5];
511 assert_eq!(
512 dot,
513 R::dot_product::<6>(u[..6].try_into().unwrap(), v[..6].try_into().unwrap())
514 );
515 dot += u[6] * v[6];
516 assert_eq!(
517 dot,
518 R::dot_product::<7>(u[..7].try_into().unwrap(), v[..7].try_into().unwrap())
519 );
520 dot += u[7] * v[7];
521 assert_eq!(
522 dot,
523 R::dot_product::<8>(u[..8].try_into().unwrap(), v[..8].try_into().unwrap())
524 );
525 dot += u[8] * v[8];
526 assert_eq!(
527 dot,
528 R::dot_product::<9>(u[..9].try_into().unwrap(), v[..9].try_into().unwrap())
529 );
530 dot += u[9] * v[9];
531 assert_eq!(
532 dot,
533 R::dot_product::<10>(u[..10].try_into().unwrap(), v[..10].try_into().unwrap())
534 );
535 dot += u[10] * v[10];
536 assert_eq!(
537 dot,
538 R::dot_product::<11>(u[..11].try_into().unwrap(), v[..11].try_into().unwrap())
539 );
540 dot += u[11] * v[11];
541 assert_eq!(
542 dot,
543 R::dot_product::<12>(u[..12].try_into().unwrap(), v[..12].try_into().unwrap())
544 );
545 dot += u[12] * v[12];
546 assert_eq!(
547 dot,
548 R::dot_product::<13>(u[..13].try_into().unwrap(), v[..13].try_into().unwrap())
549 );
550 dot += u[13] * v[13];
551 assert_eq!(
552 dot,
553 R::dot_product::<14>(u[..14].try_into().unwrap(), v[..14].try_into().unwrap())
554 );
555 dot += u[14] * v[14];
556 assert_eq!(
557 dot,
558 R::dot_product::<15>(u[..15].try_into().unwrap(), v[..15].try_into().unwrap())
559 );
560 dot += u[15] * v[15];
561 assert_eq!(
562 dot,
563 R::dot_product::<16>(u[..16].try_into().unwrap(), v[..16].try_into().unwrap())
564 );
565
566 let dot_64: R = u
567 .iter()
568 .zip(v.iter())
569 .fold(R::ZERO, |acc, (&lhs, &rhs)| acc + (lhs * rhs));
570 assert_eq!(dot_64, R::dot_product::<64>(u, v));
571}
572
573pub fn test_sums<R: PrimeCharacteristicRing + Eq + Copy>(u: &[R; 16]) {
574 let mut sum = R::ZERO;
575 assert_eq!(sum, R::sum_array::<0>(u[..0].try_into().unwrap()));
576 assert_eq!(sum, u[..0].iter().copied().sum());
577 sum += u[0];
578 assert_eq!(sum, R::sum_array::<1>(u[..1].try_into().unwrap()));
579 assert_eq!(sum, u[..1].iter().copied().sum());
580 sum += u[1];
581 assert_eq!(sum, R::sum_array::<2>(u[..2].try_into().unwrap()));
582 assert_eq!(sum, u[..2].iter().copied().sum());
583 sum += u[2];
584 assert_eq!(sum, R::sum_array::<3>(u[..3].try_into().unwrap()));
585 assert_eq!(sum, u[..3].iter().copied().sum());
586 sum += u[3];
587 assert_eq!(sum, R::sum_array::<4>(u[..4].try_into().unwrap()));
588 assert_eq!(sum, u[..4].iter().copied().sum());
589 sum += u[4];
590 assert_eq!(sum, R::sum_array::<5>(u[..5].try_into().unwrap()));
591 assert_eq!(sum, u[..5].iter().copied().sum());
592 sum += u[5];
593 assert_eq!(sum, R::sum_array::<6>(u[..6].try_into().unwrap()));
594 assert_eq!(sum, u[..6].iter().copied().sum());
595 sum += u[6];
596 assert_eq!(sum, R::sum_array::<7>(u[..7].try_into().unwrap()));
597 assert_eq!(sum, u[..7].iter().copied().sum());
598 sum += u[7];
599 assert_eq!(sum, R::sum_array::<8>(u[..8].try_into().unwrap()));
600 assert_eq!(sum, u[..8].iter().copied().sum());
601 sum += u[8];
602 assert_eq!(sum, R::sum_array::<9>(u[..9].try_into().unwrap()));
603 assert_eq!(sum, u[..9].iter().copied().sum());
604 sum += u[9];
605 assert_eq!(sum, R::sum_array::<10>(u[..10].try_into().unwrap()));
606 assert_eq!(sum, u[..10].iter().copied().sum());
607 sum += u[10];
608 assert_eq!(sum, R::sum_array::<11>(u[..11].try_into().unwrap()));
609 assert_eq!(sum, u[..11].iter().copied().sum());
610 sum += u[11];
611 assert_eq!(sum, R::sum_array::<12>(u[..12].try_into().unwrap()));
612 assert_eq!(sum, u[..12].iter().copied().sum());
613 sum += u[12];
614 assert_eq!(sum, R::sum_array::<13>(u[..13].try_into().unwrap()));
615 assert_eq!(sum, u[..13].iter().copied().sum());
616 sum += u[13];
617 assert_eq!(sum, R::sum_array::<14>(u[..14].try_into().unwrap()));
618 assert_eq!(sum, u[..14].iter().copied().sum());
619 sum += u[14];
620 assert_eq!(sum, R::sum_array::<15>(u[..15].try_into().unwrap()));
621 assert_eq!(sum, u[..15].iter().copied().sum());
622 sum += u[15];
623 assert_eq!(sum, R::sum_array::<16>(u));
624 assert_eq!(sum, u.iter().copied().sum());
625}
626
627pub fn test_binary_ops<R: PrimeCharacteristicRing + Eq + Copy>(
628 zeros: &[R],
629 ones: &[R],
630 x: R,
631 y: R,
632 z: R,
633) {
634 for zero in zeros {
635 for one in ones {
636 assert_eq!(one.xor(one), R::ZERO, "Error when testing xor(1, 1) = 0.");
637 assert_eq!(zero.xor(one), R::ONE, "Error when testing xor(0, 1) = 1.");
638 assert_eq!(one.xor(zero), R::ONE, "Error when testing xor(1, 0) = 1.");
639 assert_eq!(zero.xor(zero), R::ZERO, "Error when testing xor(0, 0) = 0.");
640 assert_eq!(one.andn(one), R::ZERO, "Error when testing andn(1, 1) = 0.");
641 assert_eq!(zero.andn(one), R::ONE, "Error when testing andn(0, 1) = 1.");
642 assert_eq!(
643 one.andn(zero),
644 R::ZERO,
645 "Error when testing andn(1, 0) = 0."
646 );
647 assert_eq!(
648 zero.andn(zero),
649 R::ZERO,
650 "Error when testing andn(0, 0) = 0."
651 );
652 assert_eq!(
653 zero.bool_check(),
654 R::ZERO,
655 "Error when testing bool_check(0) = 0."
656 );
657 assert_eq!(
658 one.bool_check(),
659 R::ZERO,
660 "Error when testing bool_check(1) = 0."
661 );
662 }
663 }
664
665 assert_eq!(
666 R::ONE.xor(&R::NEG_ONE),
667 R::TWO,
668 "Error when testing xor(1, -1) = 2."
669 );
670 assert_eq!(
671 R::NEG_ONE.xor(&R::ONE),
672 R::TWO,
673 "Error when testing xor(-1, 1) = 2."
674 );
675 assert_eq!(
676 R::NEG_ONE.xor(&R::NEG_ONE),
677 R::from_i8(-4),
678 "Error when testing xor(-1, -1) = -4."
679 );
680 assert_eq!(
681 R::ONE.andn(&R::NEG_ONE),
682 R::ZERO,
683 "Error when testing andn(1, -1) = 0."
684 );
685 assert_eq!(
686 R::NEG_ONE.andn(&R::ONE),
687 R::TWO,
688 "Error when testing andn(-1, 1) = 2."
689 );
690 assert_eq!(
691 R::NEG_ONE.andn(&R::NEG_ONE),
692 -R::TWO,
693 "Error when testing andn(-1, -1) = -2."
694 );
695
696 assert_eq!(x.xor(&y), x + y - x * y.double(), "Error when testing xor.");
697
698 assert_eq!(x.andn(&y), (R::ONE - x) * y, "Error when testing andn.");
699
700 assert_eq!(
701 x.xor3(&y, &z),
702 x + y + z - (x * y + x * z + y * z).double() + x * y * z.double().double(),
703 "Error when testing xor3."
704 );
705}
706
707pub fn test_powers_collect<F: Field>() {
709 let small_powers_serial = [0, 1, 2, 3, 4, 15];
711 let small_powers_packed = [16, 17];
713 let powers_of_two = [5, 6, 7, 8, 9, 10, 13];
715
716 let num_powers_tests: Vec<usize> = small_powers_serial
717 .into_iter()
718 .chain(small_powers_packed)
719 .chain(powers_of_two.iter().flat_map(|exp| {
720 let n = 1 << exp;
722 [n - 1, n, n + 1]
723 }))
724 .collect();
725
726 let base = F::TWO;
727 let shift = F::GENERATOR;
728
729 let expected_iter = successors(Some(shift), |prev| Some(*prev * base));
731
732 for num_powers in num_powers_tests {
733 let expected: Vec<_> = expected_iter.clone().take(num_powers).collect();
734 let actual = base.shifted_powers(shift).collect_n(num_powers);
735 assert_eq!(
736 expected, actual,
737 "Got different powers when taking {num_powers}"
738 );
739 }
740}
741
742pub(crate) fn exp_biguint<F: Field>(x: F, exponent: &BigUint) -> F {
748 let digits = exponent.to_u64_digits();
749 let size = digits.len();
750
751 let mut power = F::ONE;
752
753 let bases = (0..size).map(|i| x.exp_power_of_2(64 * i));
754 digits
755 .iter()
756 .zip(bases)
757 .for_each(|(digit, base)| power *= base.exp_u64(*digit));
758 power
759}
760
761pub fn test_generator<F: Field>(multiplicative_group_factors: &[(BigUint, u32)]) {
764 let product: BigUint = multiplicative_group_factors
771 .iter()
772 .map(|(factor, exponent)| factor.pow(*exponent))
773 .product();
774 assert_eq!(product + BigUint::from(1u32), F::order());
775
776 let mut partial_products: Vec<F> = (0..=multiplicative_group_factors.len())
779 .map(|i| {
780 let mut generator_power = F::GENERATOR;
781 multiplicative_group_factors
782 .iter()
783 .enumerate()
784 .for_each(|(j, (factor, exponent))| {
785 let modified_exponent = if i == j { exponent - 1 } else { *exponent };
786 for _ in 0..modified_exponent {
787 generator_power = exp_biguint(generator_power, factor);
788 }
789 });
790 generator_power
791 })
792 .collect();
793
794 assert_eq!(partial_products.pop().unwrap(), F::ONE);
795
796 for elem in partial_products.into_iter() {
797 assert_ne!(elem, F::ONE);
798 }
799}
800
801pub fn test_two_adic_generator_consistency<F: TwoAdicField>() {
802 let log_n = F::TWO_ADICITY;
803 let g = F::two_adic_generator(log_n);
804 for bits in 0..=log_n {
805 assert_eq!(g.exp_power_of_2(bits), F::two_adic_generator(log_n - bits));
806 }
807}
808
809pub fn test_two_adic_point_collection<F: TwoAdicField>() {
810 let log_n = F::TWO_ADICITY.min(15);
811 for bits in 0..=log_n {
812 let group = TwoAdicMultiplicativeCoset::new(F::ONE, bits).unwrap();
813 let points = group.iter().collect();
814 #[allow(clippy::map_identity)]
816 let points_expected = group.iter().map(|x| x).collect::<Vec<_>>();
817 assert_eq!(points, points_expected);
818 }
819}
820
821pub fn test_ef_two_adic_generator_consistency<
822 F: TwoAdicField,
823 EF: TwoAdicField + ExtensionField<F>,
824>() {
825 assert_eq!(
826 Into::<EF>::into(F::two_adic_generator(F::TWO_ADICITY)),
827 EF::two_adic_generator(F::TWO_ADICITY)
828 );
829}
830
831pub fn test_into_bytes_32<F: PrimeField32>(zeros: &[F], ones: &[F])
832where
833 StandardUniform: Distribution<F>,
834{
835 let mut rng = SmallRng::seed_from_u64(1);
836 let x = rng.random::<F>();
837
838 assert_eq!(
839 x.into_bytes().into_iter().collect::<Vec<_>>(),
840 x.to_unique_u32().to_le_bytes()
841 );
842 for one in ones {
843 assert_eq!(
844 one.into_bytes().into_iter().collect::<Vec<_>>(),
845 F::ONE.to_unique_u32().to_le_bytes()
846 );
847 }
848 for zero in zeros {
849 assert_eq!(zero.into_bytes().into_iter().collect::<Vec<_>>(), [0; 4]);
850 }
851}
852
853pub fn test_into_bytes_64<F: PrimeField64>(zeros: &[F], ones: &[F])
854where
855 StandardUniform: Distribution<F>,
856{
857 let mut rng = SmallRng::seed_from_u64(1);
858 let x = rng.random::<F>();
859
860 assert_eq!(
861 x.into_bytes().into_iter().collect::<Vec<_>>(),
862 x.to_unique_u64().to_le_bytes()
863 );
864 for one in ones {
865 assert_eq!(
866 one.into_bytes().into_iter().collect::<Vec<_>>(),
867 F::ONE.to_unique_u64().to_le_bytes()
868 );
869 }
870 for zero in zeros {
871 assert_eq!(zero.into_bytes().into_iter().collect::<Vec<_>>(), [0; 8]);
872 }
873}
874
875pub fn test_into_stream<F: Field>()
876where
877 StandardUniform: Distribution<[F; 16]>,
878{
879 let mut rng = SmallRng::seed_from_u64(1);
880 let xs: [F; 16] = rng.random();
881
882 let byte_vec = F::into_byte_stream(xs).into_iter().collect::<Vec<_>>();
883 let u32_vec = F::into_u32_stream(xs).into_iter().collect::<Vec<_>>();
884 let u64_vec = F::into_u64_stream(xs).into_iter().collect::<Vec<_>>();
885
886 let expected_bytes = xs
887 .into_iter()
888 .flat_map(|x| x.into_bytes())
889 .collect::<Vec<_>>();
890 let expected_u32s = iter_array_chunks_padded(byte_vec.iter().copied(), 0)
891 .map(u32::from_le_bytes)
892 .collect::<Vec<_>>();
893 let expected_u64s = iter_array_chunks_padded(byte_vec.iter().copied(), 0)
894 .map(u64::from_le_bytes)
895 .collect::<Vec<_>>();
896
897 assert_eq!(byte_vec, expected_bytes);
898 assert_eq!(u32_vec, expected_u32s);
899 assert_eq!(u64_vec, expected_u64s);
900
901 let ys: [F; 16] = rng.random();
902 let zs: [F; 16] = rng.random();
903
904 let combs: [[F; 3]; 16] = array::from_fn(|i| [xs[i], ys[i], zs[i]]);
905
906 let byte_vec_ys = F::into_byte_stream(ys).into_iter().collect::<Vec<_>>();
907 let byte_vec_zs = F::into_byte_stream(zs).into_iter().collect::<Vec<_>>();
908 let u32_vec_ys = F::into_u32_stream(ys).into_iter().collect::<Vec<_>>();
909 let u32_vec_zs = F::into_u32_stream(zs).into_iter().collect::<Vec<_>>();
910 let u64_vec_ys = F::into_u64_stream(ys).into_iter().collect::<Vec<_>>();
911 let u64_vec_zs = F::into_u64_stream(zs).into_iter().collect::<Vec<_>>();
912
913 let combined_bytes = F::into_parallel_byte_streams(combs)
914 .into_iter()
915 .collect::<Vec<_>>();
916 let combined_u32s = F::into_parallel_u32_streams(combs)
917 .into_iter()
918 .collect::<Vec<_>>();
919 let combined_u64s = F::into_parallel_u64_streams(combs)
920 .into_iter()
921 .collect::<Vec<_>>();
922
923 let expected_combined_bytes: Vec<[u8; 3]> = (0..byte_vec.len())
924 .map(|i| [byte_vec[i], byte_vec_ys[i], byte_vec_zs[i]])
925 .collect();
926 let expected_combined_u32s: Vec<[u32; 3]> = (0..u32_vec.len())
927 .map(|i| [u32_vec[i], u32_vec_ys[i], u32_vec_zs[i]])
928 .collect();
929 let expected_combined_u64s: Vec<[u64; 3]> = (0..u64_vec.len())
930 .map(|i| [u64_vec[i], u64_vec_ys[i], u64_vec_zs[i]])
931 .collect();
932
933 assert_eq!(combined_bytes, expected_combined_bytes);
934 assert_eq!(combined_u32s, expected_combined_u32s);
935 assert_eq!(combined_u64s, expected_combined_u64s);
936}
937
938pub fn test_ring_axioms_proptest<R>()
944where
945 R: PrimeCharacteristicRing + Copy + Eq + core::fmt::Debug + 'static,
946 StandardUniform: Distribution<R>,
947{
948 let config = ProptestConfig::with_cases(256);
949 proptest!(config, |(x in arb_field::<R>(), y in arb_field::<R>(), z in arb_field::<R>())| {
950 prop_assert_eq!(x + y, y + x, "addition commutativity");
952 prop_assert_eq!(x * y, y * x, "multiplication commutativity");
953
954 prop_assert_eq!(x + (y + z), (x + y) + z, "addition associativity");
956 prop_assert_eq!(x * (y * z), (x * y) * z, "multiplication associativity");
957
958 prop_assert_eq!(x * (y + z), x * y + x * z, "left distributivity");
960 prop_assert_eq!((x + y) * z, x * z + y * z, "right distributivity");
961
962 prop_assert_eq!(x + (-x), R::ZERO, "additive inverse");
964 prop_assert_eq!(-(-x), x, "double negation");
965
966 prop_assert_eq!(x - (y - z), (x - y) + z, "sub-sub identity");
968 prop_assert_eq!(x - (y + z), (x - y) - z, "sub-add identity");
969
970 prop_assert_eq!(x * x, x.square(), "square");
972 prop_assert_eq!(x * x * x, x.cube(), "cube");
973
974 prop_assert_eq!(x.double(), x + x, "double");
976 prop_assert_eq!(x.halve().double(), x, "halve roundtrip");
977
978 prop_assert_eq!(x * R::ZERO, R::ZERO, "x * 0 == 0");
980 prop_assert_eq!(R::NEG_ONE * x, -x, "-1 * x == -x");
981 });
982}
983
984pub fn test_field_axioms_proptest<F>()
987where
988 F: Field + core::fmt::Debug + 'static,
989 StandardUniform: Distribution<F>,
990{
991 assert_eq!(F::TWO.inverse(), F::ONE.halve());
993 assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
994 assert_eq!(
995 F::GENERATOR.inverse() * F::GENERATOR,
996 F::ONE,
997 "generator inverse roundtrip"
998 );
999
1000 let config = ProptestConfig::with_cases(256);
1002 proptest!(config, |(x in arb_field::<F>(), y in arb_field::<F>(), z in arb_field::<F>())| {
1003 if x.is_zero() || y.is_zero() || z.is_zero() {
1005 return Ok(());
1006 }
1007
1008 prop_assert_eq!(x * x.inverse(), F::ONE, "x * x^-1 == 1");
1010 prop_assert_eq!(x.inverse().inverse(), x, "double inverse");
1011 prop_assert_eq!(x.square().inverse(), x.inverse().square(), "square-inverse commutativity");
1012
1013 prop_assert_eq!((x / y) * y, x, "division roundtrip");
1015
1016 prop_assert_eq!(x / (y * z), (x / y) / z, "division-multiplication associativity");
1018 prop_assert_eq!((x * y) / z, x * (y / z), "multiplication-division associativity");
1019 });
1020}
1021
1022#[macro_export]
1023macro_rules! test_ring_with_eq {
1024 ($ring:ty, $zeros: expr, $ones: expr) => {
1025 mod ring_tests {
1026 use p3_field::PrimeCharacteristicRing;
1027
1028 #[test]
1029 fn test_ring_with_eq() {
1030 $crate::test_ring_with_eq::<$ring>($zeros, $ones);
1031 }
1032 #[test]
1033 fn test_mul_2exp_u64() {
1034 $crate::test_mul_2exp_u64::<$ring>();
1035 }
1036 #[test]
1037 fn test_div_2exp_u64() {
1038 $crate::test_div_2exp_u64::<$ring>();
1039 }
1040 }
1041 };
1042}
1043
1044#[macro_export]
1045macro_rules! test_field {
1046 ($field:ty, $zeros: expr, $ones: expr, $factors: expr) => {
1047 $crate::test_ring_with_eq!($field, $zeros, $ones);
1048
1049 mod field_tests {
1050 #[test]
1051 fn test_inverse() {
1052 $crate::test_inverse::<$field>();
1053 }
1054 #[test]
1055 fn test_batch_multiplicative_inverse() {
1056 $crate::test_batch_multiplicative_inverse::<$field>();
1057 }
1058 #[test]
1059 fn test_generator() {
1060 $crate::test_generator::<$field>($factors);
1061 }
1062 #[test]
1063 fn test_streaming() {
1064 $crate::test_into_stream::<$field>();
1065 }
1066 #[test]
1067 fn test_powers_collect() {
1068 $crate::test_powers_collect::<$field>();
1069 }
1070 #[test]
1071 fn test_ring_axioms_proptest() {
1072 $crate::test_ring_axioms_proptest::<$field>();
1073 }
1074 #[test]
1075 fn test_field_axioms_proptest() {
1076 $crate::test_field_axioms_proptest::<$field>();
1077 }
1078 }
1079
1080 mod trivial_extension_tests {
1083 #[test]
1084 fn test_to_from_trivial_extension() {
1085 $crate::test_to_from_extension_field::<$field, $field>();
1086 }
1087
1088 #[test]
1089 fn test_trivial_packed_extension() {
1090 $crate::test_packed_extension::<$field, $field>();
1091 }
1092 }
1093 };
1094}
1095
1096#[macro_export]
1097macro_rules! test_prime_field {
1098 ($field:ty) => {
1099 mod from_integer_small_tests {
1100 use p3_field::integers::QuotientMap;
1101 use p3_field::{Field, PrimeCharacteristicRing};
1102
1103 #[test]
1104 fn test_small_integer_conversions() {
1105 $crate::generate_from_small_int_tests!(
1106 $field,
1107 [
1108 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1109 ]
1110 );
1111 }
1112
1113 #[test]
1114 fn test_small_signed_integer_conversions() {
1115 $crate::generate_from_small_neg_int_tests!(
1116 $field,
1117 [i8, i16, i32, i64, i128, isize]
1118 );
1119 }
1120 }
1121 };
1122}
1123
1124#[macro_export]
1125macro_rules! test_prime_field_64 {
1126 ($field:ty, $zeros: expr, $ones: expr) => {
1127 mod from_integer_tests_prime_field_64 {
1128 use p3_field::integers::QuotientMap;
1129 use p3_field::{Field, PrimeCharacteristicRing, PrimeField64, RawDataSerializable};
1130 use rand::rngs::SmallRng;
1131 use rand::{RngExt, SeedableRng};
1132
1133 #[test]
1134 fn test_as_canonical_u64() {
1135 let mut rng = SmallRng::seed_from_u64(1);
1136 let x: u64 = rng.random();
1137 let x_mod_order = x % <$field>::ORDER_U64;
1138
1139 assert_eq!(<$field>::ZERO.as_canonical_u64(), 0);
1140 assert_eq!(<$field>::ONE.as_canonical_u64(), 1);
1141 assert_eq!(<$field>::TWO.as_canonical_u64(), 2 % <$field>::ORDER_U64);
1142 assert_eq!(
1143 <$field>::NEG_ONE.as_canonical_u64(),
1144 <$field>::ORDER_U64 - 1
1145 );
1146
1147 assert_eq!(
1148 <$field>::from_int(<$field>::ORDER_U64).as_canonical_u64(),
1149 0
1150 );
1151 assert_eq!(<$field>::from_int(x).as_canonical_u64(), x_mod_order);
1152 assert_eq!(
1153 unsafe { <$field>::from_canonical_unchecked(x_mod_order).as_canonical_u64() },
1154 x_mod_order
1155 );
1156 }
1157
1158 #[test]
1159 fn test_as_unique_u64() {
1160 assert_ne!(
1161 <$field>::ZERO.to_unique_u64(),
1162 <$field>::ONE.to_unique_u64()
1163 );
1164 assert_ne!(
1165 <$field>::ZERO.to_unique_u64(),
1166 <$field>::NEG_ONE.to_unique_u64()
1167 );
1168 assert_eq!(
1169 <$field>::from_int(<$field>::ORDER_U64).to_unique_u64(),
1170 <$field>::ZERO.to_unique_u64()
1171 );
1172 }
1173
1174 #[test]
1175 fn test_large_unsigned_integer_conversions() {
1176 $crate::generate_from_large_u_int_tests!($field, <$field>::ORDER_U64, [u64, u128]);
1177 }
1178
1179 #[test]
1180 fn test_large_signed_integer_conversions() {
1181 $crate::generate_from_large_i_int_tests!($field, <$field>::ORDER_U64, [i64, i128]);
1182 }
1183
1184 #[test]
1185 fn test_raw_data_serializable() {
1186 if <$field>::NUM_BYTES == 8 {
1189 $crate::test_into_bytes_64::<$field>($zeros, $ones);
1190 }
1191 }
1192 }
1193 };
1194}
1195
1196#[macro_export]
1197macro_rules! test_prime_field_32 {
1198 ($field:ty, $zeros: expr, $ones: expr) => {
1199 mod from_integer_tests_prime_field_32 {
1200 use p3_field::integers::QuotientMap;
1201 use p3_field::{Field, PrimeCharacteristicRing, PrimeField32, PrimeField64};
1202 use rand::rngs::SmallRng;
1203 use rand::{RngExt, SeedableRng};
1204
1205 #[test]
1206 fn test_as_canonical_u32() {
1207 let mut rng = SmallRng::seed_from_u64(1);
1208 let x: u32 = rng.random();
1209 let x_mod_order = x % <$field>::ORDER_U32;
1210
1211 for zero in $zeros {
1212 assert_eq!(zero.as_canonical_u32(), 0);
1213 assert_eq!(zero.to_unique_u32() as u64, zero.to_unique_u64());
1214 }
1215 for one in $ones {
1216 assert_eq!(one.as_canonical_u32(), 1);
1217 assert_eq!(one.to_unique_u32() as u64, one.to_unique_u64());
1218 }
1219 assert_eq!(<$field>::TWO.as_canonical_u32(), 2 % <$field>::ORDER_U32);
1220 assert_eq!(
1221 <$field>::NEG_ONE.as_canonical_u32(),
1222 <$field>::ORDER_U32 - 1
1223 );
1224 assert_eq!(
1225 <$field>::from_int(<$field>::ORDER_U32).as_canonical_u32(),
1226 0
1227 );
1228 assert_eq!(<$field>::from_int(x).as_canonical_u32(), x_mod_order);
1229 assert_eq!(
1230 <$field>::from_int(x).to_unique_u32() as u64,
1231 <$field>::from_int(x).to_unique_u64()
1232 );
1233 assert_eq!(
1234 unsafe { <$field>::from_canonical_unchecked(x_mod_order).as_canonical_u32() },
1235 x_mod_order
1236 );
1237 }
1238
1239 #[test]
1240 fn test_as_unique_u32() {
1241 assert_ne!(
1242 <$field>::ZERO.to_unique_u32(),
1243 <$field>::ONE.to_unique_u32()
1244 );
1245 assert_ne!(
1246 <$field>::ZERO.to_unique_u32(),
1247 <$field>::NEG_ONE.to_unique_u32()
1248 );
1249 assert_eq!(
1250 <$field>::from_int(<$field>::ORDER_U32).to_unique_u32(),
1251 <$field>::ZERO.to_unique_u32()
1252 );
1253 }
1254
1255 #[test]
1256 fn test_large_unsigned_integer_conversions() {
1257 $crate::generate_from_large_u_int_tests!(
1258 $field,
1259 <$field>::ORDER_U32,
1260 [u32, u64, u128]
1261 );
1262 }
1263
1264 #[test]
1265 fn test_large_signed_integer_conversions() {
1266 $crate::generate_from_large_i_int_tests!(
1267 $field,
1268 <$field>::ORDER_U32,
1269 [i32, i64, i128]
1270 );
1271 }
1272
1273 #[test]
1274 fn test_raw_data_serializable() {
1275 $crate::test_into_bytes_32::<$field>($zeros, $ones);
1276 }
1277
1278 #[test]
1279 fn test_json_deserialization_boundaries() {
1280 $crate::test_prime_field_32_json_deserialization_boundaries::<$field>();
1281 }
1282 }
1283 };
1284}
1285
1286#[macro_export]
1287macro_rules! test_two_adic_field {
1288 ($field:ty) => {
1289 mod two_adic_field_tests {
1290 #[test]
1291 fn test_two_adic_consistency() {
1292 $crate::test_two_adic_generator_consistency::<$field>();
1293 $crate::test_two_adic_point_collection::<$field>();
1294 }
1295
1296 #[test]
1299 fn test_two_adic_generator_consistency_as_trivial_extension() {
1300 $crate::test_ef_two_adic_generator_consistency::<$field, $field>();
1301 }
1302 }
1303 };
1304}
1305
1306#[macro_export]
1307macro_rules! test_extension_field {
1308 ($field:ty, $ef:ty) => {
1309 mod extension_field_tests {
1310 #[test]
1311 fn test_to_from_extension() {
1312 $crate::test_to_from_extension_field::<$field, $ef>();
1313 }
1314
1315 #[test]
1316 fn test_galois_extension() {
1317 $crate::test_galois_extension::<$field, $ef>();
1318 }
1319
1320 #[test]
1321 fn test_packed_extension() {
1322 $crate::test_packed_extension::<$field, $ef>();
1323 }
1324 }
1325 };
1326}
1327
1328#[macro_export]
1329macro_rules! test_two_adic_extension_field {
1330 ($field:ty, $ef:ty) => {
1331 use $crate::test_two_adic_field;
1332
1333 test_two_adic_field!($ef);
1334
1335 mod two_adic_extension_field_tests {
1336
1337 #[test]
1338 fn test_ef_two_adic_generator_consistency() {
1339 $crate::test_ef_two_adic_generator_consistency::<$field, $ef>();
1340 }
1341 }
1342 };
1343}
1344
1345#[macro_export]
1346macro_rules! test_frobenius {
1347 ($field:ty, $ef:ty) => {
1348 mod frobenius_tests {
1349 #[test]
1350 fn test_frobenius_fixes_base_field() {
1351 $crate::test_frobenius_fixes_base_field::<$field, $ef>();
1352 }
1353
1354 #[test]
1355 fn test_frobenius_proptest() {
1356 $crate::test_frobenius_proptest::<$field, $ef>();
1357 }
1358 }
1359 };
1360}