Skip to main content

p3_binary_field/
gf2.rs

1use core::fmt::{self, Debug, Display, Formatter};
2use core::iter::{Product, Sum};
3use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5use num_bigint::BigUint;
6use p3_field::integers::QuotientMap;
7use p3_field::op_assign_macros::{
8    impl_add_assign, impl_div_methods, impl_mul_methods, impl_sub_assign, ring_sum,
9};
10use p3_field::{
11    Field, Packable, PrimeCharacteristicRing, PrimeField, PrimeField32, PrimeField64,
12    RawDataSerializable, quotient_map_large_iint, quotient_map_large_uint,
13};
14use rand::Rng;
15use rand::distr::{Distribution, StandardUniform};
16use serde::de::Error;
17use serde::{Deserialize, Deserializer, Serialize};
18
19/// The prime field `GF(2) = {0, 1}`, with addition given by `XOR` and multiplication by `AND`.
20///
21/// This is the base case of the characteristic-2 tower `GF(2) ⊂ GF(4) ⊂ … ⊂ GF(2^128)`.
22///
23/// The serde encoding is canonical: every field element has exactly one valid byte
24/// representation (see the manual [`Deserialize`] impl below). `#[serde(transparent)]` makes the
25/// derived [`Serialize`] emit the backing integer itself, which is what that impl reads back.
26#[derive(Copy, Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
27#[serde(transparent)]
28#[repr(transparent)]
29#[must_use]
30pub struct Gf2(u8);
31
32impl Gf2 {
33    /// Create a new field element from a bit.
34    ///
35    /// Only the least significant bit of `bit` is used.
36    #[inline]
37    const fn new(bit: u8) -> Self {
38        Self(bit & 1)
39    }
40
41    /// Construct a field element from its little-endian byte representation.
42    ///
43    /// Every byte is a valid input; only its least significant bit is used.
44    #[inline]
45    pub const fn from_le_bytes(bytes: [u8; 1]) -> Self {
46        Self::new(bytes[0])
47    }
48
49    /// The bottom of the recursion that the tower levels above multiply through.
50    ///
51    /// `GF(2)` has no faster multiplication to dispatch to, so this is `Mul` itself; it exists
52    /// so that the tower's reference multiplication never routes through a level whose `Mul`
53    /// has been swapped out for a hardware fast path.
54    #[doc(hidden)]
55    #[inline]
56    pub fn reference_mul(self, rhs: Self) -> Self {
57        self * rhs
58    }
59}
60
61impl Packable for Gf2 {}
62
63impl<'de> Deserialize<'de> for Gf2 {
64    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
65        let val = u8::deserialize(d)?;
66        // Reject non-canonical encodings so a proof cannot be re-encoded without the witness.
67        // Only `0` and `1` are canonical for `GF(2)`.
68        if val < 2 {
69            Ok(Self(val))
70        } else {
71            Err(D::Error::custom("Value is out of range"))
72        }
73    }
74}
75
76impl Display for Gf2 {
77    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
78        Display::fmt(&self.0, f)
79    }
80}
81
82impl Debug for Gf2 {
83    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
84        Debug::fmt(&self.0, f)
85    }
86}
87
88impl Distribution<Gf2> for StandardUniform {
89    #[inline]
90    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Gf2 {
91        Gf2::new((rng.next_u32() & 1) as u8)
92    }
93}
94
95impl PrimeCharacteristicRing for Gf2 {
96    type PrimeSubfield = Self;
97
98    const ZERO: Self = Self(0);
99    const ONE: Self = Self(1);
100    // The characteristic is 2, so `TWO = ONE + ONE = ZERO`.
101    const TWO: Self = Self(0);
102    // The characteristic is 2, so `NEG_ONE = ONE`.
103    const NEG_ONE: Self = Self(1);
104
105    #[inline]
106    fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
107        f
108    }
109
110    #[inline]
111    fn from_bool(b: bool) -> Self {
112        Self(b as u8)
113    }
114
115    #[inline]
116    fn double(&self) -> Self {
117        // `a + a = 0` in characteristic 2.
118        Self::ZERO
119    }
120
121    /// # Panics
122    /// Always panics: `2` is not invertible in characteristic 2.
123    #[inline]
124    fn halve(&self) -> Self {
125        panic!("halve is undefined in characteristic 2")
126    }
127
128    #[inline]
129    fn square(&self) -> Self {
130        // `0^2 = 0` and `1^2 = 1`.
131        *self
132    }
133
134    #[inline]
135    fn xor(&self, y: &Self) -> Self {
136        *self + *y
137    }
138
139    #[inline]
140    fn mul_2exp_u64(&self, exp: u64) -> Self {
141        if exp == 0 { *self } else { Self::ZERO }
142    }
143
144    /// # Panics
145    /// Always panics: `2` is not invertible in characteristic 2.
146    #[inline]
147    fn div_2exp_u64(&self, _exp: u64) -> Self {
148        panic!("div_2exp_u64 is undefined in characteristic 2")
149    }
150}
151
152impl Field for Gf2 {
153    type Packing = Self;
154
155    // The only nonzero element, `1`, trivially generates the (trivial) multiplicative group.
156    const GENERATOR: Self = Self::ONE;
157
158    #[inline]
159    fn try_inverse(&self) -> Option<Self> {
160        (self.0 == 1).then_some(Self::ONE)
161    }
162
163    #[inline]
164    fn try_sqrt(&self) -> Option<Self> {
165        // `0^2 = 0` and `1^2 = 1`, so every element is its own (unique) square root.
166        Some(*self)
167    }
168
169    #[inline]
170    fn order() -> BigUint {
171        BigUint::from(2u8)
172    }
173
174    /// An element of `GF(2)` is exactly one bit wide.
175    ///
176    /// The default implementation returns `order().bits()`, which over-reports by one whenever
177    /// the order is an exact power of two.
178    #[inline]
179    fn bits() -> usize {
180        1
181    }
182
183    /// The enumeration `interpolation_node(0) = 0, interpolation_node(1) = 1` is the only
184    /// injective enumeration of the two elements of `GF(2)` satisfying `Field::interpolation_node`'s
185    /// contract.
186    ///
187    /// # Panics
188    /// Panics if `i > 1`. `new` keeps only the low bit, so a larger index would otherwise alias
189    /// one of the two nodes and break an interpolation argument silently.
190    #[inline]
191    fn interpolation_node(i: usize) -> Self {
192        assert!(i < 2, "interpolation node index out of range");
193        Self::new(i as u8)
194    }
195}
196
197impl QuotientMap<u8> for Gf2 {
198    /// Convert a given `u8` integer into an element of the `Gf2` field.
199    #[inline]
200    fn from_int(int: u8) -> Self {
201        Self::new(int)
202    }
203
204    /// Convert a given `u8` integer into an element of the `Gf2` field.
205    ///
206    /// Returns `None` if the input does not lie in the range `[0, 1]`.
207    #[inline]
208    fn from_canonical_checked(int: u8) -> Option<Self> {
209        (int < 2).then(|| Self::new(int))
210    }
211
212    /// Convert a given `u8` integer into an element of the `Gf2` field.
213    ///
214    /// # Safety
215    /// The caller must guarantee that `int < 2`.
216    #[inline]
217    unsafe fn from_canonical_unchecked(int: u8) -> Self {
218        // SAFETY: the caller guarantees `int < 2`, so `int` is already the canonical
219        // representative and masking to its least significant bit is a no-op.
220        debug_assert!(int < 2);
221        Self::new(int)
222    }
223}
224
225impl QuotientMap<i8> for Gf2 {
226    /// Convert a given `i8` integer into an element of the `Gf2` field.
227    #[inline]
228    fn from_int(int: i8) -> Self {
229        // Two's-complement `& 1` extracts the parity bit regardless of sign.
230        Self::new((int & 1) as u8)
231    }
232
233    /// Convert a given `i8` integer into an element of the `Gf2` field.
234    ///
235    /// Returns `None` if the input does not lie in the range `[0, 1]`.
236    #[inline]
237    fn from_canonical_checked(int: i8) -> Option<Self> {
238        (0..2).contains(&int).then(|| Self::new(int as u8))
239    }
240
241    /// Convert a given `i8` integer into an element of the `Gf2` field.
242    ///
243    /// # Safety
244    /// The caller must guarantee that `int` lies in `[0, 1]`.
245    #[inline]
246    unsafe fn from_canonical_unchecked(int: i8) -> Self {
247        // SAFETY: the caller guarantees `0 <= int < 2`, so `int` is already the
248        // canonical representative and casting to `u8` is exact.
249        debug_assert!((0..2).contains(&int));
250        Self::new(int as u8)
251    }
252}
253
254// `u8` is the smallest integer type, so `QuotientMap<u8>` is implemented by hand above.
255quotient_map_large_uint!(Gf2, u8, 2u8, "`[0, 1]`", "`[0, 1]`", [u16, u32, u64, u128]);
256
257// `i8` is the smallest signed integer type, so `QuotientMap<i8>` is implemented by hand above.
258quotient_map_large_iint!(
259    Gf2,
260    i8,
261    "`[0, 1]`",
262    "`[0, 1]`",
263    [(i16, u16), (i32, u32), (i64, u64), (i128, u128)]
264);
265
266impl PrimeField for Gf2 {
267    #[inline]
268    fn as_canonical_biguint(&self) -> BigUint {
269        BigUint::from(self.0)
270    }
271}
272
273impl PrimeField64 for Gf2 {
274    const ORDER_U64: u64 = 2;
275
276    #[inline]
277    fn as_canonical_u64(&self) -> u64 {
278        self.0 as u64
279    }
280}
281
282impl PrimeField32 for Gf2 {
283    const ORDER_U32: u32 = 2;
284
285    #[inline]
286    fn as_canonical_u32(&self) -> u32 {
287        self.0 as u32
288    }
289}
290
291impl RawDataSerializable for Gf2 {
292    const NUM_BYTES: usize = 1;
293
294    #[inline]
295    fn into_bytes(self) -> impl IntoIterator<Item = u8> {
296        [self.0]
297    }
298}
299
300impl Add for Gf2 {
301    type Output = Self;
302
303    #[inline]
304    #[allow(clippy::suspicious_arithmetic_impl)]
305    fn add(self, rhs: Self) -> Self {
306        // Addition in `GF(2)` is `XOR`.
307        Self(self.0 ^ rhs.0)
308    }
309}
310
311impl Sub for Gf2 {
312    type Output = Self;
313
314    #[inline]
315    #[allow(clippy::suspicious_arithmetic_impl)]
316    fn sub(self, rhs: Self) -> Self {
317        // Subtraction coincides with addition in characteristic 2.
318        self + rhs
319    }
320}
321
322impl Neg for Gf2 {
323    type Output = Self;
324
325    #[inline]
326    fn neg(self) -> Self::Output {
327        // `-x = x` in characteristic 2.
328        self
329    }
330}
331
332impl Mul for Gf2 {
333    type Output = Self;
334
335    #[inline]
336    #[allow(clippy::suspicious_arithmetic_impl)]
337    fn mul(self, rhs: Self) -> Self {
338        // Multiplication in `GF(2)` is `AND`.
339        Self(self.0 & rhs.0)
340    }
341}
342
343impl_add_assign!(Gf2);
344impl_sub_assign!(Gf2);
345impl_mul_methods!(Gf2);
346impl_div_methods!(Gf2, Gf2);
347ring_sum!(Gf2);
348
349#[cfg(test)]
350mod tests {
351    use p3_field::integers::QuotientMap;
352    use p3_field::{
353        Field, PrimeCharacteristicRing, PrimeField, PrimeField32, PrimeField64, RawDataSerializable,
354    };
355
356    use super::Gf2;
357
358    #[test]
359    fn arithmetic_is_boolean() {
360        assert_eq!(Gf2::ONE + Gf2::ONE, Gf2::ZERO);
361        assert_eq!(Gf2::TWO, Gf2::ZERO);
362        assert_eq!(Gf2::NEG_ONE, Gf2::ONE);
363        assert_eq!(Gf2::ONE * Gf2::ONE, Gf2::ONE);
364        assert_eq!(Gf2::ONE.inverse(), Gf2::ONE);
365        assert_eq!(Gf2::ZERO.try_inverse(), None);
366        assert_eq!(Gf2::from_u64(7), Gf2::ONE);
367        assert_eq!(Gf2::from_u64(6), Gf2::ZERO);
368    }
369
370    // `p3_field_testing`'s `test_prime_field!`/`test_prime_field_64!`/`test_prime_field_32!`
371    // are not usable against `Gf2`: they hard-code assumptions that only hold for fields with
372    // a "reasonably large" order (e.g. `generate_from_small_int_tests!` asserts
373    // `from_canonical_checked` is `Some` for literal test values up to `108`;
374    // `generate_from_large_u_int_tests!`/`generate_from_large_i_int_tests!` unconditionally
375    // call `.halve()`, which is undefined in characteristic 2; and
376    // `test_prime_field_32!`'s raw-data-serializable/JSON-boundary sub-tests assume a 4-byte,
377    // ~31-bit representative). The tests below cover the same ground by hand, adapted to
378    // `GF(2)`'s actual canonical range of `{0, 1}`.
379
380    /// Every integer type required by `PrimeField`'s `QuotientMap<Int>` bound reduces mod 2,
381    /// and `from_canonical_checked`/`from_canonical_unchecked` agree with `from_int` exactly on
382    /// `{0, 1}` and reject (or are only guaranteed correct for) everything else.
383    #[test]
384    fn quotient_map_covers_every_integer_type() {
385        macro_rules! check_unsigned {
386            ($int:ty) => {
387                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(0), Gf2::ZERO);
388                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(1), Gf2::ONE);
389                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(2), Gf2::ZERO);
390                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(3), Gf2::ONE);
391                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(<$int>::MAX), Gf2::ONE);
392                assert_eq!(
393                    <Gf2 as QuotientMap<$int>>::from_canonical_checked(0),
394                    Some(Gf2::ZERO)
395                );
396                assert_eq!(
397                    <Gf2 as QuotientMap<$int>>::from_canonical_checked(1),
398                    Some(Gf2::ONE)
399                );
400                assert_eq!(<Gf2 as QuotientMap<$int>>::from_canonical_checked(2), None);
401                assert_eq!(
402                    <Gf2 as QuotientMap<$int>>::from_canonical_checked(<$int>::MAX),
403                    None
404                );
405                unsafe {
406                    assert_eq!(
407                        <Gf2 as QuotientMap<$int>>::from_canonical_unchecked(0),
408                        Gf2::ZERO
409                    );
410                    assert_eq!(
411                        <Gf2 as QuotientMap<$int>>::from_canonical_unchecked(1),
412                        Gf2::ONE
413                    );
414                }
415            };
416        }
417        macro_rules! check_signed {
418            ($int:ty) => {
419                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(0), Gf2::ZERO);
420                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(1), Gf2::ONE);
421                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(-1), Gf2::ONE);
422                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(-2), Gf2::ZERO);
423                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(-3), Gf2::ONE);
424                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(<$int>::MIN), Gf2::ZERO);
425                assert_eq!(<Gf2 as QuotientMap<$int>>::from_int(<$int>::MAX), Gf2::ONE);
426                assert_eq!(
427                    <Gf2 as QuotientMap<$int>>::from_canonical_checked(0),
428                    Some(Gf2::ZERO)
429                );
430                assert_eq!(
431                    <Gf2 as QuotientMap<$int>>::from_canonical_checked(1),
432                    Some(Gf2::ONE)
433                );
434                assert_eq!(<Gf2 as QuotientMap<$int>>::from_canonical_checked(2), None);
435                assert_eq!(<Gf2 as QuotientMap<$int>>::from_canonical_checked(-1), None);
436                assert_eq!(
437                    <Gf2 as QuotientMap<$int>>::from_canonical_checked(<$int>::MIN),
438                    None
439                );
440                unsafe {
441                    assert_eq!(
442                        <Gf2 as QuotientMap<$int>>::from_canonical_unchecked(0),
443                        Gf2::ZERO
444                    );
445                    assert_eq!(
446                        <Gf2 as QuotientMap<$int>>::from_canonical_unchecked(1),
447                        Gf2::ONE
448                    );
449                }
450            };
451        }
452
453        check_unsigned!(u8);
454        check_unsigned!(u16);
455        check_unsigned!(u32);
456        check_unsigned!(u64);
457        check_unsigned!(u128);
458        check_unsigned!(usize);
459        check_signed!(i8);
460        check_signed!(i16);
461        check_signed!(i32);
462        check_signed!(i64);
463        check_signed!(i128);
464        check_signed!(isize);
465    }
466
467    /// Large values reduce mod 2 rather than saturating or panicking, on both sides of a
468    /// `u8`-internal-representation boundary (256) and near the top of wider integer ranges.
469    #[test]
470    fn quotient_map_large_value_reduction() {
471        assert_eq!(<Gf2 as QuotientMap<u16>>::from_int(60_000), Gf2::ZERO);
472        assert_eq!(<Gf2 as QuotientMap<u16>>::from_int(60_001), Gf2::ONE);
473        assert_eq!(
474            <Gf2 as QuotientMap<u32>>::from_int(4_000_000_000),
475            Gf2::ZERO
476        );
477        assert_eq!(<Gf2 as QuotientMap<u32>>::from_int(4_000_000_001), Gf2::ONE);
478        assert_eq!(
479            <Gf2 as QuotientMap<u64>>::from_int(18_000_000_000_000_000_002),
480            Gf2::ZERO
481        );
482        assert_eq!(
483            <Gf2 as QuotientMap<u128>>::from_int(u128::MAX - 1),
484            Gf2::ZERO
485        );
486        assert_eq!(
487            <Gf2 as QuotientMap<i32>>::from_int(-2_000_000_001),
488            Gf2::ONE
489        );
490        assert_eq!(
491            <Gf2 as QuotientMap<i64>>::from_int(-9_000_000_000_000_000_002),
492            Gf2::ZERO
493        );
494        assert_eq!(
495            <Gf2 as QuotientMap<i128>>::from_int(i128::MIN + 1),
496            Gf2::ONE
497        );
498    }
499
500    #[test]
501    fn as_canonical_and_raw_bytes() {
502        assert_eq!(Gf2::ORDER_U32, 2);
503        assert_eq!(Gf2::ORDER_U64, 2);
504        assert_eq!(Gf2::ZERO.as_canonical_u32(), 0);
505        assert_eq!(Gf2::ONE.as_canonical_u32(), 1);
506        assert_eq!(Gf2::ZERO.as_canonical_u64(), 0);
507        assert_eq!(Gf2::ONE.as_canonical_u64(), 1);
508        assert_eq!(
509            Gf2::ONE.as_canonical_biguint(),
510            num_bigint::BigUint::from(1u8)
511        );
512        assert_eq!(
513            Gf2::ZERO.as_canonical_biguint(),
514            num_bigint::BigUint::from(0u8)
515        );
516
517        assert_eq!(Gf2::NUM_BYTES, 1);
518        let mut ones_bytes = Gf2::ONE.into_bytes().into_iter();
519        assert_eq!(ones_bytes.next(), Some(1u8));
520        assert_eq!(ones_bytes.next(), None);
521        let mut zeros_bytes = Gf2::ZERO.into_bytes().into_iter();
522        assert_eq!(zeros_bytes.next(), Some(0u8));
523        assert_eq!(zeros_bytes.next(), None);
524
525        assert_eq!(Gf2::from_le_bytes([0]), Gf2::ZERO);
526        assert_eq!(Gf2::from_le_bytes([1]), Gf2::ONE);
527        // Every byte is a valid input: only its least significant bit is used.
528        assert_eq!(Gf2::from_le_bytes([2]), Gf2::ZERO);
529        assert_eq!(Gf2::from_le_bytes([255]), Gf2::ONE);
530    }
531
532    #[test]
533    #[should_panic = "halve is undefined in characteristic 2"]
534    fn halve_panics() {
535        let _halved = Gf2::ONE.halve();
536    }
537
538    #[test]
539    #[should_panic = "div_2exp_u64 is undefined in characteristic 2"]
540    fn div_2exp_u64_panics() {
541        let _divided = Gf2::ONE.div_2exp_u64(1);
542    }
543
544    #[test]
545    fn field_order_and_interpolation_nodes() {
546        assert_eq!(Gf2::order(), num_bigint::BigUint::from(2u8));
547        assert_eq!(Gf2::bits(), 1);
548        assert_eq!(Gf2::interpolation_node(0), Gf2::ZERO);
549        assert_eq!(Gf2::interpolation_node(1), Gf2::ONE);
550    }
551
552    #[test]
553    #[should_panic = "interpolation node index out of range"]
554    fn interpolation_node_rejects_an_index_beyond_the_field() {
555        let _node = Gf2::interpolation_node(2);
556    }
557
558    /// Serialization always emits the canonical byte, and deserialization rejects any byte
559    /// other than `0`/`1`. Without that rejection, deserializing corrupted or adversarial
560    /// bytes could construct a `Gf2` whose invariant (`.0 in {0, 1}`) is broken, silently
561    /// propagating an invalid field element through arithmetic.
562    #[test]
563    fn serde_round_trip_rejects_non_canonical_encodings() {
564        assert_eq!(serde_json::to_string(&Gf2::ZERO).unwrap(), "0");
565        assert_eq!(serde_json::to_string(&Gf2::ONE).unwrap(), "1");
566
567        let decoded_zero: Gf2 = serde_json::from_str("0").unwrap();
568        let decoded_one: Gf2 = serde_json::from_str("1").unwrap();
569        assert_eq!(decoded_zero, Gf2::ZERO);
570        assert_eq!(decoded_one, Gf2::ONE);
571
572        // Every byte other than 0/1 must be rejected, not silently truncated into range.
573        assert!(serde_json::from_str::<Gf2>("2").is_err());
574        assert!(serde_json::from_str::<Gf2>("255").is_err());
575    }
576}