1#![allow(clippy::multiple_bound_locations)]
11
12use std::{
13 fmt::Debug,
14 iter::{Product, Sum},
15 marker::PhantomData,
16 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
17};
18
19use binius_utils::{
20 DeserializeBytes, FixedSizeSerializeBytes, SerializationError, SerializeBytes,
21 bytes::{Buf, BufMut},
22 checked_arithmetics::checked_int_div,
23 iter::IterExtensions,
24};
25use bytemuck::{Pod, TransparentWrapper, Zeroable};
26use rand::{
27 Rng,
28 distr::{Distribution, StandardUniform},
29};
30
31use crate::{
32 BinaryField, Divisible, ExtensionField, Field, Maskable, PackedField, WideMul,
33 arithmetic_traits::{InvertOrZero, Square},
34 field::FieldOps,
35 underlier::{U1, Underlier, UnderlierView},
36};
37
38#[derive(PartialEq, Eq, Clone, Copy, Default, bytemuck::TransparentWrapper)]
39#[repr(transparent)]
40#[transparent(U)]
41pub struct PackedPrimitiveType<U: Underlier, Scalar: BinaryField>(pub U, pub PhantomData<Scalar>);
42
43impl<U: Underlier, Scalar: BinaryField> PackedPrimitiveType<U, Scalar> {
44 pub const WIDTH: usize = {
45 assert!(U::BITS.is_multiple_of(Scalar::N_BITS));
46
47 U::BITS / Scalar::N_BITS
48 };
49
50 pub const LOG_WIDTH: usize = {
51 let result = Self::WIDTH.ilog2();
52
53 assert!(2usize.pow(result) == Self::WIDTH);
54
55 result as usize
56 };
57
58 #[inline]
59 pub const fn from_underlier(val: U) -> Self {
60 Self(val, PhantomData)
61 }
62
63 #[inline]
64 pub const fn to_underlier(self) -> U {
65 self.0
66 }
67}
68
69impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField>
70 PackedPrimitiveType<U, Scalar>
71{
72 #[inline]
73 pub fn broadcast(scalar: Scalar) -> Self {
74 <U as Divisible<_>>::broadcast(scalar.to_underlier()).into()
75 }
76}
77
78unsafe impl<U: Underlier, Scalar: BinaryField> UnderlierView for PackedPrimitiveType<U, Scalar> {
79 type Underlier = U;
80
81 #[inline(always)]
82 fn to_underlier(self) -> Self::Underlier {
83 TransparentWrapper::peel(self)
84 }
85
86 #[inline(always)]
87 fn to_underlier_ref(&self) -> &Self::Underlier {
88 TransparentWrapper::peel_ref(self)
89 }
90
91 #[inline(always)]
92 fn to_underlier_ref_mut(&mut self) -> &mut Self::Underlier {
93 TransparentWrapper::peel_mut(self)
94 }
95
96 #[inline(always)]
97 fn to_underliers_ref(val: &[Self]) -> &[Self::Underlier] {
98 TransparentWrapper::peel_slice(val)
99 }
100
101 #[inline(always)]
102 fn to_underliers_ref_mut(val: &mut [Self]) -> &mut [Self::Underlier] {
103 TransparentWrapper::peel_slice_mut(val)
104 }
105
106 #[inline(always)]
107 fn from_underlier(val: Self::Underlier) -> Self {
108 TransparentWrapper::wrap(val)
109 }
110
111 #[inline(always)]
112 fn from_underlier_ref(val: &Self::Underlier) -> &Self {
113 TransparentWrapper::wrap_ref(val)
114 }
115
116 #[inline(always)]
117 fn from_underlier_ref_mut(val: &mut Self::Underlier) -> &mut Self {
118 TransparentWrapper::wrap_mut(val)
119 }
120
121 #[inline(always)]
122 fn from_underliers_ref(val: &[Self::Underlier]) -> &[Self] {
123 TransparentWrapper::wrap_slice(val)
124 }
125
126 #[inline(always)]
127 fn from_underliers_ref_mut(val: &mut [Self::Underlier]) -> &mut [Self] {
128 TransparentWrapper::wrap_slice_mut(val)
129 }
130}
131
132impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> Debug
137 for PackedPrimitiveType<U, Scalar>
138{
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 let width = checked_int_div(U::BITS, Scalar::N_BITS);
141 let values_str = (0..width)
142 .map(|i| {
144 Scalar::from_underlier(unsafe {
145 Divisible::<Scalar::Underlier>::get_unchecked(&self.0, i)
146 })
147 })
148 .map(|value| format!("{value}"))
149 .collect::<Vec<_>>()
150 .join(",");
151
152 write!(f, "Packed{}x{}([{}])", width, Scalar::N_BITS, values_str)
153 }
154}
155
156impl<U: Underlier, Scalar: BinaryField> From<U> for PackedPrimitiveType<U, Scalar> {
157 #[inline]
158 fn from(val: U) -> Self {
159 Self(val, PhantomData)
160 }
161}
162
163impl<U: Underlier + SerializeBytes, Scalar: BinaryField> SerializeBytes
167 for PackedPrimitiveType<U, Scalar>
168{
169 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
170 self.0.serialize(write_buf)
171 }
172}
173
174impl<U: Underlier + DeserializeBytes, Scalar: BinaryField> DeserializeBytes
175 for PackedPrimitiveType<U, Scalar>
176{
177 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError> {
178 Ok(Self(U::deserialize(read_buf)?, PhantomData))
179 }
180}
181
182impl<U: Underlier + FixedSizeSerializeBytes, Scalar: BinaryField> FixedSizeSerializeBytes
183 for PackedPrimitiveType<U, Scalar>
184{
185 const BYTE_SIZE: usize = U::BYTE_SIZE;
186}
187
188impl<U: Underlier, Scalar: BinaryField> Neg for PackedPrimitiveType<U, Scalar> {
189 type Output = Self;
190
191 #[inline]
192 fn neg(self) -> Self::Output {
193 self
194 }
195}
196
197impl<U: Underlier, Scalar: BinaryField> Add for PackedPrimitiveType<U, Scalar> {
198 type Output = Self;
199
200 #[inline]
201 #[allow(clippy::suspicious_arithmetic_impl)]
202 fn add(self, rhs: Self) -> Self::Output {
203 (self.0 ^ rhs.0).into()
204 }
205}
206
207impl<U: Underlier, Scalar: BinaryField> Add<&Self> for PackedPrimitiveType<U, Scalar> {
208 type Output = Self;
209
210 #[inline]
211 #[allow(clippy::suspicious_arithmetic_impl)]
212 fn add(self, rhs: &Self) -> Self::Output {
213 (self.0 ^ rhs.0).into()
214 }
215}
216
217impl<U: Underlier, Scalar: BinaryField> Sub for PackedPrimitiveType<U, Scalar> {
218 type Output = Self;
219
220 #[inline]
221 #[allow(clippy::suspicious_arithmetic_impl)]
222 fn sub(self, rhs: Self) -> Self::Output {
223 (self.0 ^ rhs.0).into()
224 }
225}
226
227impl<U: Underlier, Scalar: BinaryField> Sub<&Self> for PackedPrimitiveType<U, Scalar> {
228 type Output = Self;
229
230 #[inline]
231 #[allow(clippy::suspicious_arithmetic_impl)]
232 fn sub(self, rhs: &Self) -> Self::Output {
233 (self.0 ^ rhs.0).into()
234 }
235}
236
237impl<U: Underlier, Scalar: BinaryField> AddAssign for PackedPrimitiveType<U, Scalar>
238where
239 Self: Add<Output = Self>,
240{
241 fn add_assign(&mut self, rhs: Self) {
242 *self = *self + rhs;
243 }
244}
245
246impl<U: Underlier, Scalar: BinaryField> AddAssign<&Self> for PackedPrimitiveType<U, Scalar>
247where
248 Self: for<'a> Add<&'a Self, Output = Self>,
249{
250 fn add_assign(&mut self, rhs: &Self) {
251 *self = *self + rhs;
252 }
253}
254
255impl<U: Underlier, Scalar: BinaryField> SubAssign for PackedPrimitiveType<U, Scalar>
256where
257 Self: Sub<Output = Self>,
258{
259 fn sub_assign(&mut self, rhs: Self) {
260 *self = *self - rhs;
261 }
262}
263
264impl<U: Underlier, Scalar: BinaryField> SubAssign<&Self> for PackedPrimitiveType<U, Scalar>
265where
266 Self: for<'a> Sub<&'a Self, Output = Self>,
267{
268 fn sub_assign(&mut self, rhs: &Self) {
269 *self = *self - rhs;
270 }
271}
272
273impl<U: Underlier, Scalar: BinaryField> MulAssign for PackedPrimitiveType<U, Scalar>
274where
275 Self: Mul<Output = Self>,
276{
277 fn mul_assign(&mut self, rhs: Self) {
278 *self = *self * rhs;
279 }
280}
281
282impl<U: Underlier, Scalar: BinaryField> MulAssign<&Self> for PackedPrimitiveType<U, Scalar>
283where
284 Self: for<'a> Mul<&'a Self, Output = Self>,
285{
286 fn mul_assign(&mut self, rhs: &Self) {
287 *self = *self * rhs;
288 }
289}
290
291impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> Add<Scalar>
292 for PackedPrimitiveType<U, Scalar>
293{
294 type Output = Self;
295
296 fn add(self, rhs: Scalar) -> Self::Output {
297 self + Self::broadcast(rhs)
298 }
299}
300
301impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> Sub<Scalar>
302 for PackedPrimitiveType<U, Scalar>
303{
304 type Output = Self;
305
306 fn sub(self, rhs: Scalar) -> Self::Output {
307 self - Self::broadcast(rhs)
308 }
309}
310
311impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> Mul<Scalar>
312 for PackedPrimitiveType<U, Scalar>
313where
314 Self: Mul<Output = Self>,
315{
316 type Output = Self;
317
318 fn mul(self, rhs: Scalar) -> Self::Output {
319 self * Self::broadcast(rhs)
320 }
321}
322
323impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> AddAssign<Scalar>
324 for PackedPrimitiveType<U, Scalar>
325{
326 fn add_assign(&mut self, rhs: Scalar) {
327 *self += Self::broadcast(rhs);
328 }
329}
330
331impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> SubAssign<Scalar>
332 for PackedPrimitiveType<U, Scalar>
333{
334 fn sub_assign(&mut self, rhs: Scalar) {
335 *self -= Self::broadcast(rhs);
336 }
337}
338
339impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> MulAssign<Scalar>
340 for PackedPrimitiveType<U, Scalar>
341where
342 Self: MulAssign<Self>,
343{
344 fn mul_assign(&mut self, rhs: Scalar) {
345 *self *= Self::broadcast(rhs);
346 }
347}
348
349impl<U: Underlier, Scalar: BinaryField> Sum for PackedPrimitiveType<U, Scalar>
350where
351 Self: Add<Output = Self>,
352{
353 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
354 iter.fold(Self::from(U::default()), |result, next| result + next)
355 }
356}
357
358impl<'a, U: Underlier, Scalar: BinaryField> Sum<&'a Self> for PackedPrimitiveType<U, Scalar>
359where
360 Self: Add<Output = Self>,
361{
362 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
363 iter.fold(Self::from(U::default()), |result, next| result + *next)
364 }
365}
366
367impl<U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> Product
368 for PackedPrimitiveType<U, Scalar>
369where
370 Self: Mul<Output = Self>,
371{
372 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
373 iter.fold(Self::broadcast(Scalar::ONE), |result, next| result * next)
374 }
375}
376
377impl<'a, U: Underlier + Divisible<Scalar::Underlier>, Scalar: BinaryField> Product<&'a Self>
378 for PackedPrimitiveType<U, Scalar>
379where
380 Self: Mul<Output = Self>,
381{
382 fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
383 iter.fold(Self::broadcast(Scalar::ONE), |result, next| result * *next)
384 }
385}
386
387impl<U: Underlier, Scalar: BinaryField> Mul<&Self> for PackedPrimitiveType<U, Scalar>
388where
389 Self: Mul<Output = Self>,
390{
391 type Output = Self;
392
393 #[inline]
394 fn mul(self, rhs: &Self) -> Self::Output {
395 self * *rhs
396 }
397}
398
399unsafe impl<U: Underlier + Zeroable, Scalar: BinaryField> Zeroable
400 for PackedPrimitiveType<U, Scalar>
401{
402}
403
404unsafe impl<U: Underlier + Pod, Scalar: BinaryField> Pod for PackedPrimitiveType<U, Scalar> {}
405
406impl<U, Scalar> FieldOps for PackedPrimitiveType<U, Scalar>
407where
408 Self: Square + InvertOrZero + Mul<Output = Self>,
409 U: Underlier + Divisible<Scalar::Underlier>,
410 Scalar: BinaryField,
411{
412 type Scalar = Scalar;
413
414 #[inline]
415 fn zero() -> Self {
416 Self::from_underlier(U::ZERO)
417 }
418
419 #[inline]
420 fn one() -> Self {
421 Self::broadcast(Scalar::ONE)
422 }
423
424 fn square_transpose<FSub: Field>(elems: &mut [Self])
425 where
426 Scalar: ExtensionField<FSub>,
427 {
428 let log_degree = <Scalar as ExtensionField<FSub>>::LOG_DEGREE;
429 let degree = <Scalar as ExtensionField<FSub>>::DEGREE;
430 assert_eq!(elems.len(), degree);
431
432 let log_sub_bits = Scalar::N_BITS.ilog2() as usize - log_degree;
433
434 for i in 0..log_degree {
436 for j in 0..1 << (log_degree - i - 1) {
437 for k in 0..1 << i {
438 let idx0 = (j << (i + 1)) | k;
439 let idx1 = idx0 | (1 << i);
440 let (u0, u1) = elems[idx0].0.interleave(elems[idx1].0, i + log_sub_bits);
441 elems[idx0] = u0.into();
442 elems[idx1] = u1.into();
443 }
444 }
445 }
446 }
447}
448
449impl<U, Scalar> Divisible<Scalar> for PackedPrimitiveType<U, Scalar>
452where
453 U: Underlier + Divisible<Scalar::Underlier>,
454 Scalar: BinaryField,
455{
456 const LOG_N: usize = (U::BITS / Scalar::N_BITS).ilog2() as usize;
457
458 #[inline]
460 fn value_iter(value: Self) -> impl ExactSizeIterator<Item = Scalar> + Send + Clone {
461 Divisible::<Scalar::Underlier>::value_iter(value.0).map_skippable(Scalar::from_underlier)
462 }
463
464 #[inline]
465 fn ref_iter(value: &Self) -> impl ExactSizeIterator<Item = Scalar> + Send + Clone + '_ {
466 Divisible::<Scalar::Underlier>::ref_iter(&value.0).map_skippable(Scalar::from_underlier)
467 }
468
469 #[inline]
470 fn slice_iter(slice: &[Self]) -> impl ExactSizeIterator<Item = Scalar> + Send + Clone + '_ {
471 Divisible::<Scalar::Underlier>::slice_iter(Self::to_underliers_ref(slice))
472 .map_skippable(Scalar::from_underlier)
473 }
474
475 #[inline]
476 unsafe fn get_unchecked(&self, index: usize) -> Scalar {
477 Scalar::from_underlier(unsafe {
479 Divisible::<Scalar::Underlier>::get_unchecked(&self.0, index)
480 })
481 }
482
483 #[inline]
484 unsafe fn set_unchecked(&mut self, index: usize, val: Scalar) {
485 unsafe { U::set_unchecked(&mut self.0, index, val.to_underlier()) };
487 }
488
489 #[inline]
490 fn broadcast(val: Scalar) -> Self {
491 U::broadcast(val.to_underlier()).into()
492 }
493
494 #[inline]
495 fn from_iter(iter: impl Iterator<Item = Scalar>) -> Self {
496 U::from_iter(iter.map(Scalar::to_underlier)).into()
497 }
498}
499
500impl<U, Scalar> Maskable<Scalar> for PackedPrimitiveType<U, Scalar>
503where
504 U: Underlier + Divisible<Scalar::Underlier>,
505 Scalar: BinaryField,
506{
507 type Mask = U;
508
509 #[inline]
510 fn make_mask(selectors: impl Iterator<Item = bool>) -> U {
511 U::from_iter(
513 selectors
514 .take(Self::N)
515 .map(|selected| Scalar::Underlier::broadcast(U1::from(selected))),
516 )
517 }
518
519 #[inline]
520 fn select(&self, mask: &U) -> Self {
521 Self::from_underlier(self.to_underlier() & *mask)
522 }
523}
524
525impl<U, Scalar> PackedField for PackedPrimitiveType<U, Scalar>
526where
527 Self:
528 Square + InvertOrZero + Mul<Output = Self> + WideMul<Output: Debug + Send + Sync + 'static>,
529 U: Underlier + Divisible<Scalar::Underlier>,
530 Scalar: BinaryField,
531{
532 #[inline]
533 fn interleave(self, other: Self, log_block_len: usize) -> (Self, Self) {
534 assert!(log_block_len < Self::LOG_WIDTH);
535 let log_bit_len = Self::Scalar::N_BITS.ilog2() as usize;
536 let (c, d) = self.0.interleave(other.0, log_block_len + log_bit_len);
537 (c.into(), d.into())
538 }
539
540 #[inline]
541 fn unzip(self, other: Self, log_block_len: usize) -> (Self, Self) {
542 assert!(log_block_len < Self::LOG_WIDTH);
543 let log_bit_len = Self::Scalar::N_BITS.ilog2() as usize;
544 let (c, d) = self.0.transpose(other.0, log_block_len + log_bit_len);
545 (c.into(), d.into())
546 }
547
548 #[inline]
549 fn from_fn(mut f: impl FnMut(usize) -> Self::Scalar) -> Self {
550 U::from_fn(move |i| f(i).to_underlier()).into()
551 }
552}
553
554impl<U: Underlier, Scalar: BinaryField> Distribution<PackedPrimitiveType<U, Scalar>>
555 for StandardUniform
556{
557 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PackedPrimitiveType<U, Scalar> {
558 PackedPrimitiveType::from_underlier(U::random(rng))
559 }
560}