1pub mod ghash;
7pub mod ghash_sq;
8pub mod primitive;
9pub mod rijndael;
10pub mod sliced;
11
12use std::ops::Mul;
13
14pub use ghash::*;
15pub use ghash_sq::*;
16pub use rijndael::*;
17
18use crate::{
19 BinaryField1b,
20 arch::{M128, M256, M512},
21 arithmetic_traits::{InvertOrZero, Square, WideMul},
22 packed_fields::primitive::PackedPrimitiveType,
23 underlier::{U1, U2, U4, Underlier},
24};
25
26pub type PackedBinaryField1x1b = PackedPrimitiveType<U1, BinaryField1b>;
29pub type PackedBinaryField2x1b = PackedPrimitiveType<U2, BinaryField1b>;
30pub type PackedBinaryField4x1b = PackedPrimitiveType<U4, BinaryField1b>;
31pub type PackedBinaryField8x1b = PackedPrimitiveType<u8, BinaryField1b>;
32pub type PackedBinaryField16x1b = PackedPrimitiveType<u16, BinaryField1b>;
33pub type PackedBinaryField32x1b = PackedPrimitiveType<u32, BinaryField1b>;
34pub type PackedBinaryField64x1b = PackedPrimitiveType<u64, BinaryField1b>;
35pub type PackedBinaryField128x1b = PackedPrimitiveType<M128, BinaryField1b>;
36pub type PackedBinaryField256x1b = PackedPrimitiveType<M256, BinaryField1b>;
37pub type PackedBinaryField512x1b = PackedPrimitiveType<M512, BinaryField1b>;
38
39impl<U: Underlier> Mul for PackedPrimitiveType<U, BinaryField1b> {
45 type Output = Self;
46
47 #[inline]
48 #[allow(clippy::suspicious_arithmetic_impl)]
49 fn mul(self, rhs: Self) -> Self {
50 (self.0 & rhs.0).into()
51 }
52}
53
54impl<U: Underlier> Square for PackedPrimitiveType<U, BinaryField1b> {
55 #[inline]
56 fn square(self) -> Self {
57 self
58 }
59}
60
61impl<U: Underlier> InvertOrZero for PackedPrimitiveType<U, BinaryField1b> {
62 #[inline]
63 fn invert_or_zero(self) -> Self {
64 self
65 }
66}
67
68impl<U: Underlier> WideMul for PackedPrimitiveType<U, BinaryField1b> {
69 type Output = Self;
70
71 #[inline]
72 fn wide_mul(a: Self, b: Self) -> Self {
73 a * b
74 }
75
76 #[inline]
77 fn reduce(wide: Self) -> Self {
78 wide
79 }
80}
81
82#[cfg(test)]
84pub mod test_utils {
85 use proptest::{
86 arbitrary::{Arbitrary, any},
87 strategy::{BoxedStrategy, Strategy},
88 };
89
90 use crate::{
91 Field, PackedField,
92 arch::{M128, M256, M512},
93 underlier::UnderlierView,
94 };
95
96 impl Arbitrary for M128 {
99 type Parameters = ();
100 type Strategy = BoxedStrategy<Self>;
101
102 fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
103 any::<u128>().prop_map(Self::from).boxed()
104 }
105 }
106
107 impl Arbitrary for M256 {
108 type Parameters = ();
109 type Strategy = BoxedStrategy<Self>;
110
111 fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
112 any::<[u128; 2]>().prop_map(Self::from).boxed()
113 }
114 }
115
116 impl Arbitrary for M512 {
117 type Parameters = ();
118 type Strategy = BoxedStrategy<Self>;
119
120 fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
121 any::<[u128; 4]>().prop_map(Self::from).boxed()
122 }
123 }
124
125 pub fn check_mul<P: PackedField + UnderlierView>(a: P::Underlier, b: P::Underlier) {
127 let (a, b) = (P::from_underlier(a), P::from_underlier(b));
128
129 let c = a * b;
130 for i in 0..P::WIDTH {
131 assert_eq!(c.get(i), a.get(i) * b.get(i));
132 }
133 }
134
135 pub fn check_square<P: PackedField + UnderlierView>(a: P::Underlier) {
137 let a = P::from_underlier(a);
138
139 let c = a.square();
140 for i in 0..P::WIDTH {
141 assert_eq!(c.get(i), a.get(i) * a.get(i));
142 }
143 }
144
145 pub fn check_invert_or_zero<P: PackedField + UnderlierView>(a: P::Underlier) {
147 let a = P::from_underlier(a);
148
149 let c = a.invert_or_zero();
150 for i in 0..P::WIDTH {
151 if a.get(i).is_zero() {
152 assert!(c.get(i).is_zero());
153 } else {
154 assert_eq!(a.get(i) * c.get(i), P::Scalar::ONE);
155 }
156 }
157 }
158
159 pub fn check_wide_mul<P: PackedField + UnderlierView>(a: P::Underlier, b: P::Underlier) {
161 let (a, b) = (P::from_underlier(a), P::from_underlier(b));
162
163 assert_eq!(P::reduce(P::wide_mul(a, b)), a * b);
164 }
165
166 pub fn check_wide_mul_linearity<P: PackedField + UnderlierView>(
168 a1: P::Underlier,
169 b1: P::Underlier,
170 a2: P::Underlier,
171 b2: P::Underlier,
172 ) {
173 let (a1, b1) = (P::from_underlier(a1), P::from_underlier(b1));
174 let (a2, b2) = (P::from_underlier(a2), P::from_underlier(b2));
175
176 let sum = P::wide_mul(a1, b1) + P::wide_mul(a2, b2);
179 assert_eq!(P::reduce(sum), a1 * b1 + a2 * b2);
180 }
181
182 macro_rules! packed_field_tests {
184 ($mod:ident, $ty:ty) => {
185 mod $mod {
186 use proptest::{prelude::any, proptest};
187 use $crate::packed_fields::test_utils::{
188 check_invert_or_zero, check_mul, check_square, check_wide_mul,
189 check_wide_mul_linearity,
190 };
191
192 use super::*;
193
194 type U = <$ty as $crate::underlier::UnderlierView>::Underlier;
196
197 proptest! {
198 #[test]
199 fn mul(a in any::<U>(), b in any::<U>()) {
200 check_mul::<$ty>(a, b);
201 }
202
203 #[test]
204 fn square(a in any::<U>()) {
205 check_square::<$ty>(a);
206 }
207
208 #[test]
209 fn invert_or_zero(a in any::<U>()) {
210 check_invert_or_zero::<$ty>(a);
211 }
212
213 #[test]
214 fn wide_mul(a in any::<U>(), b in any::<U>()) {
215 check_wide_mul::<$ty>(a, b);
216 }
217
218 #[test]
219 fn wide_mul_linearity(
220 a1 in any::<U>(), b1 in any::<U>(),
221 a2 in any::<U>(), b2 in any::<U>(),
222 ) {
223 check_wide_mul_linearity::<$ty>(a1, b1, a2, b2);
224 }
225 }
226 }
227 };
228 }
229
230 pub(crate) use packed_field_tests;
231
232 pub fn check_interleave<P: PackedField + UnderlierView>(
233 lhs: P::Underlier,
234 rhs: P::Underlier,
235 log_block_len: usize,
236 ) {
237 let lhs = P::from_underlier(lhs);
238 let rhs = P::from_underlier(rhs);
239 let (a, b) = lhs.interleave(rhs, log_block_len);
240 let block_len = 1 << log_block_len;
241 for i in (0..P::WIDTH).step_by(block_len * 2) {
242 for j in 0..block_len {
243 assert_eq!(a.get(i + j), lhs.get(i + j));
244 assert_eq!(a.get(i + j + block_len), rhs.get(i + j));
245
246 assert_eq!(b.get(i + j), lhs.get(i + j + block_len));
247 assert_eq!(b.get(i + j + block_len), rhs.get(i + j + block_len));
248 }
249 }
250 }
251
252 pub fn check_interleave_all_heights<P: PackedField + UnderlierView>(
253 lhs: P::Underlier,
254 rhs: P::Underlier,
255 ) {
256 for log_block_len in 0..P::LOG_WIDTH {
257 check_interleave::<P>(lhs, rhs, log_block_len);
258 }
259 }
260
261 pub fn check_unzip<P: PackedField + UnderlierView>(
262 lhs: P::Underlier,
263 rhs: P::Underlier,
264 log_block_len: usize,
265 ) {
266 let lhs = P::from_underlier(lhs);
267 let rhs = P::from_underlier(rhs);
268 let block_len = 1 << log_block_len;
269 let (a, b) = lhs.unzip(rhs, log_block_len);
270 for i in (0..P::WIDTH / 2).step_by(block_len) {
271 for j in 0..block_len {
272 assert_eq!(
273 a.get(i + j),
274 lhs.get(2 * i + j),
275 "i: {}, j: {}, log_block_len: {}, P: {:?}",
276 i,
277 j,
278 log_block_len,
279 P::zero()
280 );
281 assert_eq!(
282 b.get(i + j),
283 lhs.get(2 * i + j + block_len),
284 "i: {}, j: {}, log_block_len: {}, P: {:?}",
285 i,
286 j,
287 log_block_len,
288 P::zero()
289 );
290 }
291 }
292
293 for i in (0..P::WIDTH / 2).step_by(block_len) {
294 for j in 0..block_len {
295 assert_eq!(
296 a.get(i + j + P::WIDTH / 2),
297 rhs.get(2 * i + j),
298 "i: {}, j: {}, log_block_len: {}, P: {:?}",
299 i,
300 j,
301 log_block_len,
302 P::zero()
303 );
304 assert_eq!(b.get(i + j + P::WIDTH / 2), rhs.get(2 * i + j + block_len));
305 }
306 }
307 }
308
309 pub fn check_transpose_all_heights<P: PackedField + UnderlierView>(
310 lhs: P::Underlier,
311 rhs: P::Underlier,
312 ) {
313 for log_block_len in 0..P::LOG_WIDTH {
314 check_unzip::<P>(lhs, rhs, log_block_len);
315 }
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use std::{fmt::Debug, iter::repeat_with};
322
323 use binius_utils::{
324 DeserializeBytes, FixedSizeSerializeBytes, SerializeBytes, bytes::BytesMut,
325 };
326 use proptest::prelude::*;
327 use rand::prelude::*;
328 use test_utils::check_interleave_all_heights;
329
330 use super::{test_utils::packed_field_tests, *};
331 use crate::{
332 Divisible, PackedField, PackedGhash1x128b, PackedGhash2x128b, PackedGhash4x128b,
333 PackedRijndael1x8b, PackedRijndael16x8b, PackedRijndael32x8b, PackedRijndael64x8b, Random,
334 test_utils::check_transpose_all_heights,
335 underlier::{U2, U4},
336 };
337
338 fn test_add_packed<P: PackedField + From<u128>>(a_val: u128, b_val: u128) {
339 let a = P::from(a_val);
340 let b = P::from(b_val);
341 let c = a + b;
342 for i in 0..P::WIDTH {
343 assert_eq!(c.get(i), a.get(i) + b.get(i));
344 }
345 }
346
347 fn test_mul_packed<P: PackedField>(a: P, b: P) {
348 let c = a * b;
349 for i in 0..P::WIDTH {
350 assert_eq!(c.get(i), a.get(i) * b.get(i));
351 }
352 }
353
354 fn test_mul_packed_random<P: PackedField>() {
355 let mut rng = StdRng::seed_from_u64(0);
356 test_mul_packed(P::random(&mut rng), P::random(&mut rng));
357 }
358
359 fn test_set_then_get<P: PackedField>() {
360 let mut rng = StdRng::seed_from_u64(0);
361 let mut elem = P::random(&mut rng);
362
363 let scalars = repeat_with(|| P::Scalar::random(&mut rng))
364 .take(P::WIDTH)
365 .collect::<Vec<_>>();
366
367 for (i, val) in scalars.iter().enumerate() {
368 elem.set(i, *val);
369 }
370 for (i, val) in scalars.iter().enumerate() {
371 assert_eq!(elem.get(i), *val);
372 }
373 }
374
375 fn test_serialize_then_deserialize<P: PackedField + DeserializeBytes + SerializeBytes>() {
376 let mut buffer = BytesMut::new();
377 let mut rng = StdRng::seed_from_u64(0);
378 let packed = P::random(&mut rng);
379 packed.serialize(&mut buffer).unwrap();
380
381 let mut read_buffer = buffer.freeze();
382
383 assert_eq!(P::deserialize(&mut read_buffer).unwrap(), packed);
384 }
385
386 #[test]
387 fn test_set_then_get_128b() {
388 test_set_then_get::<PackedGhash1x128b>();
389 test_set_then_get::<PackedGhash2x128b>();
390 test_set_then_get::<PackedGhash4x128b>();
391 }
392
393 #[test]
394 fn test_serialize_then_deserialize_128b() {
395 test_serialize_then_deserialize::<PackedGhash1x128b>();
396 test_serialize_then_deserialize::<PackedGhash2x128b>();
397 test_serialize_then_deserialize::<PackedGhash4x128b>();
398 }
399
400 #[test]
401 fn test_serialize_deserialize_different_packing_width() {
402 let mut rng = StdRng::seed_from_u64(0);
403
404 let packed0 = PackedGhash1x128b::random(&mut rng);
405 let packed1 = PackedGhash1x128b::random(&mut rng);
406
407 let mut buffer = BytesMut::new();
408 packed0.serialize(&mut buffer).unwrap();
409 packed1.serialize(&mut buffer).unwrap();
410
411 let mut read_buffer = buffer.freeze();
412 let packed01 = PackedGhash2x128b::deserialize(&mut read_buffer).unwrap();
413
414 assert!(
415 packed01
416 .iter()
417 .zip([packed0, packed1])
418 .all(|(x, y)| x == y.get(0))
419 );
420 }
421
422 proptest! {
424 #[test]
425 fn test_add_packed_128x1b(a_val in any::<u128>(), b_val in any::<u128>()) {
426 test_add_packed::<PackedBinaryField128x1b>(a_val, b_val);
427 }
428
429 #[test]
430 fn test_add_packed_16x8b(a_val in any::<u128>(), b_val in any::<u128>()) {
431 test_add_packed::<PackedRijndael16x8b>(a_val, b_val);
432 }
433
434 #[test]
435 fn test_add_packed_1x128b(a_val in any::<u128>(), b_val in any::<u128>()) {
436 test_add_packed::<PackedGhash1x128b>(a_val, b_val);
437 }
438 }
439
440 #[test]
441 fn test_mul_packed_256x1b() {
442 test_mul_packed_random::<PackedBinaryField256x1b>();
443 }
444
445 #[test]
446 fn test_mul_packed_32x8b() {
447 test_mul_packed_random::<PackedRijndael32x8b>();
448 }
449
450 #[test]
451 fn test_mul_packed_2x128b() {
452 test_mul_packed_random::<PackedGhash2x128b>();
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::<PackedRijndael1x8b>(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::<PackedRijndael16x8b>(a_val.into(), b_val.into());
500 check_interleave_all_heights::<PackedGhash1x128b>(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::<PackedRijndael32x8b>(a_val.into(), b_val.into());
507 check_interleave_all_heights::<PackedGhash2x128b>(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::<PackedRijndael64x8b>(a_val.into(), b_val.into());
514 check_interleave_all_heights::<PackedGhash4x128b>(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::<PackedRijndael1x8b>(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::<PackedRijndael16x8b>(a_val.into(), b_val.into());
553 check_transpose_all_heights::<PackedGhash1x128b>(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::<PackedRijndael32x8b>(a_val.into(), b_val.into());
560 check_transpose_all_heights::<PackedGhash2x128b>(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::<PackedRijndael64x8b>(a_val.into(), b_val.into());
567 check_transpose_all_heights::<PackedGhash4x128b>(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::<PackedGhash1x128b>(&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}