binius_field/
packed_binary_field.rs

1// Copyright 2023-2025 Irreducible Inc.
2
3pub use crate::arch::{
4	packed_1::*, packed_128::*, packed_16::*, packed_2::*, packed_256::*, packed_32::*,
5	packed_4::*, packed_512::*, packed_64::*, packed_8::*,
6};
7
8/// Common code to test different multiply, square and invert implementations
9#[cfg(test)]
10pub mod test_utils {
11	use crate::{
12		linear_transformation::PackedTransformationFactory,
13		underlier::{WithUnderlier, U1, U2, U4},
14		BinaryField, PackedField,
15	};
16
17	pub struct Unit;
18
19	impl From<U1> for Unit {
20		fn from(_: U1) -> Self {
21			Self
22		}
23	}
24
25	impl From<U2> for Unit {
26		fn from(_: U2) -> Self {
27			Self
28		}
29	}
30
31	impl From<U4> for Unit {
32		fn from(_: U4) -> Self {
33			Self
34		}
35	}
36
37	impl From<u8> for Unit {
38		fn from(_: u8) -> Self {
39			Self
40		}
41	}
42
43	impl From<u16> for Unit {
44		fn from(_: u16) -> Self {
45			Self
46		}
47	}
48
49	impl From<u32> for Unit {
50		fn from(_: u32) -> Self {
51			Self
52		}
53	}
54
55	impl From<u64> for Unit {
56		fn from(_: u64) -> Self {
57			Self
58		}
59	}
60
61	impl From<u128> for Unit {
62		fn from(_: u128) -> Self {
63			Self
64		}
65	}
66
67	impl From<[u128; 2]> for Unit {
68		fn from(_: [u128; 2]) -> Self {
69			Self
70		}
71	}
72
73	impl From<[u128; 4]> for Unit {
74		fn from(_: [u128; 4]) -> Self {
75			Self
76		}
77	}
78
79	/// We use such helper macros to run tests only for the
80	/// types that implement the `constraint` trait.
81	/// The idea is inspired by `impls` trait.
82	macro_rules! define_check_packed_mul {
83		($mult_func:path, $constraint:path) => {
84			#[allow(unused)]
85			trait TestMulTrait<T> {
86				fn test_mul(_a: T, _b: T) {}
87			}
88
89			impl<T> TestMulTrait<$crate::packed_binary_field::test_utils::Unit> for T {}
90
91			struct TestMult<T>(std::marker::PhantomData<T>);
92
93			impl<T: $constraint + PackedField + $crate::underlier::WithUnderlier> TestMult<T> {
94				fn test_mul(
95					a: <T as $crate::underlier::WithUnderlier>::Underlier,
96					b: <T as $crate::underlier::WithUnderlier>::Underlier,
97				) {
98					let a = T::from_underlier(a);
99					let b = T::from_underlier(b);
100
101					let c = $mult_func(a, b);
102					for i in 0..T::WIDTH {
103						assert_eq!(c.get(i), a.get(i) * b.get(i));
104					}
105				}
106			}
107		};
108	}
109
110	pub(crate) use define_check_packed_mul;
111
112	macro_rules! define_check_packed_square {
113		($square_func:path, $constraint:path) => {
114			#[allow(unused)]
115			trait TestSquareTrait<T> {
116				fn test_square(_a: T) {}
117			}
118
119			impl<T> TestSquareTrait<$crate::packed_binary_field::test_utils::Unit> for T {}
120
121			struct TestSquare<T>(std::marker::PhantomData<T>);
122
123			impl<T: $constraint + PackedField + $crate::underlier::WithUnderlier> TestSquare<T> {
124				fn test_square(a: <T as $crate::underlier::WithUnderlier>::Underlier) {
125					let a = T::from_underlier(a);
126
127					let c = $square_func(a);
128					for i in 0..T::WIDTH {
129						assert_eq!(c.get(i), a.get(i) * a.get(i));
130					}
131				}
132			}
133		};
134	}
135
136	pub(crate) use define_check_packed_square;
137
138	macro_rules! define_check_packed_inverse {
139		($invert_func:path, $constraint:path) => {
140			#[allow(unused)]
141			trait TestInvertTrait<T> {
142				fn test_invert(_a: T) {}
143			}
144
145			impl<T> TestInvertTrait<$crate::packed_binary_field::test_utils::Unit> for T {}
146
147			struct TestInvert<T>(std::marker::PhantomData<T>);
148
149			#[allow(unused)]
150			impl<T: $constraint + PackedField + $crate::underlier::WithUnderlier> TestInvert<T> {
151				fn test_invert(a: <T as $crate::underlier::WithUnderlier>::Underlier) {
152					use crate::Field;
153
154					let a = T::from_underlier(a);
155
156					let c = $invert_func(a);
157					for i in 0..T::WIDTH {
158						assert!(
159							(c.get(i).is_zero().into()
160								&& a.get(i).is_zero().into()
161								&& c.get(i).is_zero().into())
162								|| T::Scalar::ONE == a.get(i) * c.get(i)
163						);
164					}
165				}
166			}
167		};
168	}
169
170	pub(crate) use define_check_packed_inverse;
171
172	macro_rules! define_check_packed_mul_alpha {
173		($mul_alpha_func:path, $constraint:path) => {
174			#[allow(unused)]
175			trait TestMulAlphaTrait<T> {
176				fn test_mul_alpha(_a: T) {}
177			}
178
179			impl<T> TestMulAlphaTrait<$crate::packed_binary_field::test_utils::Unit> for T {}
180
181			struct TestMulAlpha<T>(std::marker::PhantomData<T>);
182
183			impl<T: $constraint + PackedField + $crate::underlier::WithUnderlier> TestMulAlpha<T>
184			where
185				T::Scalar: $crate::arithmetic_traits::MulAlpha,
186			{
187				fn test_mul_alpha(a: <T as $crate::underlier::WithUnderlier>::Underlier) {
188					use $crate::arithmetic_traits::MulAlpha;
189
190					let a = T::from_underlier(a);
191
192					let c = $mul_alpha_func(a);
193					for i in 0..T::WIDTH {
194						assert_eq!(c.get(i), MulAlpha::mul_alpha(a.get(i)));
195					}
196				}
197			}
198		};
199	}
200
201	pub(crate) use define_check_packed_mul_alpha;
202
203	macro_rules! define_check_packed_transformation {
204		($constraint:path) => {
205			#[allow(unused)]
206			trait TestTransformationTrait<T> {
207				fn test_transformation(_a: T) {}
208			}
209
210			impl<T> TestTransformationTrait<$crate::packed_binary_field::test_utils::Unit> for T {}
211
212			struct TestTransformation<T>(std::marker::PhantomData<T>);
213
214			impl<T: $constraint + PackedField + $crate::underlier::WithUnderlier>
215				TestTransformation<T>
216			{
217				fn test_transformation(a: <T as $crate::underlier::WithUnderlier>::Underlier) {
218					use $crate::linear_transformation::{
219						FieldLinearTransformation, Transformation,
220					};
221
222					let a = T::from_underlier(a);
223
224					// TODO: think how we can use random seed from proptests here
225					let field_transformation =
226						FieldLinearTransformation::<T::Scalar, _>::random(rand::thread_rng());
227					let packed_transformation =
228						T::make_packed_transformation(field_transformation.clone());
229
230					let c = packed_transformation.transform(&a);
231					for i in 0..T::WIDTH {
232						assert_eq!(c.get(i), field_transformation.transform(&a.get(i)));
233					}
234				}
235			}
236		};
237	}
238
239	pub(crate) use define_check_packed_transformation;
240
241	/// Test if `mult_func` operation is a valid multiply operation on the given values for
242	/// all possible packed fields defined on u128.
243	macro_rules! define_multiply_tests {
244		($mult_func:path, $constraint:path) => {
245			$crate::packed_binary_field::test_utils::define_check_packed_mul!(
246				$mult_func,
247				$constraint
248			);
249
250			proptest::proptest! {
251				#[test]
252				fn test_mul_packed_8(a_val in proptest::prelude::any::<u8>(), b_val in proptest::prelude::any::<u8>()) {
253					use $crate::arch::packed_8::*;
254
255					TestMult::<PackedBinaryField8x1b>::test_mul(a_val.into(), b_val.into());
256					TestMult::<PackedBinaryField4x2b>::test_mul(a_val.into(), b_val.into());
257					TestMult::<PackedBinaryField2x4b>::test_mul(a_val.into(), b_val.into());
258					TestMult::<PackedBinaryField1x8b>::test_mul(a_val.into(), b_val.into());
259				}
260
261				#[test]
262				fn test_mul_packed_16(a_val in proptest::prelude::any::<u16>(), b_val in proptest::prelude::any::<u16>()) {
263					use $crate::arch::packed_16::*;
264
265					TestMult::<PackedBinaryField16x1b>::test_mul(a_val.into(), b_val.into());
266					TestMult::<PackedBinaryField8x2b>::test_mul(a_val.into(), b_val.into());
267					TestMult::<PackedBinaryField4x4b>::test_mul(a_val.into(), b_val.into());
268					TestMult::<PackedBinaryField2x8b>::test_mul(a_val.into(), b_val.into());
269					TestMult::<PackedBinaryField1x16b>::test_mul(a_val.into(), b_val.into());
270				}
271
272				#[test]
273				fn test_mul_packed_32(a_val in proptest::prelude::any::<u32>(), b_val in proptest::prelude::any::<u32>()) {
274					use $crate::arch::packed_32::*;
275
276					TestMult::<PackedBinaryField32x1b>::test_mul(a_val.into(), b_val.into());
277					TestMult::<PackedBinaryField16x2b>::test_mul(a_val.into(), b_val.into());
278					TestMult::<PackedBinaryField8x4b>::test_mul(a_val.into(), b_val.into());
279					TestMult::<PackedBinaryField4x8b>::test_mul(a_val.into(), b_val.into());
280					TestMult::<PackedBinaryField2x16b>::test_mul(a_val.into(), b_val.into());
281					TestMult::<PackedBinaryField1x32b>::test_mul(a_val.into(), b_val.into());
282				}
283
284				#[test]
285				fn test_mul_packed_64(a_val in proptest::prelude::any::<u64>(), b_val in proptest::prelude::any::<u64>()) {
286					use $crate::arch::packed_64::*;
287
288					TestMult::<PackedBinaryField64x1b>::test_mul(a_val.into(), b_val.into());
289					TestMult::<PackedBinaryField32x2b>::test_mul(a_val.into(), b_val.into());
290					TestMult::<PackedBinaryField16x4b>::test_mul(a_val.into(), b_val.into());
291					TestMult::<PackedBinaryField8x8b>::test_mul(a_val.into(), b_val.into());
292					TestMult::<PackedBinaryField4x16b>::test_mul(a_val.into(), b_val.into());
293					TestMult::<PackedBinaryField2x32b>::test_mul(a_val.into(), b_val.into());
294					TestMult::<PackedBinaryField1x64b>::test_mul(a_val.into(), b_val.into());
295				}
296
297				#[test]
298				fn test_mul_packed_128(a_val in proptest::prelude::any::<u128>(), b_val in proptest::prelude::any::<u128>()) {
299					use $crate::arch::packed_128::*;
300
301					TestMult::<PackedBinaryField128x1b>::test_mul(a_val.into(), b_val.into());
302					TestMult::<PackedBinaryField64x2b>::test_mul(a_val.into(), b_val.into());
303					TestMult::<PackedBinaryField32x4b>::test_mul(a_val.into(), b_val.into());
304					TestMult::<PackedBinaryField16x8b>::test_mul(a_val.into(), b_val.into());
305					TestMult::<PackedBinaryField8x16b>::test_mul(a_val.into(), b_val.into());
306					TestMult::<PackedBinaryField4x32b>::test_mul(a_val.into(), b_val.into());
307					TestMult::<PackedBinaryField2x64b>::test_mul(a_val.into(), b_val.into());
308					TestMult::<PackedBinaryField1x128b>::test_mul(a_val.into(), b_val.into());
309				}
310
311				#[test]
312				fn test_mul_packed_256(a_val in proptest::prelude::any::<[u128; 2]>(), b_val in proptest::prelude::any::<[u128; 2]>()) {
313					use $crate::arch::packed_256::*;
314
315					TestMult::<PackedBinaryField256x1b>::test_mul(a_val.into(), b_val.into());
316					TestMult::<PackedBinaryField128x2b>::test_mul(a_val.into(), b_val.into());
317					TestMult::<PackedBinaryField64x4b>::test_mul(a_val.into(), b_val.into());
318					TestMult::<PackedBinaryField32x8b>::test_mul(a_val.into(), b_val.into());
319					TestMult::<PackedBinaryField16x16b>::test_mul(a_val.into(), b_val.into());
320					TestMult::<PackedBinaryField8x32b>::test_mul(a_val.into(), b_val.into());
321					TestMult::<PackedBinaryField4x64b>::test_mul(a_val.into(), b_val.into());
322					TestMult::<PackedBinaryField2x128b>::test_mul(a_val.into(), b_val.into());
323				}
324
325				#[test]
326				fn test_mul_packed_512(a_val in proptest::prelude::any::<[u128; 4]>(), b_val in proptest::prelude::any::<[u128; 4]>()) {
327					use $crate::arch::packed_512::*;
328
329					TestMult::<PackedBinaryField512x1b>::test_mul(a_val.into(), b_val.into());
330					TestMult::<PackedBinaryField256x2b>::test_mul(a_val.into(), b_val.into());
331					TestMult::<PackedBinaryField128x4b>::test_mul(a_val.into(), b_val.into());
332					TestMult::<PackedBinaryField64x8b>::test_mul(a_val.into(), b_val.into());
333					TestMult::<PackedBinaryField32x16b>::test_mul(a_val.into(), b_val.into());
334					TestMult::<PackedBinaryField16x32b>::test_mul(a_val.into(), b_val.into());
335					TestMult::<PackedBinaryField8x64b>::test_mul(a_val.into(), b_val.into());
336					TestMult::<PackedBinaryField4x128b>::test_mul(a_val.into(), b_val.into());
337				}
338			}
339		};
340	}
341
342	/// Test if `square_func` operation is a valid square operation on the given value for
343	/// all possible packed fields.
344	macro_rules! define_square_tests {
345		($square_func:path, $constraint:path) => {
346			$crate::packed_binary_field::test_utils::define_check_packed_square!(
347				$square_func,
348				$constraint
349			);
350
351			proptest::proptest! {
352				#[test]
353				fn test_square_packed_8(a_val in proptest::prelude::any::<u8>()) {
354					use $crate::arch::packed_8::*;
355
356					TestSquare::<PackedBinaryField8x1b>::test_square(a_val.into());
357					TestSquare::<PackedBinaryField4x2b>::test_square(a_val.into());
358					TestSquare::<PackedBinaryField2x4b>::test_square(a_val.into());
359					TestSquare::<PackedBinaryField1x8b>::test_square(a_val.into());
360				}
361
362				#[test]
363				fn test_square_packed_16(a_val in proptest::prelude::any::<u16>()) {
364					use $crate::arch::packed_16::*;
365
366					TestSquare::<PackedBinaryField16x1b>::test_square(a_val.into());
367					TestSquare::<PackedBinaryField8x2b>::test_square(a_val.into());
368					TestSquare::<PackedBinaryField4x4b>::test_square(a_val.into());
369					TestSquare::<PackedBinaryField2x8b>::test_square(a_val.into());
370					TestSquare::<PackedBinaryField1x16b>::test_square(a_val.into());
371				}
372
373				#[test]
374				fn test_square_packed_32(a_val in proptest::prelude::any::<u32>()) {
375					use $crate::arch::packed_32::*;
376
377					TestSquare::<PackedBinaryField32x1b>::test_square(a_val.into());
378					TestSquare::<PackedBinaryField16x2b>::test_square(a_val.into());
379					TestSquare::<PackedBinaryField8x4b>::test_square(a_val.into());
380					TestSquare::<PackedBinaryField4x8b>::test_square(a_val.into());
381					TestSquare::<PackedBinaryField2x16b>::test_square(a_val.into());
382					TestSquare::<PackedBinaryField1x32b>::test_square(a_val.into());
383				}
384
385				#[test]
386				fn test_square_packed_64(a_val in proptest::prelude::any::<u64>()) {
387					use $crate::arch::packed_64::*;
388
389					TestSquare::<PackedBinaryField64x1b>::test_square(a_val.into());
390					TestSquare::<PackedBinaryField32x2b>::test_square(a_val.into());
391					TestSquare::<PackedBinaryField16x4b>::test_square(a_val.into());
392					TestSquare::<PackedBinaryField8x8b>::test_square(a_val.into());
393					TestSquare::<PackedBinaryField4x16b>::test_square(a_val.into());
394					TestSquare::<PackedBinaryField2x32b>::test_square(a_val.into());
395					TestSquare::<PackedBinaryField1x64b>::test_square(a_val.into());
396				}
397
398				#[test]
399				fn test_square_packed_128(a_val in proptest::prelude::any::<u128>()) {
400					use $crate::arch::packed_128::*;
401
402					TestSquare::<PackedBinaryField128x1b>::test_square(a_val.into());
403					TestSquare::<PackedBinaryField64x2b>::test_square(a_val.into());
404					TestSquare::<PackedBinaryField32x4b>::test_square(a_val.into());
405					TestSquare::<PackedBinaryField16x8b>::test_square(a_val.into());
406					TestSquare::<PackedBinaryField8x16b>::test_square(a_val.into());
407					TestSquare::<PackedBinaryField4x32b>::test_square(a_val.into());
408					TestSquare::<PackedBinaryField2x64b>::test_square(a_val.into());
409					TestSquare::<PackedBinaryField1x128b>::test_square(a_val.into());
410				}
411
412				#[test]
413				fn test_square_packed_256(a_val in proptest::prelude::any::<[u128; 2]>()) {
414					use $crate::arch::packed_256::*;
415
416					TestSquare::<PackedBinaryField256x1b>::test_square(a_val.into());
417					TestSquare::<PackedBinaryField128x2b>::test_square(a_val.into());
418					TestSquare::<PackedBinaryField64x4b>::test_square(a_val.into());
419					TestSquare::<PackedBinaryField32x8b>::test_square(a_val.into());
420					TestSquare::<PackedBinaryField16x16b>::test_square(a_val.into());
421					TestSquare::<PackedBinaryField8x32b>::test_square(a_val.into());
422					TestSquare::<PackedBinaryField4x64b>::test_square(a_val.into());
423					TestSquare::<PackedBinaryField2x128b>::test_square(a_val.into());
424				}
425
426				#[test]
427				fn test_square_packed_512(a_val in proptest::prelude::any::<[u128; 4]>()) {
428					use $crate::arch::packed_512::*;
429
430					TestSquare::<PackedBinaryField512x1b>::test_square(a_val.into());
431					TestSquare::<PackedBinaryField256x2b>::test_square(a_val.into());
432					TestSquare::<PackedBinaryField128x4b>::test_square(a_val.into());
433					TestSquare::<PackedBinaryField64x8b>::test_square(a_val.into());
434					TestSquare::<PackedBinaryField32x16b>::test_square(a_val.into());
435					TestSquare::<PackedBinaryField16x32b>::test_square(a_val.into());
436					TestSquare::<PackedBinaryField8x64b>::test_square(a_val.into());
437					TestSquare::<PackedBinaryField4x128b>::test_square(a_val.into());
438				}
439			}
440		};
441	}
442
443	/// Test if `invert_func` operation is a valid invert operation on the given value for
444	/// all possible packed fields.
445	macro_rules! define_invert_tests {
446		($invert_func:path, $constraint:path) => {
447			$crate::packed_binary_field::test_utils::define_check_packed_inverse!(
448				$invert_func,
449				$constraint
450			);
451
452			proptest::proptest! {
453				#[test]
454				fn test_invert_packed_8(a_val in proptest::prelude::any::<u8>()) {
455					use $crate::arch::packed_8::*;
456
457					TestInvert::<PackedBinaryField8x1b>::test_invert(a_val.into());
458					TestInvert::<PackedBinaryField4x2b>::test_invert(a_val.into());
459					TestInvert::<PackedBinaryField2x4b>::test_invert(a_val.into());
460					TestInvert::<PackedBinaryField1x8b>::test_invert(a_val.into());
461				}
462
463				#[test]
464				fn test_invert_packed_16(a_val in proptest::prelude::any::<u16>()) {
465					use $crate::arch::packed_16::*;
466
467					TestInvert::<PackedBinaryField16x1b>::test_invert(a_val.into());
468					TestInvert::<PackedBinaryField8x2b>::test_invert(a_val.into());
469					TestInvert::<PackedBinaryField4x4b>::test_invert(a_val.into());
470					TestInvert::<PackedBinaryField2x8b>::test_invert(a_val.into());
471					TestInvert::<PackedBinaryField1x16b>::test_invert(a_val.into());
472				}
473
474				#[test]
475				fn test_invert_packed_32(a_val in proptest::prelude::any::<u32>()) {
476					use $crate::arch::packed_32::*;
477
478					TestInvert::<PackedBinaryField32x1b>::test_invert(a_val.into());
479					TestInvert::<PackedBinaryField16x2b>::test_invert(a_val.into());
480					TestInvert::<PackedBinaryField8x4b>::test_invert(a_val.into());
481					TestInvert::<PackedBinaryField4x8b>::test_invert(a_val.into());
482					TestInvert::<PackedBinaryField2x16b>::test_invert(a_val.into());
483					TestInvert::<PackedBinaryField1x32b>::test_invert(a_val.into());
484				}
485
486				#[test]
487				fn test_invert_packed_64(a_val in proptest::prelude::any::<u64>()) {
488					use $crate::arch::packed_64::*;
489
490					TestInvert::<PackedBinaryField64x1b>::test_invert(a_val.into());
491					TestInvert::<PackedBinaryField32x2b>::test_invert(a_val.into());
492					TestInvert::<PackedBinaryField16x4b>::test_invert(a_val.into());
493					TestInvert::<PackedBinaryField8x8b>::test_invert(a_val.into());
494					TestInvert::<PackedBinaryField4x16b>::test_invert(a_val.into());
495					TestInvert::<PackedBinaryField2x32b>::test_invert(a_val.into());
496					TestInvert::<PackedBinaryField1x64b>::test_invert(a_val.into());
497				}
498
499				#[test]
500				fn test_invert_packed_128(a_val in proptest::prelude::any::<u128>()) {
501					use $crate::arch::packed_128::*;
502
503					TestInvert::<PackedBinaryField128x1b>::test_invert(a_val.into());
504					TestInvert::<PackedBinaryField64x2b>::test_invert(a_val.into());
505					TestInvert::<PackedBinaryField32x4b>::test_invert(a_val.into());
506					TestInvert::<PackedBinaryField16x8b>::test_invert(a_val.into());
507					TestInvert::<PackedBinaryField8x16b>::test_invert(a_val.into());
508					TestInvert::<PackedBinaryField4x32b>::test_invert(a_val.into());
509					TestInvert::<PackedBinaryField2x64b>::test_invert(a_val.into());
510					TestInvert::<PackedBinaryField1x128b>::test_invert(a_val.into());
511				}
512
513				#[test]
514				fn test_invert_packed_256(a_val in proptest::prelude::any::<[u128; 2]>()) {
515					use $crate::arch::packed_256::*;
516
517					TestInvert::<PackedBinaryField256x1b>::test_invert(a_val.into());
518					TestInvert::<PackedBinaryField128x2b>::test_invert(a_val.into());
519					TestInvert::<PackedBinaryField64x4b>::test_invert(a_val.into());
520					TestInvert::<PackedBinaryField32x8b>::test_invert(a_val.into());
521					TestInvert::<PackedBinaryField16x16b>::test_invert(a_val.into());
522					TestInvert::<PackedBinaryField8x32b>::test_invert(a_val.into());
523					TestInvert::<PackedBinaryField4x64b>::test_invert(a_val.into());
524					TestInvert::<PackedBinaryField2x128b>::test_invert(a_val.into());
525				}
526
527				#[test]
528				fn test_invert_packed_512(a_val in proptest::prelude::any::<[u128; 4]>()) {
529					use $crate::arch::packed_512::*;
530
531					TestInvert::<PackedBinaryField512x1b>::test_invert(a_val.into());
532					TestInvert::<PackedBinaryField256x2b>::test_invert(a_val.into());
533					TestInvert::<PackedBinaryField128x4b>::test_invert(a_val.into());
534					TestInvert::<PackedBinaryField64x8b>::test_invert(a_val.into());
535					TestInvert::<PackedBinaryField32x16b>::test_invert(a_val.into());
536					TestInvert::<PackedBinaryField16x32b>::test_invert(a_val.into());
537					TestInvert::<PackedBinaryField8x64b>::test_invert(a_val.into());
538					TestInvert::<PackedBinaryField4x128b>::test_invert(a_val.into());
539				}
540			}
541		};
542	}
543
544	/// Test if `mul_alpha_func` operation is a valid multiply by alpha operation on the given value for
545	/// all possible packed fields.
546	macro_rules! define_mul_alpha_tests {
547		($mul_alpha_func:path, $constraint:path) => {
548			$crate::packed_binary_field::test_utils::define_check_packed_mul_alpha!(
549				$mul_alpha_func,
550				$constraint
551			);
552
553			proptest::proptest! {
554				#[test]
555				fn test_mul_alpha_packed_8(a_val in proptest::prelude::any::<u8>()) {
556					use $crate::arch::packed_8::*;
557
558					TestMulAlpha::<PackedBinaryField8x1b>::test_mul_alpha(a_val.into());
559					TestMulAlpha::<PackedBinaryField4x2b>::test_mul_alpha(a_val.into());
560					TestMulAlpha::<PackedBinaryField2x4b>::test_mul_alpha(a_val.into());
561					TestMulAlpha::<PackedBinaryField1x8b>::test_mul_alpha(a_val.into());
562				}
563
564				#[test]
565				fn test_mul_alpha_packed_16(a_val in proptest::prelude::any::<u16>()) {
566					use $crate::arch::packed_16::*;
567
568					TestMulAlpha::<PackedBinaryField16x1b>::test_mul_alpha(a_val.into());
569					TestMulAlpha::<PackedBinaryField8x2b>::test_mul_alpha(a_val.into());
570					TestMulAlpha::<PackedBinaryField4x4b>::test_mul_alpha(a_val.into());
571					TestMulAlpha::<PackedBinaryField2x8b>::test_mul_alpha(a_val.into());
572					TestMulAlpha::<PackedBinaryField1x16b>::test_mul_alpha(a_val.into());
573				}
574
575				#[test]
576				fn test_mul_alpha_packed_32(a_val in proptest::prelude::any::<u32>()) {
577					use $crate::arch::packed_32::*;
578
579					TestMulAlpha::<PackedBinaryField32x1b>::test_mul_alpha(a_val.into());
580					TestMulAlpha::<PackedBinaryField16x2b>::test_mul_alpha(a_val.into());
581					TestMulAlpha::<PackedBinaryField8x4b>::test_mul_alpha(a_val.into());
582					TestMulAlpha::<PackedBinaryField4x8b>::test_mul_alpha(a_val.into());
583					TestMulAlpha::<PackedBinaryField2x16b>::test_mul_alpha(a_val.into());
584					TestMulAlpha::<PackedBinaryField1x32b>::test_mul_alpha(a_val.into());
585				}
586
587				#[test]
588				fn test_mul_alpha_packed_64(a_val in proptest::prelude::any::<u64>()) {
589					use $crate::arch::packed_64::*;
590
591					TestMulAlpha::<PackedBinaryField64x1b>::test_mul_alpha(a_val.into());
592					TestMulAlpha::<PackedBinaryField32x2b>::test_mul_alpha(a_val.into());
593					TestMulAlpha::<PackedBinaryField16x4b>::test_mul_alpha(a_val.into());
594					TestMulAlpha::<PackedBinaryField8x8b>::test_mul_alpha(a_val.into());
595					TestMulAlpha::<PackedBinaryField4x16b>::test_mul_alpha(a_val.into());
596					TestMulAlpha::<PackedBinaryField2x32b>::test_mul_alpha(a_val.into());
597					TestMulAlpha::<PackedBinaryField1x64b>::test_mul_alpha(a_val.into());
598				}
599
600				#[test]
601				fn test_mul_alpha_packed_128(a_val in proptest::prelude::any::<u128>()) {
602					use $crate::arch::packed_128::*;
603
604					TestMulAlpha::<PackedBinaryField128x1b>::test_mul_alpha(a_val.into());
605					TestMulAlpha::<PackedBinaryField64x2b>::test_mul_alpha(a_val.into());
606					TestMulAlpha::<PackedBinaryField32x4b>::test_mul_alpha(a_val.into());
607					TestMulAlpha::<PackedBinaryField16x8b>::test_mul_alpha(a_val.into());
608					TestMulAlpha::<PackedBinaryField8x16b>::test_mul_alpha(a_val.into());
609					TestMulAlpha::<PackedBinaryField4x32b>::test_mul_alpha(a_val.into());
610					TestMulAlpha::<PackedBinaryField2x64b>::test_mul_alpha(a_val.into());
611					TestMulAlpha::<PackedBinaryField1x128b>::test_mul_alpha(a_val.into());
612				}
613
614				#[test]
615				fn test_mul_alpha_packed_256(a_val in proptest::prelude::any::<[u128; 2]>()) {
616					use $crate::arch::packed_256::*;
617
618					TestMulAlpha::<PackedBinaryField256x1b>::test_mul_alpha(a_val.into());
619					TestMulAlpha::<PackedBinaryField128x2b>::test_mul_alpha(a_val.into());
620					TestMulAlpha::<PackedBinaryField64x4b>::test_mul_alpha(a_val.into());
621					TestMulAlpha::<PackedBinaryField32x8b>::test_mul_alpha(a_val.into());
622					TestMulAlpha::<PackedBinaryField16x16b>::test_mul_alpha(a_val.into());
623					TestMulAlpha::<PackedBinaryField8x32b>::test_mul_alpha(a_val.into());
624					TestMulAlpha::<PackedBinaryField4x64b>::test_mul_alpha(a_val.into());
625					TestMulAlpha::<PackedBinaryField2x128b>::test_mul_alpha(a_val.into());
626				}
627
628				#[test]
629				fn test_mul_alpha_packed_512(a_val in proptest::prelude::any::<[u128; 4]>()) {
630					use $crate::arch::packed_512::*;
631
632					TestMulAlpha::<PackedBinaryField512x1b>::test_mul_alpha(a_val.into());
633					TestMulAlpha::<PackedBinaryField256x2b>::test_mul_alpha(a_val.into());
634					TestMulAlpha::<PackedBinaryField128x4b>::test_mul_alpha(a_val.into());
635					TestMulAlpha::<PackedBinaryField64x8b>::test_mul_alpha(a_val.into());
636					TestMulAlpha::<PackedBinaryField32x16b>::test_mul_alpha(a_val.into());
637					TestMulAlpha::<PackedBinaryField16x32b>::test_mul_alpha(a_val.into());
638					TestMulAlpha::<PackedBinaryField8x64b>::test_mul_alpha(a_val.into());
639					TestMulAlpha::<PackedBinaryField4x128b>::test_mul_alpha(a_val.into());
640				}
641			}
642		};
643	}
644
645	/// Test if `$constraint::make_packed_transformation` operation creates a valid transformation operation on the given value for
646	/// all possible packed fields.
647	macro_rules! define_transformation_tests {
648		($constraint:path) => {
649			$crate::packed_binary_field::test_utils::define_check_packed_transformation!(
650				$constraint
651			);
652
653			proptest::proptest! {
654				#[test]
655				fn test_transformation_packed_1(a_val in 0..2u8) {
656					use crate::arch::packed_1::*;
657
658					TestTransformation::<PackedBinaryField1x1b>::test_transformation($crate::underlier::U1::new_unchecked(a_val).into());
659				}
660
661				#[test]
662				fn test_transformation_packed_2(a_val in 0..4u8) {
663					use crate::arch::packed_2::*;
664
665					TestTransformation::<PackedBinaryField2x1b>::test_transformation($crate::underlier::U2::new_unchecked(a_val).into());
666					TestTransformation::<PackedBinaryField1x2b>::test_transformation($crate::underlier::U2::new_unchecked(a_val).into());
667				}
668
669				#[test]
670				fn test_transformation_packed_4(a_val in 0..16u8) {
671					use crate::arch::packed_4::*;
672
673					TestTransformation::<PackedBinaryField4x1b>::test_transformation($crate::underlier::U4::new_unchecked(a_val).into());
674					TestTransformation::<PackedBinaryField2x2b>::test_transformation($crate::underlier::U4::new_unchecked(a_val).into());
675					TestTransformation::<PackedBinaryField1x4b>::test_transformation($crate::underlier::U4::new_unchecked(a_val).into());
676				}
677
678				#[test]
679				fn test_transformation_packed_8(a_val in proptest::prelude::any::<u8>()) {
680					use crate::arch::packed_8::*;
681
682					TestTransformation::<PackedBinaryField8x1b>::test_transformation(a_val.into());
683					TestTransformation::<PackedBinaryField4x2b>::test_transformation(a_val.into());
684					TestTransformation::<PackedBinaryField2x4b>::test_transformation(a_val.into());
685					TestTransformation::<PackedBinaryField1x8b>::test_transformation(a_val.into());
686				}
687
688				#[test]
689				fn test_transformation_packed_16(a_val in proptest::prelude::any::<u16>()) {
690					use crate::arch::packed_16::*;
691
692					TestTransformation::<PackedBinaryField16x1b>::test_transformation(a_val.into());
693					TestTransformation::<PackedBinaryField8x2b>::test_transformation(a_val.into());
694					TestTransformation::<PackedBinaryField4x4b>::test_transformation(a_val.into());
695					TestTransformation::<PackedBinaryField2x8b>::test_transformation(a_val.into());
696					TestTransformation::<PackedBinaryField1x16b>::test_transformation(a_val.into());
697				}
698
699				#[test]
700				fn test_transformation_packed_32(a_val in proptest::prelude::any::<u32>()) {
701					use crate::arch::packed_32::*;
702
703					TestTransformation::<PackedBinaryField32x1b>::test_transformation(a_val.into());
704					TestTransformation::<PackedBinaryField16x2b>::test_transformation(a_val.into());
705					TestTransformation::<PackedBinaryField8x4b>::test_transformation(a_val.into());
706					TestTransformation::<PackedBinaryField4x8b>::test_transformation(a_val.into());
707					TestTransformation::<PackedBinaryField2x16b>::test_transformation(a_val.into());
708					TestTransformation::<PackedBinaryField1x32b>::test_transformation(a_val.into());
709				}
710
711				#[test]
712				fn test_transformation_packed_64(a_val in proptest::prelude::any::<u64>()) {
713					use $crate::arch::packed_64::*;
714
715					TestTransformation::<PackedBinaryField64x1b>::test_transformation(a_val.into());
716					TestTransformation::<PackedBinaryField32x2b>::test_transformation(a_val.into());
717					TestTransformation::<PackedBinaryField16x4b>::test_transformation(a_val.into());
718					TestTransformation::<PackedBinaryField8x8b>::test_transformation(a_val.into());
719					TestTransformation::<PackedBinaryField4x16b>::test_transformation(a_val.into());
720					TestTransformation::<PackedBinaryField2x32b>::test_transformation(a_val.into());
721					TestTransformation::<PackedBinaryField1x64b>::test_transformation(a_val.into());
722				}
723
724				#[test]
725				fn test_transformation_packed_128(a_val in proptest::prelude::any::<u128>()) {
726					use $crate::arch::packed_128::*;
727
728					TestTransformation::<PackedBinaryField128x1b>::test_transformation(a_val.into());
729					TestTransformation::<PackedBinaryField64x2b>::test_transformation(a_val.into());
730					TestTransformation::<PackedBinaryField32x4b>::test_transformation(a_val.into());
731					TestTransformation::<PackedBinaryField16x8b>::test_transformation(a_val.into());
732					TestTransformation::<PackedBinaryField8x16b>::test_transformation(a_val.into());
733					TestTransformation::<PackedBinaryField4x32b>::test_transformation(a_val.into());
734					TestTransformation::<PackedBinaryField2x64b>::test_transformation(a_val.into());
735					TestTransformation::<PackedBinaryField1x128b>::test_transformation(a_val.into());
736				}
737
738				#[test]
739				fn test_transformation_packed_256(a_val in proptest::prelude::any::<[u128; 2]>()) {
740					use $crate::arch::packed_256::*;
741
742					TestTransformation::<PackedBinaryField256x1b>::test_transformation(a_val.into());
743					TestTransformation::<PackedBinaryField128x2b>::test_transformation(a_val.into());
744					TestTransformation::<PackedBinaryField64x4b>::test_transformation(a_val.into());
745					TestTransformation::<PackedBinaryField32x8b>::test_transformation(a_val.into());
746					TestTransformation::<PackedBinaryField16x16b>::test_transformation(a_val.into());
747					TestTransformation::<PackedBinaryField8x32b>::test_transformation(a_val.into());
748					TestTransformation::<PackedBinaryField4x64b>::test_transformation(a_val.into());
749					TestTransformation::<PackedBinaryField2x128b>::test_transformation(a_val.into());
750				}
751
752				#[test]
753				fn test_transformation_packed_512(a_val in proptest::prelude::any::<[u128; 4]>()) {
754					use $crate::arch::packed_512::*;
755
756					TestTransformation::<PackedBinaryField512x1b>::test_transformation(a_val.into());
757					TestTransformation::<PackedBinaryField256x2b>::test_transformation(a_val.into());
758					TestTransformation::<PackedBinaryField128x4b>::test_transformation(a_val.into());
759					TestTransformation::<PackedBinaryField64x8b>::test_transformation(a_val.into());
760					TestTransformation::<PackedBinaryField32x16b>::test_transformation(a_val.into());
761					TestTransformation::<PackedBinaryField16x32b>::test_transformation(a_val.into());
762					TestTransformation::<PackedBinaryField8x64b>::test_transformation(a_val.into());
763					TestTransformation::<PackedBinaryField4x128b>::test_transformation(a_val.into());
764				}
765			}
766		};
767	}
768
769	pub(crate) use define_invert_tests;
770	pub(crate) use define_mul_alpha_tests;
771	pub(crate) use define_multiply_tests;
772	pub(crate) use define_square_tests;
773	pub(crate) use define_transformation_tests;
774
775	/// Helper function for compile-time checks
776	#[allow(unused)]
777	pub const fn implements_transformation_factory<
778		P1: PackedField<Scalar: BinaryField>,
779		P2: PackedTransformationFactory<P1>,
780	>() {
781	}
782
783	pub fn check_interleave<P: PackedField + WithUnderlier>(
784		lhs: P::Underlier,
785		rhs: P::Underlier,
786		log_block_len: usize,
787	) {
788		let lhs = P::from_underlier(lhs);
789		let rhs = P::from_underlier(rhs);
790		let (a, b) = lhs.interleave(rhs, log_block_len);
791		let block_len = 1 << log_block_len;
792		for i in (0..P::WIDTH).step_by(block_len * 2) {
793			for j in 0..block_len {
794				assert_eq!(a.get(i + j), lhs.get(i + j));
795				assert_eq!(a.get(i + j + block_len), rhs.get(i + j));
796
797				assert_eq!(b.get(i + j), lhs.get(i + j + block_len));
798				assert_eq!(b.get(i + j + block_len), rhs.get(i + j + block_len));
799			}
800		}
801	}
802
803	pub fn check_interleave_all_heights<P: PackedField + WithUnderlier>(
804		lhs: P::Underlier,
805		rhs: P::Underlier,
806	) {
807		for log_block_len in 0..P::LOG_WIDTH {
808			check_interleave::<P>(lhs, rhs, log_block_len);
809		}
810	}
811
812	pub fn check_unzip<P: PackedField + WithUnderlier>(
813		lhs: P::Underlier,
814		rhs: P::Underlier,
815		log_block_len: usize,
816	) {
817		let lhs = P::from_underlier(lhs);
818		let rhs = P::from_underlier(rhs);
819		let block_len = 1 << log_block_len;
820		let (a, b) = lhs.unzip(rhs, log_block_len);
821		for i in (0..P::WIDTH / 2).step_by(block_len) {
822			for j in 0..block_len {
823				assert_eq!(
824					a.get(i + j),
825					lhs.get(2 * i + j),
826					"i: {}, j: {}, log_block_len: {}, P: {:?}",
827					i,
828					j,
829					log_block_len,
830					P::zero()
831				);
832				assert_eq!(
833					b.get(i + j),
834					lhs.get(2 * i + j + block_len),
835					"i: {}, j: {}, log_block_len: {}, P: {:?}",
836					i,
837					j,
838					log_block_len,
839					P::zero()
840				);
841			}
842		}
843
844		for i in (0..P::WIDTH / 2).step_by(block_len) {
845			for j in 0..block_len {
846				assert_eq!(
847					a.get(i + j + P::WIDTH / 2),
848					rhs.get(2 * i + j),
849					"i: {}, j: {}, log_block_len: {}, P: {:?}",
850					i,
851					j,
852					log_block_len,
853					P::zero()
854				);
855				assert_eq!(b.get(i + j + P::WIDTH / 2), rhs.get(2 * i + j + block_len));
856			}
857		}
858	}
859
860	pub fn check_transpose_all_heights<P: PackedField + WithUnderlier>(
861		lhs: P::Underlier,
862		rhs: P::Underlier,
863	) {
864		for log_block_len in 0..P::LOG_WIDTH {
865			check_unzip::<P>(lhs, rhs, log_block_len);
866		}
867	}
868}
869
870#[cfg(test)]
871mod tests {
872	use std::{iter::repeat_with, ops::Mul, slice};
873
874	use proptest::prelude::*;
875	use rand::{rngs::StdRng, thread_rng, SeedableRng};
876	use test_utils::{check_interleave_all_heights, implements_transformation_factory};
877
878	use super::{
879		test_utils::{
880			define_invert_tests, define_mul_alpha_tests, define_multiply_tests,
881			define_square_tests, define_transformation_tests,
882		},
883		*,
884	};
885	use crate::{
886		arch::{
887			packed_aes_128::*, packed_aes_16::*, packed_aes_256::*, packed_aes_32::*,
888			packed_aes_512::*, packed_aes_64::*,
889		},
890		arithmetic_traits::MulAlpha,
891		linear_transformation::PackedTransformationFactory,
892		test_utils::check_transpose_all_heights,
893		underlier::{U2, U4},
894		Field, PackedField, PackedFieldIndexable,
895	};
896
897	fn test_add_packed<P: PackedField + From<u128>>(a_val: u128, b_val: u128) {
898		let a = P::from(a_val);
899		let b = P::from(b_val);
900		let c = a + b;
901		for i in 0..P::WIDTH {
902			assert_eq!(c.get(i), a.get(i) + b.get(i));
903		}
904	}
905
906	fn test_mul_packed<P: PackedField>(a: P, b: P) {
907		let c = a * b;
908		for i in 0..P::WIDTH {
909			assert_eq!(c.get(i), a.get(i) * b.get(i));
910		}
911	}
912
913	fn test_mul_packed_random<P: PackedField>(mut rng: impl Rng) {
914		test_mul_packed(P::random(&mut rng), P::random(&mut rng))
915	}
916
917	fn test_set_then_get<P: PackedField>() {
918		let mut rng = StdRng::seed_from_u64(0);
919		let mut elem = P::random(&mut rng);
920
921		let scalars = repeat_with(|| Field::random(&mut rng))
922			.take(P::WIDTH)
923			.collect::<Vec<P::Scalar>>();
924
925		for (i, val) in scalars.iter().enumerate() {
926			elem.set(i, *val);
927		}
928		for (i, val) in scalars.iter().enumerate() {
929			assert_eq!(elem.get(i), *val);
930		}
931	}
932
933	fn test_elements_order<P: PackedFieldIndexable>() {
934		let mut rng = StdRng::seed_from_u64(0);
935		let packed = P::random(&mut rng);
936		let scalars = P::unpack_scalars(slice::from_ref(&packed));
937		for (i, val) in scalars.iter().enumerate() {
938			assert_eq!(packed.get(i), *val, "index: {i}");
939		}
940	}
941
942	#[test]
943	fn test_set_then_get_4b() {
944		test_set_then_get::<PackedBinaryField32x4b>();
945		test_set_then_get::<PackedBinaryField64x4b>();
946		test_set_then_get::<PackedBinaryField128x4b>();
947	}
948
949	#[test]
950	fn test_set_then_get_32b() {
951		test_set_then_get::<PackedBinaryField4x32b>();
952		test_set_then_get::<PackedBinaryField8x32b>();
953		test_set_then_get::<PackedBinaryField16x32b>();
954
955		test_elements_order::<PackedBinaryField4x32b>();
956		test_elements_order::<PackedBinaryField8x32b>();
957		test_elements_order::<PackedBinaryField16x32b>();
958	}
959
960	#[test]
961	fn test_set_then_get_64b() {
962		test_set_then_get::<PackedBinaryField2x64b>();
963		test_set_then_get::<PackedBinaryField4x64b>();
964		test_set_then_get::<PackedBinaryField8x64b>();
965
966		test_elements_order::<PackedBinaryField2x64b>();
967		test_elements_order::<PackedBinaryField4x64b>();
968		test_elements_order::<PackedBinaryField8x64b>();
969	}
970
971	#[test]
972	fn test_set_then_get_128b() {
973		test_set_then_get::<PackedBinaryField1x128b>();
974		test_set_then_get::<PackedBinaryField2x128b>();
975		test_set_then_get::<PackedBinaryField4x128b>();
976
977		test_elements_order::<PackedBinaryField1x128b>();
978		test_elements_order::<PackedBinaryField2x128b>();
979		test_elements_order::<PackedBinaryField4x128b>();
980	}
981
982	// TODO: Generate lots more proptests using macros
983	proptest! {
984		#[test]
985		fn test_add_packed_128x1b(a_val in any::<u128>(), b_val in any::<u128>()) {
986			test_add_packed::<PackedBinaryField128x1b>(a_val, b_val)
987		}
988
989		#[test]
990		fn test_add_packed_16x8b(a_val in any::<u128>(), b_val in any::<u128>()) {
991			test_add_packed::<PackedBinaryField16x8b>(a_val, b_val)
992		}
993
994		#[test]
995		fn test_add_packed_8x16b(a_val in any::<u128>(), b_val in any::<u128>()) {
996			test_add_packed::<PackedBinaryField8x16b>(a_val, b_val)
997		}
998
999		#[test]
1000		fn test_add_packed_4x32b(a_val in any::<u128>(), b_val in any::<u128>()) {
1001			test_add_packed::<PackedBinaryField4x32b>(a_val, b_val)
1002		}
1003
1004		#[test]
1005		fn test_add_packed_2x64b(a_val in any::<u128>(), b_val in any::<u128>()) {
1006			test_add_packed::<PackedBinaryField2x64b>(a_val, b_val)
1007		}
1008
1009		#[test]
1010		fn test_add_packed_1x128b(a_val in any::<u128>(), b_val in any::<u128>()) {
1011			test_add_packed::<PackedBinaryField1x128b>(a_val, b_val)
1012		}
1013	}
1014
1015	#[test]
1016	fn test_mul_packed_256x1b() {
1017		test_mul_packed_random::<PackedBinaryField256x1b>(thread_rng())
1018	}
1019
1020	#[test]
1021	fn test_mul_packed_32x8b() {
1022		test_mul_packed_random::<PackedBinaryField32x8b>(thread_rng())
1023	}
1024
1025	#[test]
1026	fn test_mul_packed_16x16b() {
1027		test_mul_packed_random::<PackedBinaryField16x16b>(thread_rng())
1028	}
1029
1030	#[test]
1031	fn test_mul_packed_8x32b() {
1032		test_mul_packed_random::<PackedBinaryField8x32b>(thread_rng())
1033	}
1034
1035	#[test]
1036	fn test_mul_packed_4x64b() {
1037		test_mul_packed_random::<PackedBinaryField4x64b>(thread_rng())
1038	}
1039
1040	#[test]
1041	fn test_mul_packed_2x128b() {
1042		test_mul_packed_random::<PackedBinaryField2x128b>(thread_rng())
1043	}
1044
1045	#[test]
1046	fn test_iter_size_hint() {
1047		assert_valid_iterator_with_exact_size_hint::<crate::BinaryField128b>();
1048		assert_valid_iterator_with_exact_size_hint::<crate::BinaryField32b>();
1049		assert_valid_iterator_with_exact_size_hint::<crate::BinaryField1b>();
1050		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField128x1b>();
1051		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField64x2b>();
1052		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField32x4b>();
1053		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField16x16b>();
1054		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField8x32b>();
1055		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField4x64b>();
1056	}
1057
1058	fn assert_valid_iterator_with_exact_size_hint<P: PackedField>() {
1059		assert_eq!(P::default().iter().size_hint(), (P::WIDTH, Some(P::WIDTH)));
1060		assert_eq!(P::default().into_iter().size_hint(), (P::WIDTH, Some(P::WIDTH)));
1061		assert_eq!(P::default().iter().count(), P::WIDTH);
1062		assert_eq!(P::default().into_iter().count(), P::WIDTH);
1063	}
1064
1065	define_multiply_tests!(Mul::mul, PackedField);
1066
1067	define_square_tests!(PackedField::square, PackedField);
1068
1069	define_invert_tests!(PackedField::invert_or_zero, PackedField);
1070
1071	define_mul_alpha_tests!(MulAlpha::mul_alpha, MulAlpha);
1072
1073	#[allow(unused)]
1074	trait SelfTransformationFactory: PackedTransformationFactory<Self> {}
1075
1076	impl<T: PackedTransformationFactory<T>> SelfTransformationFactory for T {}
1077
1078	define_transformation_tests!(SelfTransformationFactory);
1079
1080	/// Compile-time test to ensure packed fields implement `PackedTransformationFactory`.
1081	#[allow(unused)]
1082	const fn test_implement_transformation_factory() {
1083		// 1 bit packed binary tower
1084		implements_transformation_factory::<PackedBinaryField1x1b, PackedBinaryField1x1b>();
1085
1086		// 2 bit packed binary tower
1087		implements_transformation_factory::<PackedBinaryField2x1b, PackedBinaryField2x1b>();
1088		implements_transformation_factory::<PackedBinaryField1x2b, PackedBinaryField1x2b>();
1089
1090		// 4 bit packed binary tower
1091		implements_transformation_factory::<PackedBinaryField4x1b, PackedBinaryField4x1b>();
1092		implements_transformation_factory::<PackedBinaryField2x2b, PackedBinaryField2x2b>();
1093		implements_transformation_factory::<PackedBinaryField1x4b, PackedBinaryField1x4b>();
1094
1095		// 8 bit packed binary tower
1096		implements_transformation_factory::<PackedBinaryField8x1b, PackedBinaryField8x1b>();
1097		implements_transformation_factory::<PackedBinaryField4x2b, PackedBinaryField4x2b>();
1098		implements_transformation_factory::<PackedBinaryField2x4b, PackedBinaryField2x4b>();
1099		implements_transformation_factory::<PackedBinaryField1x8b, PackedBinaryField1x8b>();
1100
1101		// 16 bit packed binary tower
1102		implements_transformation_factory::<PackedBinaryField16x1b, PackedBinaryField16x1b>();
1103		implements_transformation_factory::<PackedBinaryField8x2b, PackedBinaryField8x2b>();
1104		implements_transformation_factory::<PackedBinaryField4x4b, PackedBinaryField4x4b>();
1105		implements_transformation_factory::<PackedBinaryField2x8b, PackedBinaryField2x8b>();
1106		implements_transformation_factory::<PackedAESBinaryField2x8b, PackedBinaryField2x8b>();
1107		implements_transformation_factory::<PackedBinaryField1x16b, PackedBinaryField1x16b>();
1108		implements_transformation_factory::<PackedAESBinaryField1x16b, PackedBinaryField1x16b>();
1109
1110		// 32 bit packed binary tower
1111		implements_transformation_factory::<PackedBinaryField32x1b, PackedBinaryField32x1b>();
1112		implements_transformation_factory::<PackedBinaryField16x2b, PackedBinaryField16x2b>();
1113		implements_transformation_factory::<PackedBinaryField8x4b, PackedBinaryField8x4b>();
1114		implements_transformation_factory::<PackedBinaryField4x8b, PackedBinaryField4x8b>();
1115		implements_transformation_factory::<PackedAESBinaryField4x8b, PackedBinaryField4x8b>();
1116		implements_transformation_factory::<PackedBinaryField2x16b, PackedBinaryField2x16b>();
1117		implements_transformation_factory::<PackedAESBinaryField2x16b, PackedBinaryField2x16b>();
1118		implements_transformation_factory::<PackedBinaryField1x32b, PackedBinaryField1x32b>();
1119		implements_transformation_factory::<PackedAESBinaryField1x32b, PackedBinaryField1x32b>();
1120
1121		// 64 bit packed binary tower
1122		implements_transformation_factory::<PackedBinaryField64x1b, PackedBinaryField64x1b>();
1123		implements_transformation_factory::<PackedBinaryField32x2b, PackedBinaryField32x2b>();
1124		implements_transformation_factory::<PackedBinaryField16x4b, PackedBinaryField16x4b>();
1125		implements_transformation_factory::<PackedBinaryField8x8b, PackedBinaryField8x8b>();
1126		implements_transformation_factory::<PackedAESBinaryField8x8b, PackedBinaryField8x8b>();
1127		implements_transformation_factory::<PackedBinaryField4x16b, PackedBinaryField4x16b>();
1128		implements_transformation_factory::<PackedAESBinaryField4x16b, PackedBinaryField4x16b>();
1129		implements_transformation_factory::<PackedBinaryField2x32b, PackedBinaryField2x32b>();
1130		implements_transformation_factory::<PackedAESBinaryField2x32b, PackedBinaryField2x32b>();
1131		implements_transformation_factory::<PackedBinaryField1x64b, PackedBinaryField1x64b>();
1132		implements_transformation_factory::<PackedAESBinaryField1x64b, PackedBinaryField1x64b>();
1133
1134		// 128 bit packed binary tower
1135		implements_transformation_factory::<PackedBinaryField128x1b, PackedBinaryField128x1b>();
1136		implements_transformation_factory::<PackedBinaryField64x2b, PackedBinaryField64x2b>();
1137		implements_transformation_factory::<PackedBinaryField32x4b, PackedBinaryField32x4b>();
1138		implements_transformation_factory::<PackedBinaryField16x8b, PackedBinaryField16x8b>();
1139		implements_transformation_factory::<PackedAESBinaryField16x8b, PackedBinaryField16x8b>();
1140		implements_transformation_factory::<PackedBinaryField8x16b, PackedBinaryField8x16b>();
1141		implements_transformation_factory::<PackedAESBinaryField8x16b, PackedBinaryField8x16b>();
1142		implements_transformation_factory::<PackedBinaryField4x32b, PackedBinaryField4x32b>();
1143		implements_transformation_factory::<PackedAESBinaryField4x32b, PackedBinaryField4x32b>();
1144		implements_transformation_factory::<PackedBinaryField2x64b, PackedBinaryField2x64b>();
1145		implements_transformation_factory::<PackedAESBinaryField2x64b, PackedBinaryField2x64b>();
1146		implements_transformation_factory::<PackedBinaryField1x128b, PackedBinaryField1x128b>();
1147		implements_transformation_factory::<PackedAESBinaryField1x128b, PackedBinaryField1x128b>();
1148
1149		// 256 bit packed binary tower
1150		implements_transformation_factory::<PackedBinaryField256x1b, PackedBinaryField256x1b>();
1151		implements_transformation_factory::<PackedBinaryField128x2b, PackedBinaryField128x2b>();
1152		implements_transformation_factory::<PackedBinaryField64x4b, PackedBinaryField64x4b>();
1153		implements_transformation_factory::<PackedBinaryField32x8b, PackedBinaryField32x8b>();
1154		implements_transformation_factory::<PackedAESBinaryField32x8b, PackedBinaryField32x8b>();
1155		implements_transformation_factory::<PackedBinaryField16x16b, PackedBinaryField16x16b>();
1156		implements_transformation_factory::<PackedAESBinaryField16x16b, PackedBinaryField16x16b>();
1157		implements_transformation_factory::<PackedBinaryField8x32b, PackedBinaryField8x32b>();
1158		implements_transformation_factory::<PackedAESBinaryField8x32b, PackedBinaryField8x32b>();
1159		implements_transformation_factory::<PackedBinaryField4x64b, PackedBinaryField4x64b>();
1160		implements_transformation_factory::<PackedAESBinaryField4x64b, PackedBinaryField4x64b>();
1161		implements_transformation_factory::<PackedBinaryField2x128b, PackedBinaryField2x128b>();
1162		implements_transformation_factory::<PackedAESBinaryField2x128b, PackedBinaryField2x128b>();
1163
1164		// 512 bit packed binary tower
1165		implements_transformation_factory::<PackedBinaryField512x1b, PackedBinaryField512x1b>();
1166		implements_transformation_factory::<PackedBinaryField256x2b, PackedBinaryField256x2b>();
1167		implements_transformation_factory::<PackedBinaryField128x4b, PackedBinaryField128x4b>();
1168		implements_transformation_factory::<PackedBinaryField64x8b, PackedBinaryField64x8b>();
1169		implements_transformation_factory::<PackedAESBinaryField64x8b, PackedBinaryField64x8b>();
1170		implements_transformation_factory::<PackedBinaryField32x16b, PackedBinaryField32x16b>();
1171		implements_transformation_factory::<PackedAESBinaryField32x16b, PackedBinaryField32x16b>();
1172		implements_transformation_factory::<PackedBinaryField16x32b, PackedBinaryField16x32b>();
1173		implements_transformation_factory::<PackedAESBinaryField16x32b, PackedBinaryField16x32b>();
1174		implements_transformation_factory::<PackedBinaryField8x64b, PackedBinaryField8x64b>();
1175		implements_transformation_factory::<PackedAESBinaryField8x64b, PackedBinaryField8x64b>();
1176		implements_transformation_factory::<PackedBinaryField4x128b, PackedBinaryField4x128b>();
1177		implements_transformation_factory::<PackedAESBinaryField4x128b, PackedBinaryField4x128b>();
1178	}
1179
1180	proptest! {
1181		#[test]
1182		fn test_interleave_2b(a_val in 0u8..3, b_val in 0u8..3) {
1183			check_interleave_all_heights::<PackedBinaryField2x1b>(U2::new(a_val), U2::new(b_val));
1184			check_interleave_all_heights::<PackedBinaryField1x2b>(U2::new(a_val), U2::new(b_val));
1185		}
1186
1187		#[test]
1188		fn test_interleave_4b(a_val in 0u8..16, b_val in 0u8..16) {
1189			check_interleave_all_heights::<PackedBinaryField4x1b>(U4::new(a_val), U4::new(b_val));
1190			check_interleave_all_heights::<PackedBinaryField2x2b>(U4::new(a_val), U4::new(b_val));
1191			check_interleave_all_heights::<PackedBinaryField1x4b>(U4::new(a_val), U4::new(b_val));
1192		}
1193
1194		#[test]
1195		fn test_interleave_8b(a_val in 0u8.., b_val in 0u8..) {
1196			check_interleave_all_heights::<PackedBinaryField8x1b>(a_val, b_val);
1197			check_interleave_all_heights::<PackedBinaryField4x2b>(a_val, b_val);
1198			check_interleave_all_heights::<PackedBinaryField2x4b>(a_val, b_val);
1199			check_interleave_all_heights::<PackedBinaryField1x8b>(a_val, b_val);
1200		}
1201
1202		#[test]
1203		fn test_interleave_16b(a_val in 0u16.., b_val in 0u16..) {
1204			check_interleave_all_heights::<PackedBinaryField16x1b>(a_val, b_val);
1205			check_interleave_all_heights::<PackedBinaryField8x2b>(a_val, b_val);
1206			check_interleave_all_heights::<PackedBinaryField4x4b>(a_val, b_val);
1207			check_interleave_all_heights::<PackedBinaryField2x8b>(a_val, b_val);
1208			check_interleave_all_heights::<PackedBinaryField1x16b>(a_val, b_val);
1209		}
1210
1211		#[test]
1212		fn test_interleave_32b(a_val in 0u32.., b_val in 0u32..) {
1213			check_interleave_all_heights::<PackedBinaryField32x1b>(a_val, b_val);
1214			check_interleave_all_heights::<PackedBinaryField16x2b>(a_val, b_val);
1215			check_interleave_all_heights::<PackedBinaryField8x4b>(a_val, b_val);
1216			check_interleave_all_heights::<PackedBinaryField4x8b>(a_val, b_val);
1217			check_interleave_all_heights::<PackedBinaryField2x16b>(a_val, b_val);
1218			check_interleave_all_heights::<PackedBinaryField1x32b>(a_val, b_val);
1219		}
1220
1221		#[test]
1222		fn test_interleave_64b(a_val in 0u64.., b_val in 0u64..) {
1223			check_interleave_all_heights::<PackedBinaryField64x1b>(a_val, b_val);
1224			check_interleave_all_heights::<PackedBinaryField32x2b>(a_val, b_val);
1225			check_interleave_all_heights::<PackedBinaryField16x4b>(a_val, b_val);
1226			check_interleave_all_heights::<PackedBinaryField8x8b>(a_val, b_val);
1227			check_interleave_all_heights::<PackedBinaryField4x16b>(a_val, b_val);
1228			check_interleave_all_heights::<PackedBinaryField2x32b>(a_val, b_val);
1229			check_interleave_all_heights::<PackedBinaryField1x64b>(a_val, b_val);
1230		}
1231
1232		#[test]
1233		#[allow(clippy::useless_conversion)] // this warning depends on the target platform
1234		fn test_interleave_128b(a_val in 0u128.., b_val in 0u128..) {
1235			check_interleave_all_heights::<PackedBinaryField128x1b>(a_val.into(), b_val.into());
1236			check_interleave_all_heights::<PackedBinaryField64x2b>(a_val.into(), b_val.into());
1237			check_interleave_all_heights::<PackedBinaryField32x4b>(a_val.into(), b_val.into());
1238			check_interleave_all_heights::<PackedBinaryField16x8b>(a_val.into(), b_val.into());
1239			check_interleave_all_heights::<PackedBinaryField8x16b>(a_val.into(), b_val.into());
1240			check_interleave_all_heights::<PackedBinaryField4x32b>(a_val.into(), b_val.into());
1241			check_interleave_all_heights::<PackedBinaryField2x64b>(a_val.into(), b_val.into());
1242			check_interleave_all_heights::<PackedBinaryField1x128b>(a_val.into(), b_val.into());
1243		}
1244
1245		#[test]
1246		fn test_interleave_256b(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
1247			check_interleave_all_heights::<PackedBinaryField256x1b>(a_val.into(), b_val.into());
1248			check_interleave_all_heights::<PackedBinaryField128x2b>(a_val.into(), b_val.into());
1249			check_interleave_all_heights::<PackedBinaryField64x4b>(a_val.into(), b_val.into());
1250			check_interleave_all_heights::<PackedBinaryField32x8b>(a_val.into(), b_val.into());
1251			check_interleave_all_heights::<PackedBinaryField16x16b>(a_val.into(), b_val.into());
1252			check_interleave_all_heights::<PackedBinaryField8x32b>(a_val.into(), b_val.into());
1253			check_interleave_all_heights::<PackedBinaryField4x64b>(a_val.into(), b_val.into());
1254			check_interleave_all_heights::<PackedBinaryField2x128b>(a_val.into(), b_val.into());
1255		}
1256
1257		#[test]
1258		fn test_interleave_512b(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
1259			check_interleave_all_heights::<PackedBinaryField512x1b>(a_val.into(), b_val.into());
1260			check_interleave_all_heights::<PackedBinaryField256x2b>(a_val.into(), b_val.into());
1261			check_interleave_all_heights::<PackedBinaryField128x4b>(a_val.into(), b_val.into());
1262			check_interleave_all_heights::<PackedBinaryField64x8b>(a_val.into(), b_val.into());
1263			check_interleave_all_heights::<PackedBinaryField32x16b>(a_val.into(), b_val.into());
1264			check_interleave_all_heights::<PackedBinaryField16x32b>(a_val.into(), b_val.into());
1265			check_interleave_all_heights::<PackedBinaryField8x64b>(a_val.into(), b_val.into());
1266			check_interleave_all_heights::<PackedBinaryField4x128b>(a_val.into(), b_val.into());
1267		}
1268
1269		#[test]
1270		fn check_transpose_2b(a_val in 0u8..3, b_val in 0u8..3) {
1271			check_transpose_all_heights::<PackedBinaryField2x1b>(U2::new(a_val), U2::new(b_val));
1272			check_transpose_all_heights::<PackedBinaryField1x2b>(U2::new(a_val), U2::new(b_val));
1273		}
1274
1275		#[test]
1276		fn check_transpose_4b(a_val in 0u8..16, b_val in 0u8..16) {
1277			check_transpose_all_heights::<PackedBinaryField4x1b>(U4::new(a_val), U4::new(b_val));
1278			check_transpose_all_heights::<PackedBinaryField2x2b>(U4::new(a_val), U4::new(b_val));
1279			check_transpose_all_heights::<PackedBinaryField1x4b>(U4::new(a_val), U4::new(b_val));
1280		}
1281
1282		#[test]
1283		fn check_transpose_8b(a_val in 0u8.., b_val in 0u8..) {
1284			check_transpose_all_heights::<PackedBinaryField8x1b>(a_val, b_val);
1285			check_transpose_all_heights::<PackedBinaryField4x2b>(a_val, b_val);
1286			check_transpose_all_heights::<PackedBinaryField2x4b>(a_val, b_val);
1287			check_transpose_all_heights::<PackedBinaryField1x8b>(a_val, b_val);
1288		}
1289
1290		#[test]
1291		fn check_transpose_16b(a_val in 0u16.., b_val in 0u16..) {
1292			check_transpose_all_heights::<PackedBinaryField16x1b>(a_val, b_val);
1293			check_transpose_all_heights::<PackedBinaryField8x2b>(a_val, b_val);
1294			check_transpose_all_heights::<PackedBinaryField4x4b>(a_val, b_val);
1295			check_transpose_all_heights::<PackedBinaryField2x8b>(a_val, b_val);
1296			check_transpose_all_heights::<PackedBinaryField1x16b>(a_val, b_val);
1297		}
1298
1299		#[test]
1300		fn check_transpose_32b(a_val in 0u32.., b_val in 0u32..) {
1301			check_transpose_all_heights::<PackedBinaryField32x1b>(a_val, b_val);
1302			check_transpose_all_heights::<PackedBinaryField16x2b>(a_val, b_val);
1303			check_transpose_all_heights::<PackedBinaryField8x4b>(a_val, b_val);
1304			check_transpose_all_heights::<PackedBinaryField4x8b>(a_val, b_val);
1305			check_transpose_all_heights::<PackedBinaryField2x16b>(a_val, b_val);
1306			check_transpose_all_heights::<PackedBinaryField1x32b>(a_val, b_val);
1307		}
1308
1309		#[test]
1310		fn check_transpose_64b(a_val in 0u64.., b_val in 0u64..) {
1311			check_transpose_all_heights::<PackedBinaryField64x1b>(a_val, b_val);
1312			check_transpose_all_heights::<PackedBinaryField32x2b>(a_val, b_val);
1313			check_transpose_all_heights::<PackedBinaryField16x4b>(a_val, b_val);
1314			check_transpose_all_heights::<PackedBinaryField8x8b>(a_val, b_val);
1315			check_transpose_all_heights::<PackedBinaryField4x16b>(a_val, b_val);
1316			check_transpose_all_heights::<PackedBinaryField2x32b>(a_val, b_val);
1317			check_transpose_all_heights::<PackedBinaryField1x64b>(a_val, b_val);
1318		}
1319
1320		#[test]
1321		#[allow(clippy::useless_conversion)] // this warning depends on the target platform
1322		fn check_transpose_128b(a_val in 0u128.., b_val in 0u128..) {
1323			check_transpose_all_heights::<PackedBinaryField128x1b>(a_val.into(), b_val.into());
1324			check_transpose_all_heights::<PackedBinaryField64x2b>(a_val.into(), b_val.into());
1325			check_transpose_all_heights::<PackedBinaryField32x4b>(a_val.into(), b_val.into());
1326			check_transpose_all_heights::<PackedBinaryField16x8b>(a_val.into(), b_val.into());
1327			check_transpose_all_heights::<PackedBinaryField8x16b>(a_val.into(), b_val.into());
1328			check_transpose_all_heights::<PackedBinaryField4x32b>(a_val.into(), b_val.into());
1329			check_transpose_all_heights::<PackedBinaryField2x64b>(a_val.into(), b_val.into());
1330			check_transpose_all_heights::<PackedBinaryField1x128b>(a_val.into(), b_val.into());
1331		}
1332
1333		#[test]
1334		fn check_transpose_256b(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
1335			check_transpose_all_heights::<PackedBinaryField256x1b>(a_val.into(), b_val.into());
1336			check_transpose_all_heights::<PackedBinaryField128x2b>(a_val.into(), b_val.into());
1337			check_transpose_all_heights::<PackedBinaryField64x4b>(a_val.into(), b_val.into());
1338			check_transpose_all_heights::<PackedBinaryField32x8b>(a_val.into(), b_val.into());
1339			check_transpose_all_heights::<PackedBinaryField16x16b>(a_val.into(), b_val.into());
1340			check_transpose_all_heights::<PackedBinaryField8x32b>(a_val.into(), b_val.into());
1341			check_transpose_all_heights::<PackedBinaryField4x64b>(a_val.into(), b_val.into());
1342			check_transpose_all_heights::<PackedBinaryField2x128b>(a_val.into(), b_val.into());
1343		}
1344
1345		#[test]
1346		fn check_transpose_512b(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
1347			check_transpose_all_heights::<PackedBinaryField512x1b>(a_val.into(), b_val.into());
1348			check_transpose_all_heights::<PackedBinaryField256x2b>(a_val.into(), b_val.into());
1349			check_transpose_all_heights::<PackedBinaryField128x4b>(a_val.into(), b_val.into());
1350			check_transpose_all_heights::<PackedBinaryField64x8b>(a_val.into(), b_val.into());
1351			check_transpose_all_heights::<PackedBinaryField32x16b>(a_val.into(), b_val.into());
1352			check_transpose_all_heights::<PackedBinaryField16x32b>(a_val.into(), b_val.into());
1353			check_transpose_all_heights::<PackedBinaryField8x64b>(a_val.into(), b_val.into());
1354			check_transpose_all_heights::<PackedBinaryField4x128b>(a_val.into(), b_val.into());
1355		}
1356	}
1357}