Skip to main content

binius_field/
packed_binary_field.rs

1// Copyright 2023-2025 Irreducible Inc.
2// Copyright 2026 The Binius Developers
3
4use std::ops::Mul;
5
6use crate::{
7	BinaryField1b,
8	arch::{M128, M256, M512, PackedPrimitiveType},
9	arithmetic_traits::{InvertOrZero, Square, WideMul},
10	underlier::{U1, U2, U4, UnderlierType},
11};
12
13// Type aliases for the `BinaryField1b` packings. The underlier determines the width; `M128`/`M256`/
14// `M512` resolve to the architecture-appropriate type (SIMD where available, scaled otherwise).
15pub type PackedBinaryField1x1b = PackedPrimitiveType<U1, BinaryField1b>;
16pub type PackedBinaryField2x1b = PackedPrimitiveType<U2, BinaryField1b>;
17pub type PackedBinaryField4x1b = PackedPrimitiveType<U4, BinaryField1b>;
18pub type PackedBinaryField8x1b = PackedPrimitiveType<u8, BinaryField1b>;
19pub type PackedBinaryField16x1b = PackedPrimitiveType<u16, BinaryField1b>;
20pub type PackedBinaryField32x1b = PackedPrimitiveType<u32, BinaryField1b>;
21pub type PackedBinaryField64x1b = PackedPrimitiveType<u64, BinaryField1b>;
22pub type PackedBinaryField128x1b = PackedPrimitiveType<M128, BinaryField1b>;
23pub type PackedBinaryField256x1b = PackedPrimitiveType<M256, BinaryField1b>;
24pub type PackedBinaryField512x1b = PackedPrimitiveType<M512, BinaryField1b>;
25
26// Every `BinaryField1b` packing shares the same arithmetic, which is available for any underlier:
27// addition is bitwise XOR (provided generically for all `PackedPrimitiveType` in `packed.rs`) and
28// multiplication is bitwise AND. Squaring and inversion are the identity, since `0` and `1` are
29// each their own square and inverse. A single blanket impl over `U` therefore replaces the
30// per-type definitions that the `define_packed_binary_field` macro used to generate.
31impl<U: UnderlierType> Mul for PackedPrimitiveType<U, BinaryField1b> {
32	type Output = Self;
33
34	#[inline]
35	#[allow(clippy::suspicious_arithmetic_impl)]
36	fn mul(self, rhs: Self) -> Self {
37		(self.0 & rhs.0).into()
38	}
39}
40
41impl<U: UnderlierType> Square for PackedPrimitiveType<U, BinaryField1b> {
42	#[inline]
43	fn square(self) -> Self {
44		self
45	}
46}
47
48impl<U: UnderlierType> InvertOrZero for PackedPrimitiveType<U, BinaryField1b> {
49	#[inline]
50	fn invert_or_zero(self) -> Self {
51		self
52	}
53}
54
55impl<U: UnderlierType> WideMul for PackedPrimitiveType<U, BinaryField1b> {
56	type Output = Self;
57
58	#[inline]
59	fn wide_mul(a: Self, b: Self) -> Self {
60		a * b
61	}
62
63	#[inline]
64	fn reduce(wide: Self) -> Self {
65		wide
66	}
67}
68
69/// Common code to test different multiply, square and invert implementations
70#[cfg(test)]
71pub mod test_utils {
72	use proptest::{
73		arbitrary::{Arbitrary, any},
74		strategy::{BoxedStrategy, Strategy},
75	};
76
77	use crate::{
78		Field, PackedField,
79		arch::{M128, M256, M512},
80		underlier::WithUnderlier,
81	};
82
83	// Proptest generates primitive underliers itself; a SIMD underlier borrows the strategy of the
84	// `u128` array it converts from, so `any::<P::Underlier>()` resolves at every packing width.
85	impl Arbitrary for M128 {
86		type Parameters = ();
87		type Strategy = BoxedStrategy<Self>;
88
89		fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
90			any::<u128>().prop_map(Self::from).boxed()
91		}
92	}
93
94	impl Arbitrary for M256 {
95		type Parameters = ();
96		type Strategy = BoxedStrategy<Self>;
97
98		fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
99			any::<[u128; 2]>().prop_map(Self::from).boxed()
100		}
101	}
102
103	impl Arbitrary for M512 {
104		type Parameters = ();
105		type Strategy = BoxedStrategy<Self>;
106
107		fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
108			any::<[u128; 4]>().prop_map(Self::from).boxed()
109		}
110	}
111
112	/// Every lane of the product is the product of the operands' lanes.
113	pub fn check_mul<P: PackedField + WithUnderlier>(a: P::Underlier, b: P::Underlier) {
114		let (a, b) = (P::from_underlier(a), P::from_underlier(b));
115
116		let c = a * b;
117		for i in 0..P::WIDTH {
118			assert_eq!(c.get(i), a.get(i) * b.get(i));
119		}
120	}
121
122	/// Every lane of the square is its own lane multiplied by itself.
123	pub fn check_square<P: PackedField + WithUnderlier>(a: P::Underlier) {
124		let a = P::from_underlier(a);
125
126		let c = a.square();
127		for i in 0..P::WIDTH {
128			assert_eq!(c.get(i), a.get(i) * a.get(i));
129		}
130	}
131
132	/// A non-zero lane inverts to its multiplicative inverse, and a zero lane inverts to zero.
133	pub fn check_invert_or_zero<P: PackedField + WithUnderlier>(a: P::Underlier) {
134		let a = P::from_underlier(a);
135
136		let c = a.invert_or_zero();
137		for i in 0..P::WIDTH {
138			if a.get(i).is_zero() {
139				assert!(c.get(i).is_zero());
140			} else {
141				assert_eq!(a.get(i) * c.get(i), P::Scalar::ONE);
142			}
143		}
144	}
145
146	/// One deferred product, reduced immediately, equals the plain multiply.
147	pub fn check_wide_mul<P: PackedField + WithUnderlier>(a: P::Underlier, b: P::Underlier) {
148		let (a, b) = (P::from_underlier(a), P::from_underlier(b));
149
150		assert_eq!(P::reduce(P::wide_mul(a, b)), a * b);
151	}
152
153	/// Two deferred products summed and reduced once equal the sum of the plain multiplies.
154	pub fn check_wide_mul_linearity<P: PackedField + WithUnderlier>(
155		a1: P::Underlier,
156		b1: P::Underlier,
157		a2: P::Underlier,
158		b2: P::Underlier,
159	) {
160		let (a1, b1) = (P::from_underlier(a1), P::from_underlier(b1));
161		let (a2, b2) = (P::from_underlier(a2), P::from_underlier(b2));
162
163		// The sum reaches wide values no single product produces, so this exercises the reduction
164		// over its full accumulated domain.
165		let sum = P::wide_mul(a1, b1) + P::wide_mul(a2, b2);
166		assert_eq!(P::reduce(sum), a1 * b1 + a2 * b2);
167	}
168
169	/// Check the packed arithmetic of `$ty` lane-by-lane against its own scalar field.
170	macro_rules! packed_field_tests {
171		($mod:ident, $ty:ty) => {
172			mod $mod {
173				use proptest::{prelude::any, proptest};
174				use $crate::packed_binary_field::test_utils::{
175					check_invert_or_zero, check_mul, check_square, check_wide_mul,
176					check_wide_mul_linearity,
177				};
178
179				use super::*;
180
181				// The underlier is the packing's raw bit pattern, so one strategy fits every width.
182				type U = <$ty as $crate::underlier::WithUnderlier>::Underlier;
183
184				proptest! {
185					#[test]
186					fn mul(a in any::<U>(), b in any::<U>()) {
187						check_mul::<$ty>(a, b);
188					}
189
190					#[test]
191					fn square(a in any::<U>()) {
192						check_square::<$ty>(a);
193					}
194
195					#[test]
196					fn invert_or_zero(a in any::<U>()) {
197						check_invert_or_zero::<$ty>(a);
198					}
199
200					#[test]
201					fn wide_mul(a in any::<U>(), b in any::<U>()) {
202						check_wide_mul::<$ty>(a, b);
203					}
204
205					#[test]
206					fn wide_mul_linearity(
207						a1 in any::<U>(), b1 in any::<U>(),
208						a2 in any::<U>(), b2 in any::<U>(),
209					) {
210						check_wide_mul_linearity::<$ty>(a1, b1, a2, b2);
211					}
212				}
213			}
214		};
215	}
216
217	pub(crate) use packed_field_tests;
218
219	pub fn check_interleave<P: PackedField + WithUnderlier>(
220		lhs: P::Underlier,
221		rhs: P::Underlier,
222		log_block_len: usize,
223	) {
224		let lhs = P::from_underlier(lhs);
225		let rhs = P::from_underlier(rhs);
226		let (a, b) = lhs.interleave(rhs, log_block_len);
227		let block_len = 1 << log_block_len;
228		for i in (0..P::WIDTH).step_by(block_len * 2) {
229			for j in 0..block_len {
230				assert_eq!(a.get(i + j), lhs.get(i + j));
231				assert_eq!(a.get(i + j + block_len), rhs.get(i + j));
232
233				assert_eq!(b.get(i + j), lhs.get(i + j + block_len));
234				assert_eq!(b.get(i + j + block_len), rhs.get(i + j + block_len));
235			}
236		}
237	}
238
239	pub fn check_interleave_all_heights<P: PackedField + WithUnderlier>(
240		lhs: P::Underlier,
241		rhs: P::Underlier,
242	) {
243		for log_block_len in 0..P::LOG_WIDTH {
244			check_interleave::<P>(lhs, rhs, log_block_len);
245		}
246	}
247
248	pub fn check_unzip<P: PackedField + WithUnderlier>(
249		lhs: P::Underlier,
250		rhs: P::Underlier,
251		log_block_len: usize,
252	) {
253		let lhs = P::from_underlier(lhs);
254		let rhs = P::from_underlier(rhs);
255		let block_len = 1 << log_block_len;
256		let (a, b) = lhs.unzip(rhs, log_block_len);
257		for i in (0..P::WIDTH / 2).step_by(block_len) {
258			for j in 0..block_len {
259				assert_eq!(
260					a.get(i + j),
261					lhs.get(2 * i + j),
262					"i: {}, j: {}, log_block_len: {}, P: {:?}",
263					i,
264					j,
265					log_block_len,
266					P::zero()
267				);
268				assert_eq!(
269					b.get(i + j),
270					lhs.get(2 * i + j + block_len),
271					"i: {}, j: {}, log_block_len: {}, P: {:?}",
272					i,
273					j,
274					log_block_len,
275					P::zero()
276				);
277			}
278		}
279
280		for i in (0..P::WIDTH / 2).step_by(block_len) {
281			for j in 0..block_len {
282				assert_eq!(
283					a.get(i + j + P::WIDTH / 2),
284					rhs.get(2 * i + j),
285					"i: {}, j: {}, log_block_len: {}, P: {:?}",
286					i,
287					j,
288					log_block_len,
289					P::zero()
290				);
291				assert_eq!(b.get(i + j + P::WIDTH / 2), rhs.get(2 * i + j + block_len));
292			}
293		}
294	}
295
296	pub fn check_transpose_all_heights<P: PackedField + WithUnderlier>(
297		lhs: P::Underlier,
298		rhs: P::Underlier,
299	) {
300		for log_block_len in 0..P::LOG_WIDTH {
301			check_unzip::<P>(lhs, rhs, log_block_len);
302		}
303	}
304}
305
306#[cfg(test)]
307mod tests {
308	use std::{fmt::Debug, iter::repeat_with};
309
310	use binius_utils::{
311		DeserializeBytes, FixedSizeSerializeBytes, SerializeBytes, bytes::BytesMut,
312	};
313	use proptest::prelude::*;
314	use rand::prelude::*;
315	use test_utils::check_interleave_all_heights;
316
317	use super::{test_utils::packed_field_tests, *};
318	use crate::{
319		Divisible, PackedAESBinaryField1x8b, PackedAESBinaryField16x8b, PackedAESBinaryField32x8b,
320		PackedAESBinaryField64x8b, PackedBinaryGhash1x128b, PackedBinaryGhash2x128b,
321		PackedBinaryGhash4x128b, PackedField, Random,
322		test_utils::check_transpose_all_heights,
323		underlier::{U2, U4},
324	};
325
326	fn test_add_packed<P: PackedField + From<u128>>(a_val: u128, b_val: u128) {
327		let a = P::from(a_val);
328		let b = P::from(b_val);
329		let c = a + b;
330		for i in 0..P::WIDTH {
331			assert_eq!(c.get(i), a.get(i) + b.get(i));
332		}
333	}
334
335	fn test_mul_packed<P: PackedField>(a: P, b: P) {
336		let c = a * b;
337		for i in 0..P::WIDTH {
338			assert_eq!(c.get(i), a.get(i) * b.get(i));
339		}
340	}
341
342	fn test_mul_packed_random<P: PackedField>() {
343		let mut rng = StdRng::seed_from_u64(0);
344		test_mul_packed(P::random(&mut rng), P::random(&mut rng));
345	}
346
347	fn test_set_then_get<P: PackedField>() {
348		let mut rng = StdRng::seed_from_u64(0);
349		let mut elem = P::random(&mut rng);
350
351		let scalars = repeat_with(|| P::Scalar::random(&mut rng))
352			.take(P::WIDTH)
353			.collect::<Vec<_>>();
354
355		for (i, val) in scalars.iter().enumerate() {
356			elem.set(i, *val);
357		}
358		for (i, val) in scalars.iter().enumerate() {
359			assert_eq!(elem.get(i), *val);
360		}
361	}
362
363	fn test_serialize_then_deserialize<P: PackedField + DeserializeBytes + SerializeBytes>() {
364		let mut buffer = BytesMut::new();
365		let mut rng = StdRng::seed_from_u64(0);
366		let packed = P::random(&mut rng);
367		packed.serialize(&mut buffer).unwrap();
368
369		let mut read_buffer = buffer.freeze();
370
371		assert_eq!(P::deserialize(&mut read_buffer).unwrap(), packed);
372	}
373
374	#[test]
375	fn test_set_then_get_128b() {
376		test_set_then_get::<PackedBinaryGhash1x128b>();
377		test_set_then_get::<PackedBinaryGhash2x128b>();
378		test_set_then_get::<PackedBinaryGhash4x128b>();
379	}
380
381	#[test]
382	fn test_serialize_then_deserialize_128b() {
383		test_serialize_then_deserialize::<PackedBinaryGhash1x128b>();
384		test_serialize_then_deserialize::<PackedBinaryGhash2x128b>();
385		test_serialize_then_deserialize::<PackedBinaryGhash4x128b>();
386	}
387
388	#[test]
389	fn test_serialize_deserialize_different_packing_width() {
390		let mut rng = StdRng::seed_from_u64(0);
391
392		let packed0 = PackedBinaryGhash1x128b::random(&mut rng);
393		let packed1 = PackedBinaryGhash1x128b::random(&mut rng);
394
395		let mut buffer = BytesMut::new();
396		packed0.serialize(&mut buffer).unwrap();
397		packed1.serialize(&mut buffer).unwrap();
398
399		let mut read_buffer = buffer.freeze();
400		let packed01 = PackedBinaryGhash2x128b::deserialize(&mut read_buffer).unwrap();
401
402		assert!(
403			packed01
404				.iter()
405				.zip([packed0, packed1])
406				.all(|(x, y)| x == y.get(0))
407		);
408	}
409
410	// TODO: Generate lots more proptests using macros
411	proptest! {
412		#[test]
413		fn test_add_packed_128x1b(a_val in any::<u128>(), b_val in any::<u128>()) {
414			test_add_packed::<PackedBinaryField128x1b>(a_val, b_val);
415		}
416
417		#[test]
418		fn test_add_packed_16x8b(a_val in any::<u128>(), b_val in any::<u128>()) {
419			test_add_packed::<PackedAESBinaryField16x8b>(a_val, b_val);
420		}
421
422		#[test]
423		fn test_add_packed_1x128b(a_val in any::<u128>(), b_val in any::<u128>()) {
424			test_add_packed::<PackedBinaryGhash1x128b>(a_val, b_val);
425		}
426	}
427
428	#[test]
429	fn test_mul_packed_256x1b() {
430		test_mul_packed_random::<PackedBinaryField256x1b>();
431	}
432
433	#[test]
434	fn test_mul_packed_32x8b() {
435		test_mul_packed_random::<PackedAESBinaryField32x8b>();
436	}
437
438	#[test]
439	fn test_mul_packed_2x128b() {
440		test_mul_packed_random::<PackedBinaryGhash2x128b>();
441	}
442
443	#[test]
444	fn test_iter_size_hint() {
445		assert_valid_iterator_with_exact_size_hint::<PackedBinaryField128x1b>();
446	}
447
448	fn assert_valid_iterator_with_exact_size_hint<P: PackedField>() {
449		assert_eq!(P::default().iter().size_hint(), (P::WIDTH, Some(P::WIDTH)));
450		assert_eq!(P::default().into_iter().size_hint(), (P::WIDTH, Some(P::WIDTH)));
451		assert_eq!(P::default().iter().count(), P::WIDTH);
452		assert_eq!(P::default().into_iter().count(), P::WIDTH);
453	}
454
455	packed_field_tests!(packed_8x1b, PackedBinaryField8x1b);
456	packed_field_tests!(packed_16x1b, PackedBinaryField16x1b);
457	packed_field_tests!(packed_32x1b, PackedBinaryField32x1b);
458	packed_field_tests!(packed_64x1b, PackedBinaryField64x1b);
459	packed_field_tests!(packed_128x1b, PackedBinaryField128x1b);
460	packed_field_tests!(packed_256x1b, PackedBinaryField256x1b);
461	packed_field_tests!(packed_512x1b, PackedBinaryField512x1b);
462
463	proptest! {
464		#[test]
465		fn test_interleave_2b(a_val in 0u8..3, b_val in 0u8..3) {
466			check_interleave_all_heights::<PackedBinaryField2x1b>(U2::new(a_val), U2::new(b_val));
467		}
468
469		#[test]
470		fn test_interleave_4b(a_val in 0u8..16, b_val in 0u8..16) {
471			check_interleave_all_heights::<PackedBinaryField4x1b>(U4::new(a_val), U4::new(b_val));
472		}
473
474		#[test]
475		fn test_interleave_8b(a_val in 0u8.., b_val in 0u8..) {
476			check_interleave_all_heights::<PackedBinaryField8x1b>(a_val, b_val);
477			check_interleave_all_heights::<PackedAESBinaryField1x8b>(a_val, b_val);
478		}
479
480		#[test]
481		fn test_interleave_16b(a_val in 0u16.., b_val in 0u16..) {
482			check_interleave_all_heights::<PackedBinaryField16x1b>(a_val, b_val);
483		}
484
485		#[test]
486		fn test_interleave_32b(a_val in 0u32.., b_val in 0u32..) {
487			check_interleave_all_heights::<PackedBinaryField32x1b>(a_val, b_val);
488		}
489
490		#[test]
491		fn test_interleave_64b(a_val in 0u64.., b_val in 0u64..) {
492			check_interleave_all_heights::<PackedBinaryField64x1b>(a_val, b_val);
493		}
494
495		#[test]
496		#[allow(clippy::useless_conversion)] // this warning depends on the target platform
497		fn test_interleave_128b(a_val in 0u128.., b_val in 0u128..) {
498			check_interleave_all_heights::<PackedBinaryField128x1b>(a_val.into(), b_val.into());
499			check_interleave_all_heights::<PackedAESBinaryField16x8b>(a_val.into(), b_val.into());
500			check_interleave_all_heights::<PackedBinaryGhash1x128b>(a_val.into(), b_val.into());
501		}
502
503		#[test]
504		fn test_interleave_256b(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
505			check_interleave_all_heights::<PackedBinaryField256x1b>(a_val.into(), b_val.into());
506			check_interleave_all_heights::<PackedAESBinaryField32x8b>(a_val.into(), b_val.into());
507			check_interleave_all_heights::<PackedBinaryGhash2x128b>(a_val.into(), b_val.into());
508		}
509
510		#[test]
511		fn test_interleave_512b(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
512			check_interleave_all_heights::<PackedBinaryField512x1b>(a_val.into(), b_val.into());
513			check_interleave_all_heights::<PackedAESBinaryField64x8b>(a_val.into(), b_val.into());
514			check_interleave_all_heights::<PackedBinaryGhash4x128b>(a_val.into(), b_val.into());
515		}
516
517		#[test]
518		fn check_transpose_2b(a_val in 0u8..3, b_val in 0u8..3) {
519			check_transpose_all_heights::<PackedBinaryField2x1b>(U2::new(a_val), U2::new(b_val));
520		}
521
522		#[test]
523		fn check_transpose_4b(a_val in 0u8..16, b_val in 0u8..16) {
524			check_transpose_all_heights::<PackedBinaryField4x1b>(U4::new(a_val), U4::new(b_val));
525		}
526
527		#[test]
528		fn check_transpose_8b(a_val in 0u8.., b_val in 0u8..) {
529			check_transpose_all_heights::<PackedBinaryField8x1b>(a_val, b_val);
530			check_transpose_all_heights::<PackedAESBinaryField1x8b>(a_val, b_val);
531		}
532
533		#[test]
534		fn check_transpose_16b(a_val in 0u16.., b_val in 0u16..) {
535			check_transpose_all_heights::<PackedBinaryField16x1b>(a_val, b_val);
536		}
537
538		#[test]
539		fn check_transpose_32b(a_val in 0u32.., b_val in 0u32..) {
540			check_transpose_all_heights::<PackedBinaryField32x1b>(a_val, b_val);
541		}
542
543		#[test]
544		fn check_transpose_64b(a_val in 0u64.., b_val in 0u64..) {
545			check_transpose_all_heights::<PackedBinaryField64x1b>(a_val, b_val);
546		}
547
548		#[test]
549		#[allow(clippy::useless_conversion)] // this warning depends on the target platform
550		fn check_transpose_128b(a_val in 0u128.., b_val in 0u128..) {
551			check_transpose_all_heights::<PackedBinaryField128x1b>(a_val.into(), b_val.into());
552			check_transpose_all_heights::<PackedAESBinaryField16x8b>(a_val.into(), b_val.into());
553			check_transpose_all_heights::<PackedBinaryGhash1x128b>(a_val.into(), b_val.into());
554		}
555
556		#[test]
557		fn check_transpose_256b(a_val in any::<[u128; 2]>(), b_val in any::<[u128; 2]>()) {
558			check_transpose_all_heights::<PackedBinaryField256x1b>(a_val.into(), b_val.into());
559			check_transpose_all_heights::<PackedAESBinaryField32x8b>(a_val.into(), b_val.into());
560			check_transpose_all_heights::<PackedBinaryGhash2x128b>(a_val.into(), b_val.into());
561		}
562
563		#[test]
564		fn check_transpose_512b(a_val in any::<[u128; 4]>(), b_val in any::<[u128; 4]>()) {
565			check_transpose_all_heights::<PackedBinaryField512x1b>(a_val.into(), b_val.into());
566			check_transpose_all_heights::<PackedAESBinaryField64x8b>(a_val.into(), b_val.into());
567			check_transpose_all_heights::<PackedBinaryGhash4x128b>(a_val.into(), b_val.into());
568		}
569	}
570
571	// The generic `SerializeBytes`/`DeserializeBytes` impls on `PackedPrimitiveType` round-trip
572	// across both integer underliers and (where applicable) SIMD underliers.
573	#[test]
574	fn test_serialize_roundtrip() {
575		fn check_roundtrip<
576			P: PackedField + SerializeBytes + DeserializeBytes + PartialEq + Debug,
577		>(
578			rng: &mut StdRng,
579		) {
580			let value = P::random(rng);
581			let mut buf = BytesMut::new();
582			value.serialize(&mut buf).unwrap();
583			let deserialized = P::deserialize(buf.freeze()).unwrap();
584			assert_eq!(value, deserialized);
585		}
586
587		let mut rng = StdRng::seed_from_u64(0);
588		check_roundtrip::<PackedBinaryField8x1b>(&mut rng);
589		check_roundtrip::<PackedBinaryField64x1b>(&mut rng);
590		check_roundtrip::<PackedBinaryField128x1b>(&mut rng);
591		check_roundtrip::<PackedBinaryGhash1x128b>(&mut rng);
592	}
593
594	// `FixedSizeSerializeBytes` propagates from the underlier. Integer-backed packed fields (here,
595	// `u8`- and `u64`-backed on every arch) report the underlier's byte size.
596	#[test]
597	fn test_fixed_size_byte_size() {
598		assert_eq!(<PackedBinaryField8x1b as FixedSizeSerializeBytes>::BYTE_SIZE, 1);
599		assert_eq!(<PackedBinaryField64x1b as FixedSizeSerializeBytes>::BYTE_SIZE, 8);
600	}
601}