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		arithmetic_traits::{InvertOrZero, Square},
528		test_utils::check_transpose_all_heights,
529		underlier::{U2, U4},
530	};
531
532	fn test_add_packed<P: PackedField + From<u128>>(a_val: u128, b_val: u128) {
533		let a = P::from(a_val);
534		let b = P::from(b_val);
535		let c = a + b;
536		for i in 0..P::WIDTH {
537			assert_eq!(c.get(i), a.get(i) + b.get(i));
538		}
539	}
540
541	fn test_mul_packed<P: PackedField>(a: P, b: P) {
542		let c = a * b;
543		for i in 0..P::WIDTH {
544			assert_eq!(c.get(i), a.get(i) * b.get(i));
545		}
546	}
547
548	fn test_mul_packed_random<P: PackedField>() {
549		let mut rng = StdRng::seed_from_u64(0);
550		test_mul_packed(P::random(&mut rng), P::random(&mut rng))
551	}
552
553	fn test_set_then_get<P: PackedField>() {
554		let mut rng = StdRng::seed_from_u64(0);
555		let mut elem = P::random(&mut rng);
556
557		let scalars = repeat_with(|| P::Scalar::random(&mut rng))
558			.take(P::WIDTH)
559			.collect::<Vec<_>>();
560
561		for (i, val) in scalars.iter().enumerate() {
562			elem.set(i, *val);
563		}
564		for (i, val) in scalars.iter().enumerate() {
565			assert_eq!(elem.get(i), *val);
566		}
567	}
568
569	fn test_serialize_then_deserialize<P: PackedField + DeserializeBytes + SerializeBytes>() {
570		let mut buffer = BytesMut::new();
571		let mut rng = StdRng::seed_from_u64(0);
572		let packed = P::random(&mut rng);
573		packed.serialize(&mut buffer).unwrap();
574
575		let mut read_buffer = buffer.freeze();
576
577		assert_eq!(P::deserialize(&mut read_buffer).unwrap(), packed);
578	}
579
580	#[test]
581	fn test_set_then_get_128b() {
582		test_set_then_get::<PackedBinaryGhash1x128b>();
583		test_set_then_get::<PackedBinaryGhash2x128b>();
584		test_set_then_get::<PackedBinaryGhash4x128b>();
585	}
586
587	#[test]
588	fn test_serialize_then_deserialize_128b() {
589		test_serialize_then_deserialize::<PackedBinaryGhash1x128b>();
590		test_serialize_then_deserialize::<PackedBinaryGhash2x128b>();
591		test_serialize_then_deserialize::<PackedBinaryGhash4x128b>();
592	}
593
594	#[test]
595	fn test_serialize_deserialize_different_packing_width() {
596		let mut rng = StdRng::seed_from_u64(0);
597
598		let packed0 = PackedBinaryGhash1x128b::random(&mut rng);
599		let packed1 = PackedBinaryGhash1x128b::random(&mut rng);
600
601		let mut buffer = BytesMut::new();
602		packed0.serialize(&mut buffer).unwrap();
603		packed1.serialize(&mut buffer).unwrap();
604
605		let mut read_buffer = buffer.freeze();
606		let packed01 = PackedBinaryGhash2x128b::deserialize(&mut read_buffer).unwrap();
607
608		assert!(
609			packed01
610				.iter()
611				.zip([packed0, packed1])
612				.all(|(x, y)| x == y.get(0))
613		);
614	}
615
616	// TODO: Generate lots more proptests using macros
617	proptest! {
618		#[test]
619		fn test_add_packed_128x1b(a_val in any::<u128>(), b_val in any::<u128>()) {
620			test_add_packed::<PackedBinaryField128x1b>(a_val, b_val)
621		}
622
623		#[test]
624		fn test_add_packed_16x8b(a_val in any::<u128>(), b_val in any::<u128>()) {
625			test_add_packed::<PackedAESBinaryField16x8b>(a_val, b_val)
626		}
627
628		#[test]
629		fn test_add_packed_1x128b(a_val in any::<u128>(), b_val in any::<u128>()) {
630			test_add_packed::<PackedBinaryGhash1x128b>(a_val, b_val)
631		}
632	}
633
634	#[test]
635	fn test_mul_packed_256x1b() {
636		test_mul_packed_random::<PackedBinaryField256x1b>()
637	}
638
639	#[test]
640	fn test_mul_packed_32x8b() {
641		test_mul_packed_random::<PackedAESBinaryField32x8b>()
642	}
643
644	#[test]
645	fn test_mul_packed_2x128b() {
646		test_mul_packed_random::<PackedBinaryGhash2x128b>()
647	}
648
649	#[test]
650	fn test_iter_size_hint() {
651		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField128x1b>();
652	}
653
654	fn assert_valid_iterator_with_exact_size_hint<P: PackedField>() {
655		assert_eq!(P::default().iter().size_hint(), (P::WIDTH, Some(P::WIDTH)));
656		assert_eq!(P::default().into_iter().size_hint(), (P::WIDTH, Some(P::WIDTH)));
657		assert_eq!(P::default().iter().count(), P::WIDTH);
658		assert_eq!(P::default().into_iter().count(), P::WIDTH);
659	}
660
661	define_multiply_tests!(Mul::mul, PackedField);
662
663	define_square_tests!(Square::square, PackedField);
664
665	define_invert_tests!(InvertOrZero::invert_or_zero, PackedField);
666
667	proptest! {
668		#[test]
669		fn test_interleave_2b(a_val in 0u8..3, b_val in 0u8..3) {
670			check_interleave_all_heights::<PackedBinaryField2x1b>(U2::new(a_val), U2::new(b_val));
671		}
672
673		#[test]
674		fn test_interleave_4b(a_val in 0u8..16, b_val in 0u8..16) {
675			check_interleave_all_heights::<PackedBinaryField4x1b>(U4::new(a_val), U4::new(b_val));
676		}
677
678		#[test]
679		fn test_interleave_8b(a_val in 0u8.., b_val in 0u8..) {
680			check_interleave_all_heights::<PackedBinaryField8x1b>(a_val, b_val);
681			check_interleave_all_heights::<PackedAESBinaryField1x8b>(a_val, b_val);
682		}
683
684		#[test]
685		fn test_interleave_16b(a_val in 0u16.., b_val in 0u16..) {
686			check_interleave_all_heights::<PackedBinaryField16x1b>(a_val, b_val);
687			check_interleave_all_heights::<PackedAESBinaryField2x8b>(a_val, b_val);
688		}
689
690		#[test]
691		fn test_interleave_32b(a_val in 0u32.., b_val in 0u32..) {
692			check_interleave_all_heights::<PackedBinaryField32x1b>(a_val, b_val);
693			check_interleave_all_heights::<PackedAESBinaryField4x8b>(a_val, b_val);
694		}
695
696		#[test]
697		fn test_interleave_64b(a_val in 0u64.., b_val in 0u64..) {
698			check_interleave_all_heights::<PackedBinaryField64x1b>(a_val, b_val);
699			check_interleave_all_heights::<PackedAESBinaryField8x8b>(a_val, b_val);
700		}
701
702		#[test]
703		#[allow(clippy::useless_conversion)] // this warning depends on the target platform
704		fn test_interleave_128b(a_val in 0u128.., b_val in 0u128..) {
705			check_interleave_all_heights::<PackedBinaryField128x1b>(a_val.into(), b_val.into());
706			check_interleave_all_heights::<PackedAESBinaryField16x8b>(a_val.into(), b_val.into());
707			check_interleave_all_heights::<PackedBinaryGhash1x128b>(a_val.into(), b_val.into());
708		}
709
710		#[test]
711		fn test_interleave_256b(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
712			check_interleave_all_heights::<PackedBinaryField256x1b>(a_val.into(), b_val.into());
713			check_interleave_all_heights::<PackedAESBinaryField32x8b>(a_val.into(), b_val.into());
714			check_interleave_all_heights::<PackedBinaryGhash2x128b>(a_val.into(), b_val.into());
715		}
716
717		#[test]
718		fn test_interleave_512b(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
719			check_interleave_all_heights::<PackedBinaryField512x1b>(a_val.into(), b_val.into());
720			check_interleave_all_heights::<PackedAESBinaryField64x8b>(a_val.into(), b_val.into());
721			check_interleave_all_heights::<PackedBinaryGhash4x128b>(a_val.into(), b_val.into());
722		}
723
724		#[test]
725		fn check_transpose_2b(a_val in 0u8..3, b_val in 0u8..3) {
726			check_transpose_all_heights::<PackedBinaryField2x1b>(U2::new(a_val), U2::new(b_val));
727		}
728
729		#[test]
730		fn check_transpose_4b(a_val in 0u8..16, b_val in 0u8..16) {
731			check_transpose_all_heights::<PackedBinaryField4x1b>(U4::new(a_val), U4::new(b_val));
732		}
733
734		#[test]
735		fn check_transpose_8b(a_val in 0u8.., b_val in 0u8..) {
736			check_transpose_all_heights::<PackedBinaryField8x1b>(a_val, b_val);
737			check_transpose_all_heights::<PackedAESBinaryField1x8b>(a_val, b_val);
738		}
739
740		#[test]
741		fn check_transpose_16b(a_val in 0u16.., b_val in 0u16..) {
742			check_transpose_all_heights::<PackedBinaryField16x1b>(a_val, b_val);
743			check_transpose_all_heights::<PackedAESBinaryField2x8b>(a_val, b_val);
744		}
745
746		#[test]
747		fn check_transpose_32b(a_val in 0u32.., b_val in 0u32..) {
748			check_transpose_all_heights::<PackedBinaryField32x1b>(a_val, b_val);
749			check_transpose_all_heights::<PackedAESBinaryField4x8b>(a_val, b_val);
750		}
751
752		#[test]
753		fn check_transpose_64b(a_val in 0u64.., b_val in 0u64..) {
754			check_transpose_all_heights::<PackedBinaryField64x1b>(a_val, b_val);
755			check_transpose_all_heights::<PackedAESBinaryField8x8b>(a_val, b_val);
756		}
757
758		#[test]
759		#[allow(clippy::useless_conversion)] // this warning depends on the target platform
760		fn check_transpose_128b(a_val in 0u128.., b_val in 0u128..) {
761			check_transpose_all_heights::<PackedBinaryField128x1b>(a_val.into(), b_val.into());
762			check_transpose_all_heights::<PackedAESBinaryField16x8b>(a_val.into(), b_val.into());
763			check_transpose_all_heights::<PackedBinaryGhash1x128b>(a_val.into(), b_val.into());
764		}
765
766		#[test]
767		fn check_transpose_256b(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
768			check_transpose_all_heights::<PackedBinaryField256x1b>(a_val.into(), b_val.into());
769			check_transpose_all_heights::<PackedAESBinaryField32x8b>(a_val.into(), b_val.into());
770			check_transpose_all_heights::<PackedBinaryGhash2x128b>(a_val.into(), b_val.into());
771		}
772
773		#[test]
774		fn check_transpose_512b(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
775			check_transpose_all_heights::<PackedBinaryField512x1b>(a_val.into(), b_val.into());
776			check_transpose_all_heights::<PackedAESBinaryField64x8b>(a_val.into(), b_val.into());
777			check_transpose_all_heights::<PackedBinaryGhash4x128b>(a_val.into(), b_val.into());
778		}
779	}
780}