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}