Skip to main content

fancy_garbling/circuits/binary/
binary_constant.rs

1use crate::{BinaryBundle, Fancy, circuit::Circuit, util::u128_to_bits};
2use swanky_channel::Channel;
3use swanky_error::Result;
4
5/// Binary constant.
6///
7/// For `(value, nbits)`, return a [`BinaryBundle`] containing `value` in its
8/// bit representation.
9pub struct BinaryConstant<F: Fancy> {
10    value: u128,
11    nbits: usize,
12    zero: Option<F::Item>,
13    one: Option<F::Item>,
14}
15
16impl<F: Fancy> BinaryConstant<F> {
17    /// Create a new [`BinaryConstant`] circuit for `value % 2^nbits`.
18    pub fn new(value: u128, nbits: usize) -> Self {
19        Self::new_with_constants(value, nbits, None, None)
20    }
21
22    /// Create a new [`BinaryConstant`] circuit for `value % 2^nbits`, using the
23    /// provided zero and one constants.
24    pub fn new_with_constants(
25        value: u128,
26        nbits: usize,
27        zero: Option<F::Item>,
28        one: Option<F::Item>,
29    ) -> Self {
30        Self {
31            value,
32            nbits,
33            zero,
34            one,
35        }
36    }
37}
38
39impl<F: Fancy> Circuit<F> for BinaryConstant<F> {
40    type Input = ();
41    type Output = BinaryBundle<F::Item>;
42
43    fn execute(
44        &self,
45        backend: &mut F,
46        _: Self::Input,
47        channel: &mut Channel,
48    ) -> Result<Self::Output> {
49        let xs = u128_to_bits(self.value, self.nbits);
50        xs.into_iter()
51            .map(|x| match x != 0 {
52                true => {
53                    if let Some(one) = &self.one {
54                        Ok(one.clone())
55                    } else {
56                        backend.constant(1, 2, channel)
57                    }
58                }
59                false => {
60                    if let Some(zero) = &self.zero {
61                        Ok(zero.clone())
62                    } else {
63                        backend.constant(0, 2, channel)
64                    }
65                }
66            })
67            .collect::<Result<_>>()
68            .map(BinaryBundle::new)
69    }
70}
71
72pub mod test {
73    use super::*;
74    use crate::circuit::CircuitInputMapper;
75
76    /// Circuit for testing [`BinaryConstant`].
77    pub struct TestBinaryConstant(pub u128, pub usize);
78    impl<F: Fancy> Circuit<F> for TestBinaryConstant {
79        type Input = <BinaryConstant<F> as Circuit<F>>::Input;
80        type Output = <BinaryConstant<F> as Circuit<F>>::Output;
81
82        fn execute(
83            &self,
84            backend: &mut F,
85            inputs: Self::Input,
86            channel: &mut swanky_channel::Channel,
87        ) -> Result<Self::Output> {
88            BinaryConstant::new(self.0, self.1).execute(backend, inputs, channel)
89        }
90    }
91
92    impl<F: Fancy> CircuitInputMapper<F> for TestBinaryConstant {
93        fn map(&self, inputs: Vec<<F as Fancy>::Item>) -> Self::Input {
94            assert!(inputs.is_empty());
95        }
96
97        fn ninputs(&self) -> usize {
98            0
99        }
100
101        fn modulus(&self, _: usize) -> u16 {
102            2
103        }
104    }
105
106    #[test]
107    fn binary_constant() {
108        use crate::dummy::{Dummy, DummyVal};
109        use rand::Rng;
110
111        let mut rng = rand::thread_rng();
112        for _ in 0..16 {
113            let nbits = 1 + rng.r#gen::<usize>() % 127;
114            let value = rng.r#gen::<u128>() % (nbits as u128);
115            let c = TestBinaryConstant(value, nbits);
116            let output = Dummy::eval(&c, ()).unwrap();
117            assert_eq!(DummyVal::from_binary(&output), value);
118        }
119    }
120}