arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
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}