1use alloc::vec;
2use alloc::vec::Vec;
3
4use p3_field::{Field, PackedField, PackedValue};
5use rand::distributions::{Distribution, Standard};
6use rand::{Rng, SeedableRng};
7use rand_chacha::ChaCha20Rng;
8
9fn packed_from_random<PV>(seed: u64) -> PV
10where
11 PV: PackedValue,
12 Standard: Distribution<PV::Value>,
13{
14 let mut rng = ChaCha20Rng::seed_from_u64(seed);
15 PV::from_fn(|_| rng.gen())
16}
17
18fn interleave<T: Copy + Default>(arr1: &[T], arr2: &[T], i: usize) -> (Vec<T>, Vec<T>) {
20 let width = arr1.len();
21 assert_eq!(width, arr2.len());
22 assert_eq!(width % i, 0);
23
24 if i == width {
25 return (arr1.to_vec(), arr2.to_vec());
26 }
27
28 let mut outleft = vec![T::default(); width];
29 let mut outright = vec![T::default(); width];
30
31 let mut flag = false;
32
33 for j in 0..width {
34 if j % i == 0 {
35 flag = !flag;
36 }
37 if flag {
38 outleft[j] = arr1[j];
39 outleft[j + i] = arr2[j];
40 } else {
41 outright[j - i] = arr1[j];
42 outright[j] = arr2[j];
43 }
44 }
45
46 (outleft, outright)
47}
48
49fn test_interleave<PF>(i: usize)
50where
51 PF: PackedField + Eq,
52 Standard: Distribution<PF::Scalar>,
53{
54 assert!(PF::WIDTH % i == 0);
55
56 let vec1 = packed_from_random::<PF>(0x4ff5dec04791e481);
57 let vec2 = packed_from_random::<PF>(0x5806c495e9451f8e);
58
59 let arr1 = vec1.as_slice();
60 let arr2 = vec2.as_slice();
61
62 let (res1, res2) = vec1.interleave(vec2, i);
63 let (out1, out2) = interleave(arr1, arr2, i);
64
65 assert_eq!(
66 res1.as_slice(),
67 &out1,
68 "Error in left output when testing interleave {}.",
69 i
70 );
71 assert_eq!(
72 res2.as_slice(),
73 &out2,
74 "Error in right output when testing interleave {}.",
75 i
76 );
77}
78
79pub fn test_interleaves<PF>()
80where
81 PF: PackedField + Eq,
82 Standard: Distribution<PF::Scalar>,
83{
84 let mut i = 1;
85 while i <= PF::WIDTH {
86 test_interleave::<PF>(i);
87 i *= 2;
88 }
89}
90
91#[allow(clippy::eq_op)]
92pub fn test_add_neg<PF>(zeros: PF)
93where
94 PF: PackedField + Eq,
95 Standard: Distribution<PF::Scalar>,
96{
97 let vec0 = packed_from_random::<PF>(0x8b078c2b693c893f);
98 let vec1 = packed_from_random::<PF>(0x4ff5dec04791e481);
99 let vec2 = packed_from_random::<PF>(0x5806c495e9451f8e);
100
101 assert_eq!(
102 (vec0 + vec1) + vec2,
103 vec0 + (vec1 + vec2),
104 "Error when testing associativity of add."
105 );
106 assert_eq!(
107 vec0 + vec1,
108 vec1 + vec0,
109 "Error when testing commutativity of add."
110 );
111 assert_eq!(
112 vec0,
113 vec0 + zeros,
114 "Error when testing additive identity right."
115 );
116 assert_eq!(
117 vec0,
118 zeros + vec0,
119 "Error when testing additive identity left."
120 );
121 assert_eq!(
122 vec0 + (-vec0),
123 PF::zero(),
124 "Error when testing additive inverse."
125 );
126 assert_eq!(
127 vec0 - vec0,
128 PF::zero(),
129 "Error when testing subtracting of self."
130 );
131 assert_eq!(
132 vec0 - vec1,
133 -(vec1 - vec0),
134 "Error when testing anticommutativity of sub."
135 );
136 assert_eq!(vec0, vec0 - zeros, "Error when testing subtracting zero.");
137 assert_eq!(
138 -vec0,
139 zeros - vec0,
140 "Error when testing subtracting from zero"
141 );
142 assert_eq!(vec0, -(-vec0), "Error when testing double negation");
143 assert_eq!(
144 vec0 - vec1,
145 vec0 + (-vec1),
146 "Error when testing addition of negation"
147 );
148 assert_eq!(PF::one() + PF::one(), PF::two(), "Error 1 + 1 =/= 2");
149 assert_eq!(PF::neg_one() + PF::two(), PF::one(), "Error -1 + 2 =/= 1");
150 assert_eq!(
151 vec0.double(),
152 vec0 + vec0,
153 "Error when comparing x.double() to x + x"
154 );
155}
156
157pub fn test_mul<PF>(zeros: PF)
158where
159 PF: PackedField + Eq,
160 Standard: Distribution<PF::Scalar>,
161{
162 let vec0 = packed_from_random::<PF>(0x0b1ee4d7c979d50c);
163 let vec1 = packed_from_random::<PF>(0x39faa0844a36e45a);
164 let vec2 = packed_from_random::<PF>(0x08fac4ee76260e44);
165
166 assert_eq!(
167 (vec0 * vec1) * vec2,
168 vec0 * (vec1 * vec2),
169 "Error when testing associativity of mul."
170 );
171 assert_eq!(
172 vec0 * vec1,
173 vec1 * vec0,
174 "Error when testing commutativity of mul."
175 );
176 assert_eq!(
177 vec0,
178 vec0 * PF::one(),
179 "Error when testing multiplicative identity right."
180 );
181 assert_eq!(
182 vec0,
183 PF::one() * vec0,
184 "Error when testing multiplicative identity left."
185 );
186 assert_eq!(
187 vec0 * zeros,
188 PF::zero(),
189 "Error when testing right multiplication by 0."
190 );
191 assert_eq!(
192 zeros * vec0,
193 PF::zero(),
194 "Error when testing left multiplication by 0."
195 );
196 assert_eq!(
197 vec0 * PF::neg_one(),
198 -(vec0),
199 "Error when testing right multiplication by -1."
200 );
201 assert_eq!(
202 PF::neg_one() * vec0,
203 -(vec0),
204 "Error when testing left multiplication by -1."
205 );
206 assert_eq!(
207 vec0.double(),
208 PF::two() * vec0,
209 "Error when comparing x.double() to 2 * x."
210 );
211}
212
213pub fn test_distributivity<PF>()
214where
215 PF: PackedField + Eq,
216 Standard: Distribution<PF::Scalar>,
217{
218 let vec0 = packed_from_random::<PF>(0x278d9e202925a1d1);
219 let vec1 = packed_from_random::<PF>(0xf04cbac0cbad419f);
220 let vec2 = packed_from_random::<PF>(0x76976e2abdc5a056);
221
222 assert_eq!(
223 vec0 * (-vec1),
224 -(vec0 * vec1),
225 "Error when testing distributivity of mul and right neg."
226 );
227 assert_eq!(
228 (-vec0) * vec1,
229 -(vec0 * vec1),
230 "Error when testing distributivity of mul and left neg."
231 );
232
233 assert_eq!(
234 vec0 * (vec1 + vec2),
235 vec0 * vec1 + vec0 * vec2,
236 "Error when testing distributivity of add and left mul."
237 );
238 assert_eq!(
239 (vec0 + vec1) * vec2,
240 vec0 * vec2 + vec1 * vec2,
241 "Error when testing distributivity of add and right mul."
242 );
243 assert_eq!(
244 vec0 * (vec1 - vec2),
245 vec0 * vec1 - vec0 * vec2,
246 "Error when testing distributivity of sub and left mul."
247 );
248 assert_eq!(
249 (vec0 - vec1) * vec2,
250 vec0 * vec2 - vec1 * vec2,
251 "Error when testing distributivity of sub and right mul."
252 );
253}
254
255pub fn test_vs_scalar<PF>(special_vals: PF)
256where
257 PF: PackedField + Eq,
258 Standard: Distribution<PF::Scalar>,
259{
260 let vec0: PF = packed_from_random(0x278d9e202925a1d1);
261 let vec1: PF = packed_from_random(0xf04cbac0cbad419f);
262 let vec_special = special_vals;
263
264 let arr0 = vec0.as_slice();
265 let arr1 = vec1.as_slice();
266
267 let vec_sum = vec0 + vec1;
268 let arr_sum = vec_sum.as_slice();
269 let vec_special_sum_left = vec_special + vec0;
270 let arr_special_sum_left = vec_special_sum_left.as_slice();
271 let vec_special_sum_right = vec1 + vec_special;
272 let arr_special_sum_right = vec_special_sum_right.as_slice();
273
274 let vec_sub = vec0 - vec1;
275 let arr_sub = vec_sub.as_slice();
276 let vec_special_sub_left = vec_special - vec0;
277 let arr_special_sub_left = vec_special_sub_left.as_slice();
278 let vec_special_sub_right = vec1 - vec_special;
279 let arr_special_sub_right = vec_special_sub_right.as_slice();
280
281 let vec_mul = vec0 * vec1;
282 let arr_mul = vec_mul.as_slice();
283 let vec_special_mul_left = vec_special * vec0;
284 let arr_special_mul_left = vec_special_mul_left.as_slice();
285 let vec_special_mul_right = vec1 * vec_special;
286 let arr_special_mul_right = vec_special_mul_right.as_slice();
287
288 let vec_neg = -vec0;
289 let arr_neg = vec_neg.as_slice();
290 let vec_special_neg = -vec_special;
291 let arr_special_neg = vec_special_neg.as_slice();
292
293 let special_vals = special_vals.as_slice();
294 for i in 0..PF::WIDTH {
295 assert_eq!(
296 arr_sum[i],
297 arr0[i] + arr1[i],
298 "Error when testing add consistency of packed and scalar at location {}.",
299 i
300 );
301 assert_eq!(
302 arr_special_sum_left[i],
303 special_vals[i] + arr0[i],
304 "Error when testing consistency of left add for special values for packed and scalar at location {}.",
305 i
306 );
307 assert_eq!(
308 arr_special_sum_right[i],
309 arr1[i] + special_vals[i],
310 "Error when testing consistency of right add for special values for packed and scalar at location {}.",
311 i
312 );
313
314 assert_eq!(
315 arr_sub[i],
316 arr0[i] - arr1[i],
317 "Error when testing sub consistency of packed and scalar at location {}.",
318 i
319 );
320 assert_eq!(arr_special_sub_left[i],
321 special_vals[i] - arr0[i],
322 "Error when testing consistency of left sub for special values for packed and scalar at location {}.",
323 i
324 );
325 assert_eq!(arr_special_sub_right[i],
326 arr1[i] - special_vals[i],
327 "Error when testing consistency of right sub for special values for packed and scalar at location {}.",
328 i
329 );
330
331 assert_eq!(
332 arr_mul[i],
333 arr0[i] * arr1[i],
334 "Error when testing mul consistency of packed and scalar at location {}.",
335 i
336 );
337 assert_eq!(arr_special_mul_left[i],
338 special_vals[i] * arr0[i],
339 "Error when testing consistency of left mul for special values for packed and scalar at location {}.",
340 i
341 );
342 assert_eq!(arr_special_mul_right[i],
343 arr1[i] * special_vals[i],
344 "Error when testing consistency of right mul for special values for packed and scalar at location {}.",
345 i
346 );
347
348 assert_eq!(
349 arr_neg[i], -arr0[i],
350 "Error when testing neg consistency of packed and scalar at location {}.",
351 i
352 );
353 assert_eq!(arr_special_neg[i],
354 -special_vals[i],
355 "Error when testing consistency of neg for special values for packed and scalar at location {}.",
356 i
357 );
358 }
359}
360
361pub fn test_multiplicative_inverse<PF>()
362where
363 PF: PackedField + Eq,
364 Standard: Distribution<PF::Scalar>,
365{
366 let vec: PF = packed_from_random(0xb0c7a5153103c5a8);
367 let arr = vec.as_slice();
368 let vec_inv = PF::from_fn(|i| arr[i].inverse());
369 let res = vec * vec_inv;
370 assert_eq!(
371 res,
372 PF::one(),
373 "Error when testing multiplication by inverse."
374 );
375}
376
377#[macro_export]
378macro_rules! test_packed_field {
379 ($packedfield:ty, $zeros:expr, $specials:expr) => {
380 mod packed_field_tests {
381 use p3_field::AbstractField;
382
383 #[test]
384 fn test_interleaves() {
385 $crate::test_interleaves::<$packedfield>();
386 }
387 #[test]
388 fn test_add_neg() {
389 $crate::test_add_neg::<$packedfield>($zeros);
390 }
391 #[test]
392 fn test_mul() {
393 $crate::test_mul::<$packedfield>($zeros);
394 }
395 #[test]
396 fn test_distributivity() {
397 $crate::test_distributivity::<$packedfield>();
398 }
399 #[test]
400 fn test_vs_scalar() {
401 $crate::test_vs_scalar::<$packedfield>($specials);
402 }
403 #[test]
404 fn test_multiplicative_inverse() {
405 $crate::test_multiplicative_inverse::<$packedfield>();
406 }
407 }
408 };
409}