group_math/
int_prime.rs

1//! Group of an integer which is a `$p$`-group.
2//! `MOD` as the `$p$` is a prime number as the cardinality of the group.
3//! Some prime numbers that are the max ones less than or equal to `u*::MAX` are provided as `PRIME_MAX_LE_U*_MAX`.
4//!
5//! - Associative operation: Integer addition modulo `MOD`, `$(a + b) \mod MOD$`
6//! - Identity element: 0
7//! - Inverse element: `-x`
8
9use std::mem::size_of;
10use std::ops::{Add, AddAssign};
11
12use crate::Group;
13
14macro_rules! decl_int_prime_group {
15    ($t:ty, $t_impl:ident) => {
16        /// See [`self`]
17        #[derive(Debug, Clone, PartialEq, Eq)]
18        pub struct $t_impl<const MOD: $t>(
19            /// Always less than `MOD`
20            $t,
21        );
22
23        impl<const MOD: $t> $t_impl<MOD> {
24            pub fn new(x: $t) -> Self {
25                $t_impl(x % MOD)
26            }
27        }
28
29        impl<const MOD: $t> Add for $t_impl<MOD> {
30            type Output = Self;
31
32            fn add(self, rhs: Self) -> Self::Output {
33                $t_impl(match self.0.checked_add(rhs.0) {
34                    Some(x) => x % MOD,
35                    None => {
36                        (self.0.wrapping_add(rhs.0) % MOD)
37                            .wrapping_add(<$t>::MAX % MOD)
38                            .wrapping_add(1)
39                            % MOD
40                    }
41                })
42            }
43        }
44
45        impl<const MOD: $t> AddAssign for $t_impl<MOD> {
46            fn add_assign(&mut self, rhs: Self) {
47                self.0 = match self.0.checked_add(rhs.0) {
48                    Some(x) => x % MOD,
49                    None => {
50                        self.0
51                            .wrapping_add(rhs.0)
52                            .wrapping_add(<$t>::MAX % MOD)
53                            .wrapping_add(1)
54                            % MOD
55                    }
56                };
57            }
58        }
59
60        impl<const LAMBDA: usize, const MOD: $t> Group<LAMBDA> for $t_impl<MOD> {
61            fn zero() -> Self {
62                $t_impl(0)
63            }
64
65            fn add_inverse(mut self) -> Self {
66                self.0 = match self.0.checked_add(MOD) {
67                    Some(x) => x % MOD,
68                    None => {
69                        self.0
70                            .wrapping_add(MOD)
71                            .wrapping_add(<$t>::MAX % MOD)
72                            .wrapping_add(1)
73                            % MOD
74                    }
75                };
76                self
77            }
78        }
79
80        impl<const LAMBDA: usize, const MOD: $t> From<[u8; LAMBDA]> for $t_impl<MOD> {
81            fn from(value: [u8; LAMBDA]) -> Self {
82                if cfg!(not(feature = "int-be")) {
83                    $t_impl(<$t>::from_le_bytes(
84                        (&value[..size_of::<$t>()]).clone().try_into().unwrap(),
85                    ))
86                } else {
87                    $t_impl(<$t>::from_be_bytes(
88                        (&value[..size_of::<$t>()]).clone().try_into().unwrap(),
89                    ))
90                }
91            }
92        }
93
94        impl<const LAMBDA: usize, const MOD: $t> From<$t_impl<MOD>> for [u8; LAMBDA] {
95            fn from(value: $t_impl<MOD>) -> Self {
96                let mut bs = [0; LAMBDA];
97                if cfg!(not(feature = "int-be")) {
98                    bs[..size_of::<$t>()].copy_from_slice(&value.0.to_le_bytes());
99                } else {
100                    bs[..size_of::<$t>()].copy_from_slice(&value.0.to_be_bytes());
101                }
102                bs
103            }
104        }
105    };
106}
107
108decl_int_prime_group!(u8, U8Group);
109decl_int_prime_group!(u16, U16Group);
110decl_int_prime_group!(u32, U32Group);
111decl_int_prime_group!(u64, U64Group);
112decl_int_prime_group!(u128, U128Group);
113
114pub const PRIME_MAX_LE_U8_MAX: u8 = u8::MAX - 5 + 1;
115pub const PRIME_MAX_LE_U16_MAX: u16 = u16::MAX - 15 + 1;
116pub const PRIME_MAX_LE_U32_MAX: u32 = u32::MAX - 5 + 1;
117pub const PRIME_MAX_LE_U64_MAX: u64 = u64::MAX - 59 + 1;
118pub const PRIME_MAX_LE_U128_MAX: u128 = u128::MAX - 159 + 1;