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        Self::new(F::Packing::pack_columns_fn(|lane| ext_slice[lane].value))
265    }
266
267    #[inline]
268    fn packed_ext_powers(base: QuinticTrinomialExtensionField<F>) -> Powers<Self> {
269        use itertools::Itertools;
270        let width = F::Packing::WIDTH;
271        let powers = base.powers().take(width + 1).collect_vec();
272        // Transpose first WIDTH powers
273        let current = Self::from_ext_slice(&powers[..width]);
274
275        // Broadcast self^WIDTH
276        let multiplier = powers[width].into();
277
278        Powers {
279            base: multiplier,
280            current,
281        }
282    }
283}
284
285impl<F, PF> Neg for PackedQuinticTrinomialExtensionField<F, PF>
286where
287    F: QuinticTrinomialExtendable,
288    PF: PackedField<Scalar = F>,
289{
290    type Output = Self;
291
292    #[inline]
293    fn neg(self) -> Self {
294        Self::new(self.value.map(PF::neg))
295    }
296}
297
298impl<F, PF> Add for PackedQuinticTrinomialExtensionField<F, PF>
299where
300    F: QuinticTrinomialExtendable,
301    PF: PackedField<Scalar = F>,
302{
303    type Output = Self;
304
305    #[inline]
306    fn add(self, rhs: Self) -> Self {
307        Self::new(vector_add(&self.value, &rhs.value))
308    }
309}
310
311impl<F, PF> Add<QuinticTrinomialExtensionField<F>> for PackedQuinticTrinomialExtensionField<F, PF>
312where
313    F: QuinticTrinomialExtendable,
314    PF: PackedField<Scalar = F>,
315{
316    type Output = Self;
317
318    #[inline]
319    fn add(self, rhs: QuinticTrinomialExtensionField<F>) -> Self {
320        let value = vector_add(&self.value, &rhs.value);
321        Self { value }
322    }
323}
324
325impl<F, PF> Add<PF> for PackedQuinticTrinomialExtensionField<F, PF>
326where
327    F: QuinticTrinomialExtendable,
328    PF: PackedField<Scalar = F>,
329{
330    type Output = Self;
331
332    #[inline]
333    fn add(mut self, rhs: PF) -> Self {
334        self.value[0] += rhs;
335        self
336    }
337}
338
339impl<F, PF> AddAssign for PackedQuinticTrinomialExtensionField<F, PF>
340where
341    F: QuinticTrinomialExtendable,
342    PF: PackedField<Scalar = F>,
343{
344    #[inline]
345    fn add_assign(&mut self, rhs: Self) {
346        for i in 0..5 {
347            self.value[i] += rhs.value[i];
348        }
349    }
350}
351
352impl<F, PF> AddAssign<QuinticTrinomialExtensionField<F>>
353    for PackedQuinticTrinomialExtensionField<F, PF>
354where
355    F: QuinticTrinomialExtendable,
356    PF: PackedField<Scalar = F>,
357{
358    #[inline]
359    fn add_assign(&mut self, rhs: QuinticTrinomialExtensionField<F>) {
360        for i in 0..5 {
361            self.value[i] += rhs.value[i];
362        }
363    }
364}
365
366impl<F, PF> AddAssign<PF> for PackedQuinticTrinomialExtensionField<F, PF>
367where
368    F: QuinticTrinomialExtendable,
369    PF: PackedField<Scalar = F>,
370{
371    #[inline]
372    fn add_assign(&mut self, rhs: PF) {
373        self.value[0] += rhs;
374    }
375}
376
377impl<F, PF> Sum for PackedQuinticTrinomialExtensionField<F, PF>
378where
379    F: QuinticTrinomialExtendable,
380    PF: PackedField<Scalar = F>,
381{
382    #[inline]
383    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
384        iter.reduce(|acc, x| acc + x).unwrap_or(Self::ZERO)
385    }
386}
387
388impl<F, PF> Sub for PackedQuinticTrinomialExtensionField<F, PF>
389where
390    F: QuinticTrinomialExtendable,
391    PF: PackedField<Scalar = F>,
392{
393    type Output = Self;
394
395    #[inline]
396    fn sub(self, rhs: Self) -> Self {
397        Self::new(vector_sub(&self.value, &rhs.value))
398    }
399}
400
401impl<F, PF> Sub<QuinticTrinomialExtensionField<F>> for PackedQuinticTrinomialExtensionField<F, PF>
402where
403    F: QuinticTrinomialExtendable,
404    PF: PackedField<Scalar = F>,
405{
406    type Output = Self;
407
408    #[inline]
409    fn sub(self, rhs: QuinticTrinomialExtensionField<F>) -> Self {
410        let value = vector_sub(&self.value, &rhs.value);
411        Self { value }
412    }
413}
414
415impl<F, PF> Sub<PF> for PackedQuinticTrinomialExtensionField<F, PF>
416where
417    F: QuinticTrinomialExtendable,
418    PF: PackedField<Scalar = F>,
419{
420    type Output = Self;
421
422    #[inline]
423    fn sub(self, rhs: PF) -> Self {
424        let mut res = self.value;
425        res[0] -= rhs;
426        Self { value: res }
427    }
428}
429
430impl<F, PF> SubAssign for PackedQuinticTrinomialExtensionField<F, PF>
431where
432    F: QuinticTrinomialExtendable,
433    PF: PackedField<Scalar = F>,
434{
435    #[inline]
436    fn sub_assign(&mut self, rhs: Self) {
437        *self = *self - rhs;
438    }
439}
440
441impl<F, PF> SubAssign<QuinticTrinomialExtensionField<F>>
442    for PackedQuinticTrinomialExtensionField<F, PF>
443where
444    F: QuinticTrinomialExtendable,
445    PF: PackedField<Scalar = F>,
446{
447    #[inline]
448    fn sub_assign(&mut self, rhs: QuinticTrinomialExtensionField<F>) {
449        *self = *self - rhs;
450    }
451}
452
453impl<F, PF> SubAssign<PF> for PackedQuinticTrinomialExtensionField<F, PF>
454where
455    F: QuinticTrinomialExtendable,
456    PF: PackedField<Scalar = F>,
457{
458    #[inline]
459    fn sub_assign(&mut self, rhs: PF) {
460        *self = *self - rhs;
461    }
462}
463
464impl<F, PF> Mul for PackedQuinticTrinomialExtensionField<F, PF>
465where
466    F: QuinticTrinomialExtendable,
467    PF: PackedField<Scalar = F>,
468{
469    type Output = Self;
470
471    #[inline]
472    fn mul(self, rhs: Self) -> Self {
473        let mut res = Self::default();
474        trinomial_quintic_mul(&self.value, &rhs.value, &mut res.value);
475        res
476    }
477}
478
479impl<F, PF> Mul<QuinticTrinomialExtensionField<F>> for PackedQuinticTrinomialExtensionField<F, PF>
480where
481    F: QuinticTrinomialExtendable,
482    PF: PackedField<Scalar = F>,
483{
484    type Output = Self;
485
486    #[inline]
487    fn mul(self, rhs: QuinticTrinomialExtensionField<F>) -> Self {
488        self * Self::from(rhs)
489    }
490}
491
492impl<F, PF> Mul<PF> for PackedQuinticTrinomialExtensionField<F, PF>
493where
494    F: QuinticTrinomialExtendable,
495    PF: PackedField<Scalar = F>,
496{
497    type Output = Self;
498
499    #[inline]
500    fn mul(self, rhs: PF) -> Self {
501        Self {
502            value: self.value.map(|x| x * rhs),
503        }
504    }
505}
506
507impl<F, PF> Product for PackedQuinticTrinomialExtensionField<F, PF>
508where
509    F: QuinticTrinomialExtendable,
510    PF: PackedField<Scalar = F>,
511{
512    #[inline]
513    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
514        iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
515    }
516}
517
518impl<F, PF> MulAssign for PackedQuinticTrinomialExtensionField<F, PF>
519where
520    F: QuinticTrinomialExtendable,
521    PF: PackedField<Scalar = F>,
522{
523    #[inline]
524    fn mul_assign(&mut self, rhs: Self) {
525        *self = *self * rhs;
526    }
527}
528
529impl<F, PF> MulAssign<QuinticTrinomialExtensionField<F>>
530    for PackedQuinticTrinomialExtensionField<F, PF>
531where
532    F: QuinticTrinomialExtendable,
533    PF: PackedField<Scalar = F>,
534{
535    #[inline]
536    fn mul_assign(&mut self, rhs: QuinticTrinomialExtensionField<F>) {
537        *self = *self * rhs;
538    }
539}
540
541impl<F, PF> MulAssign<PF> for PackedQuinticTrinomialExtensionField<F, PF>
542where
543    F: QuinticTrinomialExtendable,
544    PF: PackedField<Scalar = F>,
545{
546    #[inline]
547    fn mul_assign(&mut self, rhs: PF) {
548        *self = *self * rhs;
549    }
550}
551
552impl<F, PF> Sum<QuinticTrinomialExtensionField<F>> for PackedQuinticTrinomialExtensionField<F, PF>
553where
554    F: QuinticTrinomialExtendable,
555    PF: PackedField<Scalar = F>,
556{
557    #[inline]
558    fn sum<I: Iterator<Item = QuinticTrinomialExtensionField<F>>>(iter: I) -> Self {
559        iter.map(Self::from).sum()
560    }
561}
562
563impl<F, PF> Product<QuinticTrinomialExtensionField<F>>
564    for PackedQuinticTrinomialExtensionField<F, PF>
565where
566    F: QuinticTrinomialExtendable,
567    PF: PackedField<Scalar = F>,
568{
569    #[inline]
570    fn product<I: Iterator<Item = QuinticTrinomialExtensionField<F>>>(iter: I) -> Self {
571        iter.map(Self::from).product()
572    }
573}
574
575impl<F, PF> Div<QuinticTrinomialExtensionField<F>> for PackedQuinticTrinomialExtensionField<F, PF>
576where
577    F: QuinticTrinomialExtendable,
578    PF: PackedField<Scalar = F>,
579{
580    type Output = Self;
581
582    #[allow(clippy::suspicious_arithmetic_impl)]
583    #[inline]
584    fn div(self, rhs: QuinticTrinomialExtensionField<F>) -> Self {
585        self * Self::from(rhs.inverse())
586    }
587}
588
589impl<F, PF> DivAssign<QuinticTrinomialExtensionField<F>>
590    for PackedQuinticTrinomialExtensionField<F, PF>
591where
592    F: QuinticTrinomialExtendable,
593    PF: PackedField<Scalar = F>,
594{
595    #[inline]
596    fn div_assign(&mut self, rhs: QuinticTrinomialExtensionField<F>) {
597        *self = *self / rhs;
598    }
599}