Skip to main content

fancy_garbling/circuit/
binary.rs

1use crate::{FancyBinary, circuit::CircuitExecutor};
2use swanky_channel::Channel;
3
4/// Static representation of binary computation supported by fancy garbling.
5#[derive(Clone, Debug, PartialEq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub struct BinaryCircuit {
8    pub(crate) gates: Vec<BinaryGate>,
9    pub(crate) input_refs: Vec<usize>,
10    pub(crate) const_refs: Vec<usize>,
11    pub(crate) output_refs: Vec<usize>,
12    pub(crate) num_nonfree_gates: usize,
13}
14
15impl<F: FancyBinary> CircuitExecutor<F> for BinaryCircuit {
16    fn execute(
17        &self,
18        backend: &mut F,
19        inputs: &[<F as crate::Fancy>::Item],
20        channel: &mut Channel,
21    ) -> swanky_error::Result<Vec<<F as crate::Fancy>::Item>> {
22        assert_eq!(
23            inputs.len(),
24            <BinaryCircuit as CircuitExecutor<F>>::ninputs(self)
25        );
26        self.eval_to_wirelabels(backend, inputs, channel)
27    }
28
29    fn ninputs(&self) -> usize {
30        self.input_refs.len()
31    }
32
33    fn modulus(&self, _: usize) -> u16 {
34        2
35    }
36}
37
38/// Binary computation supported by fancy garbling.
39///
40/// `id` represents the gate number. `out` gives the output wire index; if `out
41/// = None`, then we use the gate index as the output wire index.
42#[derive(Clone, Debug, PartialEq)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44pub enum BinaryGate {
45    /// Input value
46    Input {
47        /// Gate number
48        id: usize,
49    },
50    /// Constant value
51    Constant {
52        /// Value of constant
53        val: u16,
54    },
55
56    /// Xor gate
57    Xor {
58        /// Reference to input 1
59        xref: usize,
60
61        /// Reference to input 2
62        yref: usize,
63
64        /// Output wire index
65        out: Option<usize>,
66    },
67    /// And gate
68    And {
69        /// Reference to input 1
70        xref: usize,
71
72        /// Reference to input 2
73        yref: usize,
74
75        /// Gate number
76        id: usize,
77
78        /// Output wire index
79        out: Option<usize>,
80    },
81    /// Not gate
82    Inv {
83        /// Reference to input
84        xref: usize,
85
86        /// Output wire index
87        out: Option<usize>,
88    },
89}
90
91impl std::fmt::Display for BinaryGate {
92    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
93        match self {
94            Self::Input { id } => write!(f, "Input {}", id),
95            Self::Constant { val } => write!(f, "Constant {}", val),
96            Self::Xor { xref, yref, out } => write!(f, "Xor ( {}, {}, {:?} )", xref, yref, out),
97            Self::And {
98                xref,
99                yref,
100                id,
101                out,
102            } => write!(f, "And ( {}, {}, {}, {:?} )", xref, yref, id, out),
103            Self::Inv { xref, out } => write!(f, "Inv ( {}, {:?} )", xref, out),
104        }
105    }
106}
107
108impl BinaryCircuit {
109    /// Construct a new empty [`BinaryCircuit`], allocating `ngates` of space to
110    /// store gates if provided.
111    pub fn new(ngates: Option<usize>) -> Self {
112        let gates = if let Some(n) = ngates {
113            Vec::with_capacity(n)
114        } else {
115            Vec::new()
116        };
117        Self {
118            gates,
119            input_refs: Vec::new(),
120            const_refs: Vec::new(),
121            output_refs: Vec::new(),
122            num_nonfree_gates: 0,
123        }
124    }
125
126    fn eval_to_wirelabels<F: FancyBinary>(
127        &self,
128        f: &mut F,
129        inputs: &[F::Item],
130        channel: &mut Channel,
131    ) -> swanky_error::Result<Vec<F::Item>> {
132        let mut cache: Vec<Option<F::Item>> = vec![None; self.gates.len()];
133        for (i, gate) in self.gates.iter().enumerate() {
134            let q = 2;
135            let (zref_, val) = match *gate {
136                BinaryGate::Input { id } => (None, inputs[id].clone()),
137                BinaryGate::Constant { val } => (None, f.constant(val, q, channel)?),
138                BinaryGate::Inv { xref, out } => (out, f.negate(cache[xref].as_ref().unwrap())),
139                BinaryGate::Xor { xref, yref, out } => (
140                    out,
141                    f.xor(cache[xref].as_ref().unwrap(), cache[yref].as_ref().unwrap()),
142                ),
143                BinaryGate::And {
144                    xref, yref, out, ..
145                } => (
146                    out,
147                    f.and(
148                        cache[xref].as_ref().unwrap(),
149                        cache[yref].as_ref().unwrap(),
150                        channel,
151                    )?,
152                ),
153            };
154            cache[zref_.unwrap_or(i)] = Some(val);
155        }
156        let mut outputs = Vec::with_capacity(self.output_refs.len());
157        for r in self.output_refs.iter() {
158            let wirelabel = cache[*r].as_ref().unwrap();
159            outputs.push(wirelabel.clone());
160        }
161        Ok(outputs)
162    }
163}