Skip to main content

fancy_garbling/
dummy.rs

1//! Dummy implementation of `Fancy`.
2//!
3//! Useful for evaluating the circuits produced by `Fancy` without actually
4//! creating any circuits.
5
6use rand::{CryptoRng, Rng, RngCore};
7use swanky_channel::Channel;
8use swanky_error::{ErrorKind, Result};
9
10use crate::{
11    BinaryBundle, BinaryGadgets, Bundle, CrtBundle, CrtGadgets, FancyArithmetic, FancyBinary,
12    FancyEncode, FancyOutput, FancyProj, check_binary,
13    circuit::Circuit,
14    fancy::{Fancy, HasModulus},
15    util::{as_mixed_radix, crt_inv_factor, u128_from_bits},
16};
17
18/// Simple struct that performs the fancy computation over `u16`.
19pub struct Dummy;
20
21/// Wrapper around `u16`.
22#[derive(Clone, Copy, Debug, PartialEq)]
23pub struct DummyVal {
24    val: u16,
25    modulus: u16,
26}
27
28impl HasModulus for DummyVal {
29    fn modulus(&self) -> u16 {
30        self.modulus
31    }
32}
33
34impl DummyVal {
35    /// Create a new [`DummyVal`].
36    pub fn new(val: u16, modulus: u16) -> Self {
37        Self {
38            val: val % modulus,
39            modulus,
40        }
41    }
42
43    /// Create a new boolean [`DummyVal`].
44    pub fn new_bool(val: bool) -> Self {
45        Self {
46            val: val as u16,
47            modulus: 2,
48        }
49    }
50
51    /// Extract the value.
52    pub fn val(&self) -> u16 {
53        self.val
54    }
55
56    /// Generate a random boolean [`DummyVal`].
57    pub fn rand_bool<RNG: CryptoRng + RngCore>(rng: &mut RNG) -> Self {
58        Self::rand(2, rng)
59    }
60
61    /// Generate a random [`DummyVal`].
62    pub fn rand<RNG: CryptoRng + RngCore>(modulus: u16, rng: &mut RNG) -> Self {
63        Self::new(rng.r#gen::<u16>(), modulus)
64    }
65
66    /// Generate a new [`CrtBundle`] of `value % modulus`.
67    pub fn to_crt(value: u128, modulus: u128) -> CrtBundle<Self> {
68        let mut dummy = Dummy::new();
69        Channel::with(std::io::empty(), |channel| {
70            dummy.crt_encode(value, modulus, channel)
71        })
72        .unwrap()
73    }
74
75    /// Convert a [`Bundle`] representing a CRT value into its underlying
76    /// `u128`.
77    pub fn from_crt(crt: &Bundle<Self>, modulus: u128) -> u128 {
78        let crt = crt.wires().iter().map(|w| w.val()).collect::<Vec<_>>();
79        crt_inv_factor(&crt, modulus)
80    }
81
82    /// Generate a new [`BinaryBundle`] of `value`.
83    pub fn to_binary(value: u128, nbits: usize) -> BinaryBundle<Self> {
84        let mut dummy = Dummy::new();
85        Channel::with(std::io::empty(), |channel| {
86            dummy.bin_encode(value, nbits, channel)
87        })
88        .unwrap()
89    }
90
91    /// Convert a [`Bundle`] representing a binary value into its underlying
92    /// `u128`.
93    pub fn from_binary(bin: &Bundle<Self>) -> u128 {
94        let bin = bin.wires().iter().map(|w| w.val()).collect::<Vec<_>>();
95        u128_from_bits(&bin)
96    }
97
98    /// Generate a new mixed radix form [`Bundle`] for `value` using the
99    /// provided `radii`.
100    pub fn to_mixed_radix(value: u128, radii: &[u16]) -> CrtBundle<Self> {
101        let mixed = as_mixed_radix(value, radii);
102        let mixed = mixed
103            .into_iter()
104            .zip(radii)
105            .map(|(x, q)| DummyVal::new(x, *q))
106            .collect::<Vec<_>>();
107        CrtBundle::new(mixed)
108    }
109
110    /// Convert a [`Bundle`] representing mixed radix form into its underlying
111    /// `u128`.
112    pub fn from_mixed_radix(bundle: &CrtBundle<Self>) -> u128 {
113        let mut x: u128 = 0;
114        for wire in bundle.wires().iter().rev() {
115            let (xp, overflow) = x.overflowing_mul(wire.modulus as u128);
116            assert!(!overflow);
117            x = xp + wire.val as u128;
118        }
119        x
120    }
121}
122
123impl Dummy {
124    /// Create a new Dummy.
125    pub fn new() -> Dummy {
126        Dummy {}
127    }
128
129    /// Evaluate `circuit` in plaintext.
130    pub fn eval<C: Circuit<Dummy>>(circuit: &C, inputs: C::Input) -> Result<C::Output> {
131        let mut dummy = Dummy::new();
132        Channel::with(std::io::empty(), |c| circuit.execute(&mut dummy, inputs, c))
133    }
134}
135
136impl Default for Dummy {
137    fn default() -> Self {
138        Self::new()
139    }
140}
141
142impl FancyBinary for Dummy {
143    fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
144        check_binary!(x);
145        check_binary!(y);
146
147        self.add(x, y)
148    }
149
150    fn and(
151        &mut self,
152        x: &Self::Item,
153        y: &Self::Item,
154        channel: &mut Channel,
155    ) -> swanky_error::Result<Self::Item> {
156        check_binary!(x);
157        check_binary!(y);
158
159        self.mul(x, y, channel)
160    }
161
162    fn negate(&mut self, x: &Self::Item) -> Self::Item {
163        check_binary!(x);
164
165        self.xor(x, &DummyVal::new(1, 2))
166    }
167}
168
169impl FancyArithmetic for Dummy {
170    fn add(&mut self, x: &DummyVal, y: &DummyVal) -> DummyVal {
171        assert_eq!(x.modulus(), y.modulus());
172        DummyVal {
173            val: (x.val + y.val) % x.modulus,
174            modulus: x.modulus,
175        }
176    }
177
178    fn sub(&mut self, x: &DummyVal, y: &DummyVal) -> DummyVal {
179        assert_eq!(x.modulus(), y.modulus());
180        DummyVal {
181            val: (x.modulus + x.val - y.val) % x.modulus,
182            modulus: x.modulus,
183        }
184    }
185
186    fn cmul(&mut self, x: &DummyVal, c: u16) -> DummyVal {
187        DummyVal {
188            val: (x.val * c) % x.modulus,
189            modulus: x.modulus,
190        }
191    }
192
193    fn mul(
194        &mut self,
195        x: &DummyVal,
196        y: &DummyVal,
197        _channel: &mut Channel,
198    ) -> swanky_error::Result<DummyVal> {
199        if x.modulus < y.modulus {
200            return self.mul(y, x, _channel);
201        }
202        Ok(DummyVal {
203            val: x.val * y.val % x.modulus,
204            modulus: x.modulus,
205        })
206    }
207}
208
209impl FancyProj for Dummy {
210    fn proj(
211        &mut self,
212        x: &DummyVal,
213        modulus: u16,
214        tt: Option<Vec<u16>>,
215        _: &mut Channel,
216    ) -> swanky_error::Result<DummyVal> {
217        assert!(tt.is_some(), "`tt` must not be `None`");
218        let tt = tt.unwrap();
219        assert!(
220            tt.len() >= x.modulus() as usize,
221            "`tt` not large enough for `x`s modulus"
222        );
223        assert!(
224            tt.iter().all(|&x| x < modulus),
225            "`tt` value larger than `q`"
226        );
227        let val = tt[x.val as usize];
228        Ok(DummyVal { val, modulus })
229    }
230}
231
232impl Fancy for Dummy {
233    type Item = DummyVal;
234
235    fn constant(
236        &mut self,
237        val: u16,
238        modulus: u16,
239        _: &mut Channel,
240    ) -> swanky_error::Result<DummyVal> {
241        Ok(DummyVal { val, modulus })
242    }
243}
244
245impl FancyEncode for Dummy {
246    fn encode_many(
247        &mut self,
248        xs: &[u16],
249        moduli: &[u16],
250        _: &mut Channel,
251    ) -> swanky_error::Result<Vec<DummyVal>> {
252        assert_eq!(xs.len(), moduli.len());
253        Ok(xs
254            .iter()
255            .zip(moduli.iter())
256            .map(|(x, q)| DummyVal::new(*x, *q))
257            .collect())
258    }
259
260    fn receive_many(
261        &mut self,
262        _moduli: &[u16],
263        _: &mut Channel,
264    ) -> swanky_error::Result<Vec<DummyVal>> {
265        // Receive is undefined for Dummy which is a single party "protocol"
266        swanky_error::bail!(
267            ErrorKind::UnsupportedError,
268            "`receive_many` is undefined for `Dummy`"
269        );
270    }
271}
272
273impl FancyOutput for Dummy {
274    fn output(&mut self, x: &DummyVal, _: &mut Channel) -> swanky_error::Result<Option<u16>> {
275        Ok(Some(x.val))
276    }
277}