fancy_garbling/
classic.rs1use crate::{
5 WireLabel,
6 garble::{Evaluator, Garbler},
7 util::output_tweak,
8};
9use fancy_traits::{Circuit, CircuitInputMapper, CircuitOutputMapper, FancyOutput};
10use rand::CryptoRng;
11use swanky_channel::Channel;
12use swanky_error::ErrorKind;
13use swanky_field_binary::F2;
14use vectoreyes::U8x16;
15
16#[derive(Debug)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct GarbledCircuit {
23 blocks: Vec<U8x16>,
24}
25
26impl GarbledCircuit {
27 pub fn new(blocks: Vec<U8x16>) -> Self {
30 GarbledCircuit { blocks }
31 }
32
33 pub fn size(&self) -> usize {
35 self.blocks.len()
36 }
37
38 pub fn garble<
46 Wire: WireLabel<F2>,
47 C: CircuitInputMapper<Garbler<RNG, Wire>> + CircuitOutputMapper<Garbler<RNG, Wire>>,
48 RNG: CryptoRng,
49 >(
50 circuit: &C,
51 rng: RNG,
52 ) -> swanky_error::Result<(Encoder<Wire>, Self, OutputMapping)> {
53 let mut garbler = Garbler::new(rng);
54
55 let inputs = (0..circuit.ninputs())
57 .map(|_| garbler.encode_zero())
58 .collect::<Vec<_>>();
59
60 let mut channel = GarbledChannel::new_writer(None);
61 let (en, output_mapping) = Channel::with(&mut channel, |channel| {
62 let zeros = circuit.execute(&mut garbler, circuit.map(inputs.clone()), channel)?;
65 let zeros = C::flatten(zeros);
66 garbler.outputs(&zeros, channel)?;
71
72 let en = Encoder::new(inputs, garbler.delta());
73 let output_mapping = OutputMapping::new(&zeros, garbler.delta());
74
75 Ok((en, output_mapping))
76 })?;
77 let gc = GarbledCircuit::new(channel.finish_writing());
78 Ok((en, gc, output_mapping))
79 }
80
81 pub fn eval<Wire: WireLabel<F2>, C: CircuitOutputMapper<Evaluator<Wire>>>(
84 &self,
85 circuit: &C,
86 inputs: C::Input,
87 output_mapping: &OutputMapping,
88 ) -> swanky_error::Result<Vec<F2>> {
89 let wirelabels = self.eval_to_wirelabels(circuit, inputs)?;
90 output_mapping.to_outputs(&C::flatten(wirelabels))
91 }
92
93 pub fn eval_to_wirelabels<Wire: WireLabel<F2>, C: Circuit<Evaluator<Wire>>>(
96 &self,
97 circuit: &C,
98 inputs: C::Input,
99 ) -> swanky_error::Result<C::Output> {
100 let mut evaluator = Evaluator::new();
101 Channel::with(GarbledChannel::from(self), |channel| {
102 circuit.execute(&mut evaluator, inputs, channel)
103 })
104 }
105}
106
107#[derive(Debug)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
110pub struct Encoder<Wire> {
111 inputs: Vec<Wire>,
112 delta: Wire,
113}
114
115impl<Wire: WireLabel<F2>> Encoder<Wire> {
116 pub fn new(inputs: Vec<Wire>, delta: Wire) -> Self {
119 Encoder { inputs, delta }
120 }
121
122 pub fn encode_inputs(&self, inputs: &[F2]) -> Vec<Wire> {
128 assert_eq!(inputs.len(), self.inputs.len());
129 self.inputs
130 .iter()
131 .zip(inputs)
132 .map(|(zero, x)| *zero + self.delta * (*x).into())
133 .collect()
134 }
135}
136
137#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
139pub struct OutputMapping(Vec<[U8x16; 2]>);
140
141impl OutputMapping {
142 pub fn new<Wire: WireLabel<F2>>(zeros: &[Wire], delta: Wire) -> Self {
145 let outputs = zeros
146 .iter()
147 .enumerate()
148 .map(|(i, zero)| {
149 core::array::from_fn(|j| {
150 (*zero + delta * (j as u16)).hash(output_tweak(i, j as u16))
151 })
152 })
153 .collect::<Vec<_>>();
154 Self(outputs)
155 }
156
157 pub fn to_outputs<Wire: WireLabel<F2>>(
163 &self,
164 wirelabels: &[Wire],
165 ) -> swanky_error::Result<Vec<F2>> {
166 wirelabels
167 .iter()
168 .enumerate()
169 .map(|(i, wirelabel)| {
170 let mut decoded = None;
171 for k in 0..2 {
172 let hashed = wirelabel.hash(output_tweak(i, k));
173 if hashed == self.0[i][k as usize] {
174 decoded = Some(k);
175 break;
176 }
177 }
178 if let Some(output) = decoded {
179 Ok(F2::from(output != 0))
180 } else {
181 swanky_error::bail!(ErrorKind::OtherError, "Decoding failed");
182 }
183 })
184 .collect()
185 }
186}
187
188pub struct GarbledChannel {
203 reader: Option<GarbledReader>,
204 writer: Option<GarbledWriter>,
205}
206
207impl GarbledChannel {
208 pub fn new_writer(ngates: Option<usize>) -> Self {
210 Self {
211 reader: None,
212 writer: Some(GarbledWriter::new(ngates)),
213 }
214 }
215
216 pub fn finish_writing(self) -> Vec<U8x16> {
221 self.writer.unwrap().finish()
222 }
223}
224
225impl std::io::Read for GarbledChannel {
226 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
227 let reader = self.reader.as_mut().unwrap();
228 reader.read(buf)
229 }
230}
231
232impl std::io::Write for GarbledChannel {
233 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
234 let writer = self.writer.as_mut().unwrap();
235 writer.write(buf)
236 }
237
238 fn flush(&mut self) -> std::io::Result<()> {
239 let writer = self.writer.as_mut().unwrap();
240 writer.flush()
241 }
242}
243
244impl From<&GarbledCircuit> for GarbledChannel {
245 fn from(value: &GarbledCircuit) -> Self {
246 Self {
247 reader: Some(GarbledReader::new(&value.blocks)),
248 writer: None,
249 }
250 }
251}
252
253#[derive(Debug)]
255struct GarbledReader {
256 blocks: Vec<U8x16>,
257 index: usize,
258}
259
260impl GarbledReader {
261 fn new(blocks: &[U8x16]) -> Self {
262 Self {
263 blocks: blocks.to_vec(),
264 index: 0,
265 }
266 }
267}
268
269impl std::io::Read for GarbledReader {
270 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
271 assert_eq!(buf.len() % 16, 0);
272 let start = self.index;
273 for data in buf.chunks_mut(16) {
274 let block: [u8; 16] = self.blocks[self.index].into();
275 for (a, b) in data.iter_mut().zip(block.iter()) {
276 *a = *b;
277 }
278 self.index += 1;
279 if self.index == self.blocks.len() {
280 return Ok(16 * (self.index - start));
284 }
285 }
286 Ok(buf.len())
287 }
288}
289
290#[derive(Debug)]
292struct GarbledWriter {
293 blocks: Vec<U8x16>,
294}
295
296impl GarbledWriter {
297 fn new(ngates: Option<usize>) -> Self {
299 let blocks = if let Some(n) = ngates {
300 Vec::with_capacity(2 * n)
301 } else {
302 Vec::new()
303 };
304 Self { blocks }
305 }
306
307 fn finish(self) -> Vec<U8x16> {
309 self.blocks
310 }
311}
312
313impl std::io::Write for GarbledWriter {
314 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
315 for item in buf.chunks(16) {
316 let bytes: [u8; 16] = match item.try_into() {
317 Ok(bytes) => bytes,
318 Err(_) => {
319 return Err(std::io::Error::new(
320 std::io::ErrorKind::InvalidData,
321 "unable to map bytes to block",
322 ));
323 }
324 };
325 self.blocks.push(bytes.into());
326 }
327 Ok(buf.len())
328 }
329 fn flush(&mut self) -> std::io::Result<()> {
330 Ok(())
331 }
332}