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 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 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 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 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 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 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}