primitives/algebra/field/binary/
gf2.rs1use core::iter::{Product, Sum};
2use std::{
3 mem::MaybeUninit,
4 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
5};
6
7use ff::Field;
8use hybrid_array::Array;
9use serde::{Deserialize, Serialize};
10use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
11use typenum::U1;
12
13use crate::{
14 algebra::{
15 field::FieldExtension,
16 ops::{AccReduce, DefaultDotProduct, IntoWide, MulAccReduce, ReduceWide},
17 uniform_bytes::FromUniformBytes,
18 },
19 errors::PrimitiveError,
20 random::{CryptoRngCore, Random},
21 utils::codec::InPlaceCodec,
22};
23
24#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Deserialize, Serialize, Ord, PartialOrd)]
26#[repr(transparent)]
27pub struct Gf2(pub(super) u8);
28
29impl Default for Gf2 {
30 fn default() -> Self {
31 Gf2::ZERO
32 }
33}
34
35impl IntoWide for Gf2 {
36 #[inline]
37 fn to_wide(&self) -> Gf2 {
38 *self
39 }
40
41 #[inline]
42 fn zero_wide() -> Gf2 {
43 Gf2::ZERO
44 }
45}
46
47impl ReduceWide for Gf2 {
48 fn reduce_mod_order(a: Self) -> Self {
49 a
50 }
51}
52
53impl MulAccReduce for Gf2 {
55 type WideType = Self;
56
57 fn mul_acc(acc: &mut Self::WideType, a: Self, b: Self) {
58 acc.0 ^= a.0 & b.0;
59 }
60}
61
62impl DefaultDotProduct for Gf2 {}
63
64impl<'a> MulAccReduce<Self, &'a Self> for Gf2 {
66 type WideType = Self;
67
68 fn mul_acc(acc: &mut Self::WideType, a: Self, b: &'a Self) {
69 acc.0 ^= a.0 & b.0;
70 }
71}
72
73impl DefaultDotProduct<Self, &Self> for Gf2 {}
74
75impl<'a> MulAccReduce<&'a Self, Self> for Gf2 {
77 type WideType = Self;
78
79 fn mul_acc(acc: &mut Self::WideType, a: &'a Self, b: Self) {
80 acc.0 ^= a.0 & b.0;
81 }
82}
83
84impl DefaultDotProduct<&Self, Self> for Gf2 {}
85
86impl<'a, 'b> MulAccReduce<&'a Self, &'b Self> for Gf2 {
88 type WideType = Self;
89
90 fn mul_acc(acc: &mut Self::WideType, a: &'a Self, b: &'b Self) {
91 acc.0 ^= a.0 & b.0;
92 }
93}
94
95impl DefaultDotProduct<&Self, &Self> for Gf2 {}
96
97impl AccReduce for Gf2 {
98 type WideType = Gf2;
99
100 #[inline]
101 fn acc(acc: &mut Self::WideType, a: Self) {
102 acc.0 ^= a.0;
103 }
104}
105
106impl AccReduce<&Self> for Gf2 {
107 type WideType = Gf2;
108
109 #[inline]
110 fn acc(acc: &mut Self::WideType, a: &Self) {
111 acc.0 ^= a.0;
112 }
113}
114
115impl ff::Field for Gf2 {
116 const ZERO: Self = Self(0);
117 const ONE: Self = Self(1);
118
119 fn random(mut rng: impl rand::RngCore) -> Self {
120 let mut tmp = [0u8; 1];
121 rng.fill_bytes(&mut tmp);
122 Self(tmp[0] & 1)
123 }
124
125 fn square(&self) -> Self {
126 Self(self.0)
127 }
128
129 fn double(&self) -> Self {
130 Self::ZERO
131 }
132
133 fn invert(&self) -> CtOption<Self> {
134 CtOption::new(*self, self.ct_eq(&Self::ONE))
135 }
136
137 fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) {
138 unimplemented!()
139 }
140}
141
142impl FieldExtension for Gf2 {
143 type Subfield = Self;
144
145 type Degree = U1;
146 type FieldBitSize = U1;
147 type FieldBytesSize = U1;
148
149 fn to_subfield_elements(&self) -> Array<Self::Subfield, Self::Degree> {
150 Array([*self])
151 }
152
153 fn from_subfield_elements(elems: Array<Self::Subfield, Self::Degree>) -> Self {
154 elems[0]
155 }
156
157 fn to_le_bytes(&self) -> Array<u8, Self::FieldBytesSize> {
158 [self.0].into()
159 }
160
161 fn from_le_bytes(bytes: &[u8]) -> Option<Self> {
162 bytes
163 .first()
164 .and_then(|&byte| if byte <= 1 { Some(Self(byte)) } else { None })
165 }
166
167 fn mul_by_subfield(&self, other: &Self::Subfield) -> Self {
168 self * other
169 }
170
171 fn generator() -> Self {
172 Self::ONE
173 }
174}
175
176impl Random for Gf2 {
177 fn random(mut rng: impl CryptoRngCore) -> Gf2 {
178 let mut tmp = [0u8; 1];
179 rng.fill_bytes(&mut tmp);
180 Gf2(tmp[0] & 1)
181 }
182}
183
184unsafe impl InPlaceCodec for Gf2 {
189 const ENCODED_SIZE: usize = 1;
190
191 fn write_le_bytes(&self, out: &mut [MaybeUninit<u8>]) {
192 out[0].write(self.0);
193 }
194
195 fn read_le_bytes(bytes: &[u8]) -> Result<Self, PrimitiveError> {
196 if bytes[0] > 1 {
197 return Err(PrimitiveError::DeserializationFailed(
198 "Invalid Gf2 value: must be 0 or 1".to_string(),
199 ));
200 }
201 Ok(Self(bytes[0]))
202 }
203
204 const PACK: usize = 8;
208 const PACK_BYTES: usize = 1;
209
210 fn write_pack(items: &[Self], out: &mut [MaybeUninit<u8>]) {
211 let mut byte = 0u8;
213 for (i, item) in items.iter().enumerate() {
214 byte |= (item.0 & 1) << i;
215 }
216 out[0].write(byte);
217 }
218
219 fn read_pack(bytes: &[u8], out: &mut [MaybeUninit<Self>]) -> Result<(), PrimitiveError> {
220 let byte = bytes[0];
222 for (i, slot) in out.iter_mut().enumerate() {
223 slot.write(Self((byte >> i) & 1));
224 }
225 Ok(())
226 }
227}
228
229impl ConditionallySelectable for Gf2 {
232 #[inline]
233 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
234 Gf2(u8::conditional_select(&a.0, &b.0, choice))
235 }
236}
237
238impl ConstantTimeEq for Gf2 {
239 #[inline]
240 fn ct_eq(&self, other: &Self) -> Choice {
241 self.0.ct_eq(&other.0)
242 }
243}
244
245#[macros::op_variants(borrowed)]
246impl Neg for Gf2 {
247 type Output = Gf2;
248
249 #[inline]
250 fn neg(self) -> Self::Output {
251 self
252 }
253}
254
255#[macros::op_variants(owned, borrowed, flipped_commutative)]
256impl Add<&Gf2> for Gf2 {
257 type Output = Gf2;
258
259 #[inline]
260 #[allow(clippy::suspicious_arithmetic_impl)]
261 fn add(self, rhs: &Gf2) -> Self::Output {
262 Gf2(self.0 ^ rhs.0)
263 }
264}
265
266#[macros::op_variants(owned)]
267impl AddAssign<&Gf2> for Gf2 {
268 #[inline]
269 fn add_assign(&mut self, rhs: &Gf2) {
270 *self = *self + rhs;
271 }
272}
273
274#[macros::op_variants(owned, borrowed, flipped_commutative)]
275impl Sub<&Gf2> for Gf2 {
276 type Output = Gf2;
277
278 #[inline]
279 #[allow(clippy::suspicious_arithmetic_impl)]
280 fn sub(self, rhs: &Gf2) -> Self::Output {
281 self + rhs
282 }
283}
284
285#[macros::op_variants(owned)]
286impl SubAssign<&Gf2> for Gf2 {
287 #[inline]
288 fn sub_assign(&mut self, rhs: &Gf2) {
289 *self = *self - rhs;
290 }
291}
292
293#[macros::op_variants(owned, borrowed, flipped_commutative)]
294impl Mul<&Gf2> for Gf2 {
295 type Output = Gf2;
296
297 #[inline]
298 #[allow(clippy::suspicious_arithmetic_impl)]
299 fn mul(self, rhs: &Gf2) -> Self::Output {
300 Gf2(self.0 & rhs.0)
301 }
302}
303#[macros::op_variants(owned)]
304impl<'a> MulAssign<&'a Gf2> for Gf2 {
305 #[inline]
306 fn mul_assign(&mut self, rhs: &'a Gf2) {
307 *self = *self * rhs;
308 }
309}
310
311impl Sum for Gf2 {
312 #[inline]
313 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
314 iter.fold(Gf2::ZERO, |a, b| a + b)
315 }
316}
317
318impl<'a> Sum<&'a Gf2> for Gf2 {
319 #[inline]
320 fn sum<I: Iterator<Item = &'a Gf2>>(iter: I) -> Self {
321 iter.fold(Gf2::ZERO, |a, b| a + b)
322 }
323}
324
325impl Product for Gf2 {
326 #[inline]
327 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
328 iter.fold(Gf2::ONE, |a, b| a * b)
329 }
330}
331
332impl<'a> Product<&'a Gf2> for Gf2 {
333 #[inline]
334 fn product<I: Iterator<Item = &'a Gf2>>(iter: I) -> Self {
335 iter.fold(Gf2::ONE, |a, b| a * b)
336 }
337}
338
339impl From<Gf2> for bool {
340 fn from(value: Gf2) -> Self {
341 value.0 == 1
342 }
343}
344
345impl From<&Gf2> for bool {
346 fn from(value: &Gf2) -> Self {
347 value.0 == 1
348 }
349}
350
351impl From<bool> for Gf2 {
352 fn from(value: bool) -> Self {
353 Gf2(value.into())
354 }
355}
356
357impl From<&bool> for Gf2 {
358 fn from(value: &bool) -> Self {
359 (*value).into()
360 }
361}
362
363impl From<u8> for Gf2 {
364 fn from(val: u8) -> Self {
365 Gf2(val & 1)
366 }
367}
368
369impl From<Gf2> for u8 {
370 fn from(value: Gf2) -> Self {
371 value.0
372 }
373}
374
375impl From<&Gf2> for u64 {
376 fn from(value: &Gf2) -> Self {
377 value.0 as u64
378 }
379}
380
381impl From<u64> for Gf2 {
382 fn from(val: u64) -> Self {
383 Gf2((val & 1) as u8)
384 }
385}
386
387impl From<u128> for Gf2 {
388 fn from(val: u128) -> Self {
389 Gf2((val & 1) as u8)
390 }
391}
392
393impl From<Choice> for Gf2 {
394 fn from(value: Choice) -> Self {
395 Gf2(value.unwrap_u8())
396 }
397}
398
399impl From<&Choice> for Gf2 {
400 fn from(value: &Choice) -> Self {
401 (*value).into()
402 }
403}
404
405impl From<Gf2> for Choice {
406 fn from(value: Gf2) -> Self {
407 value.0.into()
408 }
409}
410
411impl From<&Gf2> for Choice {
412 fn from(value: &Gf2) -> Self {
413 value.0.into()
414 }
415}
416
417impl FromUniformBytes for Gf2 {
418 type UniformBytes = U1;
419
420 fn from_uniform_bytes(bytes: &Array<u8, Self::UniformBytes>) -> Self {
421 Gf2(bytes[0] & 1)
422 }
423}
424
425impl AsRef<[u8]> for Gf2 {
426 fn as_ref(&self) -> &[u8] {
427 unsafe {
428 std::slice::from_raw_parts(self as *const Gf2 as *const u8, std::mem::size_of::<Gf2>())
429 }
430 }
431}