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