p3_field/extension/
packed_binomial_extension.rs

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