fancy_garbling/wire/
mod2.rs1use crate::{BinaryWireLabel, WireLabel, util::tweak2, wire::hash_wires};
2use fancy_traits::HasModulus;
3use rand::{CryptoRng, 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: &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: &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
141impl BinaryWireLabel for WireMod2 {
142 fn garble_and_gate(gate_num: usize, A: &Self, B: &Self, delta: &Self) -> (U8x16, U8x16, Self) {
143 let q = A.modulus();
144 let D = delta;
145
146 let r = B.color(); let g = tweak2(gate_num as u64, 0);
149
150 let alpha = A.color(); let X1 = *A + *D * alpha;
153
154 let beta = (q - B.color()) % q;
156 let Y1 = *B + *D * beta;
157
158 let AD = *A + *D;
159 let BD = *B + *D;
160
161 let a_selector = (A.color() as u8).into();
163 let b_selector = (B.color() as u8).into();
164
165 let B = Self::conditional_select(&BD, B, b_selector);
166 let newA = Self::conditional_select(&AD, A, a_selector);
167 let idx = u8::conditional_select(&(r as u8), &0u8, a_selector);
168
169 let [hashA, hashB, hashX, hashY] = hash_wires([&newA, &B, &X1, &Y1], g);
170
171 let X = Self::hash_to_mod(hashX, q) + *D * (alpha * r % q);
172 let Y = Self::hash_to_mod(hashY, q);
173
174 let gate0 =
175 hashA ^ U8x16::conditional_select(&X.to_repr(), &(X + *D).to_repr(), idx.into());
176 let gate1 = hashB ^ (Y + *A).to_repr();
177
178 (gate0, gate1, X + Y)
179 }
180
181 fn evaluate_and_gate(
182 gate_num: usize,
183 A: &Self,
184 B: &Self,
185 gate0: &U8x16,
186 gate1: &U8x16,
187 ) -> Self {
188 let g = tweak2(gate_num as u64, 0);
189
190 let [hashA, hashB] = hash_wires([A, B], g);
191
192 let L = Self::from_repr(
194 U8x16::conditional_select(&hashA, &(hashA ^ *gate0), (A.color() as u8).into()),
195 2,
196 );
197
198 let R = Self::from_repr(
200 U8x16::conditional_select(&hashB, &(hashB ^ *gate1), (B.color() as u8).into()),
201 2,
202 );
203
204 L + R + *A * B.color()
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 #[cfg(feature = "serde")]
211 #[test]
212 fn test_serialize_mod2() {
213 use crate::{WireLabel, WireMod2};
214 use rand::rng;
215
216 let mut rng = rng();
217 let w = WireMod2::rand(&mut rng, 2);
218 let serialized = serde_json::to_string(&w).unwrap();
219
220 let deserialized: WireMod2 = serde_json::from_str(&serialized).unwrap();
221
222 assert_eq!(w, deserialized);
223 }
224}