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 add_assign_lane(&mut self, lane: usize, value: CubicTrinomialExtensionField<F>) {
172        // Add each coefficient into its own base packing at the shared lane.
173        for (coeff, v) in self.value.iter_mut().zip(value.value) {
174            coeff.as_slice_mut()[lane] += v;
175        }
176    }
177
178    #[inline]
179    fn packed_ext_powers(base: CubicTrinomialExtensionField<F>) -> Powers<Self> {
180        let width = F::Packing::WIDTH;
181        let powers = base.powers().collect_n(width + 1);
182        // Transpose first WIDTH powers
183        let current = Self::from_ext_slice(&powers[..width]);
184
185        // Broadcast self^WIDTH
186        let multiplier = powers[width].into();
187
188        Powers {
189            base: multiplier,
190            current,
191        }
192    }
193}
194
195impl<F, PF> Neg for PackedCubicTrinomialExtensionField<F, PF>
196where
197    F: CubicTrinomialExtendable,
198    PF: PackedField<Scalar = F>,
199{
200    type Output = Self;
201
202    #[inline]
203    fn neg(self) -> Self {
204        Self::new(self.value.map(PF::neg))
205    }
206}
207
208impl<F, PF> Add for PackedCubicTrinomialExtensionField<F, PF>
209where
210    F: CubicTrinomialExtendable,
211    PF: PackedField<Scalar = F>,
212{
213    type Output = Self;
214
215    #[inline]
216    fn add(self, rhs: Self) -> Self {
217        Self::new(vector_add(&self.value, &rhs.value))
218    }
219}
220
221impl<F, PF> Add<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
222where
223    F: CubicTrinomialExtendable,
224    PF: PackedField<Scalar = F>,
225{
226    type Output = Self;
227
228    #[inline]
229    fn add(self, rhs: CubicTrinomialExtensionField<F>) -> Self {
230        let value = vector_add(&self.value, &rhs.value);
231        Self::new(value)
232    }
233}
234
235impl<F, PF> Add<PF> for PackedCubicTrinomialExtensionField<F, PF>
236where
237    F: CubicTrinomialExtendable,
238    PF: PackedField<Scalar = F>,
239{
240    type Output = Self;
241
242    #[inline]
243    fn add(mut self, rhs: PF) -> Self {
244        self.value[0] += rhs;
245        self
246    }
247}
248
249impl<F, PF> AddAssign for PackedCubicTrinomialExtensionField<F, PF>
250where
251    F: CubicTrinomialExtendable,
252    PF: PackedField<Scalar = F>,
253{
254    #[inline]
255    fn add_assign(&mut self, rhs: Self) {
256        for i in 0..3 {
257            self.value[i] += rhs.value[i];
258        }
259    }
260}
261
262impl<F, PF> AddAssign<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
263where
264    F: CubicTrinomialExtendable,
265    PF: PackedField<Scalar = F>,
266{
267    #[inline]
268    fn add_assign(&mut self, rhs: CubicTrinomialExtensionField<F>) {
269        for i in 0..3 {
270            self.value[i] += rhs.value[i];
271        }
272    }
273}
274
275impl<F, PF> AddAssign<PF> for PackedCubicTrinomialExtensionField<F, PF>
276where
277    F: CubicTrinomialExtendable,
278    PF: PackedField<Scalar = F>,
279{
280    #[inline]
281    fn add_assign(&mut self, rhs: PF) {
282        self.value[0] += rhs;
283    }
284}
285
286impl<F, PF> Sum for PackedCubicTrinomialExtensionField<F, PF>
287where
288    F: CubicTrinomialExtendable,
289    PF: PackedField<Scalar = F>,
290{
291    #[inline]
292    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
293        iter.reduce(|acc, x| acc + x).unwrap_or(Self::ZERO)
294    }
295}
296
297impl<F, PF> Sub for PackedCubicTrinomialExtensionField<F, PF>
298where
299    F: CubicTrinomialExtendable,
300    PF: PackedField<Scalar = F>,
301{
302    type Output = Self;
303
304    #[inline]
305    fn sub(self, rhs: Self) -> Self {
306        Self::new(vector_sub(&self.value, &rhs.value))
307    }
308}
309
310impl<F, PF> Sub<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
311where
312    F: CubicTrinomialExtendable,
313    PF: PackedField<Scalar = F>,
314{
315    type Output = Self;
316
317    #[inline]
318    fn sub(self, rhs: CubicTrinomialExtensionField<F>) -> Self {
319        let value = vector_sub(&self.value, &rhs.value);
320        Self::new(value)
321    }
322}
323
324impl<F, PF> Sub<PF> for PackedCubicTrinomialExtensionField<F, PF>
325where
326    F: CubicTrinomialExtendable,
327    PF: PackedField<Scalar = F>,
328{
329    type Output = Self;
330
331    #[inline]
332    fn sub(self, rhs: PF) -> Self {
333        let mut res = self.value;
334        res[0] -= rhs;
335        Self::new(res)
336    }
337}
338
339impl<F, PF> SubAssign for PackedCubicTrinomialExtensionField<F, PF>
340where
341    F: CubicTrinomialExtendable,
342    PF: PackedField<Scalar = F>,
343{
344    #[inline]
345    fn sub_assign(&mut self, rhs: Self) {
346        *self = *self - rhs;
347    }
348}
349
350impl<F, PF> SubAssign<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
351where
352    F: CubicTrinomialExtendable,
353    PF: PackedField<Scalar = F>,
354{
355    #[inline]
356    fn sub_assign(&mut self, rhs: CubicTrinomialExtensionField<F>) {
357        *self = *self - rhs;
358    }
359}
360
361impl<F, PF> SubAssign<PF> for PackedCubicTrinomialExtensionField<F, PF>
362where
363    F: CubicTrinomialExtendable,
364    PF: PackedField<Scalar = F>,
365{
366    #[inline]
367    fn sub_assign(&mut self, rhs: PF) {
368        *self = *self - rhs;
369    }
370}
371
372impl<F, PF> Mul for PackedCubicTrinomialExtensionField<F, PF>
373where
374    F: CubicTrinomialExtendable,
375    PF: PackedField<Scalar = F>,
376{
377    type Output = Self;
378
379    #[inline]
380    fn mul(self, rhs: Self) -> Self {
381        let mut res = Self::default();
382        trinomial_cubic_mul(&self.value, &rhs.value, &mut res.value);
383        res
384    }
385}
386
387impl<F, PF> Mul<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
388where
389    F: CubicTrinomialExtendable,
390    PF: PackedField<Scalar = F>,
391{
392    type Output = Self;
393
394    #[inline]
395    fn mul(self, rhs: CubicTrinomialExtensionField<F>) -> Self {
396        self * Self::from(rhs)
397    }
398}
399
400impl<F, PF> Mul<PF> for PackedCubicTrinomialExtensionField<F, PF>
401where
402    F: CubicTrinomialExtendable,
403    PF: PackedField<Scalar = F>,
404{
405    type Output = Self;
406
407    #[inline]
408    fn mul(self, rhs: PF) -> Self {
409        Self::new(self.value.map(|x| x * rhs))
410    }
411}
412
413impl<F, PF> Product for PackedCubicTrinomialExtensionField<F, PF>
414where
415    F: CubicTrinomialExtendable,
416    PF: PackedField<Scalar = F>,
417{
418    #[inline]
419    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
420        iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
421    }
422}
423
424impl<F, PF> MulAssign for PackedCubicTrinomialExtensionField<F, PF>
425where
426    F: CubicTrinomialExtendable,
427    PF: PackedField<Scalar = F>,
428{
429    #[inline]
430    fn mul_assign(&mut self, rhs: Self) {
431        *self = *self * rhs;
432    }
433}
434
435impl<F, PF> MulAssign<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
436where
437    F: CubicTrinomialExtendable,
438    PF: PackedField<Scalar = F>,
439{
440    #[inline]
441    fn mul_assign(&mut self, rhs: CubicTrinomialExtensionField<F>) {
442        *self = *self * rhs;
443    }
444}
445
446impl<F, PF> MulAssign<PF> for PackedCubicTrinomialExtensionField<F, PF>
447where
448    F: CubicTrinomialExtendable,
449    PF: PackedField<Scalar = F>,
450{
451    #[inline]
452    fn mul_assign(&mut self, rhs: PF) {
453        *self = *self * rhs;
454    }
455}
456
457impl<F, PF> Sum<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
458where
459    F: CubicTrinomialExtendable,
460    PF: PackedField<Scalar = F>,
461{
462    #[inline]
463    fn sum<I: Iterator<Item = CubicTrinomialExtensionField<F>>>(iter: I) -> Self {
464        iter.map(Self::from).sum()
465    }
466}
467
468impl<F, PF> Product<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
469where
470    F: CubicTrinomialExtendable,
471    PF: PackedField<Scalar = F>,
472{
473    #[inline]
474    fn product<I: Iterator<Item = CubicTrinomialExtensionField<F>>>(iter: I) -> Self {
475        iter.map(Self::from).product()
476    }
477}
478
479impl<F, PF> Div<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
480where
481    F: CubicTrinomialExtendable,
482    PF: PackedField<Scalar = F>,
483{
484    type Output = Self;
485
486    #[allow(clippy::suspicious_arithmetic_impl)]
487    #[inline]
488    fn div(self, rhs: CubicTrinomialExtensionField<F>) -> Self {
489        self * Self::from(rhs.inverse())
490    }
491}
492
493impl<F, PF> DivAssign<CubicTrinomialExtensionField<F>> for PackedCubicTrinomialExtensionField<F, PF>
494where
495    F: CubicTrinomialExtendable,
496    PF: PackedField<Scalar = F>,
497{
498    #[inline]
499    fn div_assign(&mut self, rhs: CubicTrinomialExtensionField<F>) {
500        *self = *self / rhs;
501    }
502}
503
504impl<F: CubicTrinomialExtendable> Div for PackedCubicTrinomialExtensionField<F, F::Packing> {
505    type Output = Self;
506
507    #[allow(clippy::suspicious_arithmetic_impl)]
508    #[inline]
509    fn div(self, rhs: Self) -> Self {
510        self * crate::invert_packed_extension::<F, CubicTrinomialExtensionField<F>>(rhs)
511    }
512}
513
514impl<F: CubicTrinomialExtendable> DivAssign for PackedCubicTrinomialExtensionField<F, F::Packing> {
515    #[inline]
516    fn div_assign(&mut self, rhs: Self) {
517        *self = *self / rhs;
518    }
519}