1use super::security_warning::warn_proj;
2use crate::{
3 AllWire, ArithmeticWire, FancyArithmetic, FancyBinary, FancyProj, HasModulus, WireMod2,
4 check_binary,
5 fancy::Fancy,
6 garble::binary_and::BinaryWireLabel,
7 hash_wires,
8 util::{output_tweak, tweak, tweak2},
9 wire::WireLabel,
10};
11use swanky_channel::Channel;
12use swanky_error::ErrorKind;
13use vectoreyes::U8x16;
14
15pub struct Evaluator<Wire> {
20 one: Wire,
21 current_gate: usize,
22 current_output: usize,
23}
24
25impl<Wire: WireLabel> Evaluator<Wire> {
26 pub fn new(channel: &mut Channel) -> swanky_error::Result<Self> {
28 let one = channel.read::<U8x16>()?;
31 Ok(Evaluator {
32 one: Wire::from_repr(one, 2),
33 current_gate: 0,
34 current_output: 0,
35 })
36 }
37
38 fn current_gate(&mut self) -> usize {
40 let current = self.current_gate;
41 self.current_gate += 1;
42 current
43 }
44
45 fn current_output(&mut self) -> usize {
47 let current = self.current_output;
48 self.current_output += 1;
49 current
50 }
51}
52
53impl<W: BinaryWireLabel> FancyBinary for Evaluator<W> {
54 fn negate(&mut self, x: &Self::Item) -> Self::Item {
56 *x + self.one
57 }
58
59 fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
60 *x + *y
61 }
62
63 fn and(
64 &mut self,
65 A: &Self::Item,
66 B: &Self::Item,
67 channel: &mut Channel,
68 ) -> swanky_error::Result<Self::Item> {
69 let gate_num = self.current_gate();
70 let gate0 = channel.read()?;
71 let gate1 = channel.read()?;
72 Ok(W::evaluate_and_gate(gate_num, A, B, &gate0, &gate1))
73 }
74}
75
76impl FancyBinary for Evaluator<AllWire> {
77 fn negate(&mut self, x: &Self::Item) -> Self::Item {
79 check_binary!(x);
80
81 x.clone() + self.one.clone()
82 }
83
84 fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
85 check_binary!(x);
86 check_binary!(y);
87
88 self.add(x, y)
89 }
90
91 fn and(
92 &mut self,
93 x: &Self::Item,
94 y: &Self::Item,
95 channel: &mut Channel,
96 ) -> swanky_error::Result<Self::Item> {
97 if let (AllWire::Mod2(A), AllWire::Mod2(B)) = (x, y) {
98 let gate_num = self.current_gate();
99 let gate0 = channel.read()?;
100 let gate1 = channel.read()?;
101 return Ok(AllWire::Mod2(WireMod2::evaluate_and_gate(
102 gate_num, A, B, &gate0, &gate1,
103 )));
104 }
105
106 check_binary!(x);
108 check_binary!(y);
109
110 unreachable!()
112 }
113}
114
115impl<Wire: WireLabel + ArithmeticWire> FancyArithmetic for Evaluator<Wire> {
116 fn add(&mut self, x: &Wire, y: &Wire) -> Wire {
117 assert_eq!(x.modulus(), y.modulus());
118 x.clone() + y.clone()
119 }
120
121 fn sub(&mut self, x: &Wire, y: &Wire) -> Wire {
122 assert_eq!(x.modulus(), y.modulus());
123 x.clone() - y.clone()
124 }
125
126 fn cmul(&mut self, x: &Wire, c: u16) -> Wire {
127 x.clone() * c
128 }
129
130 fn mul(&mut self, A: &Wire, B: &Wire, channel: &mut Channel) -> swanky_error::Result<Wire> {
131 if A.modulus() < B.modulus() {
132 return self.mul(B, A, channel);
133 }
134 let q = A.modulus();
135 let qb = B.modulus();
136 let unequal = q != qb;
137 let ngates = q as usize + qb as usize - 2 + unequal as usize;
138 let mut gate = Vec::with_capacity(ngates);
139 {
140 for _ in 0..ngates {
141 let block = channel.read::<U8x16>()?;
142 gate.push(block);
143 }
144 }
145 let gate_num = self.current_gate();
146 let g = tweak2(gate_num as u64, 0);
147
148 let [hashA, hashB] = hash_wires([A, B], g);
149
150 let L = if A.color() == 0 {
152 Wire::hash_to_mod(hashA, q)
153 } else {
154 let ct_left = gate[A.color() as usize - 1];
155 Wire::from_repr(ct_left ^ hashA, q)
156 };
157
158 let R = if B.color() == 0 {
160 Wire::hash_to_mod(hashB, q)
161 } else {
162 let ct_right = gate[(q + B.color()) as usize - 2];
163 Wire::from_repr(ct_right ^ hashB, q)
164 };
165
166 let new_b_color = if unequal {
169 let minitable = *gate.last().unwrap();
170 let ct = u128::from(minitable) >> (B.color() * 16);
171 let pt = u128::from(B.hash(tweak2(gate_num as u64, 1))) ^ ct;
172 pt as u16
173 } else {
174 B.color()
175 };
176
177 let res = L + R + A.clone() * new_b_color;
178 Ok(res)
179 }
180}
181
182impl<Wire: WireLabel + ArithmeticWire> FancyProj for Evaluator<Wire> {
183 fn proj(
184 &mut self,
185 x: &Wire,
186 q: u16,
187 _: Option<Vec<u16>>,
188 channel: &mut Channel,
189 ) -> swanky_error::Result<Wire> {
190 warn_proj();
191 let ngates = (x.modulus() - 1) as usize;
192 let mut gate = Vec::with_capacity(ngates);
193 for _ in 0..ngates {
194 let block = channel.read::<U8x16>()?;
195 gate.push(block);
196 }
197 let t = tweak(self.current_gate());
198 if x.color() == 0 {
199 Ok(x.hashback(t, q))
200 } else {
201 let ct = gate[x.color() as usize - 1];
202 Ok(Wire::from_repr(ct ^ x.hash(t), q))
203 }
204 }
205}
206
207impl<Wire: WireLabel> Fancy for Evaluator<Wire> {
208 type Item = Wire;
209
210 fn encode_many(
211 &mut self,
212 _values: &[u16],
213 _moduli: &[u16],
214 _: &mut Channel,
215 ) -> swanky_error::Result<Vec<Self::Item>> {
216 unimplemented!("Evaluator cannot encode values")
217 }
218
219 fn receive_many(
220 &mut self,
221 moduli: &[u16],
222 channel: &mut Channel,
223 ) -> swanky_error::Result<Vec<Self::Item>> {
224 moduli
225 .iter()
226 .map(|q| {
227 let block = channel.read()?;
228 Ok(Wire::from_repr(block, *q))
229 })
230 .collect()
231 }
232
233 fn constant(&mut self, _: u16, q: u16, channel: &mut Channel) -> swanky_error::Result<Wire> {
234 Ok(Wire::from_repr(channel.read()?, q))
235 }
236
237 fn output(&mut self, x: &Wire, channel: &mut Channel) -> swanky_error::Result<Option<u16>> {
238 let q = x.modulus();
239 let i = self.current_output();
240
241 let mut ct = Vec::with_capacity(q as usize);
243 for _ in 0..q {
244 let block = channel.read()?;
245 ct.push(block);
246 }
247
248 let mut decoded = None;
250 for k in 0..q {
251 let hashed_wire = x.hash(output_tweak(i, k));
252 if hashed_wire == ct[k as usize] {
253 decoded = Some(k);
254 break;
255 }
256 }
257
258 if let Some(output) = decoded {
259 Ok(Some(output))
260 } else {
261 swanky_error::bail!(ErrorKind::OtherError, "Decoding failed");
262 }
263 }
264}