binius_field/arch/portable/byte_sliced/
mod.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3mod invert;
4mod multiply;
5mod packed_byte_sliced;
6mod square;
7
8pub use packed_byte_sliced::*;
9
10#[cfg(test)]
11pub mod tests {
12	use proptest::prelude::*;
13
14	use super::*;
15	use crate::{
16		packed::{get_packed_slice, set_packed_slice},
17		underlier::WithUnderlier,
18		PackedAESBinaryField16x16b, PackedAESBinaryField16x32b, PackedAESBinaryField16x8b,
19		PackedAESBinaryField1x128b, PackedAESBinaryField2x128b, PackedAESBinaryField2x64b,
20		PackedAESBinaryField32x16b, PackedAESBinaryField32x8b, PackedAESBinaryField4x128b,
21		PackedAESBinaryField4x32b, PackedAESBinaryField4x64b, PackedAESBinaryField64x8b,
22		PackedAESBinaryField8x16b, PackedAESBinaryField8x32b, PackedAESBinaryField8x64b,
23		PackedBinaryField128x1b, PackedBinaryField256x1b, PackedBinaryField512x1b, PackedField,
24	};
25
26	fn scalars_vec_strategy<P: PackedField<Scalar: WithUnderlier<Underlier: Arbitrary>>>(
27	) -> impl Strategy<Value = Vec<P::Scalar>> {
28		proptest::collection::vec(
29			any::<<P::Scalar as WithUnderlier>::Underlier>().prop_map(P::Scalar::from_underlier),
30			P::WIDTH..=P::WIDTH,
31		)
32	}
33
34	macro_rules! define_byte_sliced_test {
35		($module_name:ident, $name:ident, $scalar_type:ty, $associated_packed:ty) => {
36			mod $module_name {
37				use super::*;
38
39				proptest! {
40					#[test]
41					fn check_from_fn(scalar_elems in scalars_vec_strategy::<$name>()) {
42						let bytesliced = <$name>::from_fn(|i| scalar_elems[i]);
43						for i in 0..<$name>::WIDTH {
44							assert_eq!(scalar_elems[i], bytesliced.get(i));
45						}
46					}
47
48					#[test]
49					fn check_add(scalar_elems_a in scalars_vec_strategy::<$name>(), scalar_elems_b in scalars_vec_strategy::<$name>()) {
50						let bytesliced_a = <$name>::from_scalars(scalar_elems_a.iter().copied());
51						let bytesliced_b = <$name>::from_scalars(scalar_elems_b.iter().copied());
52
53						let bytesliced_result = bytesliced_a + bytesliced_b;
54
55						for i in 0..<$name>::WIDTH {
56							assert_eq!(scalar_elems_a[i] + scalar_elems_b[i], bytesliced_result.get(i));
57						}
58					}
59
60					#[test]
61					fn check_add_assign(scalar_elems_a in scalars_vec_strategy::<$name>(), scalar_elems_b in scalars_vec_strategy::<$name>()) {
62						let mut bytesliced_a = <$name>::from_scalars(scalar_elems_a.iter().copied());
63						let bytesliced_b = <$name>::from_scalars(scalar_elems_b.iter().copied());
64
65						bytesliced_a += bytesliced_b;
66
67						for i in 0..<$name>::WIDTH {
68							assert_eq!(scalar_elems_a[i] + scalar_elems_b[i], bytesliced_a.get(i));
69						}
70					}
71
72					#[test]
73					fn check_sub(scalar_elems_a in scalars_vec_strategy::<$name>(), scalar_elems_b in scalars_vec_strategy::<$name>()) {
74						let bytesliced_a = <$name>::from_scalars(scalar_elems_a.iter().copied());
75						let bytesliced_b = <$name>::from_scalars(scalar_elems_b.iter().copied());
76
77						let bytesliced_result = bytesliced_a - bytesliced_b;
78
79						for i in 0..<$name>::WIDTH {
80							assert_eq!(scalar_elems_a[i] - scalar_elems_b[i], bytesliced_result.get(i));
81						}
82					}
83
84					#[test]
85					fn check_sub_assign(scalar_elems_a in scalars_vec_strategy::<$name>(), scalar_elems_b in scalars_vec_strategy::<$name>()) {
86						let mut bytesliced_a = <$name>::from_scalars(scalar_elems_a.iter().copied());
87						let bytesliced_b = <$name>::from_scalars(scalar_elems_b.iter().copied());
88
89						bytesliced_a -= bytesliced_b;
90
91						for i in 0..<$name>::WIDTH {
92							assert_eq!(scalar_elems_a[i] - scalar_elems_b[i], bytesliced_a.get(i));
93						}
94					}
95
96					#[test]
97					fn check_mul(scalar_elems_a in scalars_vec_strategy::<$name>(), scalar_elems_b in scalars_vec_strategy::<$name>()) {
98						let bytesliced_a = <$name>::from_scalars(scalar_elems_a.iter().copied());
99						let bytesliced_b = <$name>::from_scalars(scalar_elems_b.iter().copied());
100
101						let bytesliced_result = bytesliced_a * bytesliced_b;
102
103						for i in 0..<$name>::WIDTH {
104							assert_eq!(scalar_elems_a[i] * scalar_elems_b[i], bytesliced_result.get(i));
105						}
106					}
107
108					#[test]
109					fn check_mul_assign(scalar_elems_a in scalars_vec_strategy::<$name>(), scalar_elems_b in scalars_vec_strategy::<$name>()) {
110						let mut bytesliced_a = <$name>::from_scalars(scalar_elems_a.iter().copied());
111						let bytesliced_b = <$name>::from_scalars(scalar_elems_b.iter().copied());
112
113						bytesliced_a *= bytesliced_b;
114
115						for i in 0..<$name>::WIDTH {
116							assert_eq!(scalar_elems_a[i] * scalar_elems_b[i], bytesliced_a.get(i));
117						}
118					}
119
120					#[test]
121					fn check_inv(scalar_elems in scalars_vec_strategy::<$name>()) {
122						let bytesliced = <$name>::from_scalars(scalar_elems.iter().copied());
123
124						let bytesliced_result = bytesliced.invert_or_zero();
125
126						for (i, scalar_elem) in scalar_elems.iter().enumerate() {
127							assert_eq!(scalar_elem.invert_or_zero(), bytesliced_result.get(i));
128						}
129					}
130
131					#[test]
132					fn check_square(scalar_elems in scalars_vec_strategy::<$name>()) {
133						let bytesliced = <$name>::from_scalars(scalar_elems.iter().copied());
134
135						let bytesliced_result = bytesliced.square();
136
137						for (i, scalar_elem) in scalar_elems.iter().enumerate() {
138							assert_eq!(scalar_elem.square(), bytesliced_result.get(i));
139						}
140					}
141
142					#[test]
143					fn check_linear_transformation(scalar_elems in scalars_vec_strategy::<$name>()) {
144						use crate::linear_transformation::{PackedTransformationFactory, FieldLinearTransformation, Transformation};
145						use rand::{rngs::StdRng, SeedableRng};
146
147						let bytesliced = <$name>::from_scalars(scalar_elems.iter().copied());
148
149						let linear_transformation = FieldLinearTransformation::random(StdRng::seed_from_u64(0));
150						let packed_transformation = <$name>::make_packed_transformation(linear_transformation.clone());
151
152						let bytesliced_result = packed_transformation.transform(&bytesliced);
153
154						for i in 0..<$name>::WIDTH {
155							assert_eq!(linear_transformation.transform(&scalar_elems[i]), bytesliced_result.get(i));
156						}
157					}
158
159					#[test]
160					fn check_interleave(scalar_elems_a in scalars_vec_strategy::<$name>(), scalar_elems_b in scalars_vec_strategy::<$name>()) {
161						let bytesliced_a = <$name>::from_scalars(scalar_elems_a.iter().copied());
162						let bytesliced_b = <$name>::from_scalars(scalar_elems_b.iter().copied());
163
164						for log_block_len in 0..<$name>::LOG_WIDTH {
165							let (bytesliced_c, bytesliced_d) = bytesliced_a.interleave(bytesliced_b, log_block_len);
166
167							let block_len = 1 << log_block_len;
168							for offset in (0..<$name>::WIDTH).step_by(2 * block_len) {
169								for i in 0..block_len {
170									assert_eq!(bytesliced_c.get(offset + i), scalar_elems_a[offset + i]);
171									assert_eq!(bytesliced_c.get(offset + block_len + i), scalar_elems_b[offset + i]);
172
173									assert_eq!(bytesliced_d.get(offset + i), scalar_elems_a[offset + block_len + i]);
174									assert_eq!(bytesliced_d.get(offset + block_len + i), scalar_elems_b[offset + block_len + i]);
175								}
176							}
177						}
178					}
179
180					#[test]
181					fn check_transpose_to(scalar_elems in scalars_vec_strategy::<$name>()) {
182						let bytesliced = <$name>::from_scalars(scalar_elems.iter().copied());
183						let mut destination = [<$associated_packed>::zero(); <$name>::HEIGHT_BYTES];
184						bytesliced.transpose_to(&mut destination);
185
186						for i in 0..<$name>::WIDTH {
187							assert_eq!(scalar_elems[i], get_packed_slice(&destination, i));
188						}
189					}
190
191					#[test]
192					fn check_transpose_from(scalar_elems in scalars_vec_strategy::<$name>()) {
193						let mut destination = [<$associated_packed>::zero(); <$name>::HEIGHT_BYTES];
194						for i in 0..<$name>::WIDTH {
195							set_packed_slice(&mut destination, i, scalar_elems[i]);
196						}
197
198						let bytesliced = <$name>::transpose_from(&destination);
199
200						for i in 0..<$name>::WIDTH {
201							assert_eq!(get_packed_slice(&destination, i), bytesliced.get(i));
202						}
203					}
204				}
205			}
206		};
207	}
208
209	// 128-bit byte-sliced
210	define_byte_sliced_test!(
211		tests_3d_16x128,
212		ByteSlicedAES16x128b,
213		AESTowerField128b,
214		PackedAESBinaryField1x128b
215	);
216	define_byte_sliced_test!(
217		tests_3d_16x64,
218		ByteSlicedAES16x64b,
219		AESTowerField64b,
220		PackedAESBinaryField2x64b
221	);
222	define_byte_sliced_test!(
223		tests_3d_2x16x64,
224		ByteSlicedAES2x16x64b,
225		AESTowerField64b,
226		PackedAESBinaryField2x64b
227	);
228	define_byte_sliced_test!(
229		tests_3d_16x32,
230		ByteSlicedAES16x32b,
231		AESTowerField32b,
232		PackedAESBinaryField4x32b
233	);
234	define_byte_sliced_test!(
235		tests_3d_4x16x32,
236		ByteSlicedAES4x16x32b,
237		AESTowerField32b,
238		PackedAESBinaryField4x32b
239	);
240	define_byte_sliced_test!(
241		tests_3d_16x16,
242		ByteSlicedAES16x16b,
243		AESTowerField16b,
244		PackedAESBinaryField8x16b
245	);
246	define_byte_sliced_test!(
247		tests_3d_8x16x16,
248		ByteSlicedAES8x16x16b,
249		AESTowerField16b,
250		PackedAESBinaryField8x16b
251	);
252	define_byte_sliced_test!(
253		tests_3d_16x8,
254		ByteSlicedAES16x8b,
255		AESTowerField8b,
256		PackedAESBinaryField16x8b
257	);
258	define_byte_sliced_test!(
259		tests_3d_16x16x8,
260		ByteSlicedAES16x16x8b,
261		AESTowerField8b,
262		PackedAESBinaryField16x8b
263	);
264
265	define_byte_sliced_test!(
266		tests_3d_16x128x1,
267		ByteSliced16x128x1b,
268		BinaryField1b,
269		PackedBinaryField128x1b
270	);
271	define_byte_sliced_test!(
272		tests_3d_8x128x1,
273		ByteSliced8x128x1b,
274		BinaryField1b,
275		PackedBinaryField128x1b
276	);
277	define_byte_sliced_test!(
278		tests_3d_4x128x1,
279		ByteSliced4x128x1b,
280		BinaryField1b,
281		PackedBinaryField128x1b
282	);
283	define_byte_sliced_test!(
284		tests_3d_2x128x1,
285		ByteSliced2x128x1b,
286		BinaryField1b,
287		PackedBinaryField128x1b
288	);
289	define_byte_sliced_test!(
290		tests_3d_1x128x1,
291		ByteSliced1x128x1b,
292		BinaryField1b,
293		PackedBinaryField128x1b
294	);
295
296	// 256-bit byte-sliced
297	define_byte_sliced_test!(
298		tests_3d_32x128,
299		ByteSlicedAES32x128b,
300		AESTowerField128b,
301		PackedAESBinaryField2x128b
302	);
303	define_byte_sliced_test!(
304		tests_3d_32x64,
305		ByteSlicedAES32x64b,
306		AESTowerField64b,
307		PackedAESBinaryField4x64b
308	);
309	define_byte_sliced_test!(
310		tests_3d_2x32x64,
311		ByteSlicedAES2x32x64b,
312		AESTowerField64b,
313		PackedAESBinaryField4x64b
314	);
315	define_byte_sliced_test!(
316		tests_3d_32x32,
317		ByteSlicedAES32x32b,
318		AESTowerField32b,
319		PackedAESBinaryField8x32b
320	);
321	define_byte_sliced_test!(
322		tests_3d_4x32x32,
323		ByteSlicedAES4x32x32b,
324		AESTowerField32b,
325		PackedAESBinaryField8x32b
326	);
327	define_byte_sliced_test!(
328		tests_3d_32x16,
329		ByteSlicedAES32x16b,
330		AESTowerField16b,
331		PackedAESBinaryField16x16b
332	);
333	define_byte_sliced_test!(
334		tests_3d_8x32x16,
335		ByteSlicedAES8x32x16b,
336		AESTowerField16b,
337		PackedAESBinaryField16x16b
338	);
339	define_byte_sliced_test!(
340		tests_3d_32x8,
341		ByteSlicedAES32x8b,
342		AESTowerField8b,
343		PackedAESBinaryField32x8b
344	);
345	define_byte_sliced_test!(
346		tests_3d_16x32x8,
347		ByteSlicedAES16x32x8b,
348		AESTowerField8b,
349		PackedAESBinaryField32x8b
350	);
351
352	define_byte_sliced_test!(
353		tests_3d_16x256x1,
354		ByteSliced16x256x1b,
355		BinaryField1b,
356		PackedBinaryField256x1b
357	);
358	define_byte_sliced_test!(
359		tests_3d_8x256x1,
360		ByteSliced8x256x1b,
361		BinaryField1b,
362		PackedBinaryField256x1b
363	);
364	define_byte_sliced_test!(
365		tests_3d_4x256x1,
366		ByteSliced4x256x1b,
367		BinaryField1b,
368		PackedBinaryField256x1b
369	);
370	define_byte_sliced_test!(
371		tests_3d_2x256x1,
372		ByteSliced2x256x1b,
373		BinaryField1b,
374		PackedBinaryField256x1b
375	);
376	define_byte_sliced_test!(
377		tests_3d_1x256x1,
378		ByteSliced1x256x1b,
379		BinaryField1b,
380		PackedBinaryField256x1b
381	);
382
383	// 512-bit byte-sliced
384	define_byte_sliced_test!(
385		tests_3d_64x128,
386		ByteSlicedAES64x128b,
387		AESTowerField128b,
388		PackedAESBinaryField4x128b
389	);
390	define_byte_sliced_test!(
391		tests_3d_64x64,
392		ByteSlicedAES64x64b,
393		AESTowerField64b,
394		PackedAESBinaryField8x64b
395	);
396	define_byte_sliced_test!(
397		tests_3d_2x64x64,
398		ByteSlicedAES2x64x64b,
399		AESTowerField64b,
400		PackedAESBinaryField8x64b
401	);
402	define_byte_sliced_test!(
403		tests_3d_64x32,
404		ByteSlicedAES64x32b,
405		AESTowerField32b,
406		PackedAESBinaryField16x32b
407	);
408	define_byte_sliced_test!(
409		tests_3d_4x64x32,
410		ByteSlicedAES4x64x32b,
411		AESTowerField32b,
412		PackedAESBinaryField16x32b
413	);
414	define_byte_sliced_test!(
415		tests_3d_64x16,
416		ByteSlicedAES64x16b,
417		AESTowerField16b,
418		PackedAESBinaryField32x16b
419	);
420	define_byte_sliced_test!(
421		tests_3d_8x64x16,
422		ByteSlicedAES8x64x16b,
423		AESTowerField16b,
424		PackedAESBinaryField32x16b
425	);
426	define_byte_sliced_test!(
427		tests_3d_64x8,
428		ByteSlicedAES64x8b,
429		AESTowerField8b,
430		PackedAESBinaryField64x8b
431	);
432	define_byte_sliced_test!(
433		tests_3d_16x64x8,
434		ByteSlicedAES16x64x8b,
435		AESTowerField8b,
436		PackedAESBinaryField64x8b
437	);
438
439	define_byte_sliced_test!(
440		tests_3d_16x512x1,
441		ByteSliced16x512x1b,
442		BinaryField1b,
443		PackedBinaryField512x1b
444	);
445	define_byte_sliced_test!(
446		tests_3d_8x512x1,
447		ByteSliced8x512x1b,
448		BinaryField1b,
449		PackedBinaryField512x1b
450	);
451	define_byte_sliced_test!(
452		tests_3d_4x512x1,
453		ByteSliced4x512x1b,
454		BinaryField1b,
455		PackedBinaryField512x1b
456	);
457	define_byte_sliced_test!(
458		tests_3d_2x512x1,
459		ByteSliced2x512x1b,
460		BinaryField1b,
461		PackedBinaryField512x1b
462	);
463	define_byte_sliced_test!(
464		tests_3d_1x512x1,
465		ByteSliced1x512x1b,
466		BinaryField1b,
467		PackedBinaryField512x1b
468	);
469}