1use crate::bytes::FieldBytes;
20use crate::error::Error;
21use crate::field::Field;
22
23const P: u64 = 0xFFFF_FFFF_0000_0001;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub struct BFieldElement(u64);
52
53impl BFieldElement {
54 #[must_use]
56 pub fn new(value: u64) -> Self {
57 Self(value % P)
58 }
59
60 #[must_use]
62 pub fn value(self) -> u64 {
63 self.0
64 }
65
66 fn reduce(x: u128) -> u64 {
73 let p_128 = u128::from(P);
74 u64::try_from(x % p_128).unwrap_or_default()
75 }
76}
77
78impl core::fmt::Display for BFieldElement {
79 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80 write!(f, "{}", self.0)
81 }
82}
83
84impl std::ops::Add for BFieldElement {
85 type Output = Self;
86 fn add(self, rhs: Self) -> Self {
87 Self(Self::reduce(u128::from(self.0) + u128::from(rhs.0)))
88 }
89}
90
91impl std::ops::Sub for BFieldElement {
92 type Output = Self;
93 fn sub(self, rhs: Self) -> Self {
94 let lhs = u128::from(self.0) + u128::from(P);
96 Self(Self::reduce(lhs - u128::from(rhs.0)))
97 }
98}
99
100impl std::ops::Mul for BFieldElement {
101 type Output = Self;
102 fn mul(self, rhs: Self) -> Self {
103 Self(Self::reduce(u128::from(self.0) * u128::from(rhs.0)))
104 }
105}
106
107impl std::ops::Neg for BFieldElement {
108 type Output = Self;
109 fn neg(self) -> Self {
110 if self.0 == 0 {
111 Self(0)
112 } else {
113 Self(P - self.0)
114 }
115 }
116}
117
118impl Field for BFieldElement {
119 fn zero() -> Self {
120 Self(0)
121 }
122
123 fn one() -> Self {
124 Self(1)
125 }
126
127 fn inv(&self) -> Result<Self, Error> {
128 if self.0 == 0 {
129 Err(Error::DivisionByZero)
130 } else {
131 Ok(pow(*self, P - 2))
133 }
134 }
135}
136
137impl FieldBytes for BFieldElement {
138 fn to_le_bytes(&self) -> Vec<u8> {
139 self.0.to_le_bytes().to_vec()
140 }
141
142 fn from_le_bytes(bytes: &[u8]) -> Result<Self, Error> {
143 bytes
144 .get(..8)
145 .ok_or(Error::InvalidFieldEncoding)
146 .and_then(|slice| <[u8; 8]>::try_from(slice).map_err(|_| Error::InvalidFieldEncoding))
147 .map(u64::from_le_bytes)
148 .map(Self::new)
149 }
150}
151
152fn pow(base: BFieldElement, exp: u64) -> BFieldElement {
158 std::iter::successors(Some(base), |&b| Some(b * b))
159 .zip(0..u64::BITS)
160 .filter(|&(_, i)| (exp >> i) & 1 == 1)
161 .map(|(p, _)| p)
162 .fold(BFieldElement::one(), |acc, p| acc * p)
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn modulus_constant_is_correct() {
171 assert_eq!(P, 0xFFFF_FFFF_0000_0001);
173 assert_eq!(P, 18_446_744_069_414_584_321);
174 }
175
176 #[test]
177 fn zero_is_additive_identity() {
178 let a = BFieldElement::new(123_456_789);
179 assert_eq!(a + BFieldElement::zero(), a);
180 assert_eq!(BFieldElement::zero() + a, a);
181 }
182
183 #[test]
184 fn one_is_multiplicative_identity() {
185 let a = BFieldElement::new(123_456_789);
186 assert_eq!(a * BFieldElement::one(), a);
187 assert_eq!(BFieldElement::one() * a, a);
188 }
189
190 #[test]
191 fn additive_inverse() {
192 let a = BFieldElement::new(999_999_999_999);
193 assert_eq!(a + (-a), BFieldElement::zero());
194 }
195
196 #[test]
197 fn multiplicative_inverse() -> Result<(), Error> {
198 let a = BFieldElement::new(42);
199 let a_inv = a.inv()?;
200 assert_eq!(a * a_inv, BFieldElement::one());
201 Ok(())
202 }
203
204 #[test]
205 fn inverse_of_zero_fails() {
206 let result = BFieldElement::zero().inv();
207 assert!(result.is_err());
208 }
209
210 #[test]
211 fn sample_inverses() -> Result<(), Error> {
212 let samples = [1u64, 2, 7, 100, 1_000_000, 1_000_000_000_000, P - 1, P - 2];
213 samples.iter().try_for_each(|&v| {
214 let a = BFieldElement::new(v);
215 let a_inv = a.inv()?;
216 assert_eq!(a * a_inv, BFieldElement::one(), "failed for {v}");
217 Ok(())
218 })
219 }
220
221 #[test]
222 fn subtraction_is_add_neg() {
223 let a = BFieldElement::new(123_456_789_000);
224 let b = BFieldElement::new(987_654_321);
225 assert_eq!(a - b, a + (-b));
226 }
227
228 #[test]
229 fn multiplication_is_commutative() {
230 let a = BFieldElement::new(12_345_678);
231 let b = BFieldElement::new(98_765_432);
232 assert_eq!(a * b, b * a);
233 }
234
235 #[test]
236 fn distributivity() {
237 let a = BFieldElement::new(111_111);
238 let b = BFieldElement::new(222_222);
239 let c = BFieldElement::new(333_333);
240 assert_eq!(a * (b + c), a * b + a * c);
241 }
242
243 #[test]
244 fn new_reduces_mod_p() {
245 assert_eq!(BFieldElement::new(P), BFieldElement::new(0));
246 assert_eq!(BFieldElement::new(P + 1), BFieldElement::new(1));
247 }
248
249 #[test]
250 fn p_minus_one_squared_is_one() -> Result<(), Error> {
251 let neg_one = BFieldElement::new(P - 1);
253 assert_eq!(neg_one * neg_one, BFieldElement::one());
254 let neg_one_inv = neg_one.inv()?;
256 assert_eq!(neg_one_inv, neg_one);
257 Ok(())
258 }
259
260 #[test]
261 fn high_u64_values_multiply_without_overflow() {
262 let a = BFieldElement::new(P - 5);
264 let b = BFieldElement::new(P - 7);
265 assert_eq!(a * b, BFieldElement::new(35));
267 }
268
269 #[test]
270 fn bytes_roundtrip() -> Result<(), Error> {
271 let a = BFieldElement::new(0xDEAD_BEEF_1234_5678);
272 let bytes = a.to_le_bytes();
273 let b = BFieldElement::from_le_bytes(&bytes)?;
274 assert_eq!(a, b);
275 Ok(())
276 }
277
278 #[test]
279 fn bytes_zero_roundtrip() -> Result<(), Error> {
280 let a = BFieldElement::zero();
281 let b = BFieldElement::from_le_bytes(&a.to_le_bytes())?;
282 assert_eq!(a, b);
283 Ok(())
284 }
285
286 #[test]
287 fn bytes_too_short_fails() {
288 let result = BFieldElement::from_le_bytes(&[1, 2, 3]);
289 assert!(result.is_err());
290 }
291
292 #[test]
293 fn bytes_empty_fails() {
294 let result = BFieldElement::from_le_bytes(&[]);
295 assert!(result.is_err());
296 }
297}