Skip to main content

fancy_garbling/circuits/binary/
binary_to_unary.rs

1use crate::{BinaryBundle, FancyBinary, circuit::Circuit};
2use core::marker::PhantomData;
3use swanky_channel::Channel;
4use swanky_error::Result;
5
6/// Convert a [`BinaryBundle`] `x` into its unary vector equivalent.
7///
8/// # Panics
9/// Panics if the length of `x` is greater than eight.
10#[derive(Default)]
11pub struct BinaryToUnary<'a>(PhantomData<&'a ()>);
12
13impl<'a> BinaryToUnary<'a> {
14    /// Create a new [`BinaryToUnary`] circuit.
15    pub fn new() -> Self {
16        Default::default()
17    }
18}
19
20impl<'a, F: FancyBinary> Circuit<F> for BinaryToUnary<'a>
21where
22    F::Item: 'a,
23{
24    type Input = &'a BinaryBundle<F::Item>;
25    type Output = Vec<F::Item>;
26
27    fn execute(
28        &self,
29        backend: &mut F,
30        inputs: Self::Input,
31        channel: &mut Channel,
32    ) -> Result<Self::Output> {
33        let wires = inputs.wires();
34        let nbits = wires.len();
35        assert!(nbits <= 8, "wire bitlength is too large");
36
37        let mut outs = Vec::with_capacity(1 << nbits);
38
39        for ix in 0..1 << nbits {
40            let mut acc = wires[0].clone();
41            if (ix & 1) == 0 {
42                acc = backend.negate(&acc);
43            }
44            for (i, w) in wires.iter().enumerate().skip(1) {
45                if ((ix >> i) & 1) > 0 {
46                    acc = backend.and(&acc, w, channel)?;
47                } else {
48                    let not_w = backend.negate(w);
49                    acc = backend.and(&acc, &not_w, channel)?;
50                }
51            }
52            outs.push(acc);
53        }
54
55        Ok(outs)
56    }
57}
58
59#[cfg(test)]
60mod test {
61    use crate::{
62        circuits::binary::BinaryToUnary,
63        dummy::{Dummy, DummyVal},
64    };
65    use rand::{Rng, thread_rng};
66
67    #[test]
68    fn binary_to_unary() {
69        let mut rng = thread_rng();
70        let nbits = 8;
71        let q = 1 << nbits;
72
73        for _ in 0..16 {
74            let x = rng.r#gen::<u128>() % q;
75            let x_input = DummyVal::to_binary(x, nbits);
76            let output = Dummy::eval(&BinaryToUnary::new(), &x_input).unwrap();
77            for (i, y) in output.into_iter().enumerate() {
78                if i as u128 == x {
79                    assert_eq!(y.val(), 1);
80                } else {
81                    assert_eq!(y.val(), 0);
82                }
83            }
84        }
85    }
86}