Skip to main content

binius_field/
packed.rs

1// Copyright 2023-2025 Irreducible Inc.
2// Copyright 2026 The Binius Developers
3
4//! Traits for packed field elements which support SIMD implementations.
5//!
6//! Interfaces are derived from [`plonky2`](https://github.com/mir-protocol/plonky2).
7
8use std::{
9	fmt::Debug,
10	iter,
11	ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
12};
13
14use binius_utils::{
15	iter::IterExtensions,
16	random_access_sequence::{RandomAccessSequence, RandomAccessSequenceMut},
17};
18use bytemuck::Zeroable;
19
20use super::{PackedExtension, Random, arithmetic_traits::Square};
21use crate::{BinaryField, Field, WideMul, field::FieldOps};
22
23/// A packed field represents a vector of underlying field elements.
24///
25/// Arithmetic operations on packed field elements can be accelerated with SIMD CPU instructions.
26/// The vector width is a constant, `WIDTH`. This trait requires that the width must be a power of
27/// two.
28pub trait PackedField:
29	Default
30	+ Debug
31	+ Clone
32	+ Copy
33	+ Eq
34	+ Sized
35	+ FieldOps
36	+ Add<Self::Scalar, Output = Self>
37	+ Sub<Self::Scalar, Output = Self>
38	+ Mul<Self::Scalar, Output = Self>
39	+ AddAssign<Self::Scalar>
40	+ SubAssign<Self::Scalar>
41	+ MulAssign<Self::Scalar>
42	+ Send
43	+ Sync
44	+ Zeroable
45	+ Random
46	+ WideMul<Output: Debug + Send + Sync + 'static>
47	+ 'static
48{
49	/// Base-2 logarithm of the number of field elements packed into one packed element.
50	const LOG_WIDTH: usize;
51
52	/// The number of field elements packed into one packed element.
53	///
54	/// WIDTH is guaranteed to equal 2^LOG_WIDTH.
55	const WIDTH: usize = 1 << Self::LOG_WIDTH;
56
57	/// Get the scalar at a given index without bounds checking.
58	/// # Safety
59	/// The caller must ensure that `i` is less than `WIDTH`.
60	unsafe fn get_unchecked(&self, i: usize) -> Self::Scalar;
61
62	/// Set the scalar at a given index without bounds checking.
63	/// # Safety
64	/// The caller must ensure that `i` is less than `WIDTH`.
65	unsafe fn set_unchecked(&mut self, i: usize, scalar: Self::Scalar);
66
67	/// Get the scalar at a given index.
68	///
69	/// # Preconditions
70	///
71	/// * `i` must be less than `WIDTH`.
72	#[inline]
73	fn get(&self, i: usize) -> Self::Scalar {
74		assert!(i < Self::WIDTH, "index {i} out of range for width {}", Self::WIDTH);
75		// Safety: assertion above guarantees i < WIDTH
76		unsafe { self.get_unchecked(i) }
77	}
78
79	/// Set the scalar at a given index.
80	///
81	/// # Preconditions
82	///
83	/// * `i` must be less than `WIDTH`.
84	#[inline]
85	fn set(&mut self, i: usize, scalar: Self::Scalar) {
86		assert!(i < Self::WIDTH, "index {i} out of range for width {}", Self::WIDTH);
87		// Safety: assertion above guarantees i < WIDTH
88		unsafe { self.set_unchecked(i, scalar) }
89	}
90
91	#[inline]
92	fn into_iter(self) -> impl Iterator<Item = Self::Scalar> + Send + Clone {
93		(0..Self::WIDTH).map_skippable(move |i|
94			// Safety: `i` is always less than `WIDTH`
95			unsafe { self.get_unchecked(i) })
96	}
97
98	#[inline]
99	fn iter(&self) -> impl Iterator<Item = Self::Scalar> + Send + Clone + '_ {
100		(0..Self::WIDTH).map_skippable(move |i|
101			// Safety: `i` is always less than `WIDTH`
102			unsafe { self.get_unchecked(i) })
103	}
104
105	#[inline]
106	fn iter_slice(slice: &[Self]) -> impl Iterator<Item = Self::Scalar> + Send + Clone + '_ {
107		slice.iter().flat_map(Self::iter)
108	}
109
110	/// Initialize zero position with `scalar`, set other elements to zero.
111	#[inline(always)]
112	fn set_single(scalar: Self::Scalar) -> Self {
113		let mut result = Self::default();
114		result.set(0, scalar);
115
116		result
117	}
118
119	fn broadcast(scalar: Self::Scalar) -> Self;
120
121	/// Construct a packed field element from a function that returns scalar values by index.
122	fn from_fn(f: impl FnMut(usize) -> Self::Scalar) -> Self;
123
124	/// Creates a packed field from a fallible function applied to each index.
125	fn try_from_fn<E>(mut f: impl FnMut(usize) -> Result<Self::Scalar, E>) -> Result<Self, E> {
126		let mut result = Self::default();
127		for i in 0..Self::WIDTH {
128			let scalar = f(i)?;
129			unsafe {
130				result.set_unchecked(i, scalar);
131			};
132		}
133		Ok(result)
134	}
135
136	/// Construct a packed field element from a sequence of scalars.
137	///
138	/// If the number of values in the sequence is less than the packing width, the remaining
139	/// elements are set to zero. If greater than the packing width, the excess elements are
140	/// ignored.
141	#[inline]
142	fn from_scalars(values: impl IntoIterator<Item = Self::Scalar>) -> Self {
143		let mut result = Self::default();
144		for (i, val) in values.into_iter().take(Self::WIDTH).enumerate() {
145			result.set(i, val);
146		}
147		result
148	}
149
150	/// Returns the value to the power `exp`.
151	fn pow(self, exp: u64) -> Self {
152		let mut res = Self::one();
153		for i in (0..64).rev() {
154			res = Square::square(res);
155			if ((exp >> i) & 1) == 1 {
156				res.mul_assign(self)
157			}
158		}
159		res
160	}
161
162	/// Interleaves blocks of this packed vector with another packed vector.
163	///
164	/// The operation can be seen as stacking the two vectors, dividing them into 2x2 matrices of
165	/// blocks, where each block is 2^`log_block_width` elements, and transposing the matrices.
166	///
167	/// Consider this example, where `LOG_WIDTH` is 3 and `log_block_len` is 1:
168	///     A = [a0, a1, a2, a3, a4, a5, a6, a7]
169	///     B = [b0, b1, b2, b3, b4, b5, b6, b7]
170	///
171	/// The interleaved result is
172	///     A' = [a0, a1, b0, b1, a4, a5, b4, b5]
173	///     B' = [a2, a3, b2, b3, a6, a7, b6, b7]
174	///
175	/// ## Preconditions
176	/// * `log_block_len` must be strictly less than `LOG_WIDTH`.
177	fn interleave(self, other: Self, log_block_len: usize) -> (Self, Self);
178
179	/// Unzips interleaved blocks of this packed vector with another packed vector.
180	///
181	/// Consider this example, where `LOG_WIDTH` is 3 and `log_block_len` is 1:
182	///    A = [a0, a1, b0, b1, a2, a3, b2, b3]
183	///    B = [a4, a5, b4, b5, a6, a7, b6, b7]
184	///
185	/// The transposed result is
186	///    A' = [a0, a1, a2, a3, a4, a5, a6, a7]
187	///    B' = [b0, b1, b2, b3, b4, b5, b6, b7]
188	///
189	/// ## Preconditions
190	/// * `log_block_len` must be strictly less than `LOG_WIDTH`.
191	fn unzip(self, other: Self, log_block_len: usize) -> (Self, Self);
192
193	/// Spread takes a block of elements within a packed field and repeats them to the full packing
194	/// width.
195	///
196	/// Spread can be seen as an extension of the functionality of [`Self::broadcast`].
197	///
198	/// ## Examples
199	///
200	/// ```
201	/// use binius_field::{BinaryField1b, PackedField, PackedBinaryField8x1b};
202	///
203	/// let input =
204	///     PackedBinaryField8x1b::from_scalars([0, 1, 0, 1, 0, 1, 0, 1].map(BinaryField1b::from));
205	/// assert_eq!(
206	///     input.spread(0, 1),
207	///     PackedBinaryField8x1b::from_scalars([1, 1, 1, 1, 1, 1, 1, 1].map(BinaryField1b::from))
208	/// );
209	/// assert_eq!(
210	///     input.spread(1, 0),
211	///     PackedBinaryField8x1b::from_scalars([0, 0, 0, 0, 1, 1, 1, 1].map(BinaryField1b::from))
212	/// );
213	/// assert_eq!(
214	///     input.spread(2, 0),
215	///     PackedBinaryField8x1b::from_scalars([0, 0, 1, 1, 0, 0, 1, 1].map(BinaryField1b::from))
216	/// );
217	/// assert_eq!(input.spread(3, 0), input);
218	/// ```
219	///
220	/// ## Preconditions
221	///
222	/// * `log_block_len` must be less than or equal to `LOG_WIDTH`.
223	/// * `block_idx` must be less than `2^(Self::LOG_WIDTH - log_block_len)`.
224	#[inline]
225	fn spread(self, log_block_len: usize, block_idx: usize) -> Self {
226		assert!(log_block_len <= Self::LOG_WIDTH);
227		assert!(block_idx < 1 << (Self::LOG_WIDTH - log_block_len));
228
229		// Safety: is guaranteed by the preconditions.
230		unsafe { self.spread_unchecked(log_block_len, block_idx) }
231	}
232
233	/// Unsafe version of [`Self::spread`].
234	///
235	/// # Safety
236	/// The caller must ensure that `log_block_len` is less than or equal to `LOG_WIDTH` and
237	/// `block_idx` is less than `2^(Self::LOG_WIDTH - log_block_len)`.
238	#[inline]
239	unsafe fn spread_unchecked(self, log_block_len: usize, block_idx: usize) -> Self {
240		let block_len = 1 << log_block_len;
241		let repeat = 1 << (Self::LOG_WIDTH - log_block_len);
242
243		Self::from_scalars(
244			self.iter()
245				.skip(block_idx * block_len)
246				.take(block_len)
247				.flat_map(|elem| iter::repeat_n(elem, repeat)),
248		)
249	}
250}
251
252/// Iterate over scalar values in a packed field slice.
253///
254/// The iterator skips the first `offset` elements. This is more efficient than skipping elements of
255/// the iterator returned.
256#[inline]
257pub fn iter_packed_slice_with_offset<P: PackedField>(
258	packed: &[P],
259	offset: usize,
260) -> impl Iterator<Item = P::Scalar> + '_ + Send {
261	let (packed, offset): (&[P], usize) = if offset < packed.len() * P::WIDTH {
262		(&packed[(offset / P::WIDTH)..], offset % P::WIDTH)
263	} else {
264		(&[], 0)
265	};
266
267	P::iter_slice(packed).skip(offset)
268}
269
270#[inline(always)]
271pub fn get_packed_slice<P: PackedField>(packed: &[P], i: usize) -> P::Scalar {
272	assert!(i >> P::LOG_WIDTH < packed.len(), "index out of bounds");
273
274	unsafe { get_packed_slice_unchecked(packed, i) }
275}
276
277/// Returns the scalar at the given index without bounds checking.
278/// # Safety
279/// The caller must ensure that `i` is less than `P::WIDTH * packed.len()`.
280#[inline(always)]
281pub unsafe fn get_packed_slice_unchecked<P: PackedField>(packed: &[P], i: usize) -> P::Scalar {
282	// TODO: Consider putting a get_in_slice method on Divisible
283
284	// Safety:
285	// - `i / P::WIDTH` is within the bounds of `packed` if `i` is less than
286	//   `len_packed_slice(packed)`
287	// - `i % P::WIDTH` is always less than `P::WIDTH
288	unsafe {
289		packed
290			.get_unchecked(i >> P::LOG_WIDTH)
291			.get_unchecked(i % P::WIDTH)
292	}
293}
294
295/// Sets the scalar at the given index without bounds checking.
296/// # Safety
297/// The caller must ensure that `i` is less than `P::WIDTH * packed.len()`.
298#[inline]
299pub unsafe fn set_packed_slice_unchecked<P: PackedField>(
300	packed: &mut [P],
301	i: usize,
302	scalar: P::Scalar,
303) {
304	// TODO: Consider putting a set_in_slice method on Divisible
305
306	// Safety: if `i` is less than `len_packed_slice(packed)`, then
307	// - `i / P::WIDTH` is within the bounds of `packed`
308	// - `i % P::WIDTH` is always less than `P::WIDTH
309	unsafe {
310		packed
311			.get_unchecked_mut(i >> P::LOG_WIDTH)
312			.set_unchecked(i % P::WIDTH, scalar)
313	}
314}
315
316#[inline]
317pub fn set_packed_slice<P: PackedField>(packed: &mut [P], i: usize, scalar: P::Scalar) {
318	assert!(i >> P::LOG_WIDTH < packed.len(), "index out of bounds");
319
320	unsafe { set_packed_slice_unchecked(packed, i, scalar) }
321}
322
323#[inline(always)]
324pub const fn len_packed_slice<P: PackedField>(packed: &[P]) -> usize {
325	packed.len() << P::LOG_WIDTH
326}
327
328/// Construct a packed field element from a function that returns scalar values by index with the
329/// given offset in packed elements. E.g. if `offset` is 2, and `WIDTH` is 4, `f(9)` will be used
330/// to set the scalar at index 1 in the packed element.
331#[inline]
332pub fn packed_from_fn_with_offset<P: PackedField>(
333	offset: usize,
334	mut f: impl FnMut(usize) -> P::Scalar,
335) -> P {
336	P::from_fn(|i| f(i + offset * P::WIDTH))
337}
338
339/// Multiply packed field element by a subfield scalar.
340pub fn mul_by_subfield_scalar<P: PackedExtension<FS>, FS: Field>(val: P, multiplier: FS) -> P {
341	P::cast_ext(P::cast_base(val) * P::PackedSubfield::broadcast(multiplier))
342}
343
344/// Pack a slice of scalars into a vector of packed field elements.
345pub fn pack_slice<P: PackedField>(scalars: &[P::Scalar]) -> Vec<P> {
346	scalars
347		.chunks(P::WIDTH)
348		.map(|chunk| P::from_scalars(chunk.iter().copied()))
349		.collect()
350}
351
352/// A slice of packed field elements as a collection of scalars.
353#[derive(Clone)]
354pub struct PackedSlice<'a, P: PackedField> {
355	slice: &'a [P],
356	len: usize,
357}
358
359impl<'a, P: PackedField> PackedSlice<'a, P> {
360	#[inline(always)]
361	pub fn new(slice: &'a [P]) -> Self {
362		Self {
363			slice,
364			len: len_packed_slice(slice),
365		}
366	}
367
368	#[inline(always)]
369	pub fn new_with_len(slice: &'a [P], len: usize) -> Self {
370		assert!(len <= len_packed_slice(slice));
371
372		Self { slice, len }
373	}
374}
375
376impl<P: PackedField> RandomAccessSequence<P::Scalar> for PackedSlice<'_, P> {
377	#[inline(always)]
378	fn len(&self) -> usize {
379		self.len
380	}
381
382	#[inline(always)]
383	unsafe fn get_unchecked(&self, index: usize) -> P::Scalar {
384		unsafe { get_packed_slice_unchecked(self.slice, index) }
385	}
386}
387
388/// A mutable slice of packed field elements as a collection of scalars.
389pub struct PackedSliceMut<'a, P: PackedField> {
390	slice: &'a mut [P],
391	len: usize,
392}
393
394impl<'a, P: PackedField> PackedSliceMut<'a, P> {
395	#[inline(always)]
396	pub fn new(slice: &'a mut [P]) -> Self {
397		let len = len_packed_slice(slice);
398		Self { slice, len }
399	}
400
401	#[inline(always)]
402	pub fn new_with_len(slice: &'a mut [P], len: usize) -> Self {
403		assert!(len <= len_packed_slice(slice));
404
405		Self { slice, len }
406	}
407}
408
409impl<P: PackedField> RandomAccessSequence<P::Scalar> for PackedSliceMut<'_, P> {
410	#[inline(always)]
411	fn len(&self) -> usize {
412		self.len
413	}
414
415	#[inline(always)]
416	unsafe fn get_unchecked(&self, index: usize) -> P::Scalar {
417		unsafe { get_packed_slice_unchecked(self.slice, index) }
418	}
419}
420impl<P: PackedField> RandomAccessSequenceMut<P::Scalar> for PackedSliceMut<'_, P> {
421	#[inline(always)]
422	unsafe fn set_unchecked(&mut self, index: usize, value: P::Scalar) {
423		unsafe { set_packed_slice_unchecked(self.slice, index, value) }
424	}
425}
426
427impl<F: Field> PackedField for F {
428	const LOG_WIDTH: usize = 0;
429
430	#[inline]
431	unsafe fn get_unchecked(&self, _i: usize) -> Self::Scalar {
432		*self
433	}
434
435	#[inline]
436	unsafe fn set_unchecked(&mut self, _i: usize, scalar: Self::Scalar) {
437		*self = scalar;
438	}
439
440	#[inline]
441	fn iter(&self) -> impl Iterator<Item = Self::Scalar> + Send + Clone + '_ {
442		iter::once(*self)
443	}
444
445	#[inline]
446	fn into_iter(self) -> impl Iterator<Item = Self::Scalar> + Send + Clone {
447		iter::once(self)
448	}
449
450	#[inline]
451	fn iter_slice(slice: &[Self]) -> impl Iterator<Item = Self::Scalar> + Send + Clone + '_ {
452		slice.iter().copied()
453	}
454
455	fn interleave(self, _other: Self, _log_block_len: usize) -> (Self, Self) {
456		panic!("cannot interleave when WIDTH = 1");
457	}
458
459	fn unzip(self, _other: Self, _log_block_len: usize) -> (Self, Self) {
460		panic!("cannot transpose when WIDTH = 1");
461	}
462
463	#[inline]
464	fn broadcast(scalar: Self::Scalar) -> Self {
465		scalar
466	}
467
468	#[inline]
469	fn from_fn(mut f: impl FnMut(usize) -> Self::Scalar) -> Self {
470		f(0)
471	}
472
473	#[inline]
474	unsafe fn spread_unchecked(self, _log_block_len: usize, _block_idx: usize) -> Self {
475		self
476	}
477}
478
479/// A helper trait to make the generic bounds shorter
480pub trait PackedBinaryField: PackedField<Scalar: BinaryField> {}
481
482impl<PT> PackedBinaryField for PT where PT: PackedField<Scalar: BinaryField> {}
483
484#[cfg(test)]
485mod tests {
486	use itertools::Itertools;
487	use rand::prelude::*;
488
489	use super::*;
490	use crate::{
491		AESTowerField8b, BinaryField1b, BinaryField128bGhash, PackedBinaryGhash1x128b,
492		PackedBinaryGhash2x128b, PackedBinaryGhash4x128b, PackedField,
493		arch::{
494			packed_1::*, packed_2::*, packed_4::*, packed_8::*, packed_16::*, packed_32::*,
495			packed_64::*, packed_128::*, packed_256::*, packed_512::*, packed_aes_8::*,
496			packed_aes_16::*, packed_aes_32::*, packed_aes_64::*, packed_aes_128::*,
497			packed_aes_256::*, packed_aes_512::*,
498		},
499	};
500
501	trait PackedFieldTest {
502		fn run<P: PackedField>(&self);
503	}
504
505	/// Run the test for all the packed fields defined in this crate.
506	fn run_for_all_packed_fields(test: &impl PackedFieldTest) {
507		// B1
508		test.run::<BinaryField1b>();
509		test.run::<PackedBinaryField1x1b>();
510		test.run::<PackedBinaryField2x1b>();
511		test.run::<PackedBinaryField4x1b>();
512		test.run::<PackedBinaryField8x1b>();
513		test.run::<PackedBinaryField16x1b>();
514		test.run::<PackedBinaryField32x1b>();
515		test.run::<PackedBinaryField64x1b>();
516		test.run::<PackedBinaryField128x1b>();
517		test.run::<PackedBinaryField256x1b>();
518		test.run::<PackedBinaryField512x1b>();
519
520		// AES
521		test.run::<AESTowerField8b>();
522		test.run::<PackedAESBinaryField1x8b>();
523		test.run::<PackedAESBinaryField2x8b>();
524		test.run::<PackedAESBinaryField4x8b>();
525		test.run::<PackedAESBinaryField8x8b>();
526		test.run::<PackedAESBinaryField16x8b>();
527		test.run::<PackedAESBinaryField32x8b>();
528		test.run::<PackedAESBinaryField64x8b>();
529
530		// GHASH
531		test.run::<BinaryField128bGhash>();
532		test.run::<PackedBinaryGhash1x128b>();
533		test.run::<PackedBinaryGhash2x128b>();
534		test.run::<PackedBinaryGhash4x128b>();
535	}
536
537	fn check_value_iteration<P: PackedField>(mut rng: impl Rng) {
538		let packed = P::random(&mut rng);
539		let mut iter = packed.iter();
540		for i in 0..P::WIDTH {
541			assert_eq!(packed.get(i), iter.next().unwrap());
542		}
543		assert!(iter.next().is_none());
544	}
545
546	fn check_ref_iteration<P: PackedField>(mut rng: impl Rng) {
547		let packed = P::random(&mut rng);
548		let mut iter = packed.into_iter();
549		for i in 0..P::WIDTH {
550			assert_eq!(packed.get(i), iter.next().unwrap());
551		}
552		assert!(iter.next().is_none());
553	}
554
555	fn check_slice_iteration<P: PackedField>(mut rng: impl Rng) {
556		for len in [0, 1, 5] {
557			let packed = std::iter::repeat_with(|| P::random(&mut rng))
558				.take(len)
559				.collect::<Vec<_>>();
560
561			let elements_count = len * P::WIDTH;
562			for offset in [
563				0,
564				1,
565				rng.random_range(0..elements_count.max(1)),
566				elements_count.saturating_sub(1),
567				elements_count,
568			] {
569				let actual = iter_packed_slice_with_offset(&packed, offset).collect::<Vec<_>>();
570				let expected = (offset..elements_count)
571					.map(|i| get_packed_slice(&packed, i))
572					.collect::<Vec<_>>();
573
574				assert_eq!(actual, expected);
575			}
576		}
577	}
578
579	struct PackedFieldIterationTest;
580
581	impl PackedFieldTest for PackedFieldIterationTest {
582		fn run<P: PackedField>(&self) {
583			let mut rng = StdRng::seed_from_u64(0);
584
585			check_value_iteration::<P>(&mut rng);
586			check_ref_iteration::<P>(&mut rng);
587			check_slice_iteration::<P>(&mut rng);
588		}
589	}
590
591	#[test]
592	fn test_iteration() {
593		run_for_all_packed_fields(&PackedFieldIterationTest);
594	}
595
596	fn check_collection<F: Field>(collection: &impl RandomAccessSequence<F>, expected: &[F]) {
597		assert_eq!(collection.len(), expected.len());
598
599		for (i, v) in expected.iter().enumerate() {
600			assert_eq!(&collection.get(i), v);
601			assert_eq!(&unsafe { collection.get_unchecked(i) }, v);
602		}
603	}
604
605	fn check_collection_get_set<F: Field>(
606		collection: &mut impl RandomAccessSequenceMut<F>,
607		random: &mut impl FnMut() -> F,
608	) {
609		for i in 0..collection.len() {
610			let value = random();
611			collection.set(i, value);
612			assert_eq!(collection.get(i), value);
613			assert_eq!(unsafe { collection.get_unchecked(i) }, value);
614		}
615	}
616
617	#[test]
618	fn check_packed_slice() {
619		let slice: &[PackedAESBinaryField16x8b] = &[];
620		let packed_slice = PackedSlice::new(slice);
621		check_collection(&packed_slice, &[]);
622		let packed_slice = PackedSlice::new_with_len(slice, 0);
623		check_collection(&packed_slice, &[]);
624
625		let mut rng = StdRng::seed_from_u64(0);
626		let slice: &[PackedAESBinaryField16x8b] = &[
627			PackedAESBinaryField16x8b::random(&mut rng),
628			PackedAESBinaryField16x8b::random(&mut rng),
629		];
630		let packed_slice = PackedSlice::new(slice);
631		check_collection(&packed_slice, &PackedField::iter_slice(slice).collect_vec());
632
633		let packed_slice = PackedSlice::new_with_len(slice, 3);
634		check_collection(&packed_slice, &PackedField::iter_slice(slice).take(3).collect_vec());
635	}
636
637	#[test]
638	fn check_packed_slice_mut() {
639		let mut rng = StdRng::seed_from_u64(0);
640		let mut random = || AESTowerField8b::random(&mut rng);
641
642		let slice: &mut [PackedAESBinaryField16x8b] = &mut [];
643		let packed_slice = PackedSliceMut::new(slice);
644		check_collection(&packed_slice, &[]);
645		let packed_slice = PackedSliceMut::new_with_len(slice, 0);
646		check_collection(&packed_slice, &[]);
647
648		let mut rng = StdRng::seed_from_u64(0);
649		let slice: &mut [PackedAESBinaryField16x8b] = &mut [
650			PackedAESBinaryField16x8b::random(&mut rng),
651			PackedAESBinaryField16x8b::random(&mut rng),
652		];
653		let values = PackedField::iter_slice(slice).collect_vec();
654		let mut packed_slice = PackedSliceMut::new(slice);
655		check_collection(&packed_slice, &values);
656		check_collection_get_set(&mut packed_slice, &mut random);
657
658		let values = PackedField::iter_slice(slice).collect_vec();
659		let mut packed_slice = PackedSliceMut::new_with_len(slice, 3);
660		check_collection(&packed_slice, &values[..3]);
661		check_collection_get_set(&mut packed_slice, &mut random);
662	}
663}