p3_field/extension/
binomial_extension.rs

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