Skip to main content

p3_field/extension/
complex.rs

1use super::{
2    Binomial, BinomialExtensionField, BinomiallyExtendable, ExtensionAlgebra,
3    HasTwoAdicBinomialExtension, binomial_mul, binomial_square,
4};
5use crate::{Algebra, Field, PrimeCharacteristicRing};
6
7pub type Complex<F> = BinomialExtensionField<F, 2>;
8
9/// A field for which `p = 3 (mod 4)`. Equivalently, `-1` is not a square,
10/// so the complex extension can be defined `F[i] = F[X]/(X^2+1)`.
11pub trait ComplexExtendable: Field {
12    /// The two-adicity of `p+1`, the order of the circle group.
13    const CIRCLE_TWO_ADICITY: usize;
14
15    const COMPLEX_GENERATOR: Complex<Self>;
16
17    fn circle_two_adic_generator(bits: usize) -> Complex<Self>;
18}
19
20impl<F: ComplexExtendable> ExtensionAlgebra<F, 2, Binomial<F>> for F {
21    #[inline]
22    fn ext_mul(a: &[Self; 2], b: &[Self; 2], res: &mut [Self; 2]) {
23        binomial_mul::<F, Self, Self, 2>(a, b, res, <F as BinomiallyExtendable<2>>::W);
24    }
25
26    #[inline]
27    fn ext_square(a: &[Self; 2], res: &mut [Self; 2]) {
28        binomial_square::<F, Self, 2>(a, res, <F as BinomiallyExtendable<2>>::W);
29    }
30}
31
32impl<F: ComplexExtendable> BinomiallyExtendable<2> for F {
33    const W: Self = F::NEG_ONE;
34
35    // since `p = 3 (mod 4)`, `(p-1)/2` is always odd,
36    // so `(-1)^((p-1)/2) = -1`
37    const DTH_ROOT: Self = F::NEG_ONE;
38
39    const EXT_GENERATOR: [Self; 2] = F::COMPLEX_GENERATOR.value;
40}
41
42/// Convenience methods for complex extensions
43impl<R: PrimeCharacteristicRing> Complex<R> {
44    #[inline(always)]
45    pub const fn new_complex(real: R, imag: R) -> Self {
46        Self::new([real, imag])
47    }
48
49    #[inline(always)]
50    pub const fn new_real(real: R) -> Self {
51        Self::new_complex(real, R::ZERO)
52    }
53
54    #[inline(always)]
55    pub const fn new_imag(imag: R) -> Self {
56        Self::new_complex(R::ZERO, imag)
57    }
58
59    #[inline(always)]
60    #[must_use]
61    pub fn real(&self) -> R {
62        self.value[0].dup()
63    }
64
65    #[inline(always)]
66    #[must_use]
67    pub fn imag(&self) -> R {
68        self.value[1].dup()
69    }
70
71    #[inline(always)]
72    pub fn conjugate(&self) -> Self {
73        Self::new_complex(self.real(), self.imag().neg())
74    }
75
76    #[inline]
77    #[must_use]
78    pub fn norm(&self) -> R {
79        self.real().square() + self.imag().square()
80    }
81
82    #[inline(always)]
83    #[must_use]
84    pub fn to_array(&self) -> [R; 2] {
85        core::array::from_fn(|i| self.value[i].dup())
86    }
87
88    // Sometimes we want to rotate over an extension that's not necessarily ComplexExtendable,
89    // but still on the circle.
90    #[inline]
91    pub fn rotate<Ext: Algebra<R>>(&self, rhs: &Complex<Ext>) -> Complex<Ext> {
92        Complex::<Ext>::new_complex(
93            rhs.real() * self.real() - rhs.imag() * self.imag(),
94            rhs.imag() * self.real() + rhs.real() * self.imag(),
95        )
96    }
97}
98
99/// The complex extension of this field has a binomial extension.
100///
101/// This exists if the polynomial ring `F[i][X]` has an irreducible polynomial `X^d-W`
102/// allowing us to define the binomial extension field `F[i][X]/(X^d-W)`.
103pub trait HasComplexBinomialExtension<const D: usize>: ComplexExtendable {
104    const W: Complex<Self>;
105
106    // DTH_ROOT = W^((n - 1)/D).
107    // n is the order of base field.
108    // Only works when exists k such that n = kD + 1.
109    const DTH_ROOT: Complex<Self>;
110
111    const EXT_GENERATOR: [Complex<Self>; D];
112
113    /// Multiply a `Complex<Self>` element by `W = Self::W`.
114    ///
115    /// The default is a general complex multiplication. Override when `W` has
116    /// structure that makes multiplication cheaper (e.g. add-only when all
117    /// coefficients of `W` are small).
118    #[inline]
119    fn mul_by_w(z: Complex<Self>) -> Complex<Self> {
120        <Complex<Self> as BinomiallyExtendable<D>>::W * z
121    }
122}
123
124impl<F, const D: usize> ExtensionAlgebra<Self, D, Binomial<Self>> for Complex<F>
125where
126    F: HasComplexBinomialExtension<D>,
127{
128    #[inline]
129    fn ext_mul(a: &[Self; D], b: &[Self; D], res: &mut [Self; D]) {
130        binomial_mul::<Self, Self, Self, D>(a, b, res, <Self as BinomiallyExtendable<D>>::W);
131    }
132
133    #[inline]
134    fn ext_square(a: &[Self; D], res: &mut [Self; D]) {
135        match D {
136            2 => {
137                // QM31-style: (a0, a1) with modulus X² − W.
138                // res[0] = a0² + W·a1²   (two CM31 squares + add-only W-mul)
139                // res[1] = 2·a0·a1        (one CM31 mul)
140                let a0 = a[0];
141                let a1 = a[1];
142                let a0_sq = a0.square();
143                let a1_sq = a1.square();
144                let w_a1_sq = F::mul_by_w(a1_sq);
145                res[0] = a0_sq + w_a1_sq;
146                res[1] = (a0 * a1).double();
147            }
148            _ => binomial_square::<Self, Self, D>(a, res, <Self as BinomiallyExtendable<D>>::W),
149        }
150    }
151}
152
153impl<F, const D: usize> BinomiallyExtendable<D> for Complex<F>
154where
155    F: HasComplexBinomialExtension<D>,
156{
157    const W: Self = <F as HasComplexBinomialExtension<D>>::W;
158
159    const DTH_ROOT: Self = <F as HasComplexBinomialExtension<D>>::DTH_ROOT;
160
161    const EXT_GENERATOR: [Self; D] = F::EXT_GENERATOR;
162}
163
164/// The complex extension of this field has a two-adic binomial extension.
165pub trait HasTwoAdicComplexBinomialExtension<const D: usize>:
166    HasComplexBinomialExtension<D>
167{
168    const COMPLEX_EXT_TWO_ADICITY: usize;
169
170    fn complex_ext_two_adic_generator(bits: usize) -> [Complex<Self>; D];
171}
172
173impl<F, const D: usize> HasTwoAdicBinomialExtension<D> for Complex<F>
174where
175    F: HasTwoAdicComplexBinomialExtension<D>,
176{
177    const EXT_TWO_ADICITY: usize = F::COMPLEX_EXT_TWO_ADICITY;
178
179    #[inline(always)]
180    fn ext_two_adic_generator(bits: usize) -> [Self; D] {
181        F::complex_ext_two_adic_generator(bits)
182    }
183}