Skip to main content

fancy_garbling/circuits/binary/
binary_adder.rs

1use crate::{FancyBinary, circuit::Circuit};
2use core::marker::PhantomData;
3use swanky_channel::Channel;
4use swanky_error::Result;
5
6/// Binary adder.
7///
8/// For input bits `x` and `y` and optional carry bit `c`, return `(x + y + c,
9/// c')`, where `c'` is the new carry bit.
10#[derive(Default)]
11pub struct BinaryAdder<'a>(PhantomData<&'a ()>);
12
13impl<'a> BinaryAdder<'a> {
14    /// Create a new [`BinaryAdder`] circuit.
15    pub fn new() -> Self {
16        Default::default()
17    }
18}
19
20impl<'a, F: FancyBinary> Circuit<F> for BinaryAdder<'a>
21where
22    F::Item: 'a,
23{
24    type Input = (&'a F::Item, &'a F::Item, Option<&'a F::Item>);
25    type Output = (F::Item, 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 (x, y, carry_in) = inputs;
34        if let Some(c) = carry_in {
35            let z1 = backend.xor(x, y);
36            let z2 = backend.xor(&z1, c);
37            let z3 = backend.xor(x, c);
38            let z4 = backend.and(&z1, &z3, channel)?;
39            let carry = backend.xor(&z4, x);
40            Ok((z2, carry))
41        } else {
42            let z = backend.xor(x, y);
43            let carry = backend.and(x, y, channel)?;
44            Ok((z, carry))
45        }
46    }
47}
48
49#[cfg(test)]
50pub mod test {
51    use super::BinaryAdder;
52
53    #[test]
54    fn binary_adder() {
55        use crate::dummy::{Dummy, DummyVal};
56
57        let circuit = BinaryAdder::new();
58        let zero = DummyVal::new(0, 2);
59        let one = DummyVal::new(1, 2);
60
61        let output = Dummy::eval(&circuit, (&zero, &zero, None)).unwrap();
62        assert_eq!(output.0, zero);
63        assert_eq!(output.1, zero);
64        let output = Dummy::eval(&circuit, (&zero, &one, None)).unwrap();
65        assert_eq!(output.0, one);
66        assert_eq!(output.1, zero);
67        let output = Dummy::eval(&circuit, (&one, &zero, None)).unwrap();
68        assert_eq!(output.0, one);
69        assert_eq!(output.1, zero);
70        let output = Dummy::eval(&circuit, (&one, &one, None)).unwrap();
71        assert_eq!(output.0, zero);
72        assert_eq!(output.1, one);
73    }
74}