fancy_garbling/circuit/
binary.rs

1use crate::{
2    FancyBinary, HasModulus,
3    circuit::{CircuitBuilder, CircuitRef, CircuitType, EvaluableCircuit, GateType},
4};
5use swanky_channel::Channel;
6
7/// Static representation of binary computation supported by fancy garbling.
8#[derive(Clone, Debug, PartialEq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct BinaryCircuit {
11    pub(crate) gates: Vec<BinaryGate>,
12    pub(crate) garbler_input_refs: Vec<CircuitRef>,
13    pub(crate) evaluator_input_refs: Vec<CircuitRef>,
14    pub(crate) const_refs: Vec<CircuitRef>,
15    pub(crate) output_refs: Vec<CircuitRef>,
16    pub(crate) num_nonfree_gates: usize,
17}
18
19/// Binary computation supported by fancy garbling.
20///
21/// `id` represents the gate number. `out` gives the output wire index; if `out
22/// = None`, then we use the gate index as the output wire index.
23#[derive(Clone, Debug, PartialEq)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub enum BinaryGate {
26    /// Input of garbler
27    GarblerInput {
28        /// Gate number
29        id: usize,
30    },
31    /// Input of evaluator
32    EvaluatorInput {
33        /// Gate number
34        id: usize,
35    },
36    /// Constant value
37    Constant {
38        /// Value of constant
39        val: u16,
40    },
41
42    /// Xor gate
43    Xor {
44        /// Reference to input 1
45        xref: CircuitRef,
46
47        /// Reference to input 2
48        yref: CircuitRef,
49
50        /// Output wire index
51        out: Option<usize>,
52    },
53    /// And gate
54    And {
55        /// Reference to input 1
56        xref: CircuitRef,
57
58        /// Reference to input 2
59        yref: CircuitRef,
60
61        /// Gate number
62        id: usize,
63
64        /// Output wire index
65        out: Option<usize>,
66    },
67    /// Not gate
68    Inv {
69        /// Reference to input
70        xref: CircuitRef,
71
72        /// Output wire index
73        out: Option<usize>,
74    },
75}
76
77impl std::fmt::Display for BinaryGate {
78    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
79        match self {
80            Self::GarblerInput { id } => write!(f, "GarblerInput {}", id),
81            Self::EvaluatorInput { id } => write!(f, "EvaluatorInput {}", id),
82            Self::Constant { val } => write!(f, "Constant {}", val),
83            Self::Xor { xref, yref, out } => write!(f, "Xor ( {}, {}, {:?} )", xref, yref, out),
84            Self::And {
85                xref,
86                yref,
87                id,
88                out,
89            } => write!(f, "And ( {}, {}, {}, {:?} )", xref, yref, id, out),
90            Self::Inv { xref, out } => write!(f, "Inv ( {}, {:?} )", xref, out),
91        }
92    }
93}
94
95impl<F: FancyBinary> EvaluableCircuit<F> for BinaryCircuit {
96    fn eval_to_wirelabels(
97        &self,
98        f: &mut F,
99        garbler_inputs: &[F::Item],
100        evaluator_inputs: &[F::Item],
101        channel: &mut Channel,
102    ) -> swanky_error::Result<Vec<F::Item>> {
103        let mut cache: Vec<Option<F::Item>> = vec![None; self.gates.len()];
104        for (i, gate) in self.gates.iter().enumerate() {
105            let q = 2;
106            let (zref_, val) = match *gate {
107                BinaryGate::GarblerInput { id } => (None, garbler_inputs[id].clone()),
108                BinaryGate::EvaluatorInput { id } => {
109                    assert!(
110                        id < evaluator_inputs.len(),
111                        "id={} ev_inps.len()={}",
112                        id,
113                        evaluator_inputs.len()
114                    );
115                    (None, evaluator_inputs[id].clone())
116                }
117                BinaryGate::Constant { val } => (None, f.constant(val, q, channel)?),
118                BinaryGate::Inv { xref, out } => (out, f.negate(cache[xref.ix].as_ref().unwrap())),
119                BinaryGate::Xor { xref, yref, out } => (
120                    out,
121                    f.xor(
122                        cache[xref.ix].as_ref().unwrap(),
123                        cache[yref.ix].as_ref().unwrap(),
124                    ),
125                ),
126                BinaryGate::And {
127                    xref, yref, out, ..
128                } => (
129                    out,
130                    f.and(
131                        cache[xref.ix].as_ref().unwrap(),
132                        cache[yref.ix].as_ref().unwrap(),
133                        channel,
134                    )?,
135                ),
136            };
137            cache[zref_.unwrap_or(i)] = Some(val);
138        }
139        let mut outputs = Vec::with_capacity(self.noutputs());
140        for r in self.get_output_refs().iter() {
141            let wirelabel = cache[r.ix].as_ref().unwrap();
142            outputs.push(wirelabel.clone());
143        }
144        Ok(outputs)
145    }
146}
147
148impl GateType for BinaryGate {
149    fn make_constant(val: u16) -> Self {
150        Self::Constant { val }
151    }
152
153    fn make_garbler_input(id: usize) -> Self {
154        Self::GarblerInput { id }
155    }
156
157    fn make_evaluator_input(id: usize) -> Self {
158        Self::EvaluatorInput { id }
159    }
160}
161
162impl CircuitType for BinaryCircuit {
163    type Gate = BinaryGate;
164
165    fn new(ngates: Option<usize>) -> Self {
166        let gates = Vec::with_capacity(ngates.unwrap_or(0));
167        Self {
168            gates,
169            garbler_input_refs: Vec::new(),
170            evaluator_input_refs: Vec::new(),
171            const_refs: Vec::new(),
172            output_refs: Vec::new(),
173            num_nonfree_gates: 0,
174        }
175    }
176
177    fn push_gates(&mut self, gate: Self::Gate) {
178        self.gates.push(gate)
179    }
180
181    fn push_const_ref(&mut self, xref: CircuitRef) {
182        self.const_refs.push(xref)
183    }
184
185    fn push_output_ref(&mut self, xref: CircuitRef) {
186        self.output_refs.push(xref)
187    }
188
189    fn push_garbler_input_ref(&mut self, xref: CircuitRef) {
190        self.garbler_input_refs.push(xref)
191    }
192
193    fn push_modulus(&mut self, modulus: u16) {
194        assert_eq!(modulus, 2);
195    }
196
197    fn push_evaluator_input_ref(&mut self, xref: CircuitRef) {
198        self.evaluator_input_refs.push(xref)
199    }
200
201    fn increment_nonfree_gates(&mut self) {
202        self.num_nonfree_gates += 1;
203    }
204
205    fn get_num_nonfree_gates(&self) -> usize {
206        self.num_nonfree_gates
207    }
208
209    fn get_output_refs(&self) -> &[CircuitRef] {
210        &self.output_refs
211    }
212
213    fn get_garbler_input_refs(&self) -> &[CircuitRef] {
214        &self.garbler_input_refs
215    }
216
217    fn get_evaluator_input_refs(&self) -> &[CircuitRef] {
218        &self.evaluator_input_refs
219    }
220
221    fn garbler_input_mod(&self, _: usize) -> u16 {
222        2
223    }
224
225    fn evaluator_input_mod(&self, _: usize) -> u16 {
226        2
227    }
228}
229
230impl FancyBinary for CircuitBuilder<BinaryCircuit> {
231    fn xor(&mut self, xref: &Self::Item, yref: &Self::Item) -> Self::Item {
232        let gate = BinaryGate::Xor {
233            xref: *xref,
234            yref: *yref,
235            out: None,
236        };
237
238        self.gate(gate, xref.modulus())
239    }
240
241    fn negate(&mut self, xref: &Self::Item) -> Self::Item {
242        let gate = BinaryGate::Inv {
243            xref: *xref,
244            out: None,
245        };
246        self.gate(gate, xref.modulus())
247    }
248
249    fn and(
250        &mut self,
251        xref: &Self::Item,
252        yref: &Self::Item,
253        _: &mut Channel,
254    ) -> swanky_error::Result<Self::Item> {
255        let gate = BinaryGate::And {
256            xref: *xref,
257            yref: *yref,
258            id: self.get_next_ciphertext_id(),
259            out: None,
260        };
261
262        Ok(self.gate(gate, xref.modulus()))
263    }
264}