Skip to main content

p3_goldilocks/
extension.rs

1use p3_field::extension::{
2    Binomial, BinomiallyExtendable, CubicTrinomial, CubicTrinomialExtendable, ExtensionAlgebra,
3    HasTwoAdicBinomialExtension, HasTwoAdicCubicExtension, binomial_mul, binomial_square,
4    cubic_square, trinomial_cubic_mul,
5};
6use p3_field::{PrimeCharacteristicRing, TwoAdicField, field_to_array};
7
8use crate::Goldilocks;
9
10impl ExtensionAlgebra<Self, 2, Binomial<Self>> for Goldilocks {
11    #[inline]
12    fn ext_mul(a: &[Self; 2], b: &[Self; 2], res: &mut [Self; 2]) {
13        binomial_mul::<Self, Self, Self, 2>(a, b, res, <Self as BinomiallyExtendable<2>>::W);
14    }
15
16    #[inline]
17    fn ext_square(a: &[Self; 2], res: &mut [Self; 2]) {
18        binomial_square::<Self, Self, 2>(a, res, <Self as BinomiallyExtendable<2>>::W);
19    }
20}
21
22impl BinomiallyExtendable<2> for Goldilocks {
23    // Verifiable in Sage with
24    // `R.<x> = GF(p)[]; assert (x^2 - 7).is_irreducible()`.
25    const W: Self = Self::new(7);
26
27    // DTH_ROOT = W^((p - 1)/2).
28    const DTH_ROOT: Self = Self::new(18446744069414584320);
29
30    const EXT_GENERATOR: [Self; 2] = [
31        Self::new(18081566051660590251),
32        Self::new(16121475356294670766),
33    ];
34}
35
36impl HasTwoAdicBinomialExtension<2> for Goldilocks {
37    const EXT_TWO_ADICITY: usize = 33;
38
39    fn ext_two_adic_generator(bits: usize) -> [Self; 2] {
40        assert!(bits <= 33);
41
42        if bits == 33 {
43            [Self::ZERO, Self::new(15659105665374529263)]
44        } else {
45            [Self::two_adic_generator(bits), Self::ZERO]
46        }
47    }
48}
49
50impl ExtensionAlgebra<Self, 3, CubicTrinomial> for Goldilocks {
51    #[inline]
52    fn ext_mul(a: &[Self; 3], b: &[Self; 3], res: &mut [Self; 3]) {
53        trinomial_cubic_mul::<Self>(a, b, res);
54    }
55
56    #[inline]
57    fn ext_square(a: &[Self; 3], res: &mut [Self; 3]) {
58        cubic_square::<Self>(a, res);
59    }
60}
61
62impl CubicTrinomialExtendable for Goldilocks {
63    // Verifiable via:
64    // ```sage
65    // p = 2**64 - 2**32 + 1
66    // R.<x> = GF(p)[]
67    // assert (x^3 - x - 1).is_irreducible()
68    // ```
69    const FROBENIUS_MATRIX: [[Self; 3]; 3] = [
70        [
71            Self::ONE,
72            Self::new(10615703402128488253),
73            Self::new(6700183068485440220),
74        ],
75        [
76            Self::ZERO,
77            Self::new(10050274602728160328),
78            Self::new(14531223735771536287),
79        ],
80        [
81            Self::ZERO,
82            Self::new(11746561000929144102),
83            Self::new(8396469466686423992),
84        ],
85    ];
86
87    // Verifiable via:
88    // ```sage
89    // p = 2**64 - 2**32 + 1
90    // F = GF(p)
91    // R.<x> = F[]
92    // K.<a> = F.extension(x^3 - x - 1)
93    // g = 2 + a
94    // order = p^3 - 1
95    // assert g.multiplicative_order() == order
96    // ```
97    const EXT_GENERATOR: [Self; 3] = [Self::TWO, Self::ONE, Self::ZERO];
98}
99
100impl HasTwoAdicCubicExtension for Goldilocks {
101    const EXT_TWO_ADICITY: usize = 32;
102
103    fn ext_two_adic_generator(bits: usize) -> [Self; 3] {
104        assert!(bits <= 32);
105
106        field_to_array(Self::two_adic_generator(bits))
107    }
108}
109
110impl ExtensionAlgebra<Self, 5, Binomial<Self>> for Goldilocks {
111    #[inline]
112    fn ext_mul(a: &[Self; 5], b: &[Self; 5], res: &mut [Self; 5]) {
113        binomial_mul::<Self, Self, Self, 5>(a, b, res, <Self as BinomiallyExtendable<5>>::W);
114    }
115
116    #[inline]
117    fn ext_square(a: &[Self; 5], res: &mut [Self; 5]) {
118        binomial_square::<Self, Self, 5>(a, res, <Self as BinomiallyExtendable<5>>::W);
119    }
120}
121
122impl BinomiallyExtendable<5> for Goldilocks {
123    // Verifiable via:
124    //  ```sage
125    //  # Define Fp
126    //  p = 2**64 - 2**32 + 1
127    //  F = GF(p)
128
129    //  # Define Fp[z]
130    //  R.<z> = PolynomialRing(F)
131
132    //  # The polynomial x^5-3 is irreducible
133    //  assert(R(z^5-3).is_irreducible())
134    //  ```
135    const W: Self = Self::new(3);
136
137    // 5-th root = w^((p - 1)/5)
138    const DTH_ROOT: Self = Self::new(1041288259238279555);
139
140    // Generator of the extension field
141    // Obtained by finding the smallest Hamming weight vector
142    // with appropriate order, starting at [0,1,0,0,0]
143    const EXT_GENERATOR: [Self; 5] = [Self::TWO, Self::ONE, Self::ZERO, Self::ZERO, Self::ZERO];
144}
145
146impl HasTwoAdicBinomialExtension<5> for Goldilocks {
147    const EXT_TWO_ADICITY: usize = 32;
148
149    fn ext_two_adic_generator(bits: usize) -> [Self; 5] {
150        assert!(bits <= 32);
151
152        field_to_array(Self::two_adic_generator(bits))
153    }
154}
155
156#[cfg(test)]
157mod test_quadratic_extension {
158
159    use num_bigint::BigUint;
160    use p3_field::extension::BinomialExtensionField;
161    use p3_field::{ExtensionField, PrimeCharacteristicRing};
162    use p3_field_testing::{
163        test_extension_field, test_field, test_packed_extension_field,
164        test_two_adic_extension_field,
165    };
166
167    use crate::Goldilocks;
168
169    type F = Goldilocks;
170    type EF = BinomialExtensionField<F, 2>;
171
172    // There is a redundant representation of zero but we already tested it
173    // when testing the base field.
174    const ZEROS: [EF; 1] = [EF::ZERO];
175    const ONES: [EF; 1] = [EF::ONE];
176
177    // Get the prime factorization of the order of the multiplicative group.
178    // i.e. the prime factorization of P^2 - 1.
179    fn multiplicative_group_prime_factorization() -> [(BigUint, u32); 9] {
180        [
181            (BigUint::from(2u8), 33),
182            (BigUint::from(3u8), 1),
183            (BigUint::from(5u8), 1),
184            (BigUint::from(7u8), 1),
185            (BigUint::from(17u8), 1),
186            (BigUint::from(179u8), 1),
187            (BigUint::from(257u16), 1),
188            (BigUint::from(65537u32), 1),
189            (BigUint::from(7361031152998637u64), 1),
190        ]
191    }
192
193    test_field!(
194        super::EF,
195        &super::ZEROS,
196        &super::ONES,
197        &super::multiplicative_group_prime_factorization()
198    );
199
200    test_extension_field!(super::F, super::EF);
201    test_two_adic_extension_field!(super::F, super::EF);
202
203    type Pef = <EF as ExtensionField<F>>::ExtensionPacking;
204    const PACKED_ZEROS: [Pef; 1] = [Pef::ZERO];
205    const PACKED_ONES: [Pef; 1] = [Pef::ONE];
206    test_packed_extension_field!(
207        super::F,
208        super::EF,
209        super::Pef,
210        &super::PACKED_ZEROS,
211        &super::PACKED_ONES
212    );
213    p3_field_testing::test_packed_binomial_extension_division!(F, 2);
214}
215
216#[cfg(test)]
217mod test_cubic_trinomial_extension {
218
219    use num_bigint::BigUint;
220    use p3_field::extension::CubicTrinomialExtensionField;
221    use p3_field::{ExtensionField, PrimeCharacteristicRing};
222    use p3_field_testing::{
223        test_extension_field, test_field, test_frobenius, test_packed_extension_field,
224        test_two_adic_extension_field,
225    };
226
227    use crate::Goldilocks;
228
229    type F = Goldilocks;
230    type EF = CubicTrinomialExtensionField<F>;
231
232    const ZEROS: [EF; 1] = [EF::ZERO];
233    const ONES: [EF; 1] = [EF::ONE];
234
235    fn multiplicative_group_prime_factorization() -> [(BigUint, u32); 9] {
236        [
237            (BigUint::from(2u8), 32),
238            (BigUint::from(3u8), 2),
239            (BigUint::from(5u8), 1),
240            (BigUint::from(17u8), 1),
241            (BigUint::from(257u16), 1),
242            (BigUint::from(937u16), 1),
243            (BigUint::from(65537u32), 1),
244            (BigUint::from(724723u32), 1),
245            (BigUint::from(167034643597991036904547663171u128), 1),
246        ]
247    }
248
249    // TODO: Consider generalizing and putting into test_extension_field!
250    #[test]
251    fn test_defining_relation() {
252        let x = EF::new([F::ZERO, F::ONE, F::ZERO]);
253        let x_cubed = x * x * x;
254        let x_plus_one = x + EF::ONE;
255        assert_eq!(x_cubed, x_plus_one, "X^3 should equal X + 1");
256    }
257
258    test_field!(
259        super::EF,
260        &super::ZEROS,
261        &super::ONES,
262        &super::multiplicative_group_prime_factorization()
263    );
264
265    test_extension_field!(super::F, super::EF);
266    test_two_adic_extension_field!(super::F, super::EF);
267    test_frobenius!(super::F, super::EF);
268
269    type Pef = <EF as ExtensionField<F>>::ExtensionPacking;
270    const PACKED_ZEROS: [Pef; 1] = [Pef::ZERO];
271    const PACKED_ONES: [Pef; 1] = [Pef::ONE];
272    test_packed_extension_field!(
273        super::F,
274        super::EF,
275        super::Pef,
276        &super::PACKED_ZEROS,
277        &super::PACKED_ONES
278    );
279}
280
281#[cfg(test)]
282mod test_quintic_extension {
283
284    use num_bigint::BigUint;
285    use p3_field::extension::BinomialExtensionField;
286    use p3_field::{ExtensionField, PrimeCharacteristicRing};
287    use p3_field_testing::{
288        test_extension_field, test_field, test_packed_extension_field,
289        test_two_adic_extension_field,
290    };
291
292    use crate::Goldilocks;
293
294    type F = Goldilocks;
295    type EF = BinomialExtensionField<F, 5>;
296
297    // There is a redundant representation of zero but we already tested it
298    // when testing the base field.
299    const ZEROS: [EF; 1] = [EF::ZERO];
300    const ONES: [EF; 1] = [EF::ONE];
301
302    // Get the prime factorization of the order of the multiplicative group.
303    // i.e. the prime factorization of P^5 - 1.
304    fn multiplicative_group_prime_factorization() -> [(num_bigint::BigUint, u32); 10] {
305        [
306            (BigUint::from(2u8), 32),
307            (BigUint::from(3u8), 1),
308            (BigUint::from(5u8), 2),
309            (BigUint::from(17u8), 1),
310            (BigUint::from(257u16), 1),
311            (BigUint::from(45971u16), 1),
312            (BigUint::from(65537u32), 1),
313            (BigUint::from(255006435240067831u64), 1),
314            (BigUint::from(280083648770327405561u128), 1),
315            (BigUint::from(7053197395277272939628824863222181u128), 1),
316        ]
317    }
318
319    test_field!(
320        super::EF,
321        &super::ZEROS,
322        &super::ONES,
323        &super::multiplicative_group_prime_factorization()
324    );
325
326    test_extension_field!(super::F, super::EF);
327    test_two_adic_extension_field!(super::F, super::EF);
328
329    type Pef = <EF as ExtensionField<F>>::ExtensionPacking;
330    const PACKED_ZEROS: [Pef; 1] = [Pef::ZERO];
331    const PACKED_ONES: [Pef; 1] = [Pef::ONE];
332    test_packed_extension_field!(
333        super::F,
334        super::EF,
335        super::Pef,
336        &super::PACKED_ZEROS,
337        &super::PACKED_ONES
338    );
339    p3_field_testing::test_packed_binomial_extension_division!(F, 5);
340}