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}