1use crate::{
2 AllWire, ArithmeticWire, FancyArithmetic, FancyBinary, HasModulus, WireLabel, WireMod2,
3 check_binary,
4 errors::{FancyError, GarblerError},
5 fancy::{BinaryBundle, CrtBundle, Fancy, FancyReveal},
6 hash_wires,
7 util::{RngExt, output_tweak, tweak, tweak2},
8};
9use rand::{CryptoRng, RngCore};
10#[cfg(feature = "serde")]
11use serde::de::DeserializeOwned;
12use std::collections::HashMap;
13use subtle::ConditionallySelectable;
14use swanky_block::Block;
15use swanky_channel_legacy::AbstractChannel;
16
17use super::security_warning::warn_proj;
18
19pub struct Garbler<C, RNG, Wire> {
21 pub(crate) channel: C,
22 deltas: HashMap<u16, Wire>, current_output: usize,
24 current_gate: usize,
25 rng: RNG,
26}
27
28#[cfg(feature = "serde")]
29impl<C: AbstractChannel, RNG: CryptoRng + RngCore, Wire: WireLabel + DeserializeOwned>
30 Garbler<C, RNG, Wire>
31{
32 pub fn load_deltas(&mut self, filename: &str) -> Result<(), Box<dyn std::error::Error>> {
34 let f = std::fs::File::open(filename)?;
35 let reader = std::io::BufReader::new(f);
36 let deltas: HashMap<u16, Wire> = serde_json::from_reader(reader)?;
37 self.deltas.extend(deltas.into_iter());
38 Ok(())
39 }
40}
41
42impl<C: AbstractChannel, RNG: CryptoRng + RngCore, Wire: WireLabel> Garbler<C, RNG, Wire> {
43 pub fn new(channel: C, rng: RNG) -> Self {
45 Garbler {
46 channel,
47 deltas: HashMap::new(),
48 current_gate: 0,
49 current_output: 0,
50 rng,
51 }
52 }
53
54 fn current_gate(&mut self) -> usize {
56 let current = self.current_gate;
57 self.current_gate += 1;
58 current
59 }
60
61 pub fn delta(&mut self, q: u16) -> Wire {
64 if let Some(delta) = self.deltas.get(&q) {
65 return delta.clone();
66 }
67 let w = Wire::rand_delta(&mut self.rng, q);
68 self.deltas.insert(q, w.clone());
69 w
70 }
71
72 fn current_output(&mut self) -> usize {
74 let current = self.current_output;
75 self.current_output += 1;
76 current
77 }
78
79 pub fn get_deltas(self) -> HashMap<u16, Wire> {
83 self.deltas
84 }
85
86 pub fn send_wire(&mut self, wire: &Wire) -> Result<(), GarblerError> {
88 self.channel.write_block(&wire.as_block())?;
89 Ok(())
90 }
91
92 pub fn encode_wire(&mut self, val: u16, modulus: u16) -> (Wire, Wire) {
94 let zero = Wire::rand(&mut self.rng, modulus);
95 let delta = self.delta(modulus);
96 let enc = zero.plus(&delta.cmul(val));
97 (zero, enc)
98 }
99
100 pub fn encode_many_wires(
102 &mut self,
103 vals: &[u16],
104 moduli: &[u16],
105 ) -> Result<(Vec<Wire>, Vec<Wire>), GarblerError> {
106 if vals.len() != moduli.len() {
107 return Err(GarblerError::EncodingError);
108 }
109 assert!(vals.len() == moduli.len());
110 let mut gbs = Vec::with_capacity(vals.len());
111 let mut evs = Vec::with_capacity(vals.len());
112 for (x, q) in vals.iter().zip(moduli.iter()) {
113 let (gb, ev) = self.encode_wire(*x, *q);
114 gbs.push(gb);
115 evs.push(ev);
116 }
117 Ok((gbs, evs))
118 }
119
120 pub fn crt_encode_wire(
122 &mut self,
123 val: u128,
124 modulus: u128,
125 ) -> Result<(CrtBundle<Wire>, CrtBundle<Wire>), GarblerError> {
126 let ms = crate::util::factor(modulus);
127 let xs = crate::util::crt(val, &ms);
128 let (gbs, evs) = self.encode_many_wires(&xs, &ms)?;
129 Ok((CrtBundle::new(gbs), CrtBundle::new(evs)))
130 }
131
132 pub fn bin_encode_wire(
134 &mut self,
135 val: u128,
136 nbits: usize,
137 ) -> Result<(BinaryBundle<Wire>, BinaryBundle<Wire>), GarblerError> {
138 let xs = crate::util::u128_to_bits(val, nbits);
139 let ms = vec![2; nbits];
140 let (gbs, evs) = self.encode_many_wires(&xs, &ms)?;
141 Ok((BinaryBundle::new(gbs), BinaryBundle::new(evs)))
142 }
143
144 fn garble_and_gate(
151 &mut self,
152 A: &WireMod2,
153 B: &WireMod2,
154 delta: &WireMod2,
155 ) -> (Block, Block, WireMod2) {
156 let q = A.modulus();
157 let D = delta;
158 let gate_num = self.current_gate();
159
160 let r = B.color(); let g = tweak2(gate_num as u64, 0);
163
164 let alpha = A.color(); let X1 = A.plus(&D.cmul(alpha));
167
168 let beta = (q - B.color()) % q;
170 let Y1 = B.plus(&D.cmul(beta));
171
172 let AD = A.plus(D);
173 let BD = B.plus(D);
174
175 let a_selector = (A.color() as u8).into();
177 let b_selector = (B.color() as u8).into();
178
179 let B = WireMod2::conditional_select(&BD, B, b_selector);
180 let newA = WireMod2::conditional_select(&AD, A, a_selector);
181 let idx = u8::conditional_select(&(r as u8), &0u8, a_selector);
182
183 let [hashA, hashB, hashX, hashY] = hash_wires([&newA, &B, &X1, &Y1], g);
184
185 let X = WireMod2::hash_to_mod(hashX, q).plus_mov(&D.cmul(alpha * r % q));
186 let Y = WireMod2::hash_to_mod(hashY, q);
187
188 let gate0 =
189 hashA ^ Block::conditional_select(&X.as_block(), &X.plus(D).as_block(), idx.into());
190 let gate1 = hashB ^ Y.plus(A).as_block();
191
192 (gate0, gate1, X.plus_mov(&Y))
193 }
194}
195
196impl<C: AbstractChannel, RNG: RngCore + CryptoRng, Wire: WireLabel> FancyReveal
197 for Garbler<C, RNG, Wire>
198{
199 fn reveal(&mut self, x: &Wire) -> Result<u16, GarblerError> {
200 self.output(x)?;
203 self.channel.flush()?;
204 let val = self.channel.read_u16()?;
205 Ok(val)
206 }
207}
208
209impl<C: AbstractChannel, RNG: RngCore + CryptoRng> FancyBinary for Garbler<C, RNG, WireMod2> {
210 fn and(&mut self, A: &Self::Item, B: &Self::Item) -> Result<Self::Item, Self::Error> {
211 let delta = self.delta(2);
212 let (gate0, gate1, C) = self.garble_and_gate(A, B, &delta);
213 self.channel.write_block(&gate0)?;
214 self.channel.write_block(&gate1)?;
215 Ok(C)
216 }
217
218 fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error> {
219 Ok(x.plus(y))
220 }
221
222 fn negate(&mut self, x: &Self::Item) -> Result<Self::Item, Self::Error> {
227 let delta = self.delta(2);
228 self.xor(&delta, x)
229 }
230}
231
232impl<C: AbstractChannel, RNG: RngCore + CryptoRng> FancyBinary for Garbler<C, RNG, AllWire> {
233 fn negate(&mut self, x: &Self::Item) -> Result<Self::Item, Self::Error> {
238 check_binary!(x);
239
240 let delta = self.delta(2);
241 self.xor(&delta, x)
242 }
243
244 fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error> {
246 check_binary!(x);
247 check_binary!(y);
248
249 self.add(x, y)
250 }
251
252 fn and(&mut self, x: &Self::Item, y: &Self::Item) -> Result<Self::Item, Self::Error> {
254 if let (AllWire::Mod2(A), AllWire::Mod2(B), AllWire::Mod2(ref delta)) =
255 (x, y, self.delta(2))
256 {
257 let (gate0, gate1, C) = self.garble_and_gate(A, B, delta);
258 self.channel.write_block(&gate0)?;
259 self.channel.write_block(&gate1)?;
260 return Ok(AllWire::Mod2(C));
261 }
262 check_binary!(x);
264 check_binary!(y);
265
266 unreachable!()
268 }
269}
270
271impl<C: AbstractChannel, RNG: RngCore + CryptoRng, Wire: WireLabel + ArithmeticWire> FancyArithmetic
272 for Garbler<C, RNG, Wire>
273{
274 fn add(&mut self, x: &Wire, y: &Wire) -> Result<Wire, GarblerError> {
275 if x.modulus() != y.modulus() {
276 return Err(GarblerError::FancyError(FancyError::UnequalModuli));
277 }
278 Ok(x.plus(y))
279 }
280
281 fn sub(&mut self, x: &Wire, y: &Wire) -> Result<Wire, GarblerError> {
282 if x.modulus() != y.modulus() {
283 return Err(GarblerError::FancyError(FancyError::UnequalModuli));
284 }
285 Ok(x.minus(y))
286 }
287
288 fn cmul(&mut self, x: &Wire, c: u16) -> Result<Wire, GarblerError> {
289 Ok(x.cmul(c))
290 }
291
292 fn mul(&mut self, A: &Wire, B: &Wire) -> Result<Wire, GarblerError> {
293 if A.modulus() < B.modulus() {
294 return self.mul(B, A);
295 }
296
297 let q = A.modulus();
298 let qb = B.modulus();
299 let gate_num = self.current_gate();
300
301 let D = self.delta(q);
302 let Db = self.delta(qb);
303
304 let r;
305 let mut gate = vec![Block::default(); q as usize + qb as usize - 2];
306
307 if q != qb {
309 if qb > 8 {
311 return Err(GarblerError::AsymmetricHalfGateModuliMax8(qb));
312 }
313
314 r = self.rng.gen_u16() % q;
315 let t = tweak2(gate_num as u64, 1);
316
317 let mut minitable = vec![u128::default(); qb as usize];
318 let mut B_ = B.clone();
319 for b in 0..qb {
320 if b > 0 {
321 B_.plus_eq(&Db);
322 }
323 let new_color = ((r + b) % q) as u128;
324 let ct = (u128::from(B_.hash(t)) & 0xFFFF) ^ new_color;
325 minitable[B_.color() as usize] = ct;
326 }
327
328 let mut packed = 0;
329 for i in 0..qb as usize {
330 packed += minitable[i] << (16 * i);
331 }
332 gate.push(Block::from(packed));
333 } else {
334 r = B.color(); }
336
337 let g = tweak2(gate_num as u64, 0);
338
339 let alpha = (q - A.color()) % q; let X1 = A.plus(&D.cmul(alpha));
342
343 let beta = (qb - B.color()) % qb;
345 let Y1 = B.plus(&Db.cmul(beta));
346
347 let [hashX, hashY] = hash_wires([&X1, &Y1], g);
348
349 let X = Wire::hash_to_mod(hashX, q).plus_mov(&D.cmul(alpha * r % q));
350 let Y = Wire::hash_to_mod(hashY, q).plus_mov(&A.cmul((beta + r) % q));
351
352 let mut precomp = Vec::with_capacity(q as usize);
353 let mut X_ = X.clone();
356 precomp.push(X_.as_block());
357 for _ in 1..q {
358 X_.plus_eq(&D);
359 precomp.push(X_.as_block());
360 }
361
362 let mut A_ = A.clone();
366 for a in 0..q {
367 if a > 0 {
368 A_.plus_eq(&D);
369 }
370 if A_.color() != 0 {
373 gate[A_.color() as usize - 1] =
374 A_.hash(g) ^ precomp[((q - (a * r % q)) % q) as usize];
375 }
376 }
377 precomp.clear();
378
379 let mut Y_ = Y.clone();
382 precomp.push(Y_.as_block());
383 for _ in 1..q {
384 Y_.plus_eq(A);
385 precomp.push(Y_.as_block());
386 }
387
388 let mut B_ = B.clone();
390 for b in 0..qb {
391 if b > 0 {
392 B_.plus_eq(&Db);
393 }
394 if B_.color() != 0 {
397 gate[q as usize - 1 + B_.color() as usize - 1] =
398 B_.hash(g) ^ precomp[((q - ((b + r) % q)) % q) as usize];
399 }
400 }
401
402 for block in gate.iter() {
403 self.channel.write_block(block)?;
404 }
405 Ok(X.plus_mov(&Y))
406 }
407
408 fn proj(&mut self, A: &Wire, q_out: u16, tt: Option<Vec<u16>>) -> Result<Wire, GarblerError> {
409 warn_proj();
410 let tt = tt.ok_or(GarblerError::TruthTableRequired)?;
411
412 let q_in = A.modulus();
413 let mut gate = vec![Block::default(); q_in as usize - 1];
414
415 let tao = A.color();
416 let g = tweak(self.current_gate());
417
418 let Din = self.delta(q_in);
419 let Dout = self.delta(q_out);
420
421 let C = A
424 .plus(&Din.cmul((q_in - tao) % q_in))
425 .hashback(g, q_out)
426 .plus_mov(&Dout.cmul((q_out - tt[((q_in - tao) % q_in) as usize]) % q_out));
427
428 let C_precomputed = {
430 let mut C_ = C.clone();
431 (0..q_out)
432 .map(|x| {
433 if x > 0 {
434 C_.plus_eq(&Dout);
435 }
436 C_.as_block()
437 })
438 .collect::<Vec<Block>>()
439 };
440
441 let mut A_ = A.clone();
442 for x in 0..q_in {
443 if x > 0 {
444 A_.plus_eq(&Din); }
446
447 let ix = (tao as usize + x as usize) % q_in as usize;
448 if ix == 0 {
449 continue;
450 }
451
452 let ct = A_.hash(g) ^ C_precomputed[tt[x as usize] as usize];
453 gate[ix - 1] = ct;
454 }
455
456 for block in gate.iter() {
457 self.channel.write_block(block)?;
458 }
459 Ok(C)
460 }
461}
462
463impl<C: AbstractChannel, RNG: RngCore + CryptoRng, Wire: WireLabel> Fancy
464 for Garbler<C, RNG, Wire>
465{
466 type Item = Wire;
467 type Error = GarblerError;
468
469 fn constant(&mut self, x: u16, q: u16) -> Result<Wire, GarblerError> {
470 let zero = Wire::rand(&mut self.rng, q);
471 let wire = zero.plus(self.delta(q).cmul_eq(x));
472 self.send_wire(&wire)?;
473 Ok(zero)
474 }
475
476 fn output(&mut self, X: &Wire) -> Result<Option<u16>, GarblerError> {
477 let q = X.modulus();
478 let i = self.current_output();
479 let D = self.delta(q);
480 for k in 0..q {
481 let block = X.plus(&D.cmul(k)).hash(output_tweak(i, k));
482 self.channel.write_block(&block)?;
483 }
484 Ok(None)
485 }
486}