binius_field/
packed_binary_field.rs

1// Copyright 2023-2025 Irreducible Inc.
2
3pub use crate::arch::{
4	packed_1::*, packed_2::*, packed_4::*, packed_8::*, packed_16::*, packed_32::*, packed_64::*,
5	packed_128::*, packed_256::*, packed_512::*, packed_aes_8::*, packed_aes_16::*,
6	packed_aes_32::*, packed_aes_64::*, packed_aes_128::*, packed_aes_256::*, packed_aes_512::*,
7};
8
9/// Common code to test different multiply, square and invert implementations
10#[cfg(test)]
11pub mod test_utils {
12	use crate::{
13		PackedField,
14		underlier::{U1, U2, U4, WithUnderlier},
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				#[allow(unused)]
95				fn test_mul(
96					a: <T as $crate::underlier::WithUnderlier>::Underlier,
97					b: <T as $crate::underlier::WithUnderlier>::Underlier,
98				) {
99					let a = T::from_underlier(a);
100					let b = T::from_underlier(b);
101
102					let c = $mult_func(a, b);
103					for i in 0..T::WIDTH {
104						assert_eq!(c.get(i), a.get(i) * b.get(i));
105					}
106				}
107			}
108		};
109	}
110
111	pub(crate) use define_check_packed_mul;
112
113	macro_rules! define_check_packed_square {
114		($square_func:path, $constraint:path) => {
115			#[allow(unused)]
116			trait TestSquareTrait<T> {
117				fn test_square(_a: T) {}
118			}
119
120			impl<T> TestSquareTrait<$crate::packed_binary_field::test_utils::Unit> for T {}
121
122			struct TestSquare<T>(std::marker::PhantomData<T>);
123
124			impl<T: $constraint + PackedField + $crate::underlier::WithUnderlier> TestSquare<T> {
125				#[allow(unused)]
126				fn test_square(a: <T as $crate::underlier::WithUnderlier>::Underlier) {
127					let a = T::from_underlier(a);
128
129					let c = $square_func(a);
130					for i in 0..T::WIDTH {
131						assert_eq!(c.get(i), a.get(i) * a.get(i));
132					}
133				}
134			}
135		};
136	}
137
138	pub(crate) use define_check_packed_square;
139
140	macro_rules! define_check_packed_inverse {
141		($invert_func:path, $constraint:path) => {
142			#[allow(unused)]
143			trait TestInvertTrait<T> {
144				fn test_invert(_a: T) {}
145			}
146
147			impl<T> TestInvertTrait<$crate::packed_binary_field::test_utils::Unit> for T {}
148
149			struct TestInvert<T>(std::marker::PhantomData<T>);
150
151			#[allow(unused)]
152			impl<T: $constraint + PackedField + $crate::underlier::WithUnderlier> TestInvert<T> {
153				fn test_invert(a: <T as $crate::underlier::WithUnderlier>::Underlier) {
154					use crate::Field;
155
156					let a = T::from_underlier(a);
157
158					let c = $invert_func(a);
159					for i in 0..T::WIDTH {
160						assert!(
161							(c.get(i).is_zero().into()
162								&& a.get(i).is_zero().into()
163								&& c.get(i).is_zero().into())
164								|| T::Scalar::ONE == a.get(i) * c.get(i)
165						);
166					}
167				}
168			}
169		};
170	}
171
172	pub(crate) use define_check_packed_inverse;
173
174	/// Test if `mult_func` operation is a valid multiply operation on the given values for
175	/// all possible packed fields defined on u128.
176	macro_rules! define_multiply_tests {
177		($mult_func:path, $constraint:path) => {
178			$crate::packed_binary_field::test_utils::define_check_packed_mul!(
179				$mult_func,
180				$constraint
181			);
182
183			proptest::proptest! {
184				#[test]
185				fn test_mul_packed_8(a_val in proptest::prelude::any::<u8>(), b_val in proptest::prelude::any::<u8>()) {
186					use $crate::arch::packed_8::*;
187					use $crate::arch::packed_aes_8::*;
188
189					TestMult::<PackedBinaryField8x1b>::test_mul(a_val.into(), b_val.into());
190					TestMult::<PackedAESBinaryField1x8b>::test_mul(a_val.into(), b_val.into());
191				}
192
193				#[test]
194				fn test_mul_packed_16(a_val in proptest::prelude::any::<u16>(), b_val in proptest::prelude::any::<u16>()) {
195					use $crate::arch::packed_16::*;
196					use $crate::arch::packed_aes_16::*;
197
198					TestMult::<PackedBinaryField16x1b>::test_mul(a_val.into(), b_val.into());
199					TestMult::<PackedAESBinaryField2x8b>::test_mul(a_val.into(), b_val.into());
200				}
201
202				#[test]
203				fn test_mul_packed_32(a_val in proptest::prelude::any::<u32>(), b_val in proptest::prelude::any::<u32>()) {
204					use $crate::arch::packed_32::*;
205					use $crate::arch::packed_aes_32::*;
206
207					TestMult::<PackedBinaryField32x1b>::test_mul(a_val.into(), b_val.into());
208					TestMult::<PackedAESBinaryField4x8b>::test_mul(a_val.into(), b_val.into());
209				}
210
211				#[test]
212				fn test_mul_packed_64(a_val in proptest::prelude::any::<u64>(), b_val in proptest::prelude::any::<u64>()) {
213					use $crate::arch::packed_64::*;
214					use $crate::arch::packed_aes_64::*;
215
216					TestMult::<PackedBinaryField64x1b>::test_mul(a_val.into(), b_val.into());
217					TestMult::<PackedAESBinaryField8x8b>::test_mul(a_val.into(), b_val.into());
218				}
219
220				#[test]
221				fn test_mul_packed_128(a_val in proptest::prelude::any::<u128>(), b_val in proptest::prelude::any::<u128>()) {
222					use $crate::arch::packed_128::*;
223					use $crate::arch::packed_aes_128::*;
224					use $crate::arch::packed_ghash_128::*;
225
226					TestMult::<PackedBinaryField128x1b>::test_mul(a_val.into(), b_val.into());
227					TestMult::<PackedAESBinaryField16x8b>::test_mul(a_val.into(), b_val.into());
228					TestMult::<PackedBinaryGhash1x128b>::test_mul(a_val.into(), b_val.into());
229				}
230
231				#[test]
232				fn test_mul_packed_256(a_val in proptest::prelude::any::<[u128; 2]>(), b_val in proptest::prelude::any::<[u128; 2]>()) {
233					use $crate::arch::packed_256::*;
234					use $crate::arch::packed_aes_256::*;
235					use $crate::arch::packed_ghash_256::*;
236
237					TestMult::<PackedBinaryField256x1b>::test_mul(a_val.into(), b_val.into());
238					TestMult::<PackedAESBinaryField32x8b>::test_mul(a_val.into(), b_val.into());
239					TestMult::<PackedBinaryGhash2x128b>::test_mul(a_val.into(), b_val.into());
240				}
241
242				#[test]
243				fn test_mul_packed_512(a_val in proptest::prelude::any::<[u128; 4]>(), b_val in proptest::prelude::any::<[u128; 4]>()) {
244					use $crate::arch::packed_512::*;
245					use $crate::arch::packed_aes_512::*;
246					use $crate::arch::packed_ghash_512::*;
247
248					TestMult::<PackedBinaryField512x1b>::test_mul(a_val.into(), b_val.into());
249					TestMult::<PackedAESBinaryField64x8b>::test_mul(a_val.into(), b_val.into());
250					TestMult::<PackedBinaryGhash4x128b>::test_mul(a_val.into(), b_val.into());
251				}
252			}
253		};
254	}
255
256	/// Test if `square_func` operation is a valid square operation on the given value for
257	/// all possible packed fields.
258	macro_rules! define_square_tests {
259		($square_func:path, $constraint:path) => {
260			$crate::packed_binary_field::test_utils::define_check_packed_square!(
261				$square_func,
262				$constraint
263			);
264
265			proptest::proptest! {
266				#[test]
267				fn test_square_packed_8(a_val in proptest::prelude::any::<u8>()) {
268					use $crate::arch::packed_8::*;
269					use $crate::arch::packed_aes_8::*;
270
271					TestSquare::<PackedBinaryField8x1b>::test_square(a_val.into());
272					TestSquare::<PackedAESBinaryField1x8b>::test_square(a_val.into());
273				}
274
275				#[test]
276				fn test_square_packed_16(a_val in proptest::prelude::any::<u16>()) {
277					use $crate::arch::packed_16::*;
278					use $crate::arch::packed_aes_16::*;
279
280					TestSquare::<PackedBinaryField16x1b>::test_square(a_val.into());
281					TestSquare::<PackedAESBinaryField2x8b>::test_square(a_val.into());
282				}
283
284				#[test]
285				fn test_square_packed_32(a_val in proptest::prelude::any::<u32>()) {
286					use $crate::arch::packed_32::*;
287					use $crate::arch::packed_aes_32::*;
288
289					TestSquare::<PackedBinaryField32x1b>::test_square(a_val.into());
290					TestSquare::<PackedAESBinaryField4x8b>::test_square(a_val.into());
291				}
292
293				#[test]
294				fn test_square_packed_64(a_val in proptest::prelude::any::<u64>()) {
295					use $crate::arch::packed_64::*;
296					use $crate::arch::packed_aes_64::*;
297
298					TestSquare::<PackedBinaryField64x1b>::test_square(a_val.into());
299					TestSquare::<PackedAESBinaryField8x8b>::test_square(a_val.into());
300				}
301
302				#[test]
303				fn test_square_packed_128(a_val in proptest::prelude::any::<u128>()) {
304					use $crate::arch::packed_128::*;
305					use $crate::arch::packed_aes_128::*;
306					use $crate::arch::packed_ghash_128::*;
307
308					TestSquare::<PackedBinaryField128x1b>::test_square(a_val.into());
309					TestSquare::<PackedAESBinaryField16x8b>::test_square(a_val.into());
310					TestSquare::<PackedBinaryGhash1x128b>::test_square(a_val.into());
311				}
312
313				#[test]
314				fn test_square_packed_256(a_val in proptest::prelude::any::<[u128; 2]>()) {
315					use $crate::arch::packed_256::*;
316					use $crate::arch::packed_aes_256::*;
317					use $crate::arch::packed_ghash_256::*;
318
319					TestSquare::<PackedBinaryField256x1b>::test_square(a_val.into());
320					TestSquare::<PackedAESBinaryField32x8b>::test_square(a_val.into());
321					TestSquare::<PackedBinaryGhash2x128b>::test_square(a_val.into());
322				}
323
324				#[test]
325				fn test_square_packed_512(a_val in proptest::prelude::any::<[u128; 4]>()) {
326					use $crate::arch::packed_512::*;
327					use $crate::arch::packed_aes_512::*;
328					use $crate::arch::packed_ghash_512::*;
329
330					TestSquare::<PackedBinaryField512x1b>::test_square(a_val.into());
331					TestSquare::<PackedAESBinaryField64x8b>::test_square(a_val.into());
332					TestSquare::<PackedBinaryGhash4x128b>::test_square(a_val.into());
333				}
334			}
335		};
336	}
337
338	/// Test if `invert_func` operation is a valid invert operation on the given value for
339	/// all possible packed fields.
340	macro_rules! define_invert_tests {
341		($invert_func:path, $constraint:path) => {
342			$crate::packed_binary_field::test_utils::define_check_packed_inverse!(
343				$invert_func,
344				$constraint
345			);
346
347			proptest::proptest! {
348				#[test]
349				fn test_invert_packed_8(a_val in proptest::prelude::any::<u8>()) {
350					use $crate::arch::packed_8::*;
351					use $crate::arch::packed_aes_8::*;
352
353					TestInvert::<PackedBinaryField8x1b>::test_invert(a_val.into());
354					TestInvert::<PackedAESBinaryField1x8b>::test_invert(a_val.into());
355				}
356
357				#[test]
358				fn test_invert_packed_16(a_val in proptest::prelude::any::<u16>()) {
359					use $crate::arch::packed_16::*;
360					use $crate::arch::packed_aes_16::*;
361
362					TestInvert::<PackedBinaryField16x1b>::test_invert(a_val.into());
363					TestInvert::<PackedAESBinaryField2x8b>::test_invert(a_val.into());
364				}
365
366				#[test]
367				fn test_invert_packed_32(a_val in proptest::prelude::any::<u32>()) {
368					use $crate::arch::packed_32::*;
369					use $crate::arch::packed_aes_32::*;
370
371					TestInvert::<PackedBinaryField32x1b>::test_invert(a_val.into());
372					TestInvert::<PackedAESBinaryField4x8b>::test_invert(a_val.into());
373				}
374
375				#[test]
376				fn test_invert_packed_64(a_val in proptest::prelude::any::<u64>()) {
377					use $crate::arch::packed_64::*;
378					use $crate::arch::packed_aes_64::*;
379
380					TestInvert::<PackedBinaryField64x1b>::test_invert(a_val.into());
381					TestInvert::<PackedAESBinaryField8x8b>::test_invert(a_val.into());
382				}
383
384				#[test]
385				fn test_invert_packed_128(a_val in proptest::prelude::any::<u128>()) {
386					use $crate::arch::packed_128::*;
387					use $crate::arch::packed_aes_128::*;
388					use $crate::arch::packed_ghash_128::*;
389
390					TestInvert::<PackedBinaryField128x1b>::test_invert(a_val.into());
391					TestInvert::<PackedAESBinaryField16x8b>::test_invert(a_val.into());
392					TestInvert::<PackedBinaryGhash1x128b>::test_invert(a_val.into());
393				}
394
395				#[test]
396				fn test_invert_packed_256(a_val in proptest::prelude::any::<[u128; 2]>()) {
397					use $crate::arch::packed_256::*;
398					use $crate::arch::packed_aes_256::*;
399					use $crate::arch::packed_ghash_256::*;
400
401					TestInvert::<PackedBinaryField256x1b>::test_invert(a_val.into());
402					TestInvert::<PackedAESBinaryField32x8b>::test_invert(a_val.into());
403					TestInvert::<PackedBinaryGhash2x128b>::test_invert(a_val.into());
404				}
405
406				#[test]
407				fn test_invert_packed_512(a_val in proptest::prelude::any::<[u128; 4]>()) {
408					use $crate::arch::packed_512::*;
409					use $crate::arch::packed_aes_512::*;
410					use $crate::arch::packed_ghash_512::*;
411
412					TestInvert::<PackedBinaryField512x1b>::test_invert(a_val.into());
413					TestInvert::<PackedAESBinaryField64x8b>::test_invert(a_val.into());
414					TestInvert::<PackedBinaryGhash4x128b>::test_invert(a_val.into());
415				}
416			}
417		};
418	}
419
420	pub(crate) use define_invert_tests;
421	pub(crate) use define_multiply_tests;
422	pub(crate) use define_square_tests;
423
424	pub fn check_interleave<P: PackedField + WithUnderlier>(
425		lhs: P::Underlier,
426		rhs: P::Underlier,
427		log_block_len: usize,
428	) {
429		let lhs = P::from_underlier(lhs);
430		let rhs = P::from_underlier(rhs);
431		let (a, b) = lhs.interleave(rhs, log_block_len);
432		let block_len = 1 << log_block_len;
433		for i in (0..P::WIDTH).step_by(block_len * 2) {
434			for j in 0..block_len {
435				assert_eq!(a.get(i + j), lhs.get(i + j));
436				assert_eq!(a.get(i + j + block_len), rhs.get(i + j));
437
438				assert_eq!(b.get(i + j), lhs.get(i + j + block_len));
439				assert_eq!(b.get(i + j + block_len), rhs.get(i + j + block_len));
440			}
441		}
442	}
443
444	pub fn check_interleave_all_heights<P: PackedField + WithUnderlier>(
445		lhs: P::Underlier,
446		rhs: P::Underlier,
447	) {
448		for log_block_len in 0..P::LOG_WIDTH {
449			check_interleave::<P>(lhs, rhs, log_block_len);
450		}
451	}
452
453	pub fn check_unzip<P: PackedField + WithUnderlier>(
454		lhs: P::Underlier,
455		rhs: P::Underlier,
456		log_block_len: usize,
457	) {
458		let lhs = P::from_underlier(lhs);
459		let rhs = P::from_underlier(rhs);
460		let block_len = 1 << log_block_len;
461		let (a, b) = lhs.unzip(rhs, log_block_len);
462		for i in (0..P::WIDTH / 2).step_by(block_len) {
463			for j in 0..block_len {
464				assert_eq!(
465					a.get(i + j),
466					lhs.get(2 * i + j),
467					"i: {}, j: {}, log_block_len: {}, P: {:?}",
468					i,
469					j,
470					log_block_len,
471					P::zero()
472				);
473				assert_eq!(
474					b.get(i + j),
475					lhs.get(2 * i + j + block_len),
476					"i: {}, j: {}, log_block_len: {}, P: {:?}",
477					i,
478					j,
479					log_block_len,
480					P::zero()
481				);
482			}
483		}
484
485		for i in (0..P::WIDTH / 2).step_by(block_len) {
486			for j in 0..block_len {
487				assert_eq!(
488					a.get(i + j + P::WIDTH / 2),
489					rhs.get(2 * i + j),
490					"i: {}, j: {}, log_block_len: {}, P: {:?}",
491					i,
492					j,
493					log_block_len,
494					P::zero()
495				);
496				assert_eq!(b.get(i + j + P::WIDTH / 2), rhs.get(2 * i + j + block_len));
497			}
498		}
499	}
500
501	pub fn check_transpose_all_heights<P: PackedField + WithUnderlier>(
502		lhs: P::Underlier,
503		rhs: P::Underlier,
504	) {
505		for log_block_len in 0..P::LOG_WIDTH {
506			check_unzip::<P>(lhs, rhs, log_block_len);
507		}
508	}
509}
510
511#[cfg(test)]
512mod tests {
513	use std::{iter::repeat_with, ops::Mul};
514
515	use binius_utils::{DeserializeBytes, SerializeBytes, bytes::BytesMut};
516	use proptest::prelude::*;
517	use rand::prelude::*;
518	use test_utils::check_interleave_all_heights;
519
520	use super::{
521		test_utils::{define_invert_tests, define_multiply_tests, define_square_tests},
522		*,
523	};
524	use crate::{
525		PackedBinaryGhash1x128b, PackedBinaryGhash2x128b, PackedBinaryGhash4x128b, PackedField,
526		Random,
527		test_utils::check_transpose_all_heights,
528		underlier::{U2, U4},
529	};
530
531	fn test_add_packed<P: PackedField + From<u128>>(a_val: u128, b_val: u128) {
532		let a = P::from(a_val);
533		let b = P::from(b_val);
534		let c = a + b;
535		for i in 0..P::WIDTH {
536			assert_eq!(c.get(i), a.get(i) + b.get(i));
537		}
538	}
539
540	fn test_mul_packed<P: PackedField>(a: P, b: P) {
541		let c = a * b;
542		for i in 0..P::WIDTH {
543			assert_eq!(c.get(i), a.get(i) * b.get(i));
544		}
545	}
546
547	fn test_mul_packed_random<P: PackedField>() {
548		let mut rng = StdRng::seed_from_u64(0);
549		test_mul_packed(P::random(&mut rng), P::random(&mut rng))
550	}
551
552	fn test_set_then_get<P: PackedField>() {
553		let mut rng = StdRng::seed_from_u64(0);
554		let mut elem = P::random(&mut rng);
555
556		let scalars = repeat_with(|| P::Scalar::random(&mut rng))
557			.take(P::WIDTH)
558			.collect::<Vec<_>>();
559
560		for (i, val) in scalars.iter().enumerate() {
561			elem.set(i, *val);
562		}
563		for (i, val) in scalars.iter().enumerate() {
564			assert_eq!(elem.get(i), *val);
565		}
566	}
567
568	fn test_serialize_then_deserialize<P: PackedField + DeserializeBytes + SerializeBytes>() {
569		let mut buffer = BytesMut::new();
570		let mut rng = StdRng::seed_from_u64(0);
571		let packed = P::random(&mut rng);
572		packed.serialize(&mut buffer).unwrap();
573
574		let mut read_buffer = buffer.freeze();
575
576		assert_eq!(P::deserialize(&mut read_buffer).unwrap(), packed);
577	}
578
579	#[test]
580	fn test_set_then_get_128b() {
581		test_set_then_get::<PackedBinaryGhash1x128b>();
582		test_set_then_get::<PackedBinaryGhash2x128b>();
583		test_set_then_get::<PackedBinaryGhash4x128b>();
584	}
585
586	#[test]
587	fn test_serialize_then_deserialize_128b() {
588		test_serialize_then_deserialize::<PackedBinaryGhash1x128b>();
589		test_serialize_then_deserialize::<PackedBinaryGhash2x128b>();
590		test_serialize_then_deserialize::<PackedBinaryGhash4x128b>();
591	}
592
593	#[test]
594	fn test_serialize_deserialize_different_packing_width() {
595		let mut rng = StdRng::seed_from_u64(0);
596
597		let packed0 = PackedBinaryGhash1x128b::random(&mut rng);
598		let packed1 = PackedBinaryGhash1x128b::random(&mut rng);
599
600		let mut buffer = BytesMut::new();
601		packed0.serialize(&mut buffer).unwrap();
602		packed1.serialize(&mut buffer).unwrap();
603
604		let mut read_buffer = buffer.freeze();
605		let packed01 = PackedBinaryGhash2x128b::deserialize(&mut read_buffer).unwrap();
606
607		assert!(
608			packed01
609				.iter()
610				.zip([packed0, packed1])
611				.all(|(x, y)| x == y.get(0))
612		);
613	}
614
615	// TODO: Generate lots more proptests using macros
616	proptest! {
617		#[test]
618		fn test_add_packed_128x1b(a_val in any::<u128>(), b_val in any::<u128>()) {
619			test_add_packed::<PackedBinaryField128x1b>(a_val, b_val)
620		}
621
622		#[test]
623		fn test_add_packed_16x8b(a_val in any::<u128>(), b_val in any::<u128>()) {
624			test_add_packed::<PackedAESBinaryField16x8b>(a_val, b_val)
625		}
626
627		#[test]
628		fn test_add_packed_1x128b(a_val in any::<u128>(), b_val in any::<u128>()) {
629			test_add_packed::<PackedBinaryGhash1x128b>(a_val, b_val)
630		}
631	}
632
633	#[test]
634	fn test_mul_packed_256x1b() {
635		test_mul_packed_random::<PackedBinaryField256x1b>()
636	}
637
638	#[test]
639	fn test_mul_packed_32x8b() {
640		test_mul_packed_random::<PackedAESBinaryField32x8b>()
641	}
642
643	#[test]
644	fn test_mul_packed_2x128b() {
645		test_mul_packed_random::<PackedBinaryGhash2x128b>()
646	}
647
648	#[test]
649	fn test_iter_size_hint() {
650		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField128x1b>();
651	}
652
653	fn assert_valid_iterator_with_exact_size_hint<P: PackedField>() {
654		assert_eq!(P::default().iter().size_hint(), (P::WIDTH, Some(P::WIDTH)));
655		assert_eq!(P::default().into_iter().size_hint(), (P::WIDTH, Some(P::WIDTH)));
656		assert_eq!(P::default().iter().count(), P::WIDTH);
657		assert_eq!(P::default().into_iter().count(), P::WIDTH);
658	}
659
660	define_multiply_tests!(Mul::mul, PackedField);
661
662	define_square_tests!(PackedField::square, PackedField);
663
664	define_invert_tests!(PackedField::invert_or_zero, PackedField);
665
666	proptest! {
667		#[test]
668		fn test_interleave_2b(a_val in 0u8..3, b_val in 0u8..3) {
669			check_interleave_all_heights::<PackedBinaryField2x1b>(U2::new(a_val), U2::new(b_val));
670		}
671
672		#[test]
673		fn test_interleave_4b(a_val in 0u8..16, b_val in 0u8..16) {
674			check_interleave_all_heights::<PackedBinaryField4x1b>(U4::new(a_val), U4::new(b_val));
675		}
676
677		#[test]
678		fn test_interleave_8b(a_val in 0u8.., b_val in 0u8..) {
679			check_interleave_all_heights::<PackedBinaryField8x1b>(a_val, b_val);
680			check_interleave_all_heights::<PackedAESBinaryField1x8b>(a_val, b_val);
681		}
682
683		#[test]
684		fn test_interleave_16b(a_val in 0u16.., b_val in 0u16..) {
685			check_interleave_all_heights::<PackedBinaryField16x1b>(a_val, b_val);
686			check_interleave_all_heights::<PackedAESBinaryField2x8b>(a_val, b_val);
687		}
688
689		#[test]
690		fn test_interleave_32b(a_val in 0u32.., b_val in 0u32..) {
691			check_interleave_all_heights::<PackedBinaryField32x1b>(a_val, b_val);
692			check_interleave_all_heights::<PackedAESBinaryField4x8b>(a_val, b_val);
693		}
694
695		#[test]
696		fn test_interleave_64b(a_val in 0u64.., b_val in 0u64..) {
697			check_interleave_all_heights::<PackedBinaryField64x1b>(a_val, b_val);
698			check_interleave_all_heights::<PackedAESBinaryField8x8b>(a_val, b_val);
699		}
700
701		#[test]
702		#[allow(clippy::useless_conversion)] // this warning depends on the target platform
703		fn test_interleave_128b(a_val in 0u128.., b_val in 0u128..) {
704			check_interleave_all_heights::<PackedBinaryField128x1b>(a_val.into(), b_val.into());
705			check_interleave_all_heights::<PackedAESBinaryField16x8b>(a_val.into(), b_val.into());
706			check_interleave_all_heights::<PackedBinaryGhash1x128b>(a_val.into(), b_val.into());
707		}
708
709		#[test]
710		fn test_interleave_256b(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
711			check_interleave_all_heights::<PackedBinaryField256x1b>(a_val.into(), b_val.into());
712			check_interleave_all_heights::<PackedAESBinaryField32x8b>(a_val.into(), b_val.into());
713			check_interleave_all_heights::<PackedBinaryGhash2x128b>(a_val.into(), b_val.into());
714		}
715
716		#[test]
717		fn test_interleave_512b(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
718			check_interleave_all_heights::<PackedBinaryField512x1b>(a_val.into(), b_val.into());
719			check_interleave_all_heights::<PackedAESBinaryField64x8b>(a_val.into(), b_val.into());
720			check_interleave_all_heights::<PackedBinaryGhash4x128b>(a_val.into(), b_val.into());
721		}
722
723		#[test]
724		fn check_transpose_2b(a_val in 0u8..3, b_val in 0u8..3) {
725			check_transpose_all_heights::<PackedBinaryField2x1b>(U2::new(a_val), U2::new(b_val));
726		}
727
728		#[test]
729		fn check_transpose_4b(a_val in 0u8..16, b_val in 0u8..16) {
730			check_transpose_all_heights::<PackedBinaryField4x1b>(U4::new(a_val), U4::new(b_val));
731		}
732
733		#[test]
734		fn check_transpose_8b(a_val in 0u8.., b_val in 0u8..) {
735			check_transpose_all_heights::<PackedBinaryField8x1b>(a_val, b_val);
736			check_transpose_all_heights::<PackedAESBinaryField1x8b>(a_val, b_val);
737		}
738
739		#[test]
740		fn check_transpose_16b(a_val in 0u16.., b_val in 0u16..) {
741			check_transpose_all_heights::<PackedBinaryField16x1b>(a_val, b_val);
742			check_transpose_all_heights::<PackedAESBinaryField2x8b>(a_val, b_val);
743		}
744
745		#[test]
746		fn check_transpose_32b(a_val in 0u32.., b_val in 0u32..) {
747			check_transpose_all_heights::<PackedBinaryField32x1b>(a_val, b_val);
748			check_transpose_all_heights::<PackedAESBinaryField4x8b>(a_val, b_val);
749		}
750
751		#[test]
752		fn check_transpose_64b(a_val in 0u64.., b_val in 0u64..) {
753			check_transpose_all_heights::<PackedBinaryField64x1b>(a_val, b_val);
754			check_transpose_all_heights::<PackedAESBinaryField8x8b>(a_val, b_val);
755		}
756
757		#[test]
758		#[allow(clippy::useless_conversion)] // this warning depends on the target platform
759		fn check_transpose_128b(a_val in 0u128.., b_val in 0u128..) {
760			check_transpose_all_heights::<PackedBinaryField128x1b>(a_val.into(), b_val.into());
761			check_transpose_all_heights::<PackedAESBinaryField16x8b>(a_val.into(), b_val.into());
762			check_transpose_all_heights::<PackedBinaryGhash1x128b>(a_val.into(), b_val.into());
763		}
764
765		#[test]
766		fn check_transpose_256b(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
767			check_transpose_all_heights::<PackedBinaryField256x1b>(a_val.into(), b_val.into());
768			check_transpose_all_heights::<PackedAESBinaryField32x8b>(a_val.into(), b_val.into());
769			check_transpose_all_heights::<PackedBinaryGhash2x128b>(a_val.into(), b_val.into());
770		}
771
772		#[test]
773		fn check_transpose_512b(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
774			check_transpose_all_heights::<PackedBinaryField512x1b>(a_val.into(), b_val.into());
775			check_transpose_all_heights::<PackedAESBinaryField64x8b>(a_val.into(), b_val.into());
776			check_transpose_all_heights::<PackedBinaryGhash4x128b>(a_val.into(), b_val.into());
777		}
778	}
779}