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