1#![no_std]
4
5extern crate alloc;
6
7pub mod bench_func;
8pub mod dft_testing;
9pub mod extension_testing;
10pub mod from_integer_tests;
11pub mod packedfield_testing;
12
13use alloc::vec::Vec;
14use core::array;
15use core::iter::successors;
16
17pub use bench_func::*;
18pub use dft_testing::*;
19pub use extension_testing::*;
20use num_bigint::BigUint;
21use p3_field::coset::TwoAdicMultiplicativeCoset;
22use p3_field::{
23 ExtensionField, Field, PackedValue, PrimeCharacteristicRing, PrimeField32, PrimeField64,
24 TwoAdicField,
25};
26use p3_util::iter_array_chunks_padded;
27pub use packedfield_testing::*;
28use proptest::prelude::*;
29use rand::distr::{Distribution, StandardUniform};
30use rand::rngs::SmallRng;
31use rand::{RngExt, SeedableRng};
32use serde::Serialize;
33use serde::de::DeserializeOwned;
34
35fn arb_field<F>() -> impl Strategy<Value = F>
37where
38 F: core::fmt::Debug + 'static,
39 StandardUniform: Distribution<F>,
40{
41 any::<u64>().prop_map(|seed| {
42 let mut rng = SmallRng::seed_from_u64(seed);
43 rng.random()
44 })
45}
46
47#[allow(clippy::eq_op)]
48pub fn test_ring_with_eq<R: PrimeCharacteristicRing + Copy + Eq>(zeros: &[R], ones: &[R])
49where
50 StandardUniform: Distribution<R> + Distribution<[R; 16]>,
51{
52 let mut rng = SmallRng::seed_from_u64(1);
55 let x = rng.random::<R>();
56 let y = rng.random::<R>();
57 let z = rng.random::<R>();
58 assert_eq!(R::ONE + R::NEG_ONE, R::ZERO, "Error 1 + (-1) =/= 0");
59 assert_eq!(R::NEG_ONE + R::TWO, R::ONE, "Error -1 + 2 =/= 1");
60 assert_eq!(x + (-x), R::ZERO, "Error x + (-x) =/= 0");
61 assert_eq!(R::ONE + R::ONE, R::TWO, "Error 1 + 1 =/= 2");
62 assert_eq!(-(-x), x, "Error when testing double negation");
63 assert_eq!(x + x, x * R::TWO, "Error when comparing x * 2 to x + x");
64 assert_eq!(
65 x * R::TWO,
66 x.double(),
67 "Error when comparing x.double() to x * 2"
68 );
69 assert_eq!(x, x.halve() * R::TWO, "Error when testing halve.");
70
71 for zero in zeros.iter().copied() {
73 assert_eq!(zero, R::ZERO);
74 assert_eq!(x + zero, x, "Error when testing additive identity right.");
75 assert_eq!(zero + x, x, "Error when testing additive identity left.");
76 assert_eq!(x - zero, x, "Error when testing subtracting zero.");
77 assert_eq!(zero - x, -x, "Error when testing subtracting from zero.");
78 assert_eq!(
79 x * zero,
80 zero,
81 "Error when testing right multiplication by 0."
82 );
83 assert_eq!(
84 zero * x,
85 zero,
86 "Error when testing left multiplication by 0."
87 );
88 }
89
90 for one in ones.iter().copied() {
92 assert_eq!(one, R::ONE);
93 assert_eq!(one * one, one);
94 assert_eq!(
95 x * one,
96 x,
97 "Error when testing multiplicative identity right."
98 );
99 assert_eq!(
100 one * x,
101 x,
102 "Error when testing multiplicative identity left."
103 );
104 }
105
106 assert_eq!(
107 x * R::NEG_ONE,
108 -x,
109 "Error when testing right multiplication by -1."
110 );
111 assert_eq!(
112 R::NEG_ONE * x,
113 -x,
114 "Error when testing left multiplication by -1."
115 );
116 assert_eq!(x * x, x.square(), "Error when testing x * x = x.square()");
117 assert_eq!(
118 x * x * x,
119 x.cube(),
120 "Error when testing x * x * x = x.cube()"
121 );
122 assert_eq!(x + y, y + x, "Error when testing commutativity of addition");
123 assert_eq!(
124 (x - y),
125 -(y - x),
126 "Error when testing anticommutativity of sub."
127 );
128 assert_eq!(
129 x * y,
130 y * x,
131 "Error when testing commutativity of multiplication."
132 );
133 assert_eq!(
134 x + (y + z),
135 (x + y) + z,
136 "Error when testing associativity of addition"
137 );
138 assert_eq!(
139 x * (y * z),
140 (x * y) * z,
141 "Error when testing associativity of multiplication."
142 );
143 assert_eq!(
144 x - (y - z),
145 (x - y) + z,
146 "Error when testing subtraction and addition"
147 );
148 assert_eq!(
149 x - (y + z),
150 (x - y) - z,
151 "Error when testing subtraction and addition"
152 );
153 assert_eq!(
154 (x + y) - z,
155 x + (y - z),
156 "Error when testing subtraction and addition"
157 );
158 assert_eq!(
159 x * (-y),
160 -(x * y),
161 "Error when testing distributivity of mul and right neg."
162 );
163 assert_eq!(
164 (-x) * y,
165 -(x * y),
166 "Error when testing distributivity of mul and left neg."
167 );
168
169 assert_eq!(
170 x * (y + z),
171 x * y + x * z,
172 "Error when testing distributivity of add and left mul."
173 );
174 assert_eq!(
175 (x + y) * z,
176 x * z + y * z,
177 "Error when testing distributivity of add and right mul."
178 );
179 assert_eq!(
180 x * (y - z),
181 x * y - x * z,
182 "Error when testing distributivity of sub and left mul."
183 );
184 assert_eq!(
185 (x - y) * z,
186 x * z - y * z,
187 "Error when testing distributivity of sub and right mul."
188 );
189
190 let vec1: [R; 64] = rng.random();
191 let vec2: [R; 64] = rng.random();
192 test_sums(&vec1[..16].try_into().unwrap());
193 test_dot_product(&vec1, &vec2);
194
195 assert_eq!(
196 x.exp_const_u64::<0>(),
197 R::ONE,
198 "Error when comparing x.exp_const_u64::<0> to R::ONE."
199 );
200 assert_eq!(
201 x.exp_const_u64::<1>(),
202 x,
203 "Error when comparing x.exp_const_u64::<3> to x."
204 );
205 assert_eq!(
206 x.exp_const_u64::<2>(),
207 x * x,
208 "Error when comparing x.exp_const_u64::<3> to x*x."
209 );
210 assert_eq!(
211 x.exp_const_u64::<3>(),
212 x * x * x,
213 "Error when comparing x.exp_const_u64::<3> to x*x*x."
214 );
215 assert_eq!(
216 x.exp_const_u64::<4>(),
217 x * x * x * x,
218 "Error when comparing x.exp_const_u64::<3> to x*x*x*x."
219 );
220 assert_eq!(
221 x.exp_const_u64::<5>(),
222 x * x * x * x * x,
223 "Error when comparing x.exp_const_u64::<5> to x*x*x*x*x."
224 );
225 assert_eq!(
226 x.exp_const_u64::<6>(),
227 x * x * x * x * x * x,
228 "Error when comparing x.exp_const_u64::<7> to x*x*x*x*x*x."
229 );
230 assert_eq!(
231 x.exp_const_u64::<7>(),
232 x * x * x * x * x * x * x,
233 "Error when comparing x.exp_const_u64::<7> to x*x*x*x*x*x*x."
234 );
235
236 test_binary_ops(zeros, ones, x, y, z);
237
238 for &a in &[R::ZERO, R::ONE, R::TWO, R::NEG_ONE] {
240 for &b in &[R::ZERO, R::ONE, R::TWO, R::NEG_ONE] {
241 assert_eq!(a + b, b + a, "commutativity with special values");
242 assert_eq!(a * b, b * a, "commutativity with special values");
243 }
244 assert_eq!(a * a, a.square(), "square with special value");
245 assert_eq!(a * a * a, a.cube(), "cube with special value");
246 assert_eq!(a.halve().double(), a, "halve/double with special value");
247 }
248
249 let empty: [R; 0] = [];
251 let product_result: R = empty.into_iter().product();
252 assert_eq!(
253 product_result,
254 R::ONE,
255 "Product of empty iterator should return ONE, not ZERO"
256 );
257}
258
259pub fn test_mul_2exp_u64<R: PrimeCharacteristicRing + Eq>()
260where
261 StandardUniform: Distribution<R>,
262{
263 let mut rng = SmallRng::seed_from_u64(1);
264 let x = rng.random::<R>();
265 assert_eq!(x.mul_2exp_u64(0), x);
266 assert_eq!(x.mul_2exp_u64(1), x.double());
267 for i in 0..128 {
268 assert_eq!(
269 x.clone().mul_2exp_u64(i),
270 x.clone() * R::from_u128(1_u128 << i)
271 );
272 }
273 for i in 128..256 {
275 assert_eq!(x.clone().mul_2exp_u64(i), x.clone() * R::TWO.exp_u64(i));
276 }
277}
278
279pub fn test_div_2exp_u64<R: PrimeCharacteristicRing + Eq>()
280where
281 StandardUniform: Distribution<R>,
282{
283 let mut rng = SmallRng::seed_from_u64(1);
284 let x = rng.random::<R>();
285 assert_eq!(x.div_2exp_u64(0), x);
286 assert_eq!(x.div_2exp_u64(1), x.halve());
287 for i in 0..128 {
288 assert_eq!(x.mul_2exp_u64(i).div_2exp_u64(i), x);
289 assert_eq!(
290 x.div_2exp_u64(i),
291 x.clone() * R::from_prime_subfield(R::PrimeSubfield::from_u128(1_u128 << i).inverse())
293 );
294 }
295 for i in 128..256 {
297 assert_eq!(x.mul_2exp_u64(i).div_2exp_u64(i), x);
298 assert_eq!(
299 x.div_2exp_u64(i),
300 x.clone() * R::from_prime_subfield(R::PrimeSubfield::TWO.inverse().exp_u64(i))
302 );
303 }
304}
305
306pub fn test_add_slice<F: Field>()
307where
308 StandardUniform: Distribution<F>,
309{
310 let mut rng = SmallRng::seed_from_u64(1);
311 let lengths = [
312 F::Packing::WIDTH - 1,
313 F::Packing::WIDTH,
314 (F::Packing::WIDTH - 1) + (F::Packing::WIDTH << 10),
315 ];
316 for len in lengths {
317 let mut slice_1: Vec<_> = (&mut rng).sample_iter(StandardUniform).take(len).collect();
318 let slice_1_copy = slice_1.clone();
319 let slice_2: Vec<_> = (&mut rng).sample_iter(StandardUniform).take(len).collect();
320
321 F::add_slices(&mut slice_1, &slice_2);
322 for i in 0..len {
323 assert_eq!(slice_1[i], slice_1_copy[i] + slice_2[i]);
324 }
325 }
326}
327
328pub fn test_inverse<F: Field>()
329where
330 StandardUniform: Distribution<F>,
331{
332 assert_eq!(None, F::ZERO.try_inverse());
333 assert_eq!(Some(F::ONE), F::ONE.try_inverse());
334 assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
335 let two_inv = F::TWO
336 .try_inverse()
337 .expect("2 must be invertible in this field (test_inverse assumes characteristic != 2)");
338 assert_eq!(two_inv, F::ONE.halve(), "inverse of 2 == halve(1)");
339 let mut rng = SmallRng::seed_from_u64(1);
340 for _ in 0..1000 {
341 let x = rng.random::<F>();
342 if !x.is_zero() && !x.is_one() {
343 let z = x.inverse();
344 assert_ne!(x, z);
345 assert_eq!(x * z, F::ONE);
346 }
347 }
348}
349
350pub fn test_field_json_serialization<F>(values: &[F])
356where
357 F: PrimeCharacteristicRing + Serialize + DeserializeOwned + Eq,
358{
359 for value in values {
360 let serialized = serde_json::to_string(value).expect("Failed to serialize field element");
362 let deserialized: F =
363 serde_json::from_str(&serialized).expect("Failed to deserialize field element");
364 assert_eq!(
365 *value, deserialized,
366 "Single round-trip serialization failed"
367 );
368
369 let serialized_again = serde_json::to_string(&deserialized)
371 .expect("Failed to serialize field element (second time)");
372 let deserialized_again: F = serde_json::from_str(&serialized_again)
373 .expect("Failed to deserialize field element (second time)");
374 assert_eq!(
375 *value, deserialized_again,
376 "Double round-trip serialization failed"
377 );
378 assert_eq!(
379 deserialized, deserialized_again,
380 "Deserialized values should be equal"
381 );
382 }
383}
384
385pub fn test_prime_field_32_json_deserialization_boundaries<F>(accepts_order_repr: bool)
390where
391 F: PrimeField32 + Serialize + DeserializeOwned + Eq,
392{
393 let zero: F = serde_json::from_str("0").expect("Failed to deserialize zero");
394 assert_eq!(zero, F::ZERO, "Deserializing 0 should produce ZERO");
395
396 let original: F = serde_json::from_str("42").expect("Failed to deserialize test value");
397 let serialized = serde_json::to_string(&original).expect("Failed to serialize test value");
398 let deserialized: F =
399 serde_json::from_str(&serialized).expect("Failed to deserialize serialized test value");
400 assert_eq!(
401 deserialized, original,
402 "Round-trip serialization should preserve the value"
403 );
404
405 let max_valid = if accepts_order_repr {
406 F::ORDER_U32
407 } else {
408 F::ORDER_U32 - 1
409 };
410 let max_valid_json = serde_json::to_string(&max_valid).expect("Failed to encode max valid u32");
411 let max_valid_result: Result<F, _> = serde_json::from_str(&max_valid_json);
412 assert!(
413 max_valid_result.is_ok(),
414 "Expected max valid representation to deserialize successfully"
415 );
416
417 if let Some(first_invalid) = max_valid.checked_add(1) {
418 let first_invalid_json =
419 serde_json::to_string(&first_invalid).expect("Failed to encode first invalid value");
420 let first_invalid_result: Result<F, _> = serde_json::from_str(&first_invalid_json);
421 assert!(
422 first_invalid_result.is_err(),
423 "Expected first out-of-range representation to fail deserialization"
424 );
425 }
426
427 if max_valid != u32::MAX {
428 let max_u32_json = serde_json::to_string(&u32::MAX).expect("Failed to encode u32::MAX");
429 let max_u32_result: Result<F, _> = serde_json::from_str(&max_u32_json);
430 assert!(
431 max_u32_result.is_err(),
432 "Expected u32::MAX to fail deserialization"
433 );
434 }
435}
436
437pub fn test_dot_product<R: PrimeCharacteristicRing + Eq + Copy>(u: &[R; 64], v: &[R; 64]) {
438 let mut dot = R::ZERO;
439 assert_eq!(
440 dot,
441 R::dot_product::<0>(u[..0].try_into().unwrap(), v[..0].try_into().unwrap())
442 );
443 dot += u[0] * v[0];
444 assert_eq!(
445 dot,
446 R::dot_product::<1>(u[..1].try_into().unwrap(), v[..1].try_into().unwrap())
447 );
448 dot += u[1] * v[1];
449 assert_eq!(
450 dot,
451 R::dot_product::<2>(u[..2].try_into().unwrap(), v[..2].try_into().unwrap())
452 );
453 dot += u[2] * v[2];
454 assert_eq!(
455 dot,
456 R::dot_product::<3>(u[..3].try_into().unwrap(), v[..3].try_into().unwrap())
457 );
458 dot += u[3] * v[3];
459 assert_eq!(
460 dot,
461 R::dot_product::<4>(u[..4].try_into().unwrap(), v[..4].try_into().unwrap())
462 );
463 dot += u[4] * v[4];
464 assert_eq!(
465 dot,
466 R::dot_product::<5>(u[..5].try_into().unwrap(), v[..5].try_into().unwrap())
467 );
468 dot += u[5] * v[5];
469 assert_eq!(
470 dot,
471 R::dot_product::<6>(u[..6].try_into().unwrap(), v[..6].try_into().unwrap())
472 );
473 dot += u[6] * v[6];
474 assert_eq!(
475 dot,
476 R::dot_product::<7>(u[..7].try_into().unwrap(), v[..7].try_into().unwrap())
477 );
478 dot += u[7] * v[7];
479 assert_eq!(
480 dot,
481 R::dot_product::<8>(u[..8].try_into().unwrap(), v[..8].try_into().unwrap())
482 );
483 dot += u[8] * v[8];
484 assert_eq!(
485 dot,
486 R::dot_product::<9>(u[..9].try_into().unwrap(), v[..9].try_into().unwrap())
487 );
488 dot += u[9] * v[9];
489 assert_eq!(
490 dot,
491 R::dot_product::<10>(u[..10].try_into().unwrap(), v[..10].try_into().unwrap())
492 );
493 dot += u[10] * v[10];
494 assert_eq!(
495 dot,
496 R::dot_product::<11>(u[..11].try_into().unwrap(), v[..11].try_into().unwrap())
497 );
498 dot += u[11] * v[11];
499 assert_eq!(
500 dot,
501 R::dot_product::<12>(u[..12].try_into().unwrap(), v[..12].try_into().unwrap())
502 );
503 dot += u[12] * v[12];
504 assert_eq!(
505 dot,
506 R::dot_product::<13>(u[..13].try_into().unwrap(), v[..13].try_into().unwrap())
507 );
508 dot += u[13] * v[13];
509 assert_eq!(
510 dot,
511 R::dot_product::<14>(u[..14].try_into().unwrap(), v[..14].try_into().unwrap())
512 );
513 dot += u[14] * v[14];
514 assert_eq!(
515 dot,
516 R::dot_product::<15>(u[..15].try_into().unwrap(), v[..15].try_into().unwrap())
517 );
518 dot += u[15] * v[15];
519 assert_eq!(
520 dot,
521 R::dot_product::<16>(u[..16].try_into().unwrap(), v[..16].try_into().unwrap())
522 );
523
524 let dot_64: R = u
525 .iter()
526 .zip(v.iter())
527 .fold(R::ZERO, |acc, (&lhs, &rhs)| acc + (lhs * rhs));
528 assert_eq!(dot_64, R::dot_product::<64>(u, v));
529}
530
531pub fn test_sums<R: PrimeCharacteristicRing + Eq + Copy>(u: &[R; 16]) {
532 let mut sum = R::ZERO;
533 assert_eq!(sum, R::sum_array::<0>(u[..0].try_into().unwrap()));
534 assert_eq!(sum, u[..0].iter().copied().sum());
535 sum += u[0];
536 assert_eq!(sum, R::sum_array::<1>(u[..1].try_into().unwrap()));
537 assert_eq!(sum, u[..1].iter().copied().sum());
538 sum += u[1];
539 assert_eq!(sum, R::sum_array::<2>(u[..2].try_into().unwrap()));
540 assert_eq!(sum, u[..2].iter().copied().sum());
541 sum += u[2];
542 assert_eq!(sum, R::sum_array::<3>(u[..3].try_into().unwrap()));
543 assert_eq!(sum, u[..3].iter().copied().sum());
544 sum += u[3];
545 assert_eq!(sum, R::sum_array::<4>(u[..4].try_into().unwrap()));
546 assert_eq!(sum, u[..4].iter().copied().sum());
547 sum += u[4];
548 assert_eq!(sum, R::sum_array::<5>(u[..5].try_into().unwrap()));
549 assert_eq!(sum, u[..5].iter().copied().sum());
550 sum += u[5];
551 assert_eq!(sum, R::sum_array::<6>(u[..6].try_into().unwrap()));
552 assert_eq!(sum, u[..6].iter().copied().sum());
553 sum += u[6];
554 assert_eq!(sum, R::sum_array::<7>(u[..7].try_into().unwrap()));
555 assert_eq!(sum, u[..7].iter().copied().sum());
556 sum += u[7];
557 assert_eq!(sum, R::sum_array::<8>(u[..8].try_into().unwrap()));
558 assert_eq!(sum, u[..8].iter().copied().sum());
559 sum += u[8];
560 assert_eq!(sum, R::sum_array::<9>(u[..9].try_into().unwrap()));
561 assert_eq!(sum, u[..9].iter().copied().sum());
562 sum += u[9];
563 assert_eq!(sum, R::sum_array::<10>(u[..10].try_into().unwrap()));
564 assert_eq!(sum, u[..10].iter().copied().sum());
565 sum += u[10];
566 assert_eq!(sum, R::sum_array::<11>(u[..11].try_into().unwrap()));
567 assert_eq!(sum, u[..11].iter().copied().sum());
568 sum += u[11];
569 assert_eq!(sum, R::sum_array::<12>(u[..12].try_into().unwrap()));
570 assert_eq!(sum, u[..12].iter().copied().sum());
571 sum += u[12];
572 assert_eq!(sum, R::sum_array::<13>(u[..13].try_into().unwrap()));
573 assert_eq!(sum, u[..13].iter().copied().sum());
574 sum += u[13];
575 assert_eq!(sum, R::sum_array::<14>(u[..14].try_into().unwrap()));
576 assert_eq!(sum, u[..14].iter().copied().sum());
577 sum += u[14];
578 assert_eq!(sum, R::sum_array::<15>(u[..15].try_into().unwrap()));
579 assert_eq!(sum, u[..15].iter().copied().sum());
580 sum += u[15];
581 assert_eq!(sum, R::sum_array::<16>(u));
582 assert_eq!(sum, u.iter().copied().sum());
583}
584
585pub fn test_binary_ops<R: PrimeCharacteristicRing + Eq + Copy>(
586 zeros: &[R],
587 ones: &[R],
588 x: R,
589 y: R,
590 z: R,
591) {
592 for zero in zeros {
593 for one in ones {
594 assert_eq!(one.xor(one), R::ZERO, "Error when testing xor(1, 1) = 0.");
595 assert_eq!(zero.xor(one), R::ONE, "Error when testing xor(0, 1) = 1.");
596 assert_eq!(one.xor(zero), R::ONE, "Error when testing xor(1, 0) = 1.");
597 assert_eq!(zero.xor(zero), R::ZERO, "Error when testing xor(0, 0) = 0.");
598 assert_eq!(one.andn(one), R::ZERO, "Error when testing andn(1, 1) = 0.");
599 assert_eq!(zero.andn(one), R::ONE, "Error when testing andn(0, 1) = 1.");
600 assert_eq!(
601 one.andn(zero),
602 R::ZERO,
603 "Error when testing andn(1, 0) = 0."
604 );
605 assert_eq!(
606 zero.andn(zero),
607 R::ZERO,
608 "Error when testing andn(0, 0) = 0."
609 );
610 assert_eq!(
611 zero.bool_check(),
612 R::ZERO,
613 "Error when testing bool_check(0) = 0."
614 );
615 assert_eq!(
616 one.bool_check(),
617 R::ZERO,
618 "Error when testing bool_check(1) = 0."
619 );
620 }
621 }
622
623 assert_eq!(
624 R::ONE.xor(&R::NEG_ONE),
625 R::TWO,
626 "Error when testing xor(1, -1) = 2."
627 );
628 assert_eq!(
629 R::NEG_ONE.xor(&R::ONE),
630 R::TWO,
631 "Error when testing xor(-1, 1) = 2."
632 );
633 assert_eq!(
634 R::NEG_ONE.xor(&R::NEG_ONE),
635 R::from_i8(-4),
636 "Error when testing xor(-1, -1) = -4."
637 );
638 assert_eq!(
639 R::ONE.andn(&R::NEG_ONE),
640 R::ZERO,
641 "Error when testing andn(1, -1) = 0."
642 );
643 assert_eq!(
644 R::NEG_ONE.andn(&R::ONE),
645 R::TWO,
646 "Error when testing andn(-1, 1) = 2."
647 );
648 assert_eq!(
649 R::NEG_ONE.andn(&R::NEG_ONE),
650 -R::TWO,
651 "Error when testing andn(-1, -1) = -2."
652 );
653
654 assert_eq!(x.xor(&y), x + y - x * y.double(), "Error when testing xor.");
655
656 assert_eq!(x.andn(&y), (R::ONE - x) * y, "Error when testing andn.");
657
658 assert_eq!(
659 x.xor3(&y, &z),
660 x + y + z - (x * y + x * z + y * z).double() + x * y * z.double().double(),
661 "Error when testing xor3."
662 );
663}
664
665pub fn test_powers_collect<F: Field>() {
667 let small_powers_serial = [0, 1, 2, 3, 4, 15];
669 let small_powers_packed = [16, 17];
671 let powers_of_two = [5, 6, 7, 8, 9, 10, 13];
673
674 let num_powers_tests: Vec<usize> = small_powers_serial
675 .into_iter()
676 .chain(small_powers_packed)
677 .chain(powers_of_two.iter().flat_map(|exp| {
678 let n = 1 << exp;
680 [n - 1, n, n + 1]
681 }))
682 .collect();
683
684 let base = F::TWO;
685 let shift = F::GENERATOR;
686
687 let expected_iter = successors(Some(shift), |prev| Some(*prev * base));
689
690 for num_powers in num_powers_tests {
691 let expected: Vec<_> = expected_iter.clone().take(num_powers).collect();
692 let actual = base.shifted_powers(shift).collect_n(num_powers);
693 assert_eq!(
694 expected, actual,
695 "Got different powers when taking {num_powers}"
696 );
697 }
698}
699
700pub(crate) fn exp_biguint<F: Field>(x: F, exponent: &BigUint) -> F {
706 let digits = exponent.to_u64_digits();
707 let size = digits.len();
708
709 let mut power = F::ONE;
710
711 let bases = (0..size).map(|i| x.exp_power_of_2(64 * i));
712 digits
713 .iter()
714 .zip(bases)
715 .for_each(|(digit, base)| power *= base.exp_u64(*digit));
716 power
717}
718
719pub fn test_generator<F: Field>(multiplicative_group_factors: &[(BigUint, u32)]) {
722 let product: BigUint = multiplicative_group_factors
729 .iter()
730 .map(|(factor, exponent)| factor.pow(*exponent))
731 .product();
732 assert_eq!(product + BigUint::from(1u32), F::order());
733
734 let mut partial_products: Vec<F> = (0..=multiplicative_group_factors.len())
737 .map(|i| {
738 let mut generator_power = F::GENERATOR;
739 multiplicative_group_factors
740 .iter()
741 .enumerate()
742 .for_each(|(j, (factor, exponent))| {
743 let modified_exponent = if i == j { exponent - 1 } else { *exponent };
744 for _ in 0..modified_exponent {
745 generator_power = exp_biguint(generator_power, factor);
746 }
747 });
748 generator_power
749 })
750 .collect();
751
752 assert_eq!(partial_products.pop().unwrap(), F::ONE);
753
754 for elem in partial_products.into_iter() {
755 assert_ne!(elem, F::ONE);
756 }
757}
758
759pub fn test_two_adic_generator_consistency<F: TwoAdicField>() {
760 let log_n = F::TWO_ADICITY;
761 let g = F::two_adic_generator(log_n);
762 for bits in 0..=log_n {
763 assert_eq!(g.exp_power_of_2(bits), F::two_adic_generator(log_n - bits));
764 }
765}
766
767pub fn test_two_adic_point_collection<F: TwoAdicField>() {
768 let log_n = F::TWO_ADICITY.min(15);
769 for bits in 0..=log_n {
770 let group = TwoAdicMultiplicativeCoset::new(F::ONE, bits).unwrap();
771 let points = group.iter().collect();
772 #[allow(clippy::map_identity)]
774 let points_expected = group.iter().map(|x| x).collect::<Vec<_>>();
775 assert_eq!(points, points_expected);
776 }
777}
778
779pub fn test_ef_two_adic_generator_consistency<
780 F: TwoAdicField,
781 EF: TwoAdicField + ExtensionField<F>,
782>() {
783 assert_eq!(
784 Into::<EF>::into(F::two_adic_generator(F::TWO_ADICITY)),
785 EF::two_adic_generator(F::TWO_ADICITY)
786 );
787}
788
789pub fn test_into_bytes_32<F: PrimeField32>(zeros: &[F], ones: &[F])
790where
791 StandardUniform: Distribution<F>,
792{
793 let mut rng = SmallRng::seed_from_u64(1);
794 let x = rng.random::<F>();
795
796 assert_eq!(
797 x.into_bytes().into_iter().collect::<Vec<_>>(),
798 x.to_unique_u32().to_le_bytes()
799 );
800 for one in ones {
801 assert_eq!(
802 one.into_bytes().into_iter().collect::<Vec<_>>(),
803 F::ONE.to_unique_u32().to_le_bytes()
804 );
805 }
806 for zero in zeros {
807 assert_eq!(zero.into_bytes().into_iter().collect::<Vec<_>>(), [0; 4]);
808 }
809}
810
811pub fn test_into_bytes_64<F: PrimeField64>(zeros: &[F], ones: &[F])
812where
813 StandardUniform: Distribution<F>,
814{
815 let mut rng = SmallRng::seed_from_u64(1);
816 let x = rng.random::<F>();
817
818 assert_eq!(
819 x.into_bytes().into_iter().collect::<Vec<_>>(),
820 x.to_unique_u64().to_le_bytes()
821 );
822 for one in ones {
823 assert_eq!(
824 one.into_bytes().into_iter().collect::<Vec<_>>(),
825 F::ONE.to_unique_u64().to_le_bytes()
826 );
827 }
828 for zero in zeros {
829 assert_eq!(zero.into_bytes().into_iter().collect::<Vec<_>>(), [0; 8]);
830 }
831}
832
833pub fn test_into_stream<F: Field>()
834where
835 StandardUniform: Distribution<[F; 16]>,
836{
837 let mut rng = SmallRng::seed_from_u64(1);
838 let xs: [F; 16] = rng.random();
839
840 let byte_vec = F::into_byte_stream(xs).into_iter().collect::<Vec<_>>();
841 let u32_vec = F::into_u32_stream(xs).into_iter().collect::<Vec<_>>();
842 let u64_vec = F::into_u64_stream(xs).into_iter().collect::<Vec<_>>();
843
844 let expected_bytes = xs
845 .into_iter()
846 .flat_map(|x| x.into_bytes())
847 .collect::<Vec<_>>();
848 let expected_u32s = iter_array_chunks_padded(byte_vec.iter().copied(), 0)
849 .map(u32::from_le_bytes)
850 .collect::<Vec<_>>();
851 let expected_u64s = iter_array_chunks_padded(byte_vec.iter().copied(), 0)
852 .map(u64::from_le_bytes)
853 .collect::<Vec<_>>();
854
855 assert_eq!(byte_vec, expected_bytes);
856 assert_eq!(u32_vec, expected_u32s);
857 assert_eq!(u64_vec, expected_u64s);
858
859 let ys: [F; 16] = rng.random();
860 let zs: [F; 16] = rng.random();
861
862 let combs: [[F; 3]; 16] = array::from_fn(|i| [xs[i], ys[i], zs[i]]);
863
864 let byte_vec_ys = F::into_byte_stream(ys).into_iter().collect::<Vec<_>>();
865 let byte_vec_zs = F::into_byte_stream(zs).into_iter().collect::<Vec<_>>();
866 let u32_vec_ys = F::into_u32_stream(ys).into_iter().collect::<Vec<_>>();
867 let u32_vec_zs = F::into_u32_stream(zs).into_iter().collect::<Vec<_>>();
868 let u64_vec_ys = F::into_u64_stream(ys).into_iter().collect::<Vec<_>>();
869 let u64_vec_zs = F::into_u64_stream(zs).into_iter().collect::<Vec<_>>();
870
871 let combined_bytes = F::into_parallel_byte_streams(combs)
872 .into_iter()
873 .collect::<Vec<_>>();
874 let combined_u32s = F::into_parallel_u32_streams(combs)
875 .into_iter()
876 .collect::<Vec<_>>();
877 let combined_u64s = F::into_parallel_u64_streams(combs)
878 .into_iter()
879 .collect::<Vec<_>>();
880
881 let expected_combined_bytes: Vec<[u8; 3]> = (0..byte_vec.len())
882 .map(|i| [byte_vec[i], byte_vec_ys[i], byte_vec_zs[i]])
883 .collect();
884 let expected_combined_u32s: Vec<[u32; 3]> = (0..u32_vec.len())
885 .map(|i| [u32_vec[i], u32_vec_ys[i], u32_vec_zs[i]])
886 .collect();
887 let expected_combined_u64s: Vec<[u64; 3]> = (0..u64_vec.len())
888 .map(|i| [u64_vec[i], u64_vec_ys[i], u64_vec_zs[i]])
889 .collect();
890
891 assert_eq!(combined_bytes, expected_combined_bytes);
892 assert_eq!(combined_u32s, expected_combined_u32s);
893 assert_eq!(combined_u64s, expected_combined_u64s);
894}
895
896pub fn test_ring_axioms_proptest<R>()
902where
903 R: PrimeCharacteristicRing + Copy + Eq + core::fmt::Debug + 'static,
904 StandardUniform: Distribution<R>,
905{
906 let config = ProptestConfig::with_cases(256);
907 proptest!(config, |(x in arb_field::<R>(), y in arb_field::<R>(), z in arb_field::<R>())| {
908 prop_assert_eq!(x + y, y + x, "addition commutativity");
910 prop_assert_eq!(x * y, y * x, "multiplication commutativity");
911
912 prop_assert_eq!(x + (y + z), (x + y) + z, "addition associativity");
914 prop_assert_eq!(x * (y * z), (x * y) * z, "multiplication associativity");
915
916 prop_assert_eq!(x * (y + z), x * y + x * z, "left distributivity");
918 prop_assert_eq!((x + y) * z, x * z + y * z, "right distributivity");
919
920 prop_assert_eq!(x + (-x), R::ZERO, "additive inverse");
922 prop_assert_eq!(-(-x), x, "double negation");
923
924 prop_assert_eq!(x - (y - z), (x - y) + z, "sub-sub identity");
926 prop_assert_eq!(x - (y + z), (x - y) - z, "sub-add identity");
927
928 prop_assert_eq!(x * x, x.square(), "square");
930 prop_assert_eq!(x * x * x, x.cube(), "cube");
931
932 prop_assert_eq!(x.double(), x + x, "double");
934 prop_assert_eq!(x.halve().double(), x, "halve roundtrip");
935
936 prop_assert_eq!(x * R::ZERO, R::ZERO, "x * 0 == 0");
938 prop_assert_eq!(R::NEG_ONE * x, -x, "-1 * x == -x");
939 });
940}
941
942pub fn test_field_axioms_proptest<F>()
945where
946 F: Field + core::fmt::Debug + 'static,
947 StandardUniform: Distribution<F>,
948{
949 assert_eq!(F::TWO.inverse(), F::ONE.halve());
951 assert_eq!(F::NEG_ONE.inverse(), F::NEG_ONE, "-1 is its own inverse");
952 assert_eq!(
953 F::GENERATOR.inverse() * F::GENERATOR,
954 F::ONE,
955 "generator inverse roundtrip"
956 );
957
958 let config = ProptestConfig::with_cases(256);
960 proptest!(config, |(x in arb_field::<F>(), y in arb_field::<F>(), z in arb_field::<F>())| {
961 if x.is_zero() || y.is_zero() || z.is_zero() {
963 return Ok(());
964 }
965
966 prop_assert_eq!(x * x.inverse(), F::ONE, "x * x^-1 == 1");
968 prop_assert_eq!(x.inverse().inverse(), x, "double inverse");
969 prop_assert_eq!(x.square().inverse(), x.inverse().square(), "square-inverse commutativity");
970
971 prop_assert_eq!((x / y) * y, x, "division roundtrip");
973
974 prop_assert_eq!(x / (y * z), (x / y) / z, "division-multiplication associativity");
976 prop_assert_eq!((x * y) / z, x * (y / z), "multiplication-division associativity");
977 });
978}
979
980#[macro_export]
981macro_rules! test_ring_with_eq {
982 ($ring:ty, $zeros: expr, $ones: expr) => {
983 mod ring_tests {
984 use p3_field::PrimeCharacteristicRing;
985
986 #[test]
987 fn test_ring_with_eq() {
988 $crate::test_ring_with_eq::<$ring>($zeros, $ones);
989 }
990 #[test]
991 fn test_mul_2exp_u64() {
992 $crate::test_mul_2exp_u64::<$ring>();
993 }
994 #[test]
995 fn test_div_2exp_u64() {
996 $crate::test_div_2exp_u64::<$ring>();
997 }
998 }
999 };
1000}
1001
1002#[macro_export]
1003macro_rules! test_field {
1004 ($field:ty, $zeros: expr, $ones: expr, $factors: expr) => {
1005 $crate::test_ring_with_eq!($field, $zeros, $ones);
1006
1007 mod field_tests {
1008 #[test]
1009 fn test_inverse() {
1010 $crate::test_inverse::<$field>();
1011 }
1012 #[test]
1013 fn test_generator() {
1014 $crate::test_generator::<$field>($factors);
1015 }
1016 #[test]
1017 fn test_streaming() {
1018 $crate::test_into_stream::<$field>();
1019 }
1020 #[test]
1021 fn test_powers_collect() {
1022 $crate::test_powers_collect::<$field>();
1023 }
1024 #[test]
1025 fn test_ring_axioms_proptest() {
1026 $crate::test_ring_axioms_proptest::<$field>();
1027 }
1028 #[test]
1029 fn test_field_axioms_proptest() {
1030 $crate::test_field_axioms_proptest::<$field>();
1031 }
1032 }
1033
1034 mod trivial_extension_tests {
1037 #[test]
1038 fn test_to_from_trivial_extension() {
1039 $crate::test_to_from_extension_field::<$field, $field>();
1040 }
1041
1042 #[test]
1043 fn test_trivial_packed_extension() {
1044 $crate::test_packed_extension::<$field, $field>();
1045 }
1046 }
1047 };
1048}
1049
1050#[macro_export]
1051macro_rules! test_prime_field {
1052 ($field:ty) => {
1053 mod from_integer_small_tests {
1054 use p3_field::integers::QuotientMap;
1055 use p3_field::{Field, PrimeCharacteristicRing};
1056
1057 #[test]
1058 fn test_small_integer_conversions() {
1059 $crate::generate_from_small_int_tests!(
1060 $field,
1061 [
1062 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1063 ]
1064 );
1065 }
1066
1067 #[test]
1068 fn test_small_signed_integer_conversions() {
1069 $crate::generate_from_small_neg_int_tests!(
1070 $field,
1071 [i8, i16, i32, i64, i128, isize]
1072 );
1073 }
1074 }
1075 };
1076}
1077
1078#[macro_export]
1079macro_rules! test_prime_field_64 {
1080 ($field:ty, $zeros: expr, $ones: expr) => {
1081 mod from_integer_tests_prime_field_64 {
1082 use p3_field::integers::QuotientMap;
1083 use p3_field::{Field, PrimeCharacteristicRing, PrimeField64, RawDataSerializable};
1084 use rand::rngs::SmallRng;
1085 use rand::{RngExt, SeedableRng};
1086
1087 #[test]
1088 fn test_as_canonical_u64() {
1089 let mut rng = SmallRng::seed_from_u64(1);
1090 let x: u64 = rng.random();
1091 let x_mod_order = x % <$field>::ORDER_U64;
1092
1093 assert_eq!(<$field>::ZERO.as_canonical_u64(), 0);
1094 assert_eq!(<$field>::ONE.as_canonical_u64(), 1);
1095 assert_eq!(<$field>::TWO.as_canonical_u64(), 2 % <$field>::ORDER_U64);
1096 assert_eq!(
1097 <$field>::NEG_ONE.as_canonical_u64(),
1098 <$field>::ORDER_U64 - 1
1099 );
1100
1101 assert_eq!(
1102 <$field>::from_int(<$field>::ORDER_U64).as_canonical_u64(),
1103 0
1104 );
1105 assert_eq!(<$field>::from_int(x).as_canonical_u64(), x_mod_order);
1106 assert_eq!(
1107 unsafe { <$field>::from_canonical_unchecked(x_mod_order).as_canonical_u64() },
1108 x_mod_order
1109 );
1110 }
1111
1112 #[test]
1113 fn test_as_unique_u64() {
1114 assert_ne!(
1115 <$field>::ZERO.to_unique_u64(),
1116 <$field>::ONE.to_unique_u64()
1117 );
1118 assert_ne!(
1119 <$field>::ZERO.to_unique_u64(),
1120 <$field>::NEG_ONE.to_unique_u64()
1121 );
1122 assert_eq!(
1123 <$field>::from_int(<$field>::ORDER_U64).to_unique_u64(),
1124 <$field>::ZERO.to_unique_u64()
1125 );
1126 }
1127
1128 #[test]
1129 fn test_large_unsigned_integer_conversions() {
1130 $crate::generate_from_large_u_int_tests!($field, <$field>::ORDER_U64, [u64, u128]);
1131 }
1132
1133 #[test]
1134 fn test_large_signed_integer_conversions() {
1135 $crate::generate_from_large_i_int_tests!($field, <$field>::ORDER_U64, [i64, i128]);
1136 }
1137
1138 #[test]
1139 fn test_raw_data_serializable() {
1140 if <$field>::NUM_BYTES == 8 {
1143 $crate::test_into_bytes_64::<$field>($zeros, $ones);
1144 }
1145 }
1146 }
1147 };
1148}
1149
1150#[macro_export]
1151macro_rules! test_prime_field_32 {
1152 ($field:ty, $zeros: expr, $ones: expr) => {
1153 mod from_integer_tests_prime_field_32 {
1154 use p3_field::integers::QuotientMap;
1155 use p3_field::{Field, PrimeCharacteristicRing, PrimeField32, PrimeField64};
1156 use rand::rngs::SmallRng;
1157 use rand::{RngExt, SeedableRng};
1158
1159 #[test]
1160 fn test_as_canonical_u32() {
1161 let mut rng = SmallRng::seed_from_u64(1);
1162 let x: u32 = rng.random();
1163 let x_mod_order = x % <$field>::ORDER_U32;
1164
1165 for zero in $zeros {
1166 assert_eq!(zero.as_canonical_u32(), 0);
1167 assert_eq!(zero.to_unique_u32() as u64, zero.to_unique_u64());
1168 }
1169 for one in $ones {
1170 assert_eq!(one.as_canonical_u32(), 1);
1171 assert_eq!(one.to_unique_u32() as u64, one.to_unique_u64());
1172 }
1173 assert_eq!(<$field>::TWO.as_canonical_u32(), 2 % <$field>::ORDER_U32);
1174 assert_eq!(
1175 <$field>::NEG_ONE.as_canonical_u32(),
1176 <$field>::ORDER_U32 - 1
1177 );
1178 assert_eq!(
1179 <$field>::from_int(<$field>::ORDER_U32).as_canonical_u32(),
1180 0
1181 );
1182 assert_eq!(<$field>::from_int(x).as_canonical_u32(), x_mod_order);
1183 assert_eq!(
1184 <$field>::from_int(x).to_unique_u32() as u64,
1185 <$field>::from_int(x).to_unique_u64()
1186 );
1187 assert_eq!(
1188 unsafe { <$field>::from_canonical_unchecked(x_mod_order).as_canonical_u32() },
1189 x_mod_order
1190 );
1191 }
1192
1193 #[test]
1194 fn test_as_unique_u32() {
1195 assert_ne!(
1196 <$field>::ZERO.to_unique_u32(),
1197 <$field>::ONE.to_unique_u32()
1198 );
1199 assert_ne!(
1200 <$field>::ZERO.to_unique_u32(),
1201 <$field>::NEG_ONE.to_unique_u32()
1202 );
1203 assert_eq!(
1204 <$field>::from_int(<$field>::ORDER_U32).to_unique_u32(),
1205 <$field>::ZERO.to_unique_u32()
1206 );
1207 }
1208
1209 #[test]
1210 fn test_large_unsigned_integer_conversions() {
1211 $crate::generate_from_large_u_int_tests!(
1212 $field,
1213 <$field>::ORDER_U32,
1214 [u32, u64, u128]
1215 );
1216 }
1217
1218 #[test]
1219 fn test_large_signed_integer_conversions() {
1220 $crate::generate_from_large_i_int_tests!(
1221 $field,
1222 <$field>::ORDER_U32,
1223 [i32, i64, i128]
1224 );
1225 }
1226
1227 #[test]
1228 fn test_raw_data_serializable() {
1229 $crate::test_into_bytes_32::<$field>($zeros, $ones);
1230 }
1231
1232 #[test]
1233 fn test_json_deserialization_boundaries() {
1234 let accepts_order_repr = $zeros.len() > 1;
1235 $crate::test_prime_field_32_json_deserialization_boundaries::<$field>(
1236 accepts_order_repr,
1237 );
1238 }
1239 }
1240 };
1241}
1242
1243#[macro_export]
1244macro_rules! test_two_adic_field {
1245 ($field:ty) => {
1246 mod two_adic_field_tests {
1247 #[test]
1248 fn test_two_adic_consistency() {
1249 $crate::test_two_adic_generator_consistency::<$field>();
1250 $crate::test_two_adic_point_collection::<$field>();
1251 }
1252
1253 #[test]
1256 fn test_two_adic_generator_consistency_as_trivial_extension() {
1257 $crate::test_ef_two_adic_generator_consistency::<$field, $field>();
1258 }
1259 }
1260 };
1261}
1262
1263#[macro_export]
1264macro_rules! test_extension_field {
1265 ($field:ty, $ef:ty) => {
1266 mod extension_field_tests {
1267 #[test]
1268 fn test_to_from_extension() {
1269 $crate::test_to_from_extension_field::<$field, $ef>();
1270 }
1271
1272 #[test]
1273 fn test_galois_extension() {
1274 $crate::test_galois_extension::<$field, $ef>();
1275 }
1276
1277 #[test]
1278 fn test_packed_extension() {
1279 $crate::test_packed_extension::<$field, $ef>();
1280 }
1281 }
1282 };
1283}
1284
1285#[macro_export]
1286macro_rules! test_two_adic_extension_field {
1287 ($field:ty, $ef:ty) => {
1288 use $crate::test_two_adic_field;
1289
1290 test_two_adic_field!($ef);
1291
1292 mod two_adic_extension_field_tests {
1293
1294 #[test]
1295 fn test_ef_two_adic_generator_consistency() {
1296 $crate::test_ef_two_adic_generator_consistency::<$field, $ef>();
1297 }
1298 }
1299 };
1300}
1301
1302#[macro_export]
1303macro_rules! test_frobenius {
1304 ($field:ty, $ef:ty) => {
1305 mod frobenius_tests {
1306 #[test]
1307 fn test_frobenius_fixes_base_field() {
1308 $crate::test_frobenius_fixes_base_field::<$field, $ef>();
1309 }
1310
1311 #[test]
1312 fn test_frobenius_proptest() {
1313 $crate::test_frobenius_proptest::<$field, $ef>();
1314 }
1315 }
1316 };
1317}