ark-r1cs-std/src/uint/and.rs
src/uint/and.rsRaw
1use ark_ff::Field;
2use ark_relations::r1cs::SynthesisError;
3use ark_std::{ops::BitAnd, ops::BitAndAssign};
4
5use super::*;
6
7impl<const N: usize, T: PrimUInt, F: Field> UInt<N, T, F> {
8 fn _and(&self, other: &Self) -> Result<Self, SynthesisError> {
9 let mut result = self.clone();
10 for (a, b) in result.bits.iter_mut().zip(&other.bits) {
11 *a &= b;
12 }
13 result.value = self.value.and_then(|a| Some(a & other.value?));
14 Ok(result)
15 }
16}
17
18impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd<Self> for &'a UInt<N, T, F> {
19 type Output = UInt<N, T, F>;
20 /// Outputs `self & other`.
21 ///
22 /// If at least one of `self` and `other` are constants, then this method
23 /// *does not* create any constraints or variables.
24 ///
25 /// ```
26 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
27 /// // We'll use the BLS12-381 scalar field for our constraints.
28 /// use ark_test_curves::bls12_381::Fr;
29 /// use ark_relations::r1cs::*;
30 /// use ark_r1cs_std::prelude::*;
31 ///
32 /// let cs = ConstraintSystem::<Fr>::new_ref();
33 /// let a = UInt8::new_witness(cs.clone(), || Ok(16))?;
34 /// let b = UInt8::new_witness(cs.clone(), || Ok(17))?;
35 /// let c = UInt8::new_witness(cs.clone(), || Ok(16 & 17))?;
36 ///
37 /// (a & &b).enforce_equal(&c)?;
38 /// assert!(cs.is_satisfied().unwrap());
39 /// # Ok(())
40 /// # }
41 /// ```
42 #[tracing::instrument(target = "r1cs", skip(self, other))]
43 fn bitand(self, other: Self) -> Self::Output {
44 self._and(other).unwrap()
45 }
46}
47
48impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd<&'a Self> for UInt<N, T, F> {
49 type Output = UInt<N, T, F>;
50 /// Outputs `self & other`.
51 ///
52 /// If at least one of `self` and `other` are constants, then this method
53 /// *does not* create any constraints or variables.
54 ///
55 /// ```
56 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
57 /// // We'll use the BLS12-381 scalar field for our constraints.
58 /// use ark_test_curves::bls12_381::Fr;
59 /// use ark_relations::r1cs::*;
60 /// use ark_r1cs_std::prelude::*;
61 ///
62 /// let cs = ConstraintSystem::<Fr>::new_ref();
63 /// let a = UInt8::new_witness(cs.clone(), || Ok(16))?;
64 /// let b = UInt8::new_witness(cs.clone(), || Ok(17))?;
65 /// let c = UInt8::new_witness(cs.clone(), || Ok(16 & 17))?;
66 ///
67 /// (a & &b).enforce_equal(&c)?;
68 /// assert!(cs.is_satisfied().unwrap());
69 /// # Ok(())
70 /// # }
71 /// ```
72 #[tracing::instrument(target = "r1cs", skip(self, other))]
73 fn bitand(self, other: &Self) -> Self::Output {
74 self._and(&other).unwrap()
75 }
76}
77
78impl<'a, const N: usize, T: PrimUInt, F: Field> BitAnd<UInt<N, T, F>> for &'a UInt<N, T, F> {
79 type Output = UInt<N, T, F>;
80
81 /// Outputs `self & other`.
82 ///
83 /// If at least one of `self` and `other` are constants, then this method
84 /// *does not* create any constraints or variables.
85 ///
86 /// ```
87 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
88 /// // We'll use the BLS12-381 scalar field for our constraints.
89 /// use ark_test_curves::bls12_381::Fr;
90 /// use ark_relations::r1cs::*;
91 /// use ark_r1cs_std::prelude::*;
92 ///
93 /// let cs = ConstraintSystem::<Fr>::new_ref();
94 /// let a = UInt8::new_witness(cs.clone(), || Ok(16))?;
95 /// let b = UInt8::new_witness(cs.clone(), || Ok(17))?;
96 /// let c = UInt8::new_witness(cs.clone(), || Ok(16 & 17))?;
97 ///
98 /// (a & &b).enforce_equal(&c)?;
99 /// assert!(cs.is_satisfied().unwrap());
100 /// # Ok(())
101 /// # }
102 /// ```
103 #[tracing::instrument(target = "r1cs", skip(self, other))]
104 fn bitand(self, other: UInt<N, T, F>) -> Self::Output {
105 self._and(&other).unwrap()
106 }
107}
108
109impl<const N: usize, T: PrimUInt, F: Field> BitAnd<Self> for UInt<N, T, F> {
110 type Output = Self;
111
112 /// Outputs `self & other`.
113 ///
114 /// If at least one of `self` and `other` are constants, then this method
115 /// *does not* create any constraints or variables.
116 ///
117 /// ```
118 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
119 /// // We'll use the BLS12-381 scalar field for our constraints.
120 /// use ark_test_curves::bls12_381::Fr;
121 /// use ark_relations::r1cs::*;
122 /// use ark_r1cs_std::prelude::*;
123 ///
124 /// let cs = ConstraintSystem::<Fr>::new_ref();
125 /// let a = UInt8::new_witness(cs.clone(), || Ok(16))?;
126 /// let b = UInt8::new_witness(cs.clone(), || Ok(17))?;
127 /// let c = UInt8::new_witness(cs.clone(), || Ok(16 & 17))?;
128 ///
129 /// (a & &b).enforce_equal(&c)?;
130 /// assert!(cs.is_satisfied().unwrap());
131 /// # Ok(())
132 /// # }
133 /// ```
134 #[tracing::instrument(target = "r1cs", skip(self, other))]
135 fn bitand(self, other: Self) -> Self::Output {
136 self._and(&other).unwrap()
137 }
138}
139
140impl<const N: usize, T: PrimUInt, F: Field> BitAndAssign<Self> for UInt<N, T, F> {
141 /// Sets `self = self & other`.
142 ///
143 /// If at least one of `self` and `other` are constants, then this method
144 /// *does not* create any constraints or variables.
145 ///
146 /// ```
147 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
148 /// // We'll use the BLS12-381 scalar field for our constraints.
149 /// use ark_test_curves::bls12_381::Fr;
150 /// use ark_relations::r1cs::*;
151 /// use ark_r1cs_std::prelude::*;
152 ///
153 /// let cs = ConstraintSystem::<Fr>::new_ref();
154 /// let mut a = UInt8::new_witness(cs.clone(), || Ok(16))?;
155 /// let b = UInt8::new_witness(cs.clone(), || Ok(17))?;
156 /// let c = UInt8::new_witness(cs.clone(), || Ok(16 & 17))?;
157 ///
158 /// a &= &b;
159 /// a.enforce_equal(&c)?;
160 /// assert!(cs.is_satisfied().unwrap());
161 /// # Ok(())
162 /// # }
163 /// ```
164 #[tracing::instrument(target = "r1cs", skip(self, other))]
165 fn bitand_assign(&mut self, other: Self) {
166 let result = self._and(&other).unwrap();
167 *self = result;
168 }
169}
170
171impl<'a, const N: usize, T: PrimUInt, F: Field> BitAndAssign<&'a Self> for UInt<N, T, F> {
172 /// Sets `self = self & other`.
173 ///
174 /// If at least one of `self` and `other` are constants, then this method
175 /// *does not* create any constraints or variables.
176 ///
177 /// ```
178 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
179 /// // We'll use the BLS12-381 scalar field for our constraints.
180 /// use ark_test_curves::bls12_381::Fr;
181 /// use ark_relations::r1cs::*;
182 /// use ark_r1cs_std::prelude::*;
183 ///
184 /// let cs = ConstraintSystem::<Fr>::new_ref();
185 /// let mut a = UInt8::new_witness(cs.clone(), || Ok(16))?;
186 /// let b = UInt8::new_witness(cs.clone(), || Ok(17))?;
187 /// let c = UInt8::new_witness(cs.clone(), || Ok(16 & 17))?;
188 ///
189 /// a &= &b;
190 /// a.enforce_equal(&c)?;
191 /// assert!(cs.is_satisfied().unwrap());
192 /// # Ok(())
193 /// # }
194 /// ```
195 #[tracing::instrument(target = "r1cs", skip(self, other))]
196 fn bitand_assign(&mut self, other: &'a Self) {
197 let result = self._and(other).unwrap();
198 *self = result;
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use crate::{
206 alloc::{AllocVar, AllocationMode},
207 prelude::EqGadget,
208 uint::test_utils::{run_binary_exhaustive, run_binary_random},
209 R1CSVar,
210 };
211 use ark_ff::PrimeField;
212 use ark_test_curves::bls12_381::Fr;
213
214 fn uint_and<T: PrimUInt, const N: usize, F: PrimeField>(
215 a: UInt<N, T, F>,
216 b: UInt<N, T, F>,
217 ) -> Result<(), SynthesisError> {
218 let cs = a.cs().or(b.cs());
219 let both_constant = a.is_constant() && b.is_constant();
220 let computed = &a & &b;
221 let expected_mode = if both_constant {
222 AllocationMode::Constant
223 } else {
224 AllocationMode::Witness
225 };
226 let expected = UInt::<N, T, F>::new_variable(
227 cs.clone(),
228 || Ok(a.value()? & b.value()?),
229 expected_mode,
230 )?;
231 assert_eq!(expected.value(), computed.value());
232 expected.enforce_equal(&computed)?;
233 if !both_constant {
234 assert!(cs.is_satisfied().unwrap());
235 }
236 Ok(())
237 }
238
239 #[test]
240 fn u8_and() {
241 run_binary_exhaustive(uint_and::<u8, 8, Fr>).unwrap()
242 }
243
244 #[test]
245 fn u16_and() {
246 run_binary_random::<1000, 16, _, _>(uint_and::<u16, 16, Fr>).unwrap()
247 }
248
249 #[test]
250 fn u32_and() {
251 run_binary_random::<1000, 32, _, _>(uint_and::<u32, 32, Fr>).unwrap()
252 }
253
254 #[test]
255 fn u64_and() {
256 run_binary_random::<1000, 64, _, _>(uint_and::<u64, 64, Fr>).unwrap()
257 }
258
259 #[test]
260 fn u128_and() {
261 run_binary_random::<1000, 128, _, _>(uint_and::<u128, 128, Fr>).unwrap()
262 }
263}