1use alloc::format;
9use alloc::string::ToString;
10use alloc::vec::Vec;
11use core::array;
12use core::fmt::{self, Display, Formatter};
13use core::iter::{Product, Sum};
14use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
15
16use itertools::Itertools;
17use num_bigint::BigUint;
18use p3_util::{as_base_slice, as_base_slice_mut, reconstitute_from_base};
19
20use super::packed_quintic_extension::PackedQuinticTrinomialExtensionField;
21use super::{ExtField, HasFrobenius, HasTwoAdicQuinticExtension};
22use crate::extension::{ExtensionAlgebra, QuinticTrinomial, QuinticTrinomialExtendable};
23use crate::field::Field;
24use crate::{
25 Algebra, ExtensionField, PackedFieldExtension, PrimeCharacteristicRing, RawDataSerializable,
26 TwoAdicField, field_to_array,
27};
28
29pub type QuinticTrinomialExtensionField<F, A = F> = ExtField<F, 5, QuinticTrinomial, A>;
35
36impl<F: Copy> QuinticTrinomialExtensionField<F, F> {
37 #[inline]
42 pub const fn new_array<const N: usize>(input: [[F; 5]; N]) -> [Self; N] {
43 const { assert!(N > 0) }
44 let mut output = [Self::new(input[0]); N];
45 let mut i = 1;
46 while i < N {
47 output[i] = Self::new(input[i]);
48 i += 1;
49 }
50 output
51 }
52}
53
54impl<F: QuinticTrinomialExtendable> ExtensionField<F> for QuinticTrinomialExtensionField<F>
55where
56 PackedQuinticTrinomialExtensionField<F, F::Packing>: PackedFieldExtension<F, Self>,
57{
58 type ExtensionPacking = PackedQuinticTrinomialExtensionField<F, F::Packing>;
59
60 #[inline]
61 fn is_in_basefield(&self) -> bool {
62 self.value[1..].iter().all(F::is_zero)
63 }
64
65 #[inline]
66 fn as_base(&self) -> Option<F> {
67 <Self as ExtensionField<F>>::is_in_basefield(self).then(|| self.value[0])
68 }
69}
70
71impl<F: QuinticTrinomialExtendable> HasFrobenius<F> for QuinticTrinomialExtensionField<F> {
72 #[inline]
73 fn frobenius(&self) -> Self {
74 let a = &self.value;
75 let fc = &F::FROBENIUS_COEFFS;
76
77 let a_tail = &[a[1], a[2], a[3], a[4]];
79 let c0 = a[0] + F::dot_product::<4>(a_tail, &[fc[0][0], fc[1][0], fc[2][0], fc[3][0]]);
80 let c1 = F::dot_product::<4>(a_tail, &[fc[0][1], fc[1][1], fc[2][1], fc[3][1]]);
81 let c2 = F::dot_product::<4>(a_tail, &[fc[0][2], fc[1][2], fc[2][2], fc[3][2]]);
82 let c3 = F::dot_product::<4>(a_tail, &[fc[0][3], fc[1][3], fc[2][3], fc[3][3]]);
83 let c4 = F::dot_product::<4>(a_tail, &[fc[0][4], fc[1][4], fc[2][4], fc[3][4]]);
84
85 Self::new([c0, c1, c2, c3, c4])
86 }
87
88 #[inline]
90 fn repeated_frobenius(&self, count: usize) -> Self {
91 match count % 5 {
92 0 => *self,
93 _ => {
94 let mut result = *self;
95 for _ in 0..(count % 5) {
96 result = result.frobenius();
97 }
98 result
99 }
100 }
101 }
102
103 #[inline]
111 fn pseudo_inv(&self) -> Self {
112 if self.is_zero() {
113 return Self::ZERO;
114 }
115
116 let a_exp_p = self.frobenius();
119 let a_exp_p_plus_p2 = (*self * a_exp_p).frobenius();
120 let prod_conj = a_exp_p_plus_p2 * a_exp_p_plus_p2.repeated_frobenius(2);
121
122 let norm = self.compute_norm_with_prod_conj(&prod_conj);
125 debug_assert_eq!(Self::from(norm), *self * prod_conj);
126
127 prod_conj * norm.inverse()
128 }
129}
130
131impl<F: QuinticTrinomialExtendable> QuinticTrinomialExtensionField<F> {
132 #[inline]
137 fn compute_norm_with_prod_conj(&self, prod_conj: &Self) -> F {
138 let a = &self.value;
139 let b = &prod_conj.value;
140
141 let c0 = a[0] * b[0];
144 let c5 = F::dot_product::<4>(&[a[1], a[2], a[3], a[4]], &[b[4], b[3], b[2], b[1]]);
145 let c8 = a[4] * b[4];
146
147 c0 + c5 - c8
148 }
149}
150
151impl<F, A> PrimeCharacteristicRing for QuinticTrinomialExtensionField<F, A>
152where
153 F: QuinticTrinomialExtendable,
154 A: ExtensionAlgebra<F, 5, QuinticTrinomial> + Copy,
155{
156 type PrimeSubfield = <A as PrimeCharacteristicRing>::PrimeSubfield;
157
158 const ZERO: Self = Self::new([A::ZERO; 5]);
159 const ONE: Self = Self::new(field_to_array(A::ONE));
160 const TWO: Self = Self::new(field_to_array(A::TWO));
161 const NEG_ONE: Self = Self::new(field_to_array(A::NEG_ONE));
162
163 #[inline]
164 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
165 <A as PrimeCharacteristicRing>::from_prime_subfield(f).into()
166 }
167
168 #[inline]
169 fn halve(&self) -> Self {
170 Self::new(array::from_fn(|i| self.value[i].halve()))
171 }
172
173 #[inline(always)]
174 fn square(&self) -> Self {
175 let mut res = Self::default();
176 <A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_square(&self.value, &mut res.value);
177 res
178 }
179
180 #[inline]
181 fn mul_2exp_u64(&self, exp: u64) -> Self {
182 Self::new(array::from_fn(|i| self.value[i].mul_2exp_u64(exp)))
183 }
184
185 #[inline]
186 fn div_2exp_u64(&self, exp: u64) -> Self {
187 Self::new(array::from_fn(|i| self.value[i].div_2exp_u64(exp)))
188 }
189
190 #[inline]
191 fn zero_vec(len: usize) -> Vec<Self> {
192 unsafe { reconstitute_from_base(A::zero_vec(len * 5)) }
194 }
195}
196
197impl<F: QuinticTrinomialExtendable> Algebra<F> for QuinticTrinomialExtensionField<F> {}
198
199impl<F: QuinticTrinomialExtendable> RawDataSerializable for QuinticTrinomialExtensionField<F> {
200 const NUM_BYTES: usize = F::NUM_BYTES * 5;
201
202 #[inline]
203 fn into_bytes(self) -> impl IntoIterator<Item = u8> {
204 self.value.into_iter().flat_map(|x| x.into_bytes())
205 }
206
207 #[inline]
208 fn into_byte_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u8> {
209 F::into_byte_stream(input.into_iter().flat_map(|x| x.value))
210 }
211
212 #[inline]
213 fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
214 F::into_u32_stream(input.into_iter().flat_map(|x| x.value))
215 }
216
217 #[inline]
218 fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
219 F::into_u64_stream(input.into_iter().flat_map(|x| x.value))
220 }
221
222 #[inline]
223 fn into_parallel_byte_streams<const N: usize>(
224 input: impl IntoIterator<Item = [Self; N]>,
225 ) -> impl IntoIterator<Item = [u8; N]> {
226 F::into_parallel_byte_streams(
227 input
228 .into_iter()
229 .flat_map(|x| (0..5).map(move |i| array::from_fn(|j| x[j].value[i]))),
230 )
231 }
232
233 #[inline]
234 fn into_parallel_u32_streams<const N: usize>(
235 input: impl IntoIterator<Item = [Self; N]>,
236 ) -> impl IntoIterator<Item = [u32; N]> {
237 F::into_parallel_u32_streams(
238 input
239 .into_iter()
240 .flat_map(|x| (0..5).map(move |i| array::from_fn(|j| x[j].value[i]))),
241 )
242 }
243
244 #[inline]
245 fn into_parallel_u64_streams<const N: usize>(
246 input: impl IntoIterator<Item = [Self; N]>,
247 ) -> impl IntoIterator<Item = [u64; N]> {
248 F::into_parallel_u64_streams(
249 input
250 .into_iter()
251 .flat_map(|x| (0..5).map(move |i| array::from_fn(|j| x[j].value[i]))),
252 )
253 }
254}
255
256impl<F: QuinticTrinomialExtendable> crate::AlgebraIdentity<F>
257 for QuinticTrinomialExtensionField<F>
258{
259 fn algebra_id() -> Vec<u8> {
260 b"p3-power-basis-v1:X^5+X^2-1".to_vec()
261 }
262}
263
264impl<F: QuinticTrinomialExtendable> Field for QuinticTrinomialExtensionField<F> {
265 type Packing = Self;
266
267 const GENERATOR: Self = Self::new(F::EXT_GENERATOR);
268
269 fn try_inverse(&self) -> Option<Self> {
270 if self.is_zero() {
271 return None;
272 }
273 Some(self.pseudo_inv())
274 }
275
276 #[inline]
277 fn add_slices(slice_1: &mut [Self], slice_2: &[Self]) {
278 unsafe {
281 let base_slice_1 = as_base_slice_mut(slice_1);
282 let base_slice_2 = as_base_slice(slice_2);
283 F::add_slices(base_slice_1, base_slice_2);
284 }
285 }
286
287 #[inline]
288 fn order() -> BigUint {
289 F::order().pow(5)
290 }
291}
292
293impl<F: QuinticTrinomialExtendable> Display for QuinticTrinomialExtensionField<F> {
294 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
295 if self.is_zero() {
296 write!(f, "0")
297 } else {
298 let str = self
299 .value
300 .iter()
301 .enumerate()
302 .filter(|(_, x)| !x.is_zero())
303 .map(|(i, x)| match (i, x.is_one()) {
304 (0, _) => format!("{x}"),
305 (1, true) => "X".to_string(),
306 (1, false) => format!("{x} X"),
307 (_, true) => format!("X^{i}"),
308 (_, false) => format!("{x} X^{i}"),
309 })
310 .join(" + ");
311 write!(f, "{str}")
312 }
313 }
314}
315
316impl<F, A> Neg for QuinticTrinomialExtensionField<F, A>
317where
318 F: QuinticTrinomialExtendable,
319 A: Algebra<F>,
320{
321 type Output = Self;
322
323 #[inline]
324 fn neg(self) -> Self {
325 Self::new(self.value.map(A::neg))
326 }
327}
328
329impl<F, A> Add for QuinticTrinomialExtensionField<F, A>
330where
331 F: QuinticTrinomialExtendable,
332 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
333{
334 type Output = Self;
335
336 #[inline]
337 fn add(self, rhs: Self) -> Self {
338 Self::new(<A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_add(
339 &self.value,
340 &rhs.value,
341 ))
342 }
343}
344
345impl<F, A> Add<A> for QuinticTrinomialExtensionField<F, A>
346where
347 F: QuinticTrinomialExtendable,
348 A: Algebra<F>,
349{
350 type Output = Self;
351
352 #[inline]
353 fn add(mut self, rhs: A) -> Self {
354 self.value[0] += rhs;
355 self
356 }
357}
358
359impl<F, A> AddAssign for QuinticTrinomialExtensionField<F, A>
360where
361 F: QuinticTrinomialExtendable,
362 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
363{
364 #[inline]
365 fn add_assign(&mut self, rhs: Self) {
366 self.value =
367 <A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_add(&self.value, &rhs.value);
368 }
369}
370
371impl<F, A> AddAssign<A> for QuinticTrinomialExtensionField<F, A>
372where
373 F: QuinticTrinomialExtendable,
374 A: Algebra<F>,
375{
376 #[inline]
377 fn add_assign(&mut self, rhs: A) {
378 self.value[0] += rhs;
379 }
380}
381
382impl<F, A> Sum for QuinticTrinomialExtensionField<F, A>
383where
384 F: QuinticTrinomialExtendable,
385 A: ExtensionAlgebra<F, 5, QuinticTrinomial> + Copy,
386{
387 #[inline]
388 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
389 iter.reduce(|acc, x| acc + x).unwrap_or(Self::ZERO)
390 }
391}
392
393impl<F, A> Sub for QuinticTrinomialExtensionField<F, A>
394where
395 F: QuinticTrinomialExtendable,
396 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
397{
398 type Output = Self;
399
400 #[inline]
401 fn sub(self, rhs: Self) -> Self {
402 Self::new(<A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_sub(
403 &self.value,
404 &rhs.value,
405 ))
406 }
407}
408
409impl<F, A> Sub<A> for QuinticTrinomialExtensionField<F, A>
410where
411 F: QuinticTrinomialExtendable,
412 A: Algebra<F>,
413{
414 type Output = Self;
415
416 #[inline]
417 fn sub(self, rhs: A) -> Self {
418 let mut res = self.value;
419 res[0] -= rhs;
420 Self::new(res)
421 }
422}
423
424impl<F, A> SubAssign for QuinticTrinomialExtensionField<F, A>
425where
426 F: QuinticTrinomialExtendable,
427 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
428{
429 #[inline]
430 fn sub_assign(&mut self, rhs: Self) {
431 self.value =
432 <A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_sub(&self.value, &rhs.value);
433 }
434}
435
436impl<F, A> SubAssign<A> for QuinticTrinomialExtensionField<F, A>
437where
438 F: QuinticTrinomialExtendable,
439 A: Algebra<F>,
440{
441 #[inline]
442 fn sub_assign(&mut self, rhs: A) {
443 self.value[0] -= rhs;
444 }
445}
446
447impl<F, A> Mul for QuinticTrinomialExtensionField<F, A>
448where
449 F: QuinticTrinomialExtendable,
450 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
451{
452 type Output = Self;
453
454 #[inline]
455 fn mul(self, rhs: Self) -> Self {
456 let mut res = Self::default();
457 <A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_mul(
458 &self.value,
459 &rhs.value,
460 &mut res.value,
461 );
462 res
463 }
464}
465
466impl<F, A> Mul<A> for QuinticTrinomialExtensionField<F, A>
467where
468 F: QuinticTrinomialExtendable,
469 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
470{
471 type Output = Self;
472
473 #[inline]
474 fn mul(self, rhs: A) -> Self {
475 Self::new(<A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_base_mul(self.value, rhs))
476 }
477}
478
479impl<F, A> MulAssign for QuinticTrinomialExtensionField<F, A>
480where
481 F: QuinticTrinomialExtendable,
482 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
483{
484 #[inline]
485 fn mul_assign(&mut self, rhs: Self) {
486 *self = self.clone() * rhs;
487 }
488}
489
490impl<F, A> MulAssign<A> for QuinticTrinomialExtensionField<F, A>
491where
492 F: QuinticTrinomialExtendable,
493 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
494{
495 #[inline]
496 fn mul_assign(&mut self, rhs: A) {
497 *self = self.clone() * rhs;
498 }
499}
500
501impl<F, A> Product for QuinticTrinomialExtensionField<F, A>
502where
503 F: QuinticTrinomialExtendable,
504 A: ExtensionAlgebra<F, 5, QuinticTrinomial> + Copy,
505{
506 #[inline]
507 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
508 iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
509 }
510}
511
512impl<F> Div for QuinticTrinomialExtensionField<F>
513where
514 F: QuinticTrinomialExtendable,
515{
516 type Output = Self;
517
518 #[allow(clippy::suspicious_arithmetic_impl)]
519 #[inline]
520 fn div(self, rhs: Self) -> Self::Output {
521 self * rhs.inverse()
522 }
523}
524
525impl<F> DivAssign for QuinticTrinomialExtensionField<F>
526where
527 F: QuinticTrinomialExtendable,
528{
529 #[inline]
530 fn div_assign(&mut self, rhs: Self) {
531 *self = *self / rhs;
532 }
533}
534
535impl<F: QuinticTrinomialExtendable + HasTwoAdicQuinticExtension> TwoAdicField
536 for QuinticTrinomialExtensionField<F>
537{
538 const TWO_ADICITY: usize = F::EXT_TWO_ADICITY;
539
540 #[inline]
541 fn two_adic_generator(bits: usize) -> Self {
542 Self::new(F::ext_two_adic_generator(bits))
543 }
544}
545
546#[inline]
548pub fn trinomial_quintic_mul<R: PrimeCharacteristicRing>(a: &[R; 5], b: &[R; 5], res: &mut [R; 5]) {
549 let c0 = a[0].dup() * b[0].dup();
551 let c1 = R::dot_product::<2>(&[a[0].dup(), a[1].dup()], &[b[1].dup(), b[0].dup()]);
552 let c2 = R::dot_product::<3>(
553 &[a[0].dup(), a[1].dup(), a[2].dup()],
554 &[b[2].dup(), b[1].dup(), b[0].dup()],
555 );
556 let c3 = R::dot_product::<4>(
557 &[a[0].dup(), a[1].dup(), a[2].dup(), a[3].dup()],
558 &[b[3].dup(), b[2].dup(), b[1].dup(), b[0].dup()],
559 );
560 let c4 = R::dot_product::<5>(
561 a,
562 &[b[4].dup(), b[3].dup(), b[2].dup(), b[1].dup(), b[0].dup()],
563 );
564
565 let c5 = R::dot_product::<4>(
567 &[a[1].dup(), a[2].dup(), a[3].dup(), a[4].dup()],
568 &[b[4].dup(), b[3].dup(), b[2].dup(), b[1].dup()],
569 );
570 let c6 = R::dot_product::<3>(
571 &[a[2].dup(), a[3].dup(), a[4].dup()],
572 &[b[4].dup(), b[3].dup(), b[2].dup()],
573 );
574 let c7 = R::dot_product::<2>(&[a[3].dup(), a[4].dup()], &[b[4].dup(), b[3].dup()]);
575 let c8 = a[4].dup() * b[4].dup();
576
577 let c5_minus_c8 = c5 - c8.dup();
579
580 res[0] = c0 + c5_minus_c8.dup();
582 res[1] = c1 + c6.dup();
583 res[2] = c2 - c5_minus_c8 + c7.dup();
584 res[3] = c3 - c6 + c8;
585 res[4] = c4 - c7;
586}
587
588#[inline]
590pub fn quintic_square<R: PrimeCharacteristicRing>(a: &[R; 5], res: &mut [R; 5]) {
591 let a0_2 = a[0].double();
593 let a1_2 = a[1].double();
594 let a2_2 = a[2].double();
595 let a3_2 = a[3].double();
596
597 let c0 = a[0].square();
600 let c1 = a0_2.dup() * a[1].dup();
602 let c2 = R::dot_product::<2>(&[a0_2.dup(), a[1].dup()], &[a[2].dup(), a[1].dup()]);
604 let c3 = R::dot_product::<2>(&[a0_2.dup(), a1_2.dup()], &[a[3].dup(), a[2].dup()]);
606 let c4 = R::dot_product::<3>(
608 &[a0_2, a1_2.dup(), a[2].dup()],
609 &[a[4].dup(), a[3].dup(), a[2].dup()],
610 );
611 let c5 = R::dot_product::<2>(&[a1_2, a2_2.dup()], &[a[4].dup(), a[3].dup()]);
613 let c6 = R::dot_product::<2>(&[a2_2, a[3].dup()], &[a[4].dup(), a[3].dup()]);
615 let c7 = a3_2 * a[4].dup();
617 let c8 = a[4].square();
619
620 let c5_minus_c8 = c5 - c8.dup();
622
623 res[0] = c0 + c5_minus_c8.dup();
625 res[1] = c1 + c6.dup();
626 res[2] = c2 - c5_minus_c8 + c7.dup();
627 res[3] = c3 - c6 + c8;
628 res[4] = c4 - c7;
629}