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) -> Option<()> {
147        *a = self.div(a, b)?;
148        Some(())
149    }
150
151    /// Perform `neg_assign` operation. By default it is implemented through 
152    /// `neg` but it can be overridden for optimization purposes.
153    fn neg_assign(&self, a: &mut Self::Item) {
154        *a = self.neg(a);
155    }
156
157    /// Perform `inv_assign` operation. By default it is implemented through 
158    /// `inv` but it can be overridden for optimization purposes.
159    fn inv_assign(&self, a: &mut Self::Item) -> Option<()> {
160        *a = self.inv(a)?;
161        Some(())
162    }
163
164    /// Perform `mul_scalar_assign` operation. By default it is implemented  
165    /// through `mul_scalar` but it can be overridden for optimization purposes.
166    fn mul_scalar_assign<I>(&self, a: &mut Self::Item, bits_iter: I)
167            where I: Iterator<Item = bool> {
168        *a = self.mul_scalar(a, bits_iter);
169    }
170
171    /// Perform `pow_scalar_assign` operation. By default it is implemented  
172    /// through `pow_scalar` but it can be overridden for optimization purposes.
173    fn pow_scalar_assign<I>(&self, a: &mut Self::Item, bits_iter: I)
174            where I: Iterator<Item = bool> {
175        *a = self.pow_scalar(a, bits_iter);
176    }
177
178    /// Represent the field as a group by addition.
179    fn as_add_group(&self) -> FieldAddGroup<Self> {
180        FieldAddGroup {
181            field: self
182        }
183    }
184
185    /// Represent the field as a group by multiplication.
186    fn as_mul_group(&self) -> FieldMulGroup<Self> {
187        FieldMulGroup {
188            field: self
189        }
190    }
191}
192
193
194/// Addition group over a field.
195///
196/// Example:
197///
198/// ```rust
199/// use finitelib::prelude::*;
200/// use finitelib::common::fields::Ff64;
201///
202/// let g_add = Ff64.as_add_group();
203///
204/// assert_eq!(g_add.zero(), 0.0);
205/// assert_eq!(g_add.add(&3.0, &5.0), 8.0);
206/// ```
207pub struct FieldAddGroup<'a, F: ?Sized> {
208    field: &'a F,
209}
210
211
212impl<'a, F: Field> Group for FieldAddGroup<'a, F> {
213    type Item = F::Item;
214
215    fn zero(&self) -> Self::Item {
216        self.field.zero()
217    }
218
219    fn eq(&self, a: &Self::Item, b: &Self::Item) -> bool {
220        self.field.eq(a, b)
221    }
222
223    fn add(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
224        self.field.add(a, b)
225    }
226
227    fn neg(&self, a: &Self::Item) -> Self::Item {
228        self.field.neg(a)
229    }
230
231    fn mul_scalar<I>(&self, a: &Self::Item, bits_iter: I) -> Self::Item 
232            where I: Iterator<Item = bool> {
233        self.field.mul_scalar(a, bits_iter)
234    }
235
236    fn sub(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
237        self.field.sub(a, b)
238    }
239
240    fn add_assign(&self, a: &mut Self::Item, b: &Self::Item) {
241        self.field.add_assign(a, b);
242    }
243
244    fn sub_assign(&self, a: &mut Self::Item, b: &Self::Item) {
245        self.field.sub_assign(a, b);
246    }
247
248    fn neg_assign(&self, a: &mut Self::Item) {
249        self.field.neg_assign(a);
250    }
251
252    fn mul_scalar_assign<I>(&self, a: &mut Self::Item, bits_iter: I)
253            where I: Iterator<Item = bool> {
254        self.field.mul_scalar_assign(a, bits_iter);
255    }
256}
257
258
259/// Multiplication group over a field.
260///
261/// Example:
262///
263/// ```rust
264/// use finitelib::prelude::*;
265/// use finitelib::common::fields::Ff64;
266///
267/// let g_mul = Ff64.as_mul_group();
268///
269/// assert_eq!(g_mul.zero(), 1.0);
270/// assert_eq!(g_mul.add(&3.0, &5.0), 15.0);
271/// ```
272pub struct FieldMulGroup<'a, F: ?Sized> {
273    field: &'a F,
274}
275
276
277impl<'a, F: Field> Group for FieldMulGroup<'a, F> {
278    type Item = F::Item;
279
280    fn zero(&self) -> Self::Item {
281        self.field.one()
282    }
283
284    fn eq(&self, a: &Self::Item, b: &Self::Item) -> bool {
285        self.field.eq(a, b)
286    }
287
288    fn add(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
289        self.field.mul(a, b)
290    }
291
292    fn neg(&self, a: &Self::Item) -> Self::Item {
293        self.field.inv(a).expect("zero division")
294    }
295
296    fn mul_scalar<I>(&self, a: &Self::Item, bits_iter: I) -> Self::Item 
297            where I: Iterator<Item = bool> {
298        self.field.pow_scalar(a, bits_iter)
299    }
300
301    fn sub(&self, a: &Self::Item, b: &Self::Item) -> Self::Item {
302        self.field.div(a, b).expect("zero division")
303    }
304
305    fn add_assign(&self, a: &mut Self::Item, b: &Self::Item) {
306        self.field.mul_assign(a, b);
307    }
308
309    fn sub_assign(&self, a: &mut Self::Item, b: &Self::Item) {
310        self.field.div_assign(a, b);
311    }
312
313    fn neg_assign(&self, a: &mut Self::Item) {
314        self.field.inv_assign(a);
315    }
316
317    fn mul_scalar_assign<I>(&self, a: &mut Self::Item, bits_iter: I)
318            where I: Iterator<Item = bool> {
319        self.field.pow_scalar_assign(a, bits_iter);
320    }
321}
322
323
324#[cfg(test)]
325mod tests {
326    use super::*;
327    use crate::common::fields::Ff32;
328
329    #[test]
330    fn test_as_add_group() {
331        let g_add = Ff32.as_add_group();
332        assert_eq!(g_add.zero(), 0.0);
333        assert_eq!(g_add.eq(&3.5, &3.5), true);
334        assert_eq!(g_add.add(&3.5, &1.5), 5.0);
335        assert_eq!(g_add.neg(&3.5), -3.5);
336    }
337
338    #[test]
339    fn test_as_mul_group() {
340        let g_mul = Ff32.as_mul_group();
341        assert_eq!(g_mul.zero(), 1.0);
342        assert_eq!(g_mul.eq(&3.5, &3.5), true);
343        assert_eq!(g_mul.add(&3.5, &1.5), 5.25);
344        assert_eq!(g_mul.neg(&0.5), 2.0);
345    }
346}