Skip to main content

p3_field/extension/
packed_binomial_extension.rs

1use alloc::vec::Vec;
2use core::array;
3use core::iter::{Product, Sum};
4use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
5
6use p3_util::{flatten_to_base, reconstitute_from_base};
7use rand::distr::{Distribution, StandardUniform};
8
9use super::{BinomialExtensionField, PackedExtField, binomial_mul, vector_add, vector_sub};
10use crate::extension::{Binomial, BinomiallyExtendable, binomial_square};
11use crate::{
12    Algebra, BasedVectorSpace, Dup, Field, PackedField, PackedFieldExtension, PackedValue, Powers,
13    PrimeCharacteristicRing, field_to_array,
14};
15
16/// Packed binomial extension field `F[X] / (X^D - W)`, one element per SIMD lane.
17///
18/// Type alias for the unified [`PackedExtField`] with `Shape = Binomial<F>`.
19pub type PackedBinomialExtensionField<F, PF, const D: usize> =
20    PackedExtField<F, PF, D, Binomial<F>>;
21
22impl<F: Field, PF: PackedField<Scalar = F>, const D: usize> Default
23    for PackedBinomialExtensionField<F, PF, D>
24{
25    #[inline]
26    fn default() -> Self {
27        Self::new(array::from_fn(|_| PF::ZERO))
28    }
29}
30
31impl<F: Field, PF: PackedField<Scalar = F>, const D: usize> From<BinomialExtensionField<F, D>>
32    for PackedBinomialExtensionField<F, PF, D>
33{
34    #[inline]
35    fn from(x: BinomialExtensionField<F, D>) -> Self {
36        Self::new(x.value.map(Into::into))
37    }
38}
39
40impl<F: Field, PF: PackedField<Scalar = F>, const D: usize> From<PF>
41    for PackedBinomialExtensionField<F, PF, D>
42{
43    #[inline]
44    fn from(x: PF) -> Self {
45        Self::new(field_to_array(x))
46    }
47}
48
49impl<F: Field, PF: PackedField<Scalar = F>, const D: usize>
50    Distribution<PackedBinomialExtensionField<F, PF, D>> for StandardUniform
51where
52    Self: Distribution<PF>,
53{
54    #[inline]
55    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> PackedBinomialExtensionField<F, PF, D> {
56        PackedBinomialExtensionField::new(array::from_fn(|_| self.sample(rng)))
57    }
58}
59
60impl<F: BinomiallyExtendable<D>, PF: PackedField<Scalar = F>, const D: usize>
61    Algebra<BinomialExtensionField<F, D>> for PackedBinomialExtensionField<F, PF, D>
62{
63}
64
65impl<F: BinomiallyExtendable<D>, PF: PackedField<Scalar = F>, const D: usize> Algebra<PF>
66    for PackedBinomialExtensionField<F, PF, D>
67{
68    #[inline]
69    fn mixed_dot_product<const N: usize>(a: &[Self; N], f: &[PF; N]) -> Self
70    where
71        PF: Dup,
72    {
73        // Output container; each coordinate is filled independently below.
74        let mut result = Self::default();
75
76        // One base-field dot product per output coordinate.
77        for k in 0..D {
78            // Strided gather of the k-th coordinate from each extension input:
79            //
80            //     coord_k = [ a_0[k], a_1[k], ..., a_{N-1}[k] ]
81            let coord_k: [PF; N] = core::array::from_fn(|i| a[i].value[k]);
82
83            // Base-level dot product.
84            //
85            // - For Monty-31 packings this is the delayed-reduction primitive;
86            // - For other packings it falls back to the eager default and the override is a no-op gain.
87            result.value[k] = PF::dot_product::<N>(&coord_k, f);
88        }
89
90        result
91    }
92}
93
94impl<F, PF, const D: usize> PrimeCharacteristicRing for PackedBinomialExtensionField<F, PF, D>
95where
96    F: BinomiallyExtendable<D>,
97    PF: PackedField<Scalar = F>,
98{
99    type PrimeSubfield = PF::PrimeSubfield;
100
101    const ZERO: Self = Self::new([PF::ZERO; D]);
102
103    const ONE: Self = Self::new(field_to_array(PF::ONE));
104
105    const TWO: Self = Self::new(field_to_array(PF::TWO));
106
107    const NEG_ONE: Self = Self::new(field_to_array(PF::NEG_ONE));
108
109    #[inline]
110    fn from_prime_subfield(val: Self::PrimeSubfield) -> Self {
111        PF::from_prime_subfield(val).into()
112    }
113
114    #[inline]
115    fn from_bool(b: bool) -> Self {
116        PF::from_bool(b).into()
117    }
118
119    #[inline]
120    fn halve(&self) -> Self {
121        Self::new(self.value.map(|x| x.halve()))
122    }
123
124    #[inline(always)]
125    fn square(&self) -> Self {
126        let mut res = Self::default();
127        let w = F::W;
128        binomial_square(&self.value, &mut res.value, w);
129        res
130    }
131
132    #[inline]
133    fn mul_2exp_u64(&self, exp: u64) -> Self {
134        Self::new(self.value.map(|x| x.mul_2exp_u64(exp)))
135    }
136
137    #[inline]
138    fn div_2exp_u64(&self, exp: u64) -> Self {
139        Self::new(self.value.map(|x| x.div_2exp_u64(exp)))
140    }
141
142    #[inline]
143    fn zero_vec(len: usize) -> Vec<Self> {
144        // SAFETY: this is a repr(transparent) wrapper around an array.
145        unsafe { reconstitute_from_base(PF::zero_vec(len * D)) }
146    }
147}
148
149impl<F, PF, const D: usize> BasedVectorSpace<PF> for PackedBinomialExtensionField<F, PF, D>
150where
151    F: BinomiallyExtendable<D>,
152    PF: PackedField<Scalar = F>,
153{
154    const DIMENSION: usize = D;
155
156    #[inline]
157    fn as_basis_coefficients_slice(&self) -> &[PF] {
158        &self.value
159    }
160
161    #[inline]
162    fn from_basis_coefficients_fn<Fn: FnMut(usize) -> PF>(f: Fn) -> Self {
163        Self::new(array::from_fn(f))
164    }
165
166    #[inline]
167    fn from_basis_coefficients_iter<I: ExactSizeIterator<Item = PF>>(mut iter: I) -> Option<Self> {
168        (iter.len() == D).then(|| Self::new(array::from_fn(|_| iter.next().unwrap()))) // The unwrap is safe as we just checked the length of iter.
169    }
170
171    #[inline]
172    fn flatten_to_base(vec: Vec<Self>) -> Vec<PF> {
173        unsafe {
174            // Safety:
175            // As `Self` is a `repr(transparent)`, it is stored identically in memory to `[PF; D]`
176            flatten_to_base(vec)
177        }
178    }
179
180    #[inline]
181    fn reconstitute_from_base(vec: Vec<PF>) -> Vec<Self> {
182        unsafe {
183            // Safety:
184            // As `Self` is a `repr(transparent)`, it is stored identically in memory to `[PF; D]`
185            reconstitute_from_base(vec)
186        }
187    }
188}
189
190impl<F, const D: usize> PackedFieldExtension<F, BinomialExtensionField<F, D>>
191    for PackedBinomialExtensionField<F, F::Packing, D>
192where
193    F: BinomiallyExtendable<D>,
194{
195    #[inline]
196    fn from_ext_fn(f: impl Fn(usize) -> BinomialExtensionField<F, D>) -> Self {
197        Self::new(F::Packing::pack_columns_fn(|lane| f(lane).value))
198    }
199
200    #[inline]
201    fn packed_ext_powers(base: BinomialExtensionField<F, D>) -> crate::Powers<Self> {
202        let width = F::Packing::WIDTH;
203        let powers = base.powers().collect_n(width + 1);
204        // Transpose first WIDTH powers
205        let current = Self::from_ext_slice(&powers[..width]);
206
207        // Broadcast self^WIDTH
208        let multiplier = powers[width].into();
209
210        Powers {
211            base: multiplier,
212            current,
213        }
214    }
215}
216
217impl<F, PF, const D: usize> Neg for PackedBinomialExtensionField<F, PF, D>
218where
219    F: BinomiallyExtendable<D>,
220    PF: PackedField<Scalar = F>,
221{
222    type Output = Self;
223
224    #[inline]
225    fn neg(self) -> Self {
226        Self::new(self.value.map(PF::neg))
227    }
228}
229
230impl<F, PF, const D: usize> Add for PackedBinomialExtensionField<F, PF, D>
231where
232    F: BinomiallyExtendable<D>,
233    PF: PackedField<Scalar = F>,
234{
235    type Output = Self;
236
237    #[inline]
238    fn add(self, rhs: Self) -> Self {
239        let value = vector_add(&self.value, &rhs.value);
240        Self::new(value)
241    }
242}
243
244impl<F, PF, const D: usize> Add<BinomialExtensionField<F, D>>
245    for PackedBinomialExtensionField<F, PF, D>
246where
247    F: BinomiallyExtendable<D>,
248    PF: PackedField<Scalar = F>,
249{
250    type Output = Self;
251
252    #[inline]
253    fn add(self, rhs: BinomialExtensionField<F, D>) -> Self {
254        let value = vector_add(&self.value, &rhs.value);
255        Self::new(value)
256    }
257}
258
259impl<F, PF, const D: usize> Add<PF> for PackedBinomialExtensionField<F, PF, D>
260where
261    F: BinomiallyExtendable<D>,
262    PF: PackedField<Scalar = F>,
263{
264    type Output = Self;
265
266    #[inline]
267    fn add(mut self, rhs: PF) -> Self {
268        self.value[0] += rhs;
269        self
270    }
271}
272
273impl<F, PF, const D: usize> AddAssign for PackedBinomialExtensionField<F, PF, D>
274where
275    F: BinomiallyExtendable<D>,
276    PF: PackedField<Scalar = F>,
277{
278    #[inline]
279    fn add_assign(&mut self, rhs: Self) {
280        for i in 0..D {
281            self.value[i] += rhs.value[i];
282        }
283    }
284}
285
286impl<F, PF, const D: usize> AddAssign<BinomialExtensionField<F, D>>
287    for PackedBinomialExtensionField<F, PF, D>
288where
289    F: BinomiallyExtendable<D>,
290    PF: PackedField<Scalar = F>,
291{
292    #[inline]
293    fn add_assign(&mut self, rhs: BinomialExtensionField<F, D>) {
294        for i in 0..D {
295            self.value[i] += rhs.value[i];
296        }
297    }
298}
299
300impl<F, PF, const D: usize> AddAssign<PF> for PackedBinomialExtensionField<F, PF, D>
301where
302    F: BinomiallyExtendable<D>,
303    PF: PackedField<Scalar = F>,
304{
305    #[inline]
306    fn add_assign(&mut self, rhs: PF) {
307        self.value[0] += rhs;
308    }
309}
310
311impl<F, PF, const D: usize> Sum for PackedBinomialExtensionField<F, PF, D>
312where
313    F: BinomiallyExtendable<D>,
314    PF: PackedField<Scalar = F>,
315{
316    #[inline]
317    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
318        iter.reduce(|acc, x| acc + x).unwrap_or(Self::ZERO)
319    }
320}
321
322impl<F, PF, const D: usize> Sub for PackedBinomialExtensionField<F, PF, D>
323where
324    F: BinomiallyExtendable<D>,
325    PF: PackedField<Scalar = F>,
326{
327    type Output = Self;
328
329    #[inline]
330    fn sub(self, rhs: Self) -> Self {
331        let value = vector_sub(&self.value, &rhs.value);
332        Self::new(value)
333    }
334}
335
336impl<F, PF, const D: usize> Sub<BinomialExtensionField<F, D>>
337    for PackedBinomialExtensionField<F, PF, D>
338where
339    F: BinomiallyExtendable<D>,
340    PF: PackedField<Scalar = F>,
341{
342    type Output = Self;
343
344    #[inline]
345    fn sub(self, rhs: BinomialExtensionField<F, D>) -> Self {
346        let value = vector_sub(&self.value, &rhs.value);
347        Self::new(value)
348    }
349}
350
351impl<F, PF, const D: usize> Sub<PF> for PackedBinomialExtensionField<F, PF, D>
352where
353    F: BinomiallyExtendable<D>,
354    PF: PackedField<Scalar = F>,
355{
356    type Output = Self;
357
358    #[inline]
359    fn sub(self, rhs: PF) -> Self {
360        let mut res = self.value;
361        res[0] -= rhs;
362        Self::new(res)
363    }
364}
365
366impl<F, PF, const D: usize> SubAssign for PackedBinomialExtensionField<F, PF, D>
367where
368    F: BinomiallyExtendable<D>,
369    PF: PackedField<Scalar = F>,
370{
371    #[inline]
372    fn sub_assign(&mut self, rhs: Self) {
373        *self = *self - rhs;
374    }
375}
376
377impl<F, PF, const D: usize> SubAssign<BinomialExtensionField<F, D>>
378    for PackedBinomialExtensionField<F, PF, D>
379where
380    F: BinomiallyExtendable<D>,
381    PF: PackedField<Scalar = F>,
382{
383    #[inline]
384    fn sub_assign(&mut self, rhs: BinomialExtensionField<F, D>) {
385        *self = *self - rhs;
386    }
387}
388
389impl<F, PF, const D: usize> SubAssign<PF> for PackedBinomialExtensionField<F, PF, D>
390where
391    F: BinomiallyExtendable<D>,
392    PF: PackedField<Scalar = F>,
393{
394    #[inline]
395    fn sub_assign(&mut self, rhs: PF) {
396        *self = *self - rhs;
397    }
398}
399
400impl<F, PF, const D: usize> Mul for PackedBinomialExtensionField<F, PF, D>
401where
402    F: BinomiallyExtendable<D>,
403    PF: PackedField<Scalar = F>,
404{
405    type Output = Self;
406
407    #[inline]
408    fn mul(self, rhs: Self) -> Self {
409        let a = self.value;
410        let b = rhs.value;
411        let mut res = Self::default();
412        let w = F::W;
413
414        binomial_mul::<F, PF, PF, D>(&a, &b, &mut res.value, w);
415
416        res
417    }
418}
419
420impl<F, PF, const D: usize> Mul<BinomialExtensionField<F, D>>
421    for PackedBinomialExtensionField<F, PF, D>
422where
423    F: BinomiallyExtendable<D>,
424    PF: PackedField<Scalar = F>,
425{
426    type Output = Self;
427
428    #[inline]
429    fn mul(self, rhs: BinomialExtensionField<F, D>) -> Self {
430        let a = self.value;
431        let b = rhs.value;
432        let mut res = Self::default();
433        let w = F::W;
434
435        binomial_mul(&a, &b, &mut res.value, w);
436
437        res
438    }
439}
440
441impl<F, PF, const D: usize> Mul<PF> for PackedBinomialExtensionField<F, PF, D>
442where
443    F: BinomiallyExtendable<D>,
444    PF: PackedField<Scalar = F>,
445{
446    type Output = Self;
447
448    #[inline]
449    fn mul(self, rhs: PF) -> Self {
450        Self::new(self.value.map(|x| x * rhs))
451    }
452}
453
454impl<F, PF, const D: usize> Product for PackedBinomialExtensionField<F, PF, D>
455where
456    F: BinomiallyExtendable<D>,
457    PF: PackedField<Scalar = F>,
458{
459    #[inline]
460    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
461        iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
462    }
463}
464
465impl<F, PF, const D: usize> MulAssign for PackedBinomialExtensionField<F, PF, D>
466where
467    F: BinomiallyExtendable<D>,
468    PF: PackedField<Scalar = F>,
469{
470    #[inline]
471    fn mul_assign(&mut self, rhs: Self) {
472        *self = *self * rhs;
473    }
474}
475
476impl<F, PF, const D: usize> MulAssign<BinomialExtensionField<F, D>>
477    for PackedBinomialExtensionField<F, PF, D>
478where
479    F: BinomiallyExtendable<D>,
480    PF: PackedField<Scalar = F>,
481{
482    #[inline]
483    fn mul_assign(&mut self, rhs: BinomialExtensionField<F, D>) {
484        *self = *self * rhs;
485    }
486}
487
488impl<F, PF, const D: usize> MulAssign<PF> for PackedBinomialExtensionField<F, PF, D>
489where
490    F: BinomiallyExtendable<D>,
491    PF: PackedField<Scalar = F>,
492{
493    #[inline]
494    fn mul_assign(&mut self, rhs: PF) {
495        *self = *self * rhs;
496    }
497}
498
499impl<F, PF, const D: usize> Div<BinomialExtensionField<F, D>>
500    for PackedBinomialExtensionField<F, PF, D>
501where
502    F: BinomiallyExtendable<D>,
503    PF: PackedField<Scalar = F>,
504{
505    type Output = Self;
506
507    #[allow(clippy::suspicious_arithmetic_impl)]
508    #[inline]
509    fn div(self, rhs: BinomialExtensionField<F, D>) -> Self {
510        self * Self::from(rhs.inverse())
511    }
512}
513
514impl<F, PF, const D: usize> DivAssign<BinomialExtensionField<F, D>>
515    for PackedBinomialExtensionField<F, PF, D>
516where
517    F: BinomiallyExtendable<D>,
518    PF: PackedField<Scalar = F>,
519{
520    #[inline]
521    fn div_assign(&mut self, rhs: BinomialExtensionField<F, D>) {
522        *self = *self / rhs;
523    }
524}
525
526impl<F: BinomiallyExtendable<D>, const D: usize> Div
527    for PackedBinomialExtensionField<F, F::Packing, D>
528{
529    type Output = Self;
530
531    #[allow(clippy::suspicious_arithmetic_impl)]
532    #[inline]
533    fn div(self, rhs: Self) -> Self {
534        self * crate::invert_packed_extension::<F, BinomialExtensionField<F, D>>(rhs)
535    }
536}
537
538impl<F: BinomiallyExtendable<D>, const D: usize> DivAssign
539    for PackedBinomialExtensionField<F, F::Packing, D>
540{
541    #[inline]
542    fn div_assign(&mut self, rhs: Self) {
543        *self = *self / rhs;
544    }
545}