Skip to main content

p3_field/extension/
packed_cubic_extension.rs

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