Skip to main content

p3_goldilocks/
extension.rs

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