Skip to main content

fancy_garbling/circuits/binary/
binary_twos_complement.rs

1use crate::{
2    BinaryBundle, FancyBinary,
3    circuit::Circuit,
4    circuits::binary::{BinaryAdditionNoCarry, BinaryConstant},
5};
6use core::marker::PhantomData;
7use swanky_channel::Channel;
8use swanky_error::Result;
9
10/// Binary two's complement.
11#[derive(Default)]
12pub struct BinaryTwosComplement<'a>(PhantomData<&'a ()>);
13
14impl<'a> BinaryTwosComplement<'a> {
15    /// Create a new [`BinaryTwosComplement`] circuit.
16    pub fn new() -> Self {
17        Default::default()
18    }
19}
20
21impl<'a, F: FancyBinary> Circuit<F> for BinaryTwosComplement<'a>
22where
23    F::Item: 'a,
24{
25    type Input = &'a BinaryBundle<F::Item>;
26    type Output = BinaryBundle<F::Item>;
27
28    fn execute(
29        &self,
30        backend: &mut F,
31        input: Self::Input,
32        channel: &mut Channel,
33    ) -> Result<Self::Output> {
34        let not_xs = BinaryBundle::new(
35            input
36                .wires()
37                .iter()
38                .map(|x| backend.negate(x))
39                .collect::<Vec<_>>(),
40        );
41        let one = BinaryConstant::new(1, input.size()).execute(backend, (), channel)?;
42        BinaryAdditionNoCarry::new().execute(backend, (&not_xs, &one), channel)
43    }
44}
45
46pub mod test {
47    use crate::circuit::CircuitInputMapper;
48
49    use super::*;
50
51    /// Circuit for testing [`BinaryTwosComplement`].
52    pub struct TestBinaryTwosComplement(pub usize);
53    impl<F: FancyBinary> Circuit<F> for TestBinaryTwosComplement {
54        type Input = BinaryBundle<F::Item>;
55        type Output = BinaryBundle<F::Item>;
56
57        fn execute(
58            &self,
59            backend: &mut F,
60            inputs: Self::Input,
61            channel: &mut Channel,
62        ) -> Result<Self::Output> {
63            BinaryTwosComplement::new().execute(backend, &inputs, channel)
64        }
65    }
66
67    impl<F: FancyBinary> CircuitInputMapper<F> for TestBinaryTwosComplement {
68        fn map(&self, inputs: Vec<<F as crate::Fancy>::Item>) -> Self::Input {
69            assert_eq!(inputs.len(), self.0);
70            BinaryBundle::new(inputs)
71        }
72
73        fn ninputs(&self) -> usize {
74            self.0
75        }
76
77        fn modulus(&self, _: usize) -> u16 {
78            2
79        }
80    }
81
82    #[test]
83    fn binary_twos_complement() {
84        use crate::dummy::{Dummy, DummyVal};
85        use rand::Rng;
86
87        let mut rng = rand::thread_rng();
88        let nbits = 64;
89        let q = 1 << nbits;
90        let c = TestBinaryTwosComplement(nbits);
91
92        for _ in 0..16 {
93            let x = rng.r#gen::<u128>() % q;
94            let x_input = DummyVal::to_binary(x, nbits);
95            let output = Dummy::eval(&c, x_input).unwrap();
96            assert_eq!(DummyVal::from_binary(&output), (((!x) % q) + 1) % q);
97        }
98    }
99}