fss_rs/group/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2023 Yulong Ming (myl7)
3
4//! See [Group].
5
6use std::ops::{Add, AddAssign, Neg};
7
8pub mod byte;
9pub mod int;
10pub mod int_prime;
11
12/// Group (mathematics).
13/// Which has:
14///
15/// - Associative operation.
16/// - Identity element.
17/// - Inverse element.
18pub trait Group<const BLEN: usize>
19where
20    Self: Add<Output = Self>
21        + AddAssign
22        + Neg<Output = Self>
23        + PartialEq
24        + Eq
25        + Clone
26        + Sync
27        + Send
28        + From<[u8; BLEN]>,
29{
30    /// Identity element.
31    ///
32    /// E.g., 0 in the integer group.
33    ///
34    /// If the compiler cannot infer `BLEN` with this static method, you can use the fully qualified syntax like:
35    ///
36    /// ```
37    /// use fss_rs::group::Group;
38    /// use fss_rs::group::byte::ByteGroup;
39    ///
40    /// let e: ByteGroup<16> = Group::<16>::zero();
41    /// ```
42    fn zero() -> Self;
43
44    /// Helper to get the inverse element if true.
45    ///
46    /// Used for expressions like `$(-1)^n x$`, in which `t` can be computed from `n`.
47    fn neg_if(self, t: bool) -> Self {
48        if t {
49            -self
50        } else {
51            self
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    #[macro_export]
59    macro_rules! test_group_axioms {
60        ($test:ident, $t_impl:ty, $blen:literal) => {
61            #[test]
62            fn $test() {
63                arbtest::arbtest(|u| {
64                    let a_bs: [u8; $blen] = u.arbitrary()?;
65                    let a: $t_impl = a_bs.into();
66                    let b_bs: [u8; $blen] = u.arbitrary()?;
67                    let b: $t_impl = b_bs.into();
68                    let c_bs: [u8; $blen] = u.arbitrary()?;
69                    let c: $t_impl = c_bs.into();
70                    let e: $t_impl = crate::group::Group::<$blen>::zero();
71                    let a_inv = -a.clone();
72
73                    let l = a.clone() + (b.clone() + c.clone());
74                    let r = (a.clone() + b.clone()) + c.clone();
75                    assert_eq!(l, r, "associativity");
76
77                    let l0 = a.clone() + e.clone();
78                    let r0 = a.clone();
79                    assert_eq!(l0, r0, "identity element");
80                    let l1 = e.clone() + a.clone();
81                    let r1 = a.clone();
82                    assert_eq!(l1, r1, "identity element");
83
84                    let l0 = a.clone() + a_inv.clone();
85                    let r0 = e.clone();
86                    assert_eq!(l0, r0, "inverse element");
87                    let l1 = a_inv.clone() + a.clone();
88                    let r1 = e.clone();
89                    assert_eq!(l1, r1, "inverse element");
90
91                    Ok(())
92                });
93            }
94        };
95    }
96}