fp/field/
mod.rs

1use self::field_internal::FieldInternal;
2use crate::prime::Prime;
3
4pub mod element;
5pub(crate) mod field_internal;
6
7pub mod fp;
8pub mod smallfq;
9
10use element::FieldElement;
11pub use fp::Fp;
12pub use smallfq::SmallFq;
13
14pub trait Field: FieldInternal + Sized {
15    type Characteristic: Prime;
16
17    fn characteristic(self) -> Self::Characteristic;
18
19    fn degree(self) -> u32;
20
21    fn q(self) -> u32 {
22        self.characteristic().pow(self.degree())
23    }
24
25    fn zero(self) -> FieldElement<Self>;
26    fn one(self) -> FieldElement<Self>;
27
28    #[cfg(feature = "proptest")]
29    fn arb_element(self) -> impl proptest::strategy::Strategy<Value = FieldElement<Self>>;
30}
31
32#[cfg(test)]
33mod tests {
34    use proptest::prelude::*;
35
36    use super::{Field, SmallFq, element::FieldElement};
37    use crate::prime::P2;
38
39    #[test]
40    fn test_f_4() {
41        // Multiplication table generated by Sage.
42        let f4 = SmallFq::new(P2, 2);
43        let one = f4.one();
44        let a = f4.a();
45
46        let mut elements = vec![one];
47        for _ in 1..f4.q() {
48            let prev = elements.last().unwrap();
49            elements.push(*prev * a);
50        }
51
52        let expansions = vec![one, a, a + one, one];
53
54        assert_eq!(elements, expansions);
55    }
56
57    #[test]
58    fn test_f_8() {
59        // Multiplication table generated by Sage.
60        let f8 = SmallFq::new(P2, 3);
61        let one = f8.one();
62        let a = f8.a();
63        let a2 = a * a;
64
65        let mut elements = vec![one];
66        for _ in 1..f8.q() {
67            let prev = elements.last().unwrap();
68            elements.push(*prev * a);
69        }
70
71        let expansions = vec![one, a, a2, a + one, a2 + a, a2 + a + one, a2 + one, one];
72
73        assert_eq!(elements, expansions);
74    }
75
76    #[test]
77    fn test_f_16() {
78        // Multiplication table generated by Sage.
79        let f16 = SmallFq::new(P2, 4);
80        let one = f16.one();
81        let a = f16.a();
82        let a2 = a * a;
83        let a3 = a2 * a;
84
85        let mut elements = vec![one];
86        for _ in 1..f16.q() {
87            let prev = elements.last().unwrap();
88            elements.push(*prev * a);
89        }
90
91        let expansions = vec![
92            one,
93            a,
94            a2,
95            a3,
96            a + one,
97            a2 + a,
98            a3 + a2,
99            a3 + a + one,
100            a2 + one,
101            a3 + a,
102            a2 + a + one,
103            a3 + a2 + a,
104            a3 + a2 + a + one,
105            a3 + a2 + one,
106            a3 + one,
107            one,
108        ];
109
110        assert_eq!(elements, expansions);
111    }
112
113    #[cfg(feature = "odd-primes")]
114    #[test]
115    fn test_f_9() {
116        use crate::prime::P3;
117
118        // Multiplication table generated by Sage.
119        let f9 = SmallFq::new(P3, 2);
120
121        let one = f9.one();
122        let two = one + one;
123        let a = f9.a();
124
125        let mut elements = vec![one];
126        for _ in 1..f9.q() {
127            let prev = elements.last().unwrap();
128            elements.push(*prev * a);
129        }
130
131        let expansions = vec![
132            one,
133            a,
134            a + one,
135            two * a + one,
136            two,
137            two * a,
138            two * a + two,
139            a + two,
140            one,
141        ];
142
143        assert_eq!(elements, expansions);
144    }
145
146    pub(super) fn arb_elements<F: Field, const N: usize>()
147    -> impl Strategy<Value = (F, [FieldElement<F>; N])> {
148        any::<F>().prop_flat_map(move |f| (Just(f), std::array::from_fn(|_| f.arb_element())))
149    }
150
151    /// Test the field axioms and good behavior of the Frobenius endomorphism.
152    macro_rules! field_tests {
153        ($field:ty) => {
154            use proptest::prelude::*;
155
156            use crate::{
157                field::{element::FieldElement, Field},
158                prime::Prime,
159            };
160
161            // We shadow the `arb_elements` function with one that is specialized to the concrete
162            // field type we're working with
163            fn arb_elements<const N: usize>(
164            ) -> impl Strategy<Value = ($field, [FieldElement<$field>; N])> {
165                crate::field::tests::arb_elements()
166            }
167
168            proptest! {
169                #[test]
170                fn test_bit_length((f, []) in arb_elements()) {
171                    use crate::field::field_internal::FieldInternal;
172                    prop_assert!(f.bit_length() <= 63);
173                }
174
175                #[test]
176                fn test_addition_associative((_, [a, b, c]) in arb_elements()) {
177                    prop_assert_eq!((a + b) + c, a + (b + c));
178                }
179
180                #[test]
181                fn test_addition_identity((f, [a]) in arb_elements()) {
182                    prop_assert_eq!(a + f.zero(), a);
183                }
184
185                #[test]
186                fn test_addition_inverse((f, [a]) in arb_elements()) {
187                    prop_assert_eq!(a + (-a), f.zero());
188                }
189
190                #[test]
191                fn test_addition_commutative((_, [a, b]) in arb_elements()) {
192                    prop_assert_eq!(a + b, b + a);
193                }
194
195                #[test]
196                fn test_multiplication_associative((_, [a, b, c]) in arb_elements()) {
197                    prop_assert_eq!((a * b) * c, a * (b * c));
198                }
199
200                #[test]
201                fn test_multiplication_identity((f, [a]) in arb_elements()) {
202                    prop_assert_eq!(a * f.one(), a);
203                }
204
205                #[test]
206                fn test_multiplication_inverse((f, [a]) in arb_elements()) {
207                    if a != f.zero() {
208                        prop_assert_eq!(a * a.inv().unwrap(), f.one());
209                    }
210                }
211
212                #[test]
213                fn test_multiplication_commutative((_, [a, b]) in arb_elements()) {
214                    prop_assert_eq!(a * b, b * a);
215                }
216
217                #[test]
218                fn test_division_is_multiplication_by_inverse((f, [a, b]) in arb_elements()) {
219                    if b != f.zero() {
220                        prop_assert_eq!((a / b).unwrap(), a * b.inv().unwrap());
221                    }
222                }
223
224                #[test]
225                fn test_distributive((_, [a, b, c]) in arb_elements()) {
226                    prop_assert_eq!(a * (b + c), a * b + a * c);
227                }
228
229                #[test]
230                fn test_frobenius_is_pth_power((f, [a]) in arb_elements()) {
231                    let a_frob = a.frobenius();
232                    let a_pth_power = (0..f.characteristic().as_u32()).fold(f.one(), |acc, _| acc * a);
233                    prop_assert_eq!(a_frob, a_pth_power);
234                }
235
236                #[test]
237                fn test_frobenius_additive((_, [a, b]) in arb_elements()) {
238                    prop_assert_eq!((a + b).frobenius(), a.frobenius() + b.frobenius());
239                }
240
241                #[test]
242                fn test_frobenius_multiplicative((_, [a, b]) in arb_elements()) {
243                    prop_assert_eq!((a * b).frobenius(), a.frobenius() * b.frobenius());
244                }
245            }
246        };
247    }
248
249    pub(super) use field_tests;
250}