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