1use crate::{
19 CanonicalDeserialize, CanonicalSerialize, Flat, HardwareField, PackableField, PackedFlat,
20 TowerField,
21};
22use core::ops::{Add, AddAssign, BitAnd, BitXor, Mul, MulAssign, Sub, SubAssign};
23use serde::{Deserialize, Serialize};
24use zeroize::Zeroize;
25
26#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Zeroize)]
32#[repr(transparent)]
33pub struct Bit(u8);
34
35impl Bit {
36 #[inline]
37 pub const fn new(val: u8) -> Self {
38 Self(val & 1)
39 }
40
41 #[inline]
42 pub const fn try_new(val: u8) -> Option<Self> {
43 match val {
44 0 | 1 => Some(Self(val)),
45 _ => None,
46 }
47 }
48
49 #[inline]
50 pub const fn get(self) -> u8 {
51 self.0
52 }
53}
54
55impl TowerField for Bit {
56 const BITS: usize = 1;
57 const ZERO: Self = Bit(0);
58 const ONE: Self = Bit(1);
59
60 const EXTENSION_TAU: Self = Bit(1);
62
63 fn invert(&self) -> Self {
64 *self
70 }
71
72 fn from_uniform_bytes(bytes: &[u8; 32]) -> Self {
73 Self(bytes[0] & 1)
75 }
76}
77
78impl Add for Bit {
81 type Output = Self;
82
83 fn add(self, rhs: Self) -> Self::Output {
84 Self(self.0.bitxor(rhs.0))
85 }
86}
87
88impl Sub for Bit {
90 type Output = Self;
91
92 fn sub(self, rhs: Self) -> Self::Output {
93 self.add(rhs)
94 }
95}
96
97impl Mul for Bit {
100 type Output = Self;
101
102 fn mul(self, rhs: Self) -> Self::Output {
103 Self(self.0.bitand(rhs.0))
104 }
105}
106
107impl AddAssign for Bit {
108 fn add_assign(&mut self, rhs: Self) {
109 *self = *self + rhs
110 }
111}
112
113impl SubAssign for Bit {
114 fn sub_assign(&mut self, rhs: Self) {
115 *self = *self - rhs
116 }
117}
118
119impl MulAssign for Bit {
120 fn mul_assign(&mut self, rhs: Self) {
121 *self = *self * rhs;
122 }
123}
124
125impl CanonicalSerialize for Bit {
126 #[inline]
127 fn serialized_size(&self) -> usize {
128 1
129 }
130
131 #[inline]
132 fn serialize(&self, writer: &mut [u8]) -> Result<(), ()> {
133 if writer.is_empty() {
134 return Err(());
135 }
136
137 writer[0] = self.0;
138
139 Ok(())
140 }
141}
142
143impl CanonicalDeserialize for Bit {
144 fn deserialize(bytes: &[u8]) -> Result<Self, ()> {
145 if bytes.is_empty() {
146 return Err(());
147 }
148
149 if bytes[0] > 1 {
150 return Err(());
151 }
152
153 Ok(Self(bytes[0]))
154 }
155}
156
157impl Serialize for Bit {
158 #[inline]
159 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
160 where
161 S: serde::Serializer,
162 {
163 serializer.serialize_u8(self.0)
164 }
165}
166
167impl<'de> Deserialize<'de> for Bit {
168 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
169 where
170 D: serde::Deserializer<'de>,
171 {
172 let raw = u8::deserialize(deserializer)?;
173 Self::try_new(raw).ok_or_else(|| serde::de::Error::custom("Bit must be 0 or 1"))
174 }
175}
176
177impl From<u8> for Bit {
178 #[inline]
179 fn from(val: u8) -> Self {
180 Self(val & 1)
181 }
182}
183
184impl From<u32> for Bit {
185 #[inline]
186 fn from(val: u32) -> Self {
187 Self((val & 1) as u8)
188 }
189}
190
191impl From<u64> for Bit {
192 #[inline]
193 fn from(val: u64) -> Self {
194 Self((val & 1) as u8)
195 }
196}
197
198impl From<u128> for Bit {
199 #[inline]
200 fn from(val: u128) -> Self {
201 Self((val & 1) as u8)
202 }
203}
204
205pub const PACKED_WIDTH_BIT: usize = 64;
211
212#[repr(C, align(64))]
213pub struct PackedBit(pub [Bit; PACKED_WIDTH_BIT]);
214
215impl Clone for PackedBit {
216 #[inline(always)]
217 fn clone(&self) -> Self {
218 *self
219 }
220}
221
222impl Copy for PackedBit {}
223
224impl Default for PackedBit {
225 #[inline(always)]
226 fn default() -> Self {
227 Self::zero()
228 }
229}
230
231impl PartialEq for PackedBit {
232 fn eq(&self, other: &Self) -> bool {
233 self.0[..] == other.0[..]
236 }
237}
238
239impl Eq for PackedBit {}
240
241impl core::fmt::Debug for PackedBit {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 write!(f, "PackedBit([size={}])", PACKED_WIDTH_BIT)
244 }
245}
246
247impl PackedBit {
248 #[inline(always)]
249 pub fn zero() -> Self {
250 Self([Bit::ZERO; PACKED_WIDTH_BIT])
251 }
252}
253
254impl PackableField for Bit {
255 type Packed = PackedBit;
256
257 const WIDTH: usize = PACKED_WIDTH_BIT;
258
259 #[inline(always)]
260 fn pack(chunk: &[Self]) -> Self::Packed {
261 assert!(
262 chunk.len() >= PACKED_WIDTH_BIT,
263 "PackableField::pack: input slice too short",
264 );
265
266 let mut arr = [Self::ZERO; PACKED_WIDTH_BIT];
267 arr.copy_from_slice(&chunk[..PACKED_WIDTH_BIT]);
268
269 PackedBit(arr)
270 }
271
272 #[inline(always)]
273 fn unpack(packed: Self::Packed, output: &mut [Self]) {
274 assert!(
275 output.len() >= PACKED_WIDTH_BIT,
276 "PackableField::unpack: output slice too short",
277 );
278
279 output[..PACKED_WIDTH_BIT].copy_from_slice(&packed.0);
280 }
281}
282
283impl Add for PackedBit {
284 type Output = Self;
285
286 #[inline(always)]
287 fn add(self, rhs: Self) -> Self {
288 #[cfg(target_arch = "aarch64")]
289 {
290 neon::add_packed_bit(self, rhs)
291 }
292
293 #[cfg(not(target_arch = "aarch64"))]
294 {
295 let mut res = [Bit::ZERO; PACKED_WIDTH_BIT];
296 for ((out, l), r) in res.iter_mut().zip(self.0.iter()).zip(rhs.0.iter()) {
297 *out = *l + *r;
298 }
299
300 Self(res)
301 }
302 }
303}
304
305impl AddAssign for PackedBit {
306 #[inline(always)]
307 fn add_assign(&mut self, rhs: Self) {
308 for (l, r) in self.0.iter_mut().zip(rhs.0.iter()) {
309 *l += *r;
310 }
311 }
312}
313
314impl Sub for PackedBit {
315 type Output = Self;
316
317 #[inline(always)]
318 fn sub(self, rhs: Self) -> Self {
319 self.add(rhs)
320 }
321}
322
323impl SubAssign for PackedBit {
324 #[inline(always)]
325 fn sub_assign(&mut self, rhs: Self) {
326 self.add_assign(rhs)
327 }
328}
329
330impl Mul for PackedBit {
331 type Output = Self;
332
333 #[inline(always)]
334 fn mul(self, rhs: Self) -> Self {
335 #[cfg(target_arch = "aarch64")]
336 {
337 neon::mul_packed_bit(self, rhs)
338 }
339
340 #[cfg(not(target_arch = "aarch64"))]
341 {
342 let mut res = [Bit::ZERO; PACKED_WIDTH_BIT];
343 for ((out, l), r) in res.iter_mut().zip(self.0.iter()).zip(rhs.0.iter()) {
344 *out = *l * *r;
345 }
346
347 Self(res)
348 }
349 }
350}
351
352impl MulAssign for PackedBit {
353 #[inline(always)]
354 fn mul_assign(&mut self, rhs: Self) {
355 *self = *self * rhs;
356 }
357}
358
359impl Mul<Bit> for PackedBit {
360 type Output = Self;
361
362 #[inline(always)]
363 fn mul(self, rhs: Bit) -> Self {
364 let mut res = [Bit::ZERO; PACKED_WIDTH_BIT];
365 for (out, v) in res.iter_mut().zip(self.0.iter()) {
366 *out = *v * rhs;
367 }
368
369 Self(res)
370 }
371}
372
373impl HardwareField for Bit {
378 #[inline(always)]
379 fn to_hardware(self) -> Flat<Self> {
380 Flat::from_raw(self)
381 }
382
383 #[inline(always)]
384 fn from_hardware(value: Flat<Self>) -> Self {
385 value.into_raw()
386 }
387
388 #[inline(always)]
389 fn add_hardware(lhs: Flat<Self>, rhs: Flat<Self>) -> Flat<Self> {
390 let lhs = lhs.into_raw();
391 let rhs = rhs.into_raw();
392
393 Flat::from_raw(Self(lhs.0 ^ rhs.0))
395 }
396
397 #[inline(always)]
398 fn add_hardware_packed(lhs: PackedFlat<Self>, rhs: PackedFlat<Self>) -> PackedFlat<Self> {
399 PackedFlat::from_raw(lhs.into_raw() + rhs.into_raw())
400 }
401
402 #[inline(always)]
403 fn mul_hardware(lhs: Flat<Self>, rhs: Flat<Self>) -> Flat<Self> {
404 let lhs = lhs.into_raw();
405 let rhs = rhs.into_raw();
406
407 Flat::from_raw(Self(lhs.0 & rhs.0))
409 }
410
411 #[inline(always)]
412 fn mul_hardware_packed(lhs: PackedFlat<Self>, rhs: PackedFlat<Self>) -> PackedFlat<Self> {
413 PackedFlat::from_raw(lhs.into_raw() * rhs.into_raw())
414 }
415
416 #[inline(always)]
417 fn mul_hardware_scalar_packed(lhs: PackedFlat<Self>, rhs: Flat<Self>) -> PackedFlat<Self> {
418 let broadcasted = PackedBit([rhs.into_raw(); PACKED_WIDTH_BIT]);
419 Self::mul_hardware_packed(lhs, PackedFlat::from_raw(broadcasted))
420 }
421
422 #[inline(always)]
423 fn tower_bit_from_hardware(value: Flat<Self>, bit_idx: usize) -> u8 {
424 assert_eq!(bit_idx, 0, "bit index out of bounds for Bit");
425
426 value.into_raw().0
429 }
430}
431
432#[cfg(target_arch = "aarch64")]
437mod neon {
438 use super::*;
439 use core::arch::aarch64::*;
440 use core::mem::transmute;
441
442 #[inline(always)]
445 pub fn add_packed_bit(lhs: PackedBit, rhs: PackedBit) -> PackedBit {
446 unsafe {
447 let l: [uint8x16_t; 4] = transmute::<[Bit; PACKED_WIDTH_BIT], [uint8x16_t; 4]>(lhs.0);
449 let r: [uint8x16_t; 4] = transmute::<[Bit; PACKED_WIDTH_BIT], [uint8x16_t; 4]>(rhs.0);
450
451 let res = [
452 veorq_u8(l[0], r[0]),
453 veorq_u8(l[1], r[1]),
454 veorq_u8(l[2], r[2]),
455 veorq_u8(l[3], r[3]),
456 ];
457
458 PackedBit(transmute::<[uint8x16_t; 4], [Bit; PACKED_WIDTH_BIT]>(res))
459 }
460 }
461
462 #[inline(always)]
465 pub fn mul_packed_bit(lhs: PackedBit, rhs: PackedBit) -> PackedBit {
466 unsafe {
467 let l: [uint8x16_t; 4] = transmute::<[Bit; PACKED_WIDTH_BIT], [uint8x16_t; 4]>(lhs.0);
468 let r: [uint8x16_t; 4] = transmute::<[Bit; PACKED_WIDTH_BIT], [uint8x16_t; 4]>(rhs.0);
469
470 let res = [
471 vandq_u8(l[0], r[0]),
472 vandq_u8(l[1], r[1]),
473 vandq_u8(l[2], r[2]),
474 vandq_u8(l[3], r[3]),
475 ];
476
477 PackedBit(transmute::<[uint8x16_t; 4], [Bit; PACKED_WIDTH_BIT]>(res))
478 }
479 }
480}
481
482#[cfg(test)]
483mod tests {
484 use super::*;
485 use rand::{RngExt, rng};
486
487 #[test]
492 fn add_truth() {
493 let zero = Bit::ZERO;
494 let one = Bit::ONE;
495
496 assert_eq!(zero + zero, zero);
497 assert_eq!(zero + one, one);
498 assert_eq!(one + zero, one);
499 assert_eq!(one + one, zero);
500 }
501
502 #[test]
503 fn mul_truth() {
504 let zero = Bit::ZERO;
505 let one = Bit::ONE;
506
507 assert_eq!(zero * zero, zero);
508 assert_eq!(zero * one, zero);
509 assert_eq!(one * one, one);
510 }
511
512 #[test]
513 fn invariant_constructors() {
514 assert_eq!(Bit::try_new(0), Some(Bit::ZERO));
515 assert_eq!(Bit::try_new(1), Some(Bit::ONE));
516
517 for v in 2u8..=255 {
518 assert_eq!(Bit::try_new(v), None, "try_new admitted {v}");
519 }
520
521 for v in 0u8..=255 {
522 assert!(Bit::new(v).get() <= 1, "new escaped GF(2) at {v}");
523 }
524 }
525
526 #[test]
527 fn security_zeroize() {
528 let mut secret_bit = Bit::ONE;
530 assert_eq!(secret_bit.0, 1);
531
532 secret_bit.zeroize();
534
535 assert_eq!(secret_bit, Bit::ZERO);
537 assert_eq!(secret_bit.0, 0, "Bit memory leak detected");
538 }
539
540 #[test]
541 fn invert_truth() {
542 let one = Bit::ONE;
547 let zero = Bit::ZERO;
548
549 assert_eq!(one.invert(), Bit::ONE, "Inversion of 1 must be 1");
550 assert_eq!(zero.invert(), Bit::ZERO, "Inversion of 0 must be 0");
551 }
552
553 #[test]
558 fn isomorphism_roundtrip() {
559 let mut rng = rng();
560 for _ in 0..100 {
561 let val = Bit::new(rng.random::<u8>());
563
564 assert_eq!(
568 val.to_hardware().to_tower(),
569 val,
570 "Bit isomorphism roundtrip failed"
571 );
572 }
573 }
574
575 #[test]
576 fn flat_mul_homomorphism() {
577 let mut rng = rng();
578 for _ in 0..100 {
579 let a = Bit::new(rng.random::<u8>());
580 let b = Bit::new(rng.random::<u8>());
581
582 let expected_flat = (a * b).to_hardware();
583 let actual_flat = a.to_hardware() * b.to_hardware();
584
585 assert_eq!(
587 actual_flat, expected_flat,
588 "Bit flat multiplication mismatch"
589 );
590 }
591 }
592
593 #[test]
594 fn packed_consistency() {
595 let mut rng = rng();
596 for _ in 0..100 {
597 let mut a_vals = [Bit::ZERO; 64];
599 let mut b_vals = [Bit::ZERO; 64];
600
601 for i in 0..64 {
602 a_vals[i] = Bit::new(rng.random::<u8>());
603 b_vals[i] = Bit::new(rng.random::<u8>());
604 }
605
606 let a_flat_vals = a_vals.map(|x| x.to_hardware());
607 let b_flat_vals = b_vals.map(|x| x.to_hardware());
608 let a_packed = Flat::<Bit>::pack(&a_flat_vals);
609 let b_packed = Flat::<Bit>::pack(&b_flat_vals);
610
611 let add_res = Bit::add_hardware_packed(a_packed, b_packed);
613
614 let mut add_out = [Bit::ZERO.to_hardware(); 64];
615 Flat::<Bit>::unpack(add_res, &mut add_out);
616
617 for i in 0..64 {
618 assert_eq!(
619 add_out[i],
620 (a_vals[i] + b_vals[i]).to_hardware(),
621 "Bit packed add mismatch at index {}",
622 i
623 );
624 }
625
626 let mul_res = Bit::mul_hardware_packed(a_packed, b_packed);
628
629 let mut mul_out = [Bit::ZERO.to_hardware(); 64];
630 Flat::<Bit>::unpack(mul_res, &mut mul_out);
631
632 for i in 0..64 {
633 assert_eq!(
634 mul_out[i],
635 (a_vals[i] * b_vals[i]).to_hardware(),
636 "Bit packed mul mismatch at index {}",
637 i
638 );
639 }
640 }
641 }
642
643 #[test]
648 fn pack_unpack_roundtrip() {
649 let mut rng = rng();
650 let mut data = [Bit::ZERO; PACKED_WIDTH_BIT];
652
653 for v in data.iter_mut() {
654 *v = Bit::new(rng.random());
655 }
656
657 let packed = Bit::pack(&data);
658 let mut unpacked = [Bit::ZERO; PACKED_WIDTH_BIT];
659 Bit::unpack(packed, &mut unpacked);
660
661 assert_eq!(data, unpacked, "Bit pack/unpack roundtrip failed");
662 }
663
664 #[test]
665 fn packed_add_consistency() {
666 let mut rng = rng();
667 let mut a_vals = [Bit::ZERO; PACKED_WIDTH_BIT];
668 let mut b_vals = [Bit::ZERO; PACKED_WIDTH_BIT];
669
670 for i in 0..PACKED_WIDTH_BIT {
671 a_vals[i] = Bit::new(rng.random());
672 b_vals[i] = Bit::new(rng.random());
673 }
674
675 let a_packed = Bit::pack(&a_vals);
676 let b_packed = Bit::pack(&b_vals);
677
678 let res_packed = a_packed + b_packed;
680
681 let mut res_unpacked = [Bit::ZERO; PACKED_WIDTH_BIT];
682 Bit::unpack(res_packed, &mut res_unpacked);
683
684 for i in 0..PACKED_WIDTH_BIT {
685 assert_eq!(
686 res_unpacked[i],
687 a_vals[i] + b_vals[i], "Bit packed add mismatch"
689 );
690 }
691 }
692
693 #[test]
694 fn packed_mul_consistency() {
695 let mut rng = rng();
696
697 for _ in 0..100 {
698 let mut a_arr = [Bit::ZERO; PACKED_WIDTH_BIT];
699 let mut b_arr = [Bit::ZERO; PACKED_WIDTH_BIT];
700
701 for i in 0..PACKED_WIDTH_BIT {
702 a_arr[i] = Bit::new(rng.random());
703 b_arr[i] = Bit::new(rng.random());
704 }
705
706 let a_packed = PackedBit(a_arr); let b_packed = PackedBit(b_arr);
708
709 let c_packed = a_packed * b_packed;
711
712 let mut c_expected = [Bit::ZERO; PACKED_WIDTH_BIT];
713 for i in 0..PACKED_WIDTH_BIT {
714 c_expected[i] = a_arr[i] * b_arr[i]; }
716
717 assert_eq!(c_packed.0, c_expected, "Bit packed mul mismatch");
718 }
719 }
720}