finitelib/field.rs
1//! A module that contains a trait for mathematical field objects.
2//!
3//! Go to [Field](crate::field::Field) to view the implementation example.
4
5use crate::utils;
6use crate::group::Group;
7
8
9/// A trait for a field over the type `Item`.
10///
11/// Use example:
12///
13/// ```
14/// use finitelib::field::Field;
15/// use finitelib::ring::EuclideanRing;
16/// use finitelib::common::rings::Ri64;
17///
18/// struct GF(u64);
19///
20/// impl Field for GF {
21/// type Item = u64;
22///
23/// fn zero(&self) -> Self::Item {
24/// 0
25/// }
26///
27/// fn one(&self) -> Self::Item {
28/// 1
29/// }
30///
31/// fn eq(&self, a: &Self::Item, b: &Self::Item) -> bool {
32/// a == b
33/// }
34///
35/// fn add(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
36/// (a + b) % self.0
37/// }
38///
39/// fn mul(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
40/// (a * b) % self.0
41/// }
42///
43/// fn neg(&self, a: &Self::Item) -> Self::Item {
44/// if *a == 0 { 0 } else { self.0 - *a }
45/// }
46///
47/// fn inv(&self, a: &Self::Item) -> Option<Self::Item> {
48/// if *a == 0 {
49/// None
50/// } else {
51/// let mut b = Ri64.euclidean_extended(
52/// &(*a as i64), &(self.0 as i64)
53/// ).1;
54/// Some(b.rem_euclid(self.0 as i64) as u64)
55/// }
56/// }
57/// }
58///
59/// let gf11 = GF(11);
60///
61/// assert_eq!(gf11.zero(), 0);
62/// assert_eq!(gf11.one(), 1);
63/// assert_eq!(gf11.eq(&5, &5), true);
64/// assert_eq!(gf11.add(&7, &8), 4);
65/// assert_eq!(gf11.mul(&7, &8), 1);
66/// assert_eq!(gf11.neg(&7), 4);
67/// assert_eq!(gf11.neg(&0), 0);
68/// assert_eq!(gf11.inv(&7), Some(8));
69/// assert_eq!(gf11.inv(&1), Some(1));
70/// assert_eq!(gf11.inv(&0), None);
71/// assert_eq!(gf11.mul_scalar(&7, [true, false, true].into_iter()), 2);
72/// assert_eq!(gf11.pow_scalar(&7, [true, false, true].into_iter()), 10);
73/// ```
74pub trait Field where
75 Self::Item: Clone {
76 /// The type of the field elements.
77 type Item;
78
79 /// Get the zero element of the field (the identity by addition).
80 fn zero(&self) -> Self::Item;
81
82 /// Get the one element of the field (the identity by multiplication).
83 fn one(&self) -> Self::Item;
84
85 /// Perform the equity operation in the field.
86 fn eq(&self, a: &Self::Item, b: &Self::Item) -> bool;
87
88 /// Perform addition operation in the field.
89 fn add(&self, a: &Self::Item, b: &Self::Item) -> Self::Item;
90
91 /// Perform multiplication operation in the field.
92 fn mul(&self, a: &Self::Item, b: &Self::Item) -> Self::Item;
93
94 /// Get inversed element by addition.
95 fn neg(&self, a: &Self::Item) -> Self::Item;
96
97 /// Get inversed element by multiplication.
98 fn inv(&self, a: &Self::Item) -> Option<Self::Item>;
99
100 /// Perform multiplication in the group by a scalar given as an iterator
101 /// of bits according to [the double and add algorithm](https://en.wikipedia.org/wiki/Exponentiation_by_squaring).
102 fn mul_scalar<I>(&self, a: &Self::Item, bits_iter: I) -> Self::Item
103 where I: Iterator<Item = bool> {
104 utils::exp_by_sqr(a, bits_iter, || self.zero(), |a, b| self.add(a, b))
105 }
106
107 /// Perform multiplication in the group by a scalar given as an iterator
108 /// of bits according to [the exponentiation by squaring algorithm](https://en.wikipedia.org/wiki/Exponentiation_by_squaring).
109 fn pow_scalar<I>(&self, a: &Self::Item, bits_iter: I) -> Self::Item
110 where I: Iterator<Item = bool> {
111 utils::exp_by_sqr(a, bits_iter, || self.one(), |a, b| self.mul(a, b))
112 }
113
114 /// Perform `sub` operation. By default it is implemented through
115 /// `add` and `neg` but it can be overridden for optimization purposes.
116 fn sub(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
117 self.add(a, &self.neg(b))
118 }
119
120 /// Perform `div` operation. By default it is implemented through
121 /// `mul` and `inv` but it can be overridden for optimization purposes.
122 fn div(&self, a: &Self::Item, b: &Self::Item) -> Option<Self::Item> {
123 self.inv(b).map(|i| self.mul(a, &i))
124 }
125
126 /// Perform `add_assign` operation. By default it is implemented through
127 /// `add` but it can be overridden for optimization purposes.
128 fn add_assign(&self, a: &mut Self::Item, b: &Self::Item) {
129 *a = self.add(a, b);
130 }
131
132 /// Perform `sub_assign` operation. By default it is implemented through
133 /// `sub` but it can be overridden for optimization purposes.
134 fn sub_assign(&self, a: &mut Self::Item, b: &Self::Item) {
135 *a = self.sub(a, b);
136 }
137
138 /// Perform `mul_assign` operation. By default it is implemented through
139 /// `mul` but it can be overridden for optimization purposes.
140 fn mul_assign(&self, a: &mut Self::Item, b: &Self::Item) {
141 *a = self.mul(a, b);
142 }
143
144 /// Perform `div_assign` operation. By default it is implemented through
145 /// `div` but it can be overridden for optimization purposes.
146 fn div_assign(&self, a: &mut Self::Item, b: &Self::Item) {
147 *a = self.div(a, b).unwrap();
148 }
149
150 /// Perform `neg_assign` operation. By default it is implemented through
151 /// `neg` but it can be overridden for optimization purposes.
152 fn neg_assign(&self, a: &mut Self::Item) {
153 *a = self.neg(a);
154 }
155
156 /// Perform `inv_assign` operation. By default it is implemented through
157 /// `inv` but it can be overridden for optimization purposes.
158 fn inv_assign(&self, a: &mut Self::Item) {
159 *a = self.inv(a).unwrap();
160 }
161
162 /// Perform `mul_scalar_assign` operation. By default it is implemented
163 /// through `mul_scalar` but it can be overridden for optimization purposes.
164 fn mul_scalar_assign<I>(&self, a: &mut Self::Item, bits_iter: I)
165 where I: Iterator<Item = bool> {
166 *a = self.mul_scalar(a, bits_iter);
167 }
168
169 /// Perform `pow_scalar_assign` operation. By default it is implemented
170 /// through `pow_scalar` but it can be overridden for optimization purposes.
171 fn pow_scalar_assign<I>(&self, a: &mut Self::Item, bits_iter: I)
172 where I: Iterator<Item = bool> {
173 *a = self.pow_scalar(a, bits_iter);
174 }
175
176 /// Represent the field as a group by addition.
177 fn as_add_group(&self) -> FieldAddGroup<Self> {
178 FieldAddGroup {
179 field: self
180 }
181 }
182
183 /// Represent the field as a group by multiplication.
184 fn as_mul_group(&self) -> FieldMulGroup<Self> {
185 FieldMulGroup {
186 field: self
187 }
188 }
189}
190
191
192/// Addition group over a field.
193///
194/// Example:
195///
196/// ```rust
197/// use finitelib::prelude::*;
198/// use finitelib::common::fields::Ff64;
199///
200/// let g_add = Ff64.as_add_group();
201///
202/// assert_eq!(g_add.zero(), 0.0);
203/// assert_eq!(g_add.add(&3.0, &5.0), 8.0);
204/// ```
205pub struct FieldAddGroup<'a, F: ?Sized> {
206 field: &'a F,
207}
208
209
210impl<'a, F: Field> Group for FieldAddGroup<'a, F> {
211 type Item = F::Item;
212
213 fn zero(&self) -> Self::Item {
214 self.field.zero()
215 }
216
217 fn eq(&self, a: &Self::Item, b: &Self::Item) -> bool {
218 self.field.eq(a, b)
219 }
220
221 fn add(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
222 self.field.add(a, b)
223 }
224
225 fn neg(&self, a: &Self::Item) -> Self::Item {
226 self.field.neg(a)
227 }
228
229 fn mul_scalar<I>(&self, a: &Self::Item, bits_iter: I) -> Self::Item
230 where I: Iterator<Item = bool> {
231 self.field.mul_scalar(a, bits_iter)
232 }
233
234 fn sub(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
235 self.field.sub(a, b)
236 }
237
238 fn add_assign(&self, a: &mut Self::Item, b: &Self::Item) {
239 self.field.add_assign(a, b);
240 }
241
242 fn sub_assign(&self, a: &mut Self::Item, b: &Self::Item) {
243 self.field.sub_assign(a, b);
244 }
245
246 fn neg_assign(&self, a: &mut Self::Item) {
247 self.field.neg_assign(a);
248 }
249
250 fn mul_scalar_assign<I>(&self, a: &mut Self::Item, bits_iter: I)
251 where I: Iterator<Item = bool> {
252 self.field.mul_scalar_assign(a, bits_iter);
253 }
254}
255
256
257/// Multiplication group over a field.
258///
259/// Example:
260///
261/// ```rust
262/// use finitelib::prelude::*;
263/// use finitelib::common::fields::Ff64;
264///
265/// let g_mul = Ff64.as_mul_group();
266///
267/// assert_eq!(g_mul.zero(), 1.0);
268/// assert_eq!(g_mul.add(&3.0, &5.0), 15.0);
269/// ```
270pub struct FieldMulGroup<'a, F: ?Sized> {
271 field: &'a F,
272}
273
274
275impl<'a, F: Field> Group for FieldMulGroup<'a, F> {
276 type Item = F::Item;
277
278 fn zero(&self) -> Self::Item {
279 self.field.one()
280 }
281
282 fn eq(&self, a: &Self::Item, b: &Self::Item) -> bool {
283 self.field.eq(a, b)
284 }
285
286 fn add(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
287 self.field.mul(a, b)
288 }
289
290 fn neg(&self, a: &Self::Item) -> Self::Item {
291 self.field.inv(a).unwrap()
292 }
293
294 fn mul_scalar<I>(&self, a: &Self::Item, bits_iter: I) -> Self::Item
295 where I: Iterator<Item = bool> {
296 self.field.pow_scalar(a, bits_iter)
297 }
298
299 fn sub(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
300 self.field.div(a, b).unwrap()
301 }
302
303 fn add_assign(&self, a: &mut Self::Item, b: &Self::Item) {
304 self.field.mul_assign(a, b);
305 }
306
307 fn sub_assign(&self, a: &mut Self::Item, b: &Self::Item) {
308 self.field.div_assign(a, b);
309 }
310
311 fn neg_assign(&self, a: &mut Self::Item) {
312 self.field.inv_assign(a);
313 }
314
315 fn mul_scalar_assign<I>(&self, a: &mut Self::Item, bits_iter: I)
316 where I: Iterator<Item = bool> {
317 self.field.pow_scalar_assign(a, bits_iter);
318 }
319}
320
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325 use crate::common::fields::Ff32;
326
327 #[test]
328 fn test_as_add_group() {
329 let g_add = Ff32.as_add_group();
330 assert_eq!(g_add.zero(), 0.0);
331 assert_eq!(g_add.eq(&3.5, &3.5), true);
332 assert_eq!(g_add.add(&3.5, &1.5), 5.0);
333 assert_eq!(g_add.neg(&3.5), -3.5);
334 }
335
336 #[test]
337 fn test_as_mul_group() {
338 let g_mul = Ff32.as_mul_group();
339 assert_eq!(g_mul.zero(), 1.0);
340 assert_eq!(g_mul.eq(&3.5, &3.5), true);
341 assert_eq!(g_mul.add(&3.5, &1.5), 5.25);
342 assert_eq!(g_mul.neg(&0.5), 2.0);
343 }
344}