Skip to main content

fancy_garbling/circuits/arithmetic/
subtraction.rs

1use crate::{CrtBundle, FancyArithmetic, circuit::Circuit};
2use core::marker::PhantomData;
3use swanky_channel::Channel;
4use swanky_error::Result;
5
6/// Given [`CrtBundle`]s `x` and `y`, output `x - y`.
7#[derive(Default)]
8pub struct Subtraction<'a>(PhantomData<&'a ()>);
9
10impl<'a> Subtraction<'a> {
11    /// Create a new [`Subtraction`] circuit.
12    pub fn new() -> Self {
13        Default::default()
14    }
15}
16
17impl<'a, F: FancyArithmetic> Circuit<F> for Subtraction<'a>
18where
19    F::Item: 'a,
20{
21    type Input = (&'a CrtBundle<F::Item>, &'a CrtBundle<F::Item>);
22    type Output = CrtBundle<F::Item>;
23
24    fn execute(
25        &self,
26        backend: &mut F,
27        inputs: Self::Input,
28        _: &mut Channel,
29    ) -> Result<Self::Output> {
30        let (x, y) = inputs;
31        assert_eq!(x.size(), y.size(), "`x` and `y` must be the same length");
32        Ok(CrtBundle::new(
33            x.wires()
34                .iter()
35                .zip(y.wires().iter())
36                .map(|(x, y)| backend.sub(x, y))
37                .collect(),
38        ))
39    }
40}
41
42#[cfg(test)]
43mod test {
44    use crate::{
45        circuits::arithmetic::Subtraction,
46        dummy::{Dummy, DummyVal},
47        util::RngExt,
48    };
49    use rand::{Rng, thread_rng};
50
51    #[test]
52    fn subtraction() {
53        let mut rng = thread_rng();
54        let q = rng.gen_usable_composite_modulus();
55
56        for _ in 0..16 {
57            let x = rng.r#gen::<u128>() % q;
58            let y = rng.r#gen::<u128>() % q;
59            let x_input = DummyVal::to_crt(x, q);
60            let y_input = DummyVal::to_crt(y, q);
61            let circuit = Subtraction::new();
62            let z = Dummy::eval(&circuit, (&x_input, &y_input)).unwrap();
63            let output = DummyVal::from_crt(&z, q);
64            assert_eq!(output, (x + q - y) % q);
65        }
66    }
67}