1use core::fmt;
4use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
11#[repr(transparent)]
12pub struct GF2(u8);
13
14impl GF2 {
15 pub const ZERO: Self = GF2(0);
16 pub const ONE: Self = GF2(1);
17
18 #[inline]
20 #[must_use]
21 pub const fn new(value: u8) -> Self {
22 GF2(value & 1)
23 }
24
25 #[inline]
27 #[must_use]
28 pub const fn from_bool(value: bool) -> Self {
29 GF2(value as u8)
30 }
31
32 #[inline]
34 #[must_use]
35 pub const fn value(self) -> u8 {
36 self.0
37 }
38
39 #[inline]
41 #[must_use]
42 pub const fn is_zero_element(self) -> bool {
43 self.0 == 0
44 }
45
46 #[inline]
48 #[must_use]
49 pub const fn is_one(self) -> bool {
50 self.0 == 1
51 }
52
53 #[inline]
55 #[must_use]
56 pub const fn inverse(self) -> Option<Self> {
57 if self.0 == 1 {
58 Some(self)
59 } else {
60 None
61 }
62 }
63}
64
65#[allow(clippy::suspicious_arithmetic_impl)]
69impl Add for GF2 {
70 type Output = Self;
71 #[inline]
72 fn add(self, rhs: Self) -> Self {
73 GF2(self.0 ^ rhs.0)
74 }
75}
76
77#[allow(clippy::suspicious_arithmetic_impl)]
78impl Sub for GF2 {
79 type Output = Self;
80 #[inline]
81 fn sub(self, rhs: Self) -> Self {
82 GF2(self.0 ^ rhs.0) }
84}
85
86#[allow(clippy::suspicious_arithmetic_impl)]
87impl Mul for GF2 {
88 type Output = Self;
89 #[inline]
90 fn mul(self, rhs: Self) -> Self {
91 GF2(self.0 & rhs.0)
92 }
93}
94
95impl Neg for GF2 {
96 type Output = Self;
97 #[inline]
98 fn neg(self) -> Self {
99 self }
101}
102
103#[allow(clippy::suspicious_op_assign_impl)]
104impl AddAssign for GF2 {
105 #[inline]
106 fn add_assign(&mut self, rhs: Self) {
107 self.0 ^= rhs.0;
108 }
109}
110
111#[allow(clippy::suspicious_op_assign_impl)]
112impl SubAssign for GF2 {
113 #[inline]
114 fn sub_assign(&mut self, rhs: Self) {
115 self.0 ^= rhs.0;
116 }
117}
118
119#[allow(clippy::suspicious_op_assign_impl)]
120impl MulAssign for GF2 {
121 #[inline]
122 fn mul_assign(&mut self, rhs: Self) {
123 self.0 &= rhs.0;
124 }
125}
126
127impl From<bool> for GF2 {
130 #[inline]
131 fn from(value: bool) -> Self {
132 GF2(value as u8)
133 }
134}
135
136impl From<u8> for GF2 {
137 #[inline]
138 fn from(value: u8) -> Self {
139 GF2(value & 1)
140 }
141}
142
143impl From<GF2> for bool {
144 #[inline]
145 fn from(value: GF2) -> Self {
146 value.0 != 0
147 }
148}
149
150impl From<GF2> for u8 {
151 #[inline]
152 fn from(value: GF2) -> Self {
153 value.0
154 }
155}
156
157impl fmt::Display for GF2 {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 write!(f, "{}", self.0)
162 }
163}
164
165impl num_traits::Zero for GF2 {
168 #[inline]
169 fn zero() -> Self {
170 GF2::ZERO
171 }
172 #[inline]
173 fn is_zero(&self) -> bool {
174 self.0 == 0
175 }
176}
177
178impl num_traits::One for GF2 {
179 #[inline]
180 fn one() -> Self {
181 GF2::ONE
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_field_addition() {
191 assert_eq!(GF2::ZERO + GF2::ZERO, GF2::ZERO);
192 assert_eq!(GF2::ZERO + GF2::ONE, GF2::ONE);
193 assert_eq!(GF2::ONE + GF2::ZERO, GF2::ONE);
194 assert_eq!(GF2::ONE + GF2::ONE, GF2::ZERO);
195 }
196
197 #[test]
198 fn test_field_multiplication() {
199 assert_eq!(GF2::ZERO * GF2::ZERO, GF2::ZERO);
200 assert_eq!(GF2::ZERO * GF2::ONE, GF2::ZERO);
201 assert_eq!(GF2::ONE * GF2::ZERO, GF2::ZERO);
202 assert_eq!(GF2::ONE * GF2::ONE, GF2::ONE);
203 }
204
205 #[test]
206 fn test_distributivity() {
207 for &a in &[GF2::ZERO, GF2::ONE] {
208 for &b in &[GF2::ZERO, GF2::ONE] {
209 for &c in &[GF2::ZERO, GF2::ONE] {
210 assert_eq!(a * (b + c), a * b + a * c);
211 }
212 }
213 }
214 }
215
216 #[test]
217 fn test_self_inverse() {
218 assert_eq!(GF2::ZERO + GF2::ZERO, GF2::ZERO);
220 assert_eq!(GF2::ONE + GF2::ONE, GF2::ZERO);
221 assert_eq!(-GF2::ZERO, GF2::ZERO);
223 assert_eq!(-GF2::ONE, GF2::ONE);
224 }
225
226 #[test]
227 fn test_multiplicative_inverse() {
228 assert_eq!(GF2::ONE.inverse(), Some(GF2::ONE));
229 assert_eq!(GF2::ZERO.inverse(), None);
230 }
231
232 #[test]
233 fn test_conversions() {
234 assert_eq!(GF2::from(true), GF2::ONE);
235 assert_eq!(GF2::from(false), GF2::ZERO);
236 assert_eq!(GF2::new(5), GF2::ONE); assert_eq!(GF2::new(4), GF2::ZERO); assert!(bool::from(GF2::ONE));
239 assert!(!bool::from(GF2::ZERO));
240 }
241}