1use alloc::format;
2use alloc::string::ToString;
3use core::array;
4use core::fmt::{self, Debug, Display, Formatter};
5use core::iter::{Product, Sum};
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7
8use itertools::Itertools;
9use num_bigint::BigUint;
10use rand::distributions::Standard;
11use rand::prelude::Distribution;
12use serde::{Deserialize, Serialize};
13
14use super::{HasFrobenius, HasTwoAdicBionmialExtension};
15use crate::extension::BinomiallyExtendable;
16use crate::field::Field;
17use crate::{
18 field_to_array, AbstractExtensionField, AbstractField, ExtensionField, Packable, TwoAdicField,
19};
20
21#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
22pub struct BinomialExtensionField<AF, const D: usize> {
23 #[serde(
24 with = "p3_util::array_serialization",
25 bound(serialize = "AF: Serialize", deserialize = "AF: Deserialize<'de>")
26 )]
27 pub(crate) value: [AF; D],
28}
29
30impl<AF: AbstractField, const D: usize> Default for BinomialExtensionField<AF, D> {
31 fn default() -> Self {
32 Self {
33 value: array::from_fn(|_| AF::zero()),
34 }
35 }
36}
37
38impl<AF: AbstractField, const D: usize> From<AF> for BinomialExtensionField<AF, D> {
39 fn from(x: AF) -> Self {
40 Self {
41 value: field_to_array::<AF, D>(x),
42 }
43 }
44}
45
46impl<F: BinomiallyExtendable<D>, const D: usize> Packable for BinomialExtensionField<F, D> {}
47
48impl<F: BinomiallyExtendable<D>, const D: usize> ExtensionField<F>
49 for BinomialExtensionField<F, D>
50{
51 type ExtensionPacking = BinomialExtensionField<F::Packing, D>;
52}
53
54impl<F: BinomiallyExtendable<D>, const D: usize> HasFrobenius<F> for BinomialExtensionField<F, D> {
55 fn frobenius(&self) -> Self {
57 self.repeated_frobenius(1)
58 }
59
60 fn repeated_frobenius(&self, count: usize) -> Self {
65 if count == 0 {
66 return *self;
67 } else if count >= D {
68 return self.repeated_frobenius(count % D);
71 }
72 let arr: &[F] = self.as_base_slice();
73
74 let mut z0 = F::dth_root();
76 for _ in 1..count {
77 z0 *= F::dth_root();
78 }
79
80 let mut res = [F::zero(); D];
81 for (i, z) in z0.powers().take(D).enumerate() {
82 res[i] = arr[i] * z;
83 }
84
85 Self::from_base_slice(&res)
86 }
87
88 fn frobenius_inv(&self) -> Self {
90 let mut f = Self::one();
93 for _ in 1..D {
94 f = (f * *self).frobenius();
95 }
96
97 let a = self.value;
100 let b = f.value;
101 let mut g = F::zero();
102 for i in 1..D {
103 g += a[i] * b[D - i];
104 }
105 g *= F::w();
106 g += a[0] * b[0];
107 debug_assert_eq!(Self::from(g), *self * f);
108
109 f * g.inverse()
110 }
111}
112
113impl<AF, const D: usize> AbstractField for BinomialExtensionField<AF, D>
114where
115 AF: AbstractField,
116 AF::F: BinomiallyExtendable<D>,
117{
118 type F = BinomialExtensionField<AF::F, D>;
119
120 fn zero() -> Self {
121 Self {
122 value: field_to_array::<AF, D>(AF::zero()),
123 }
124 }
125 fn one() -> Self {
126 Self {
127 value: field_to_array::<AF, D>(AF::one()),
128 }
129 }
130 fn two() -> Self {
131 Self {
132 value: field_to_array::<AF, D>(AF::two()),
133 }
134 }
135 fn neg_one() -> Self {
136 Self {
137 value: field_to_array::<AF, D>(AF::neg_one()),
138 }
139 }
140
141 fn from_f(f: Self::F) -> Self {
142 Self {
143 value: f.value.map(AF::from_f),
144 }
145 }
146
147 fn from_bool(b: bool) -> Self {
148 AF::from_bool(b).into()
149 }
150
151 fn from_canonical_u8(n: u8) -> Self {
152 AF::from_canonical_u8(n).into()
153 }
154
155 fn from_canonical_u16(n: u16) -> Self {
156 AF::from_canonical_u16(n).into()
157 }
158
159 fn from_canonical_u32(n: u32) -> Self {
160 AF::from_canonical_u32(n).into()
161 }
162
163 fn from_canonical_u64(n: u64) -> Self {
165 AF::from_canonical_u64(n).into()
166 }
167
168 fn from_canonical_usize(n: usize) -> Self {
170 AF::from_canonical_usize(n).into()
171 }
172
173 fn from_wrapped_u32(n: u32) -> Self {
174 AF::from_wrapped_u32(n).into()
175 }
176
177 fn from_wrapped_u64(n: u64) -> Self {
178 AF::from_wrapped_u64(n).into()
179 }
180
181 fn generator() -> Self {
182 Self {
183 value: AF::F::ext_generator().map(AF::from_f),
184 }
185 }
186
187 #[inline(always)]
188 fn square(&self) -> Self {
189 match D {
190 2 => {
191 let a = self.value.clone();
192 let mut res = Self::default();
193 res.value[0] = a[0].square() + a[1].square() * AF::from_f(AF::F::w());
194 res.value[1] = a[0].clone() * a[1].double();
195 res
196 }
197 3 => Self {
198 value: cubic_square(&self.value, AF::F::w())
199 .to_vec()
200 .try_into()
201 .unwrap(),
202 },
203 _ => <Self as Mul<Self>>::mul(self.clone(), self.clone()),
204 }
205 }
206}
207
208impl<F: BinomiallyExtendable<D>, const D: usize> Field for BinomialExtensionField<F, D> {
209 type Packing = Self;
210
211 fn try_inverse(&self) -> Option<Self> {
212 if self.is_zero() {
213 return None;
214 }
215
216 match D {
217 2 => Some(Self::from_base_slice(&qudratic_inv(&self.value, F::w()))),
218 3 => Some(Self::from_base_slice(&cubic_inv(&self.value, F::w()))),
219 _ => Some(self.frobenius_inv()),
220 }
221 }
222
223 fn halve(&self) -> Self {
224 Self {
225 value: self.value.map(|x| x.halve()),
226 }
227 }
228
229 fn order() -> BigUint {
230 F::order().pow(D as u32)
231 }
232}
233
234impl<F, const D: usize> Display for BinomialExtensionField<F, D>
235where
236 F: BinomiallyExtendable<D>,
237{
238 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
239 if self.is_zero() {
240 write!(f, "0")
241 } else {
242 let str = self
243 .value
244 .iter()
245 .enumerate()
246 .filter(|(_, x)| !x.is_zero())
247 .map(|(i, x)| match (i, x.is_one()) {
248 (0, _) => format!("{x}"),
249 (1, true) => "X".to_string(),
250 (1, false) => format!("{x} X"),
251 (_, true) => format!("X^{i}"),
252 (_, false) => format!("{x} X^{i}"),
253 })
254 .join(" + ");
255 write!(f, "{}", str)
256 }
257 }
258}
259
260impl<AF, const D: usize> Neg for BinomialExtensionField<AF, D>
261where
262 AF: AbstractField,
263 AF::F: BinomiallyExtendable<D>,
264{
265 type Output = Self;
266
267 #[inline]
268 fn neg(self) -> Self {
269 Self {
270 value: self.value.map(AF::neg),
271 }
272 }
273}
274
275impl<AF, const D: usize> Add for BinomialExtensionField<AF, D>
276where
277 AF: AbstractField,
278 AF::F: BinomiallyExtendable<D>,
279{
280 type Output = Self;
281
282 #[inline]
283 fn add(self, rhs: Self) -> Self {
284 let mut res = self.value;
285 for (r, rhs_val) in res.iter_mut().zip(rhs.value) {
286 *r += rhs_val;
287 }
288 Self { value: res }
289 }
290}
291
292impl<AF, const D: usize> Add<AF> for BinomialExtensionField<AF, D>
293where
294 AF: AbstractField,
295 AF::F: BinomiallyExtendable<D>,
296{
297 type Output = Self;
298
299 #[inline]
300 fn add(self, rhs: AF) -> Self {
301 let mut res = self.value;
302 res[0] += rhs;
303 Self { value: res }
304 }
305}
306
307impl<AF, const D: usize> AddAssign for BinomialExtensionField<AF, D>
308where
309 AF: AbstractField,
310 AF::F: BinomiallyExtendable<D>,
311{
312 fn add_assign(&mut self, rhs: Self) {
313 *self = self.clone() + rhs;
314 }
315}
316
317impl<AF, const D: usize> AddAssign<AF> for BinomialExtensionField<AF, D>
318where
319 AF: AbstractField,
320 AF::F: BinomiallyExtendable<D>,
321{
322 fn add_assign(&mut self, rhs: AF) {
323 *self = self.clone() + rhs;
324 }
325}
326
327impl<AF, const D: usize> Sum for BinomialExtensionField<AF, D>
328where
329 AF: AbstractField,
330 AF::F: BinomiallyExtendable<D>,
331{
332 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
333 let zero = Self {
334 value: field_to_array::<AF, D>(AF::zero()),
335 };
336 iter.fold(zero, |acc, x| acc + x)
337 }
338}
339
340impl<AF, const D: usize> Sub for BinomialExtensionField<AF, D>
341where
342 AF: AbstractField,
343 AF::F: BinomiallyExtendable<D>,
344{
345 type Output = Self;
346
347 #[inline]
348 fn sub(self, rhs: Self) -> Self {
349 let mut res = self.value;
350 for (r, rhs_val) in res.iter_mut().zip(rhs.value) {
351 *r -= rhs_val;
352 }
353 Self { value: res }
354 }
355}
356
357impl<AF, const D: usize> Sub<AF> for BinomialExtensionField<AF, D>
358where
359 AF: AbstractField,
360 AF::F: BinomiallyExtendable<D>,
361{
362 type Output = Self;
363
364 #[inline]
365 fn sub(self, rhs: AF) -> Self {
366 let mut res = self.value;
367 res[0] -= rhs;
368 Self { value: res }
369 }
370}
371
372impl<AF, const D: usize> SubAssign for BinomialExtensionField<AF, D>
373where
374 AF: AbstractField,
375 AF::F: BinomiallyExtendable<D>,
376{
377 #[inline]
378 fn sub_assign(&mut self, rhs: Self) {
379 *self = self.clone() - rhs;
380 }
381}
382
383impl<AF, const D: usize> SubAssign<AF> for BinomialExtensionField<AF, D>
384where
385 AF: AbstractField,
386 AF::F: BinomiallyExtendable<D>,
387{
388 #[inline]
389 fn sub_assign(&mut self, rhs: AF) {
390 *self = self.clone() - rhs;
391 }
392}
393
394impl<AF, const D: usize> Mul for BinomialExtensionField<AF, D>
395where
396 AF: AbstractField,
397 AF::F: BinomiallyExtendable<D>,
398{
399 type Output = Self;
400
401 #[inline]
402 fn mul(self, rhs: Self) -> Self {
403 let a = self.value;
404 let b = rhs.value;
405 let w = AF::F::w();
406 let w_af = AF::from_f(w);
407
408 match D {
409 2 => {
410 let mut res = Self::default();
411 res.value[0] = a[0].clone() * b[0].clone() + a[1].clone() * w_af * b[1].clone();
412 res.value[1] = a[0].clone() * b[1].clone() + a[1].clone() * b[0].clone();
413 res
414 }
415 3 => Self {
416 value: cubic_mul(&a, &b, w).to_vec().try_into().unwrap(),
417 },
418 _ => {
419 let mut res = Self::default();
420 #[allow(clippy::needless_range_loop)]
421 for i in 0..D {
422 for j in 0..D {
423 if i + j >= D {
424 res.value[i + j - D] += a[i].clone() * w_af.clone() * b[j].clone();
425 } else {
426 res.value[i + j] += a[i].clone() * b[j].clone();
427 }
428 }
429 }
430 res
431 }
432 }
433 }
434}
435
436impl<AF, const D: usize> Mul<AF> for BinomialExtensionField<AF, D>
437where
438 AF: AbstractField,
439 AF::F: BinomiallyExtendable<D>,
440{
441 type Output = Self;
442
443 #[inline]
444 fn mul(self, rhs: AF) -> Self {
445 Self {
446 value: self.value.map(|x| x * rhs.clone()),
447 }
448 }
449}
450
451impl<AF, const D: usize> Product for BinomialExtensionField<AF, D>
452where
453 AF: AbstractField,
454 AF::F: BinomiallyExtendable<D>,
455{
456 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
457 let one = Self {
458 value: field_to_array::<AF, D>(AF::one()),
459 };
460 iter.fold(one, |acc, x| acc * x)
461 }
462}
463
464impl<F, const D: usize> Div for BinomialExtensionField<F, D>
465where
466 F: BinomiallyExtendable<D>,
467{
468 type Output = Self;
469
470 #[allow(clippy::suspicious_arithmetic_impl)]
471 fn div(self, rhs: Self) -> Self::Output {
472 self * rhs.inverse()
473 }
474}
475
476impl<F, const D: usize> DivAssign for BinomialExtensionField<F, D>
477where
478 F: BinomiallyExtendable<D>,
479{
480 fn div_assign(&mut self, rhs: Self) {
481 *self = *self / rhs;
482 }
483}
484
485impl<AF, const D: usize> MulAssign for BinomialExtensionField<AF, D>
486where
487 AF: AbstractField,
488 AF::F: BinomiallyExtendable<D>,
489{
490 #[inline]
491 fn mul_assign(&mut self, rhs: Self) {
492 *self = self.clone() * rhs;
493 }
494}
495
496impl<AF, const D: usize> MulAssign<AF> for BinomialExtensionField<AF, D>
497where
498 AF: AbstractField,
499 AF::F: BinomiallyExtendable<D>,
500{
501 fn mul_assign(&mut self, rhs: AF) {
502 *self = self.clone() * rhs;
503 }
504}
505
506impl<AF, const D: usize> AbstractExtensionField<AF> for BinomialExtensionField<AF, D>
507where
508 AF: AbstractField,
509 AF::F: BinomiallyExtendable<D>,
510{
511 const D: usize = D;
512
513 fn from_base(b: AF) -> Self {
514 Self {
515 value: field_to_array(b),
516 }
517 }
518
519 fn from_base_slice(bs: &[AF]) -> Self {
520 Self {
521 value: bs.to_vec().try_into().expect("slice has wrong length"),
522 }
523 }
524
525 #[inline]
526 fn from_base_fn<F: FnMut(usize) -> AF>(f: F) -> Self {
527 Self {
528 value: array::from_fn(f),
529 }
530 }
531
532 fn as_base_slice(&self) -> &[AF] {
533 &self.value
534 }
535}
536
537impl<F: BinomiallyExtendable<D>, const D: usize> Distribution<BinomialExtensionField<F, D>>
538 for Standard
539where
540 Standard: Distribution<F>,
541{
542 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> BinomialExtensionField<F, D> {
543 let mut res = [F::zero(); D];
544 for r in res.iter_mut() {
545 *r = Standard.sample(rng);
546 }
547 BinomialExtensionField::<F, D>::from_base_slice(&res)
548 }
549}
550
551impl<F: Field + HasTwoAdicBionmialExtension<D>, const D: usize> TwoAdicField
552 for BinomialExtensionField<F, D>
553{
554 const TWO_ADICITY: usize = F::EXT_TWO_ADICITY;
555
556 fn two_adic_generator(bits: usize) -> Self {
557 Self {
558 value: F::ext_two_adic_generator(bits),
559 }
560 }
561}
562
563#[inline]
565fn qudratic_inv<F: Field>(a: &[F], w: F) -> [F; 2] {
566 let scalar = (a[0].square() - w * a[1].square()).inverse();
567 [a[0] * scalar, -a[1] * scalar]
568}
569
570#[inline]
572fn cubic_inv<F: Field>(a: &[F], w: F) -> [F; 3] {
573 let a0_square = a[0].square();
574 let a1_square = a[1].square();
575 let a2_w = w * a[2];
576 let a0_a1 = a[0] * a[1];
577
578 let scalar = (a0_square * a[0] + w * a[1] * a1_square + a2_w.square() * a[2]
580 - (F::one() + F::two()) * a2_w * a0_a1)
581 .inverse();
582
583 [
585 scalar * (a0_square - a[1] * a2_w),
586 scalar * (a2_w * a[2] - a0_a1),
587 scalar * (a1_square - a[0] * a[2]),
588 ]
589}
590
591#[inline]
593fn cubic_mul<AF: AbstractField>(a: &[AF], b: &[AF], w: AF::F) -> [AF; 3] {
594 let a0_b0 = a[0].clone() * b[0].clone();
595 let a1_b1 = a[1].clone() * b[1].clone();
596 let a2_b2 = a[2].clone() * b[2].clone();
597
598 let c0 = a0_b0.clone()
599 + ((a[1].clone() + a[2].clone()) * (b[1].clone() + b[2].clone())
600 - a1_b1.clone()
601 - a2_b2.clone())
602 * AF::from_f(w);
603 let c1 = (a[0].clone() + a[1].clone()) * (b[0].clone() + b[1].clone())
604 - a0_b0.clone()
605 - a1_b1.clone()
606 + a2_b2.clone() * AF::from_f(w);
607 let c2 = (a[0].clone() + a[2].clone()) * (b[0].clone() + b[2].clone()) - a0_b0 - a2_b2 + a1_b1;
608
609 [c0, c1, c2]
610}
611
612#[inline]
614fn cubic_square<AF: AbstractField>(a: &[AF], w: AF::F) -> [AF; 3] {
615 let w_a2 = a[2].clone() * AF::from_f(w);
616
617 let c0 = a[0].square() + (a[1].clone() * w_a2.clone()).double();
618 let c1 = w_a2 * a[2].clone() + (a[0].clone() * a[1].clone()).double();
619 let c2 = a[1].square() + (a[0].clone() * a[2].clone()).double();
620
621 [c0, c1, c2]
622}