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