1use alloc::format;
2use alloc::string::ToString;
3use alloc::vec::Vec;
4use core::array;
5use core::fmt::{self, Debug, Display, Formatter};
6use core::iter::{Product, Sum};
7use core::marker::PhantomData;
8use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
9
10use itertools::Itertools;
11use num_bigint::BigUint;
12use p3_util::{as_base_slice, as_base_slice_mut, flatten_to_base, reconstitute_from_base};
13use rand::distr::StandardUniform;
14use rand::prelude::Distribution;
15use serde::{Deserialize, Serialize};
16
17use super::{HasFrobenius, HasTwoAdicBinomialExtension, PackedBinomialExtensionField};
18use crate::extension::BinomiallyExtendable;
19use crate::field::Field;
20use crate::{
21 Algebra, BasedVectorSpace, ExtensionField, Packable, PrimeCharacteristicRing,
22 RawDataSerializable, TwoAdicField, field_to_array,
23};
24
25#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize, PartialOrd, Ord)]
26#[repr(transparent)] pub struct BinomialExtensionField<F, const D: usize, A = F> {
28 #[serde(
29 with = "p3_util::array_serialization",
30 bound(serialize = "A: Serialize", deserialize = "A: Deserialize<'de>")
31 )]
32 pub(crate) value: [A; D],
33 _phantom: PhantomData<F>,
34}
35
36impl<F, A, const D: usize> BinomialExtensionField<F, D, A> {
37 pub(crate) const fn new(value: [A; D]) -> Self {
38 Self {
39 value,
40 _phantom: PhantomData,
41 }
42 }
43}
44
45impl<F: Field, A: Algebra<F>, const D: usize> Default for BinomialExtensionField<F, D, A> {
46 fn default() -> Self {
47 Self::new(array::from_fn(|_| A::ZERO))
48 }
49}
50
51impl<F: Field, A: Algebra<F>, const D: usize> From<A> for BinomialExtensionField<F, D, A> {
52 fn from(x: A) -> Self {
53 Self::new(field_to_array(x))
54 }
55}
56
57impl<F: BinomiallyExtendable<D>, const D: usize> Packable for BinomialExtensionField<F, D> {}
58
59impl<F: BinomiallyExtendable<D>, A: Algebra<F>, const D: usize> BasedVectorSpace<A>
60 for BinomialExtensionField<F, D, A>
61{
62 const DIMENSION: usize = D;
63
64 #[inline]
65 fn as_basis_coefficients_slice(&self) -> &[A] {
66 &self.value
67 }
68
69 #[inline]
70 fn from_basis_coefficients_fn<Fn: FnMut(usize) -> A>(f: Fn) -> Self {
71 Self::new(array::from_fn(f))
72 }
73
74 #[inline]
75 fn from_basis_coefficients_iter<I: ExactSizeIterator<Item = A>>(mut iter: I) -> Option<Self> {
76 (iter.len() == D).then(|| Self::new(array::from_fn(|_| iter.next().unwrap()))) }
78
79 #[inline]
80 fn flatten_to_base(vec: Vec<Self>) -> Vec<A> {
81 unsafe {
82 flatten_to_base::<A, Self>(vec)
85 }
86 }
87
88 #[inline]
89 fn reconstitute_from_base(vec: Vec<A>) -> Vec<Self> {
90 unsafe {
91 reconstitute_from_base::<A, Self>(vec)
94 }
95 }
96}
97
98impl<F: BinomiallyExtendable<D>, const D: usize> ExtensionField<F>
99 for BinomialExtensionField<F, D>
100{
101 type ExtensionPacking = PackedBinomialExtensionField<F, F::Packing, D>;
102
103 #[inline]
104 fn is_in_basefield(&self) -> bool {
105 self.value[1..].iter().all(F::is_zero)
106 }
107
108 #[inline]
109 fn as_base(&self) -> Option<F> {
110 <Self as ExtensionField<F>>::is_in_basefield(self).then(|| self.value[0])
111 }
112}
113
114impl<F: BinomiallyExtendable<D>, const D: usize> HasFrobenius<F> for BinomialExtensionField<F, D> {
115 #[inline]
117 fn frobenius(&self) -> Self {
118 let mut res = Self::ZERO;
120 for (i, z) in F::DTH_ROOT.powers().take(D).enumerate() {
121 res.value[i] = self.value[i] * z;
122 }
123
124 res
125 }
126
127 #[inline]
132 fn repeated_frobenius(&self, count: usize) -> Self {
133 if count == 0 {
134 return *self;
135 } else if count >= D {
136 return self.repeated_frobenius(count % D);
139 }
140
141 let z0 = F::DTH_ROOT.exp_u64(count as u64);
143
144 let mut res = Self::ZERO;
145 for (i, z) in z0.powers().take(D).enumerate() {
146 res.value[i] = self.value[i] * z;
147 }
148
149 res
150 }
151
152 #[inline]
156 fn frobenius_inv(&self) -> Self {
157 let mut prod_conj = self.frobenius();
171 for _ in 2..D {
172 prod_conj = (prod_conj * *self).frobenius();
173 }
174
175 let a = self.value;
178 let b = prod_conj.value;
179 let mut w_coeff = F::ZERO;
180 for i in 1..D {
185 w_coeff += a[i] * b[D - i];
186 }
187 let norm = F::dot_product(&[a[0], F::W], &[b[0], w_coeff]);
188 debug_assert_eq!(Self::from(norm), *self * prod_conj);
189
190 prod_conj * norm.inverse()
191 }
192}
193
194impl<F, A, const D: usize> PrimeCharacteristicRing for BinomialExtensionField<F, D, A>
195where
196 F: BinomiallyExtendable<D>,
197 A: Algebra<F>,
198{
199 type PrimeSubfield = <A as PrimeCharacteristicRing>::PrimeSubfield;
200
201 const ZERO: Self = Self::new([A::ZERO; D]);
202
203 const ONE: Self = Self::new(field_to_array(A::ONE));
204
205 const TWO: Self = Self::new(field_to_array(A::TWO));
206
207 const NEG_ONE: Self = Self::new(field_to_array(A::NEG_ONE));
208
209 #[inline]
210 fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
211 <A as PrimeCharacteristicRing>::from_prime_subfield(f).into()
212 }
213
214 #[inline(always)]
215 fn square(&self) -> Self {
216 let mut res = Self::default();
217 let w = F::W;
218 match D {
219 2 => {
220 let a = &self.value;
221 let a1_w = a[1].clone() * F::W;
222 res.value[0] = A::dot_product(a[..].try_into().unwrap(), &[a[0].clone(), a1_w]);
223 res.value[1] = a[0].clone() * a[1].double();
224 }
225 3 => cubic_square(&self.value, &mut res.value),
226 4 => quartic_square(&self.value, &mut res.value, w),
227 5 => quintic_square(&self.value, &mut res.value, w),
228 _ => binomial_mul::<F, A, A, D>(&self.value, &self.value, &mut res.value, w),
229 }
230 res
231 }
232
233 #[inline]
234 fn mul_2exp_u64(&self, exp: u64) -> Self {
235 Self::new(self.value.clone().map(|x| x.mul_2exp_u64(exp)))
236 }
237
238 #[inline]
239 fn zero_vec(len: usize) -> Vec<Self> {
240 unsafe { reconstitute_from_base(F::zero_vec(len * D)) }
242 }
243}
244
245impl<F: BinomiallyExtendable<D>, const D: usize> Algebra<F> for BinomialExtensionField<F, D> {}
246
247impl<F: BinomiallyExtendable<D>, const D: usize> RawDataSerializable
248 for BinomialExtensionField<F, D>
249{
250 const NUM_BYTES: usize = F::NUM_BYTES * D;
251
252 #[inline]
253 fn into_bytes(self) -> impl IntoIterator<Item = u8> {
254 self.value.into_iter().flat_map(|x| x.into_bytes())
255 }
256
257 #[inline]
258 fn into_byte_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u8> {
259 F::into_byte_stream(input.into_iter().flat_map(|x| x.value))
260 }
261
262 #[inline]
263 fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
264 F::into_u32_stream(input.into_iter().flat_map(|x| x.value))
265 }
266
267 #[inline]
268 fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
269 F::into_u64_stream(input.into_iter().flat_map(|x| x.value))
270 }
271
272 #[inline]
273 fn into_parallel_byte_streams<const N: usize>(
274 input: impl IntoIterator<Item = [Self; N]>,
275 ) -> impl IntoIterator<Item = [u8; N]> {
276 F::into_parallel_byte_streams(
277 input
278 .into_iter()
279 .flat_map(|x| (0..D).map(move |i| array::from_fn(|j| x[j].value[i]))),
280 )
281 }
282
283 #[inline]
284 fn into_parallel_u32_streams<const N: usize>(
285 input: impl IntoIterator<Item = [Self; N]>,
286 ) -> impl IntoIterator<Item = [u32; N]> {
287 F::into_parallel_u32_streams(
288 input
289 .into_iter()
290 .flat_map(|x| (0..D).map(move |i| array::from_fn(|j| x[j].value[i]))),
291 )
292 }
293
294 #[inline]
295 fn into_parallel_u64_streams<const N: usize>(
296 input: impl IntoIterator<Item = [Self; N]>,
297 ) -> impl IntoIterator<Item = [u64; N]> {
298 F::into_parallel_u64_streams(
299 input
300 .into_iter()
301 .flat_map(|x| (0..D).map(move |i| array::from_fn(|j| x[j].value[i]))),
302 )
303 }
304}
305
306impl<F: BinomiallyExtendable<D>, const D: usize> Field for BinomialExtensionField<F, D> {
307 type Packing = Self;
308
309 const GENERATOR: Self = Self::new(F::EXT_GENERATOR);
310
311 fn try_inverse(&self) -> Option<Self> {
312 if self.is_zero() {
313 return None;
314 }
315
316 let mut res = Self::default();
317
318 match D {
319 2 => quadratic_inv(&self.value, &mut res.value, F::W),
320 3 => cubic_inv(&self.value, &mut res.value, F::W),
321 4 => quartic_inv(&self.value, &mut res.value, F::W),
322 5 => res = quintic_inv(self),
323 _ => res = self.frobenius_inv(),
324 }
325
326 Some(res)
327 }
328
329 #[inline]
330 fn halve(&self) -> Self {
331 Self::new(self.value.map(|x| x.halve()))
332 }
333
334 #[inline]
335 fn div_2exp_u64(&self, exp: u64) -> Self {
336 Self::new(self.value.map(|x| x.div_2exp_u64(exp)))
337 }
338
339 #[inline]
340 fn add_slices(slice_1: &mut [Self], slice_2: &[Self]) {
341 unsafe {
345 let base_slice_1 = as_base_slice_mut(slice_1);
346 let base_slice_2 = as_base_slice(slice_2);
347
348 F::add_slices(base_slice_1, base_slice_2);
349 }
350 }
351
352 #[inline]
353 fn order() -> BigUint {
354 F::order().pow(D as u32)
355 }
356}
357
358impl<F, const D: usize> Display for BinomialExtensionField<F, D>
359where
360 F: BinomiallyExtendable<D>,
361{
362 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
363 if self.is_zero() {
364 write!(f, "0")
365 } else {
366 let str = self
367 .value
368 .iter()
369 .enumerate()
370 .filter(|(_, x)| !x.is_zero())
371 .map(|(i, x)| match (i, x.is_one()) {
372 (0, _) => format!("{x}"),
373 (1, true) => "X".to_string(),
374 (1, false) => format!("{x} X"),
375 (_, true) => format!("X^{i}"),
376 (_, false) => format!("{x} X^{i}"),
377 })
378 .join(" + ");
379 write!(f, "{}", str)
380 }
381 }
382}
383
384impl<F, A, const D: usize> Neg for BinomialExtensionField<F, D, A>
385where
386 F: BinomiallyExtendable<D>,
387 A: Algebra<F>,
388{
389 type Output = Self;
390
391 #[inline]
392 fn neg(self) -> Self {
393 Self::new(self.value.map(A::neg))
394 }
395}
396
397impl<F, A, const D: usize> Add for BinomialExtensionField<F, D, A>
398where
399 F: BinomiallyExtendable<D>,
400 A: Algebra<F>,
401{
402 type Output = Self;
403
404 #[inline]
405 fn add(self, rhs: Self) -> Self {
406 let value = vector_add(&self.value, &rhs.value);
407 Self::new(value)
408 }
409}
410
411impl<F, A, const D: usize> Add<A> for BinomialExtensionField<F, D, A>
412where
413 F: BinomiallyExtendable<D>,
414 A: Algebra<F>,
415{
416 type Output = Self;
417
418 #[inline]
419 fn add(mut self, rhs: A) -> Self {
420 self.value[0] += rhs;
421 self
422 }
423}
424
425impl<F, A, const D: usize> AddAssign for BinomialExtensionField<F, D, A>
426where
427 F: BinomiallyExtendable<D>,
428 A: Algebra<F>,
429{
430 #[inline]
431 fn add_assign(&mut self, rhs: Self) {
432 for i in 0..D {
433 self.value[i] += rhs.value[i].clone();
434 }
435 }
436}
437
438impl<F, A, const D: usize> AddAssign<A> for BinomialExtensionField<F, D, A>
439where
440 F: BinomiallyExtendable<D>,
441 A: Algebra<F>,
442{
443 #[inline]
444 fn add_assign(&mut self, rhs: A) {
445 self.value[0] += rhs;
446 }
447}
448
449impl<F, A, const D: usize> Sum for BinomialExtensionField<F, D, A>
450where
451 F: BinomiallyExtendable<D>,
452 A: Algebra<F>,
453{
454 #[inline]
455 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
456 iter.reduce(|acc, x| acc + x).unwrap_or(Self::ZERO)
457 }
458}
459
460impl<F, A, const D: usize> Sub for BinomialExtensionField<F, D, A>
461where
462 F: BinomiallyExtendable<D>,
463 A: Algebra<F>,
464{
465 type Output = Self;
466
467 #[inline]
468 fn sub(self, rhs: Self) -> Self {
469 let value = vector_sub(&self.value, &rhs.value);
470 Self::new(value)
471 }
472}
473
474impl<F, A, const D: usize> Sub<A> for BinomialExtensionField<F, D, A>
475where
476 F: BinomiallyExtendable<D>,
477 A: Algebra<F>,
478{
479 type Output = Self;
480
481 #[inline]
482 fn sub(self, rhs: A) -> Self {
483 let mut res = self.value;
484 res[0] -= rhs;
485 Self::new(res)
486 }
487}
488
489impl<F, A, const D: usize> SubAssign for BinomialExtensionField<F, D, A>
490where
491 F: BinomiallyExtendable<D>,
492 A: Algebra<F>,
493{
494 #[inline]
495 fn sub_assign(&mut self, rhs: Self) {
496 for i in 0..D {
497 self.value[i] -= rhs.value[i].clone();
498 }
499 }
500}
501
502impl<F, A, const D: usize> SubAssign<A> for BinomialExtensionField<F, D, A>
503where
504 F: BinomiallyExtendable<D>,
505 A: Algebra<F>,
506{
507 #[inline]
508 fn sub_assign(&mut self, rhs: A) {
509 self.value[0] -= rhs;
510 }
511}
512
513impl<F, A, const D: usize> Mul for BinomialExtensionField<F, D, A>
514where
515 F: BinomiallyExtendable<D>,
516 A: Algebra<F>,
517{
518 type Output = Self;
519
520 #[inline]
521 fn mul(self, rhs: Self) -> Self {
522 let a = self.value;
523 let b = rhs.value;
524 let mut res = Self::default();
525 let w = F::W;
526
527 binomial_mul::<F, A, A, D>(&a, &b, &mut res.value, w);
528
529 res
530 }
531}
532
533impl<F, A, const D: usize> Mul<A> for BinomialExtensionField<F, D, A>
534where
535 F: BinomiallyExtendable<D>,
536 A: Algebra<F>,
537{
538 type Output = Self;
539
540 #[inline]
541 fn mul(self, rhs: A) -> Self {
542 Self::new(self.value.map(|x| x * rhs.clone()))
543 }
544}
545
546impl<F, A, const D: usize> MulAssign for BinomialExtensionField<F, D, A>
547where
548 F: BinomiallyExtendable<D>,
549 A: Algebra<F>,
550{
551 #[inline]
552 fn mul_assign(&mut self, rhs: Self) {
553 *self = self.clone() * rhs;
554 }
555}
556
557impl<F, A, const D: usize> MulAssign<A> for BinomialExtensionField<F, D, A>
558where
559 F: BinomiallyExtendable<D>,
560 A: Algebra<F>,
561{
562 #[inline]
563 fn mul_assign(&mut self, rhs: A) {
564 *self = self.clone() * rhs;
565 }
566}
567
568impl<F, A, const D: usize> Product for BinomialExtensionField<F, D, A>
569where
570 F: BinomiallyExtendable<D>,
571 A: Algebra<F>,
572{
573 #[inline]
574 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
575 iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
576 }
577}
578
579impl<F, const D: usize> Div for BinomialExtensionField<F, D>
580where
581 F: BinomiallyExtendable<D>,
582{
583 type Output = Self;
584
585 #[allow(clippy::suspicious_arithmetic_impl)]
586 #[inline]
587 fn div(self, rhs: Self) -> Self::Output {
588 self * rhs.inverse()
589 }
590}
591
592impl<F, const D: usize> DivAssign for BinomialExtensionField<F, D>
593where
594 F: BinomiallyExtendable<D>,
595{
596 #[inline]
597 fn div_assign(&mut self, rhs: Self) {
598 *self = *self / rhs;
599 }
600}
601
602impl<F: BinomiallyExtendable<D>, const D: usize> Distribution<BinomialExtensionField<F, D>>
603 for StandardUniform
604where
605 Self: Distribution<F>,
606{
607 #[inline]
608 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> BinomialExtensionField<F, D> {
609 BinomialExtensionField::new(array::from_fn(|_| self.sample(rng)))
610 }
611}
612
613impl<F: Field + HasTwoAdicBinomialExtension<D>, const D: usize> TwoAdicField
614 for BinomialExtensionField<F, D>
615{
616 const TWO_ADICITY: usize = F::EXT_TWO_ADICITY;
617
618 #[inline]
619 fn two_adic_generator(bits: usize) -> Self {
620 Self::new(F::ext_two_adic_generator(bits))
621 }
622}
623
624#[inline]
626pub(crate) fn vector_add<
627 R: PrimeCharacteristicRing + Add<R2, Output = R>,
628 R2: Clone,
629 const D: usize,
630>(
631 a: &[R; D],
632 b: &[R2; D],
633) -> [R; D] {
634 array::from_fn(|i| a[i].clone() + b[i].clone())
635}
636
637#[inline]
639pub(crate) fn vector_sub<
640 R: PrimeCharacteristicRing + Sub<R2, Output = R>,
641 R2: Clone,
642 const D: usize,
643>(
644 a: &[R; D],
645 b: &[R2; D],
646) -> [R; D] {
647 array::from_fn(|i| a[i].clone() - b[i].clone())
648}
649
650#[inline]
652pub(super) fn binomial_mul<
653 F: Field,
654 R: Algebra<F> + Algebra<R2>,
655 R2: Algebra<F>,
656 const D: usize,
657>(
658 a: &[R; D],
659 b: &[R2; D],
660 res: &mut [R; D],
661 w: F,
662) {
663 match D {
664 2 => quadratic_mul(a, b, res, w),
665 3 => cubic_mul(a, b, res, w),
666 4 => quartic_mul(a, b, res, w),
667 5 => quintic_mul(a, b, res, w),
668 _ =>
669 {
670 #[allow(clippy::needless_range_loop)]
671 for i in 0..D {
672 for j in 0..D {
673 if i + j >= D {
674 res[i + j - D] += a[i].clone() * w * b[j].clone();
675 } else {
676 res[i + j] += a[i].clone() * b[j].clone();
677 }
678 }
679 }
680 }
681 }
682}
683
684#[inline]
698fn quadratic_mul<F, R, R2, const D: usize>(a: &[R; D], b: &[R2; D], res: &mut [R; D], w: F)
699where
700 F: Field,
701 R: Algebra<F> + Algebra<R2>,
702 R2: Algebra<F>,
703{
704 let b1_w = b[1].clone() * w;
705
706 res[0] = R::dot_product(
708 a[..].try_into().unwrap(),
709 &[b[0].clone().into(), b1_w.into()],
710 );
711
712 res[1] = R::dot_product(
714 &[a[0].clone(), a[1].clone()],
715 &[b[1].clone().into(), b[0].clone().into()],
716 );
717}
718
719#[inline]
721fn quadratic_inv<F: Field, const D: usize>(a: &[F; D], res: &mut [F; D], w: F) {
722 assert_eq!(D, 2);
723 let neg_a1 = -a[1];
724 let scalar = F::dot_product(&[a[0], neg_a1], &[a[0], w * a[1]]).inverse();
725 res[0] = a[0] * scalar;
726 res[1] = neg_a1 * scalar;
727}
728
729#[inline]
731fn cubic_inv<F: Field, const D: usize>(a: &[F; D], res: &mut [F; D], w: F) {
732 assert_eq!(D, 3);
733 let a0_square = a[0].square();
734 let a1_square = a[1].square();
735 let a2_w = w * a[2];
736 let a0_a1 = a[0] * a[1];
737
738 let scalar = (a0_square * a[0] + w * a[1] * a1_square + a2_w.square() * a[2]
740 - (F::ONE + F::TWO) * a2_w * a0_a1)
741 .inverse();
742
743 res[0] = scalar * (a0_square - a[1] * a2_w);
745 res[1] = scalar * (a2_w * a[2] - a0_a1);
746 res[2] = scalar * (a1_square - a[0] * a[2]);
747}
748
749#[inline]
751pub(crate) fn cubic_mul<F: Field, R: Algebra<F> + Algebra<R2>, R2: Algebra<F>, const D: usize>(
752 a: &[R; D],
753 b: &[R2; D],
754 res: &mut [R; D],
755 w: F,
756) {
757 assert_eq!(D, 3);
758 let a0_b0 = a[0].clone() * b[0].clone();
762 let a1_b1 = a[1].clone() * b[1].clone();
763 let a2_b2 = a[2].clone() * b[2].clone();
764
765 res[0] = a0_b0.clone()
766 + ((a[1].clone() + a[2].clone()) * (b[1].clone() + b[2].clone())
767 - a1_b1.clone()
768 - a2_b2.clone())
769 * w;
770 res[1] = (a[0].clone() + a[1].clone()) * (b[0].clone() + b[1].clone())
771 - a0_b0.clone()
772 - a1_b1.clone()
773 + a2_b2.clone() * w;
774 res[2] = (a[0].clone() + a[2].clone()) * (b[0].clone() + b[2].clone()) - a0_b0 - a2_b2 + a1_b1;
775}
776
777#[inline]
779pub(crate) fn cubic_square<F: BinomiallyExtendable<D>, A: Algebra<F>, const D: usize>(
780 a: &[A; D],
781 res: &mut [A; D],
782) {
783 assert_eq!(D, 3);
784
785 let w_a2 = a[2].clone() * F::W;
786
787 res[0] = a[0].square() + (a[1].clone() * w_a2.clone()).double();
788 res[1] = w_a2 * a[2].clone() + (a[0].clone() * a[1].clone()).double();
789 res[2] = a[1].square() + (a[0].clone() * a[2].clone()).double();
790}
791
792#[inline]
797fn quartic_mul<F, R, R2, const D: usize>(a: &[R; D], b: &[R2; D], res: &mut [R; D], w: F)
798where
799 F: Field,
800 R: Algebra<F> + Algebra<R2>,
801 R2: Algebra<F>,
802{
803 assert_eq!(D, 4);
804 let b_r_rev: [R; 5] = [
805 b[3].clone().into(),
806 b[2].clone().into(),
807 b[1].clone().into(),
808 b[0].clone().into(),
809 w.into(),
810 ];
811
812 let w_coeff_0 =
814 R::dot_product::<3>(a[1..].try_into().unwrap(), b_r_rev[..3].try_into().unwrap());
815 res[0] = R::dot_product(&[a[0].clone(), w_coeff_0], b_r_rev[3..].try_into().unwrap());
816
817 let w_coeff_1 =
819 R::dot_product::<2>(a[2..].try_into().unwrap(), b_r_rev[..2].try_into().unwrap());
820 res[1] = R::dot_product(
821 &[a[0].clone(), a[1].clone(), w_coeff_1],
822 b_r_rev[2..].try_into().unwrap(),
823 );
824
825 let b3_w = b[3].clone() * w;
827 res[2] = R::dot_product::<4>(
828 a[..4].try_into().unwrap(),
829 &[
830 b_r_rev[1].clone(),
831 b_r_rev[2].clone(),
832 b_r_rev[3].clone(),
833 b3_w.into(),
834 ],
835 );
836
837 res[3] = R::dot_product::<4>(a[..].try_into().unwrap(), b_r_rev[..4].try_into().unwrap());
839}
840
841#[inline]
843fn quartic_inv<F: Field, const D: usize>(a: &[F; D], res: &mut [F; D], w: F) {
844 assert_eq!(D, 4);
845
846 let neg_a1 = -a[1];
858 let a3_w = a[3] * w;
859 let norm_0 = F::dot_product(&[a[0], a[2], neg_a1.double()], &[a[0], a[2] * w, a3_w]);
860 let norm_1 = F::dot_product(&[a[0], a[1], -a[3]], &[a[2].double(), neg_a1, a3_w]);
861
862 let mut inv = [F::ZERO; 2];
864 quadratic_inv(&[norm_0, norm_1], &mut inv, w);
865
866 let mut out_evn = [F::ZERO; 2];
871 let mut out_odd = [F::ZERO; 2];
872 quadratic_mul(&[a[0], a[2]], &inv, &mut out_evn, w);
873 quadratic_mul(&[a[1], a[3]], &inv, &mut out_odd, w);
874
875 res[0] = out_evn[0];
876 res[1] = -out_odd[0];
877 res[2] = out_evn[1];
878 res[3] = -out_odd[1];
879}
880
881#[inline]
886pub(crate) fn quartic_square<F, R, const D: usize>(a: &[R; D], res: &mut [R; D], w: F)
887where
888 F: Field,
889 R: Algebra<F>,
890{
891 assert_eq!(D, 4);
892
893 let two_a0 = a[0].double();
894 let two_a1 = a[1].double();
895 let two_a2 = a[2].double();
896 let a2_w = a[2].clone() * w;
897 let a3_w = a[3].clone() * w;
898
899 res[0] = R::dot_product(
901 &[a[0].clone(), a2_w, two_a1],
902 &[a[0].clone(), a[2].clone(), a3_w.clone()],
903 );
904
905 res[1] = R::dot_product(
907 &[two_a0.clone(), two_a2.clone()],
908 &[a[1].clone(), a3_w.clone()],
909 );
910
911 res[2] = R::dot_product(
913 &[a[1].clone(), a3_w, two_a0.clone()],
914 &[a[1].clone(), a[3].clone(), a[2].clone()],
915 );
916
917 res[3] = R::dot_product(&[two_a0, two_a2], &[a[3].clone(), a[1].clone()]);
919}
920
921fn quintic_mul<F, R, R2, const D: usize>(a: &[R; D], b: &[R2; D], res: &mut [R; D], w: F)
926where
927 F: Field,
928 R: Algebra<F> + Algebra<R2>,
929 R2: Algebra<F>,
930{
931 assert_eq!(D, 5);
932 let b_r_rev: [R; 6] = [
933 b[4].clone().into(),
934 b[3].clone().into(),
935 b[2].clone().into(),
936 b[1].clone().into(),
937 b[0].clone().into(),
938 w.into(),
939 ];
940
941 let w_coeff_0 =
943 R::dot_product::<4>(a[1..].try_into().unwrap(), b_r_rev[..4].try_into().unwrap());
944 res[0] = R::dot_product(&[a[0].clone(), w_coeff_0], b_r_rev[4..].try_into().unwrap());
945
946 let w_coeff_1 =
948 R::dot_product::<3>(a[2..].try_into().unwrap(), b_r_rev[..3].try_into().unwrap());
949 res[1] = R::dot_product(
950 &[a[0].clone(), a[1].clone(), w_coeff_1],
951 b_r_rev[3..].try_into().unwrap(),
952 );
953
954 let w_coeff_2 =
956 R::dot_product::<2>(a[3..].try_into().unwrap(), b_r_rev[..2].try_into().unwrap());
957 res[2] = R::dot_product(
958 &[a[0].clone(), a[1].clone(), a[2].clone(), w_coeff_2],
959 b_r_rev[2..].try_into().unwrap(),
960 );
961
962 let b4_w = b[4].clone() * w;
964 res[3] = R::dot_product::<5>(
965 a[..5].try_into().unwrap(),
966 &[
967 b_r_rev[1].clone(),
968 b_r_rev[2].clone(),
969 b_r_rev[3].clone(),
970 b_r_rev[4].clone(),
971 b4_w.into(),
972 ],
973 );
974
975 res[4] = R::dot_product::<5>(a[..].try_into().unwrap(), b_r_rev[..5].try_into().unwrap());
977}
978
979#[inline]
984pub(crate) fn quintic_square<F, R, const D: usize>(a: &[R; D], res: &mut [R; D], w: F)
985where
986 F: Field,
987 R: Algebra<F>,
988{
989 assert_eq!(D, 5);
990
991 let two_a0 = a[0].double();
992 let two_a1 = a[1].double();
993 let two_a2 = a[2].double();
994 let two_a3 = a[3].double();
995 let w_a3 = a[3].clone() * w;
996 let w_a4 = a[4].clone() * w;
997
998 res[0] = R::dot_product(
1000 &[a[0].clone(), w_a4.clone(), w_a3.clone()],
1001 &[a[0].clone(), two_a1.clone(), two_a2.clone()],
1002 );
1003
1004 res[1] = R::dot_product(
1006 &[w_a3, two_a0.clone(), w_a4.clone()],
1007 &[a[3].clone(), a[1].clone(), two_a2],
1008 );
1009
1010 res[2] = R::dot_product(
1012 &[a[1].clone(), two_a0.clone(), w_a4.clone()],
1013 &[a[1].clone(), a[2].clone(), two_a3],
1014 );
1015
1016 res[3] = R::dot_product(
1018 &[w_a4, two_a0.clone(), two_a1.clone()],
1019 &[a[4].clone(), a[3].clone(), a[2].clone()],
1020 );
1021
1022 res[4] = R::dot_product(
1024 &[a[2].clone(), two_a0, two_a1],
1025 &[a[2].clone(), a[4].clone(), a[3].clone()],
1026 );
1027}
1028
1029#[inline]
1031fn quintic_inv<F: BinomiallyExtendable<D>, const D: usize>(
1032 a: &BinomialExtensionField<F, D>,
1033) -> BinomialExtensionField<F, D> {
1034 let a_exp_q = a.frobenius();
1036 let a_exp_q_plus_q_sq = (*a * a_exp_q).frobenius();
1037 let prod_conj = a_exp_q_plus_q_sq * a_exp_q_plus_q_sq.repeated_frobenius(2);
1038
1039 let a_vals = a.value;
1042 let mut b = prod_conj.value;
1043 b.reverse();
1044
1045 let w_coeff = F::dot_product::<4>(a.value[1..].try_into().unwrap(), b[..4].try_into().unwrap());
1046 let norm = F::dot_product::<2>(&[a_vals[0], F::W], &[b[4], w_coeff]);
1047 debug_assert_eq!(BinomialExtensionField::<F, D>::from(norm), *a * prod_conj);
1048
1049 prod_conj * norm.inverse()
1050}