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