fancy_garbling/wire/
mod2.rs1use crate::WireLabel;
2use fancy_traits::HasModulus;
3use rand::{CryptoRng, Rng, RngExt};
4use subtle::ConditionallySelectable;
5use vectoreyes::{SimdBase, U8x16};
6
7impl HasModulus for WireMod2 {
8 fn modulus(&self) -> u16 {
9 2
10 }
11}
12
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[derive(Debug, Clone, Copy, PartialEq, Default)]
16pub struct WireMod2 {
17 pub(crate) val: U8x16,
19}
20
21impl core::ops::Add for WireMod2 {
22 type Output = Self;
23
24 #[allow(clippy::suspicious_arithmetic_impl)]
25 fn add(self, rhs: Self) -> Self::Output {
26 Self {
27 val: self.val ^ rhs.val,
28 }
29 }
30}
31
32impl core::ops::AddAssign for WireMod2 {
33 #[allow(clippy::suspicious_op_assign_impl)]
34 fn add_assign(&mut self, rhs: Self) {
35 self.val ^= rhs.val;
36 }
37}
38
39impl core::ops::Sub for WireMod2 {
40 type Output = Self;
41
42 fn sub(self, rhs: Self) -> Self::Output {
43 self + -rhs
44 }
45}
46
47impl core::ops::SubAssign for WireMod2 {
48 fn sub_assign(&mut self, rhs: Self) {
49 *self = *self - rhs;
50 }
51}
52
53impl core::ops::Neg for WireMod2 {
54 type Output = Self;
55
56 fn neg(self) -> Self::Output {
57 self
59 }
60}
61
62impl core::ops::Mul<u16> for WireMod2 {
63 type Output = Self;
64
65 fn mul(self, rhs: u16) -> Self::Output {
66 if rhs & 1 == 0 {
67 Self {
68 val: Default::default(),
69 }
70 } else {
71 self
72 }
73 }
74}
75
76impl core::ops::MulAssign<u16> for WireMod2 {
77 fn mul_assign(&mut self, rhs: u16) {
78 if rhs & 1 == 0 {
79 self.val = Default::default();
80 }
81 }
82}
83
84impl ConditionallySelectable for WireMod2 {
85 fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
86 WireMod2::from_repr(
87 U8x16::conditional_select(&a.to_repr(), &b.to_repr(), choice),
88 2,
89 )
90 }
91}
92
93impl WireLabel for WireMod2 {
94 fn rand_delta<R: CryptoRng + Rng>(rng: &mut R, q: u16) -> Self {
95 if q != 2 {
96 panic!("[WireMod2::rand_delta] Expected modulo 2. Got {}", q);
97 }
98 let mut w = Self::rand(rng, q);
99 w.val |= U8x16::set_lo(1);
100 w
101 }
102
103 fn to_repr(&self) -> U8x16 {
104 self.val
108 }
109
110 fn color(&self) -> u16 {
111 (self.val.extract::<0>() & 1) as u16
113 }
114
115 fn from_repr(inp: U8x16, q: u16) -> Self {
116 if q != 2 {
120 panic!("[WireMod2::from_block] Expected modulo 2. Got {}", q);
121 }
122 Self { val: inp }
123 }
124
125 fn rand<R: CryptoRng + Rng>(rng: &mut R, q: u16) -> Self {
126 if q != 2 {
127 panic!("[WireMod2::rand] Expected modulo 2. Got {}", q);
128 }
129
130 Self { val: rng.random() }
131 }
132
133 fn hash_to_mod(hash: U8x16, q: u16) -> Self {
134 if q != 2 {
135 panic!("[WireMod2::hash_to_mod] Expected modulo 2. Got {}", q);
136 }
137 Self::from_repr(hash, q)
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 #[cfg(feature = "serde")]
144 #[test]
145 fn test_serialize_mod2() {
146 use crate::{WireLabel, WireMod2};
147 use rand::rng;
148
149 let mut rng = rng();
150 let w = WireMod2::rand(&mut rng, 2);
151 let serialized = serde_json::to_string(&w).unwrap();
152
153 let deserialized: WireMod2 = serde_json::from_str(&serialized).unwrap();
154
155 assert_eq!(w, deserialized);
156 }
157}