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> Field for QuinticTrinomialExtensionField<F> {
257 type Packing = Self;
258
259 const GENERATOR: Self = Self::new(F::EXT_GENERATOR);
260
261 fn try_inverse(&self) -> Option<Self> {
262 if self.is_zero() {
263 return None;
264 }
265 Some(self.pseudo_inv())
266 }
267
268 #[inline]
269 fn add_slices(slice_1: &mut [Self], slice_2: &[Self]) {
270 unsafe {
273 let base_slice_1 = as_base_slice_mut(slice_1);
274 let base_slice_2 = as_base_slice(slice_2);
275 F::add_slices(base_slice_1, base_slice_2);
276 }
277 }
278
279 #[inline]
280 fn order() -> BigUint {
281 F::order().pow(5)
282 }
283}
284
285impl<F: QuinticTrinomialExtendable> Display for QuinticTrinomialExtensionField<F> {
286 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
287 if self.is_zero() {
288 write!(f, "0")
289 } else {
290 let str = self
291 .value
292 .iter()
293 .enumerate()
294 .filter(|(_, x)| !x.is_zero())
295 .map(|(i, x)| match (i, x.is_one()) {
296 (0, _) => format!("{x}"),
297 (1, true) => "X".to_string(),
298 (1, false) => format!("{x} X"),
299 (_, true) => format!("X^{i}"),
300 (_, false) => format!("{x} X^{i}"),
301 })
302 .join(" + ");
303 write!(f, "{str}")
304 }
305 }
306}
307
308impl<F, A> Neg for QuinticTrinomialExtensionField<F, A>
309where
310 F: QuinticTrinomialExtendable,
311 A: Algebra<F>,
312{
313 type Output = Self;
314
315 #[inline]
316 fn neg(self) -> Self {
317 Self::new(self.value.map(A::neg))
318 }
319}
320
321impl<F, A> Add for QuinticTrinomialExtensionField<F, A>
322where
323 F: QuinticTrinomialExtendable,
324 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
325{
326 type Output = Self;
327
328 #[inline]
329 fn add(self, rhs: Self) -> Self {
330 Self::new(<A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_add(
331 &self.value,
332 &rhs.value,
333 ))
334 }
335}
336
337impl<F, A> Add<A> for QuinticTrinomialExtensionField<F, A>
338where
339 F: QuinticTrinomialExtendable,
340 A: Algebra<F>,
341{
342 type Output = Self;
343
344 #[inline]
345 fn add(mut self, rhs: A) -> Self {
346 self.value[0] += rhs;
347 self
348 }
349}
350
351impl<F, A> AddAssign for QuinticTrinomialExtensionField<F, A>
352where
353 F: QuinticTrinomialExtendable,
354 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
355{
356 #[inline]
357 fn add_assign(&mut self, rhs: Self) {
358 self.value =
359 <A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_add(&self.value, &rhs.value);
360 }
361}
362
363impl<F, A> AddAssign<A> for QuinticTrinomialExtensionField<F, A>
364where
365 F: QuinticTrinomialExtendable,
366 A: Algebra<F>,
367{
368 #[inline]
369 fn add_assign(&mut self, rhs: A) {
370 self.value[0] += rhs;
371 }
372}
373
374impl<F, A> Sum for QuinticTrinomialExtensionField<F, A>
375where
376 F: QuinticTrinomialExtendable,
377 A: ExtensionAlgebra<F, 5, QuinticTrinomial> + Copy,
378{
379 #[inline]
380 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
381 iter.reduce(|acc, x| acc + x).unwrap_or(Self::ZERO)
382 }
383}
384
385impl<F, A> Sub for QuinticTrinomialExtensionField<F, A>
386where
387 F: QuinticTrinomialExtendable,
388 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
389{
390 type Output = Self;
391
392 #[inline]
393 fn sub(self, rhs: Self) -> Self {
394 Self::new(<A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_sub(
395 &self.value,
396 &rhs.value,
397 ))
398 }
399}
400
401impl<F, A> Sub<A> for QuinticTrinomialExtensionField<F, A>
402where
403 F: QuinticTrinomialExtendable,
404 A: Algebra<F>,
405{
406 type Output = Self;
407
408 #[inline]
409 fn sub(self, rhs: A) -> Self {
410 let mut res = self.value;
411 res[0] -= rhs;
412 Self::new(res)
413 }
414}
415
416impl<F, A> SubAssign for QuinticTrinomialExtensionField<F, A>
417where
418 F: QuinticTrinomialExtendable,
419 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
420{
421 #[inline]
422 fn sub_assign(&mut self, rhs: Self) {
423 self.value =
424 <A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_sub(&self.value, &rhs.value);
425 }
426}
427
428impl<F, A> SubAssign<A> for QuinticTrinomialExtensionField<F, A>
429where
430 F: QuinticTrinomialExtendable,
431 A: Algebra<F>,
432{
433 #[inline]
434 fn sub_assign(&mut self, rhs: A) {
435 self.value[0] -= rhs;
436 }
437}
438
439impl<F, A> Mul for QuinticTrinomialExtensionField<F, A>
440where
441 F: QuinticTrinomialExtendable,
442 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
443{
444 type Output = Self;
445
446 #[inline]
447 fn mul(self, rhs: Self) -> Self {
448 let mut res = Self::default();
449 <A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_mul(
450 &self.value,
451 &rhs.value,
452 &mut res.value,
453 );
454 res
455 }
456}
457
458impl<F, A> Mul<A> for QuinticTrinomialExtensionField<F, A>
459where
460 F: QuinticTrinomialExtendable,
461 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
462{
463 type Output = Self;
464
465 #[inline]
466 fn mul(self, rhs: A) -> Self {
467 Self::new(<A as ExtensionAlgebra<F, 5, QuinticTrinomial>>::ext_base_mul(self.value, rhs))
468 }
469}
470
471impl<F, A> MulAssign for QuinticTrinomialExtensionField<F, A>
472where
473 F: QuinticTrinomialExtendable,
474 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
475{
476 #[inline]
477 fn mul_assign(&mut self, rhs: Self) {
478 *self = self.clone() * rhs;
479 }
480}
481
482impl<F, A> MulAssign<A> for QuinticTrinomialExtensionField<F, A>
483where
484 F: QuinticTrinomialExtendable,
485 A: ExtensionAlgebra<F, 5, QuinticTrinomial>,
486{
487 #[inline]
488 fn mul_assign(&mut self, rhs: A) {
489 *self = self.clone() * rhs;
490 }
491}
492
493impl<F, A> Product for QuinticTrinomialExtensionField<F, A>
494where
495 F: QuinticTrinomialExtendable,
496 A: ExtensionAlgebra<F, 5, QuinticTrinomial> + Copy,
497{
498 #[inline]
499 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
500 iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
501 }
502}
503
504impl<F> Div for QuinticTrinomialExtensionField<F>
505where
506 F: QuinticTrinomialExtendable,
507{
508 type Output = Self;
509
510 #[allow(clippy::suspicious_arithmetic_impl)]
511 #[inline]
512 fn div(self, rhs: Self) -> Self::Output {
513 self * rhs.inverse()
514 }
515}
516
517impl<F> DivAssign for QuinticTrinomialExtensionField<F>
518where
519 F: QuinticTrinomialExtendable,
520{
521 #[inline]
522 fn div_assign(&mut self, rhs: Self) {
523 *self = *self / rhs;
524 }
525}
526
527impl<F: QuinticTrinomialExtendable + HasTwoAdicQuinticExtension> TwoAdicField
528 for QuinticTrinomialExtensionField<F>
529{
530 const TWO_ADICITY: usize = F::EXT_TWO_ADICITY;
531
532 #[inline]
533 fn two_adic_generator(bits: usize) -> Self {
534 Self::new(F::ext_two_adic_generator(bits))
535 }
536}
537
538#[inline]
540pub fn trinomial_quintic_mul<R: PrimeCharacteristicRing>(a: &[R; 5], b: &[R; 5], res: &mut [R; 5]) {
541 let c0 = a[0].dup() * b[0].dup();
543 let c1 = R::dot_product::<2>(&[a[0].dup(), a[1].dup()], &[b[1].dup(), b[0].dup()]);
544 let c2 = R::dot_product::<3>(
545 &[a[0].dup(), a[1].dup(), a[2].dup()],
546 &[b[2].dup(), b[1].dup(), b[0].dup()],
547 );
548 let c3 = R::dot_product::<4>(
549 &[a[0].dup(), a[1].dup(), a[2].dup(), a[3].dup()],
550 &[b[3].dup(), b[2].dup(), b[1].dup(), b[0].dup()],
551 );
552 let c4 = R::dot_product::<5>(
553 a,
554 &[b[4].dup(), b[3].dup(), b[2].dup(), b[1].dup(), b[0].dup()],
555 );
556
557 let c5 = R::dot_product::<4>(
559 &[a[1].dup(), a[2].dup(), a[3].dup(), a[4].dup()],
560 &[b[4].dup(), b[3].dup(), b[2].dup(), b[1].dup()],
561 );
562 let c6 = R::dot_product::<3>(
563 &[a[2].dup(), a[3].dup(), a[4].dup()],
564 &[b[4].dup(), b[3].dup(), b[2].dup()],
565 );
566 let c7 = R::dot_product::<2>(&[a[3].dup(), a[4].dup()], &[b[4].dup(), b[3].dup()]);
567 let c8 = a[4].dup() * b[4].dup();
568
569 let c5_minus_c8 = c5 - c8.dup();
571
572 res[0] = c0 + c5_minus_c8.dup();
574 res[1] = c1 + c6.dup();
575 res[2] = c2 - c5_minus_c8 + c7.dup();
576 res[3] = c3 - c6 + c8;
577 res[4] = c4 - c7;
578}
579
580#[inline]
582pub fn quintic_square<R: PrimeCharacteristicRing>(a: &[R; 5], res: &mut [R; 5]) {
583 let a0_2 = a[0].double();
585 let a1_2 = a[1].double();
586 let a2_2 = a[2].double();
587 let a3_2 = a[3].double();
588
589 let c0 = a[0].square();
592 let c1 = a0_2.dup() * a[1].dup();
594 let c2 = R::dot_product::<2>(&[a0_2.dup(), a[1].dup()], &[a[2].dup(), a[1].dup()]);
596 let c3 = R::dot_product::<2>(&[a0_2.dup(), a1_2.dup()], &[a[3].dup(), a[2].dup()]);
598 let c4 = R::dot_product::<3>(
600 &[a0_2, a1_2.dup(), a[2].dup()],
601 &[a[4].dup(), a[3].dup(), a[2].dup()],
602 );
603 let c5 = R::dot_product::<2>(&[a1_2, a2_2.dup()], &[a[4].dup(), a[3].dup()]);
605 let c6 = R::dot_product::<2>(&[a2_2, a[3].dup()], &[a[4].dup(), a[3].dup()]);
607 let c7 = a3_2 * a[4].dup();
609 let c8 = a[4].square();
611
612 let c5_minus_c8 = c5 - c8.dup();
614
615 res[0] = c0 + c5_minus_c8.dup();
617 res[1] = c1 + c6.dup();
618 res[2] = c2 - c5_minus_c8 + c7.dup();
619 res[3] = c3 - c6 + c8;
620 res[4] = c4 - c7;
621}