1use 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
13pub 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
26impl<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#[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 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 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 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 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 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 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 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 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 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 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)] 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)] 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 #[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 #[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}