Skip to main content

ark_r1cs_std/uint/
not.rs

1use ark_ff::Field;
2use ark_relations::gr1cs::SynthesisError;
3use ark_std::ops::Not;
4
5use super::*;
6
7impl<const N: usize, T: PrimUInt, F: Field> UInt<N, T, F> {
8    fn _not(&self) -> Result<Self, SynthesisError> {
9        let mut result = self.clone();
10        result._not_in_place()?;
11        Ok(result)
12    }
13
14    fn _not_in_place(&mut self) -> Result<(), SynthesisError> {
15        for a in &mut self.bits {
16            a.not_in_place()?;
17        }
18        self.value = self.value.map(Not::not);
19        Ok(())
20    }
21}
22
23impl<'a, const N: usize, T: PrimUInt, F: Field> Not for &'a UInt<N, T, F> {
24    type Output = UInt<N, T, F>;
25    /// Outputs `!self`.
26    ///
27    /// If `self` is a constant, then this method *does not* create any
28    /// constraints or variables.
29    ///
30    /// ```
31    /// # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
32    /// // We'll use the BLS12-381 scalar field for our constraints.
33    /// use ark_test_curves::bls12_381::Fr;
34    /// use ark_relations::gr1cs::*;
35    /// use ark_r1cs_std::prelude::*;
36    ///
37    /// let cs = ConstraintSystem::<Fr>::new_ref();
38    /// let a = UInt8::new_witness(cs.clone(), || Ok(2))?;
39    /// let b = UInt8::new_witness(cs.clone(), || Ok(!2))?;
40    ///
41    /// (!a).enforce_equal(&b)?;
42    /// assert!(cs.is_satisfied().unwrap());
43    /// # Ok(())
44    /// # }
45    /// ```
46    #[tracing::instrument(target = "gr1cs", skip(self))]
47    fn not(self) -> Self::Output {
48        self._not().unwrap()
49    }
50}
51
52impl<'a, const N: usize, T: PrimUInt, F: Field> Not for UInt<N, T, F> {
53    type Output = UInt<N, T, F>;
54
55    /// Outputs `!self`.
56    ///
57    /// If `self` is a constant, then this method *does not* create any
58    /// constraints or variables.
59    ///
60    /// ```
61    /// # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
62    /// // We'll use the BLS12-381 scalar field for our constraints.
63    /// use ark_test_curves::bls12_381::Fr;
64    /// use ark_relations::gr1cs::*;
65    /// use ark_r1cs_std::prelude::*;
66    ///
67    /// let cs = ConstraintSystem::<Fr>::new_ref();
68    /// let a = UInt8::new_witness(cs.clone(), || Ok(2))?;
69    /// let b = UInt8::new_witness(cs.clone(), || Ok(!2))?;
70    ///
71    /// (!a).enforce_equal(&b)?;
72    /// assert!(cs.is_satisfied().unwrap());
73    /// # Ok(())
74    /// # }
75    /// ```
76    #[tracing::instrument(target = "gr1cs", skip(self))]
77    fn not(mut self) -> Self::Output {
78        self._not_in_place().unwrap();
79        self
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use crate::{
87        alloc::{AllocVar, AllocationMode},
88        prelude::EqGadget,
89        uint::test_utils::{run_unary_exhaustive, run_unary_random},
90        GR1CSVar,
91    };
92    use ark_ff::PrimeField;
93    use ark_test_curves::bls12_381::Fr;
94
95    fn uint_not<T: PrimUInt, const N: usize, F: PrimeField>(
96        a: UInt<N, T, F>,
97    ) -> Result<(), SynthesisError> {
98        let cs = a.cs();
99        let computed = !&a;
100        let expected_mode = if a.is_constant() {
101            AllocationMode::Constant
102        } else {
103            AllocationMode::Witness
104        };
105        let expected =
106            UInt::<N, T, F>::new_variable(cs.clone(), || Ok(!a.value()?), expected_mode)?;
107        assert_eq!(expected.value(), computed.value());
108        expected.enforce_equal(&computed)?;
109        if !a.is_constant() {
110            assert!(cs.is_satisfied().unwrap());
111        }
112        Ok(())
113    }
114
115    #[test]
116    fn u8_not() {
117        run_unary_exhaustive(uint_not::<u8, 8, Fr>).unwrap()
118    }
119
120    #[test]
121    fn u16_not() {
122        run_unary_random::<1000, 16, _, _>(uint_not::<u16, 16, Fr>).unwrap()
123    }
124
125    #[test]
126    fn u32_not() {
127        run_unary_random::<1000, 32, _, _>(uint_not::<u32, 32, Fr>).unwrap()
128    }
129
130    #[test]
131    fn u64_not() {
132        run_unary_random::<1000, 64, _, _>(uint_not::<u64, 64, Fr>).unwrap()
133    }
134
135    #[test]
136    fn u128() {
137        run_unary_random::<1000, 128, _, _>(uint_not::<u128, 128, Fr>).unwrap()
138    }
139}