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