Skip to main content

p3_field/extension/
packed_quintic_extension.rs

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