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 #[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 #[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}