Skip to main content

fancy_garbling/circuits/binary/
binary_abs.rs

1use crate::{
2    BinaryBundle, FancyBinary,
3    circuit::Circuit,
4    circuits::binary::{BinaryMultiplex, BinaryTwosComplement},
5};
6use core::marker::PhantomData;
7use swanky_channel::Channel;
8use swanky_error::Result;
9
10/// For [`BinaryBundle`] `x`, output the absolute value of `x`.
11#[derive(Default)]
12pub struct BinaryAbs<'a>(PhantomData<&'a ()>);
13
14impl<'a> BinaryAbs<'a> {
15    /// Create a new [`BinaryAbs`] circuit.
16    pub fn new() -> Self {
17        Default::default()
18    }
19}
20
21impl<'a, F: FancyBinary> Circuit<F> for BinaryAbs<'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        inputs: Self::Input,
32        channel: &mut Channel,
33    ) -> Result<Self::Output> {
34        let x = inputs;
35
36        let sign = x.wires().last().unwrap();
37        let negated = BinaryTwosComplement::new().execute(backend, x, channel)?;
38        BinaryMultiplex::new().execute(backend, (sign.clone(), x, &negated), channel)
39    }
40}
41
42#[cfg(test)]
43mod test {
44    use crate::{
45        circuits::binary::BinaryAbs,
46        dummy::{Dummy, DummyVal},
47    };
48    use rand::{Rng, thread_rng};
49
50    #[test]
51    fn binary_abs() {
52        let mut rng = thread_rng();
53        let nbits = 64;
54        let q = 1 << nbits;
55
56        for _ in 0..16 {
57            let x = rng.r#gen::<u128>() % q;
58            let x_input = DummyVal::to_binary(x, nbits);
59            let circuit = BinaryAbs::new();
60            let output = Dummy::eval(&circuit, &x_input).unwrap();
61            assert_eq!(
62                DummyVal::from_binary(&output),
63                if x >> (nbits - 1) > 0 {
64                    ((!x) + 1) & ((1 << nbits) - 1)
65                } else {
66                    x
67                }
68            );
69        }
70    }
71}