arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/boolean/xor.rs
src/boolean/xor.rsRaw
  1use ark_ff::Field;
  2use ark_relations::r1cs::SynthesisError;
  3use ark_std::{ops::BitXor, ops::BitXorAssign};
  4
  5use super::Boolean;
  6
  7impl<F: Field> Boolean<F> {
  8    fn _xor(&self, other: &Self) -> Result<Self, SynthesisError> {
  9        use Boolean::*;
 10        match (self, other) {
 11            (&Constant(false), x) | (x, &Constant(false)) => Ok(x.clone()),
 12            (&Constant(true), x) | (x, &Constant(true)) => Ok(!x),
 13            (Var(ref x), Var(ref y)) => Ok(Var(x.xor(y)?)),
 14        }
 15    }
 16}
 17
 18impl<'a, F: Field> BitXor<Self> for &'a Boolean<F> {
 19    type Output = Boolean<F>;
 20
 21    /// Outputs `self ^ other`.
 22    ///
 23    /// If at least one of `self` and `other` are constants, then this method
 24    /// *does not* create any constraints or variables.
 25    ///
 26    /// ```
 27    /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
 28    /// // We'll use the BLS12-381 scalar field for our constraints.
 29    /// use ark_test_curves::bls12_381::Fr;
 30    /// use ark_relations::r1cs::*;
 31    /// use ark_r1cs_std::prelude::*;
 32    ///
 33    /// let cs = ConstraintSystem::<Fr>::new_ref();
 34    ///
 35    /// let a = Boolean::new_witness(cs.clone(), || Ok(true))?;
 36    /// let b = Boolean::new_witness(cs.clone(), || Ok(false))?;
 37    ///
 38    /// (&a ^ &b).enforce_equal(&Boolean::TRUE)?;
 39    /// (&b ^ &a).enforce_equal(&Boolean::TRUE)?;
 40    ///
 41    /// (&a ^ &a).enforce_equal(&Boolean::FALSE)?;
 42    /// (&b ^ &b).enforce_equal(&Boolean::FALSE)?;
 43    ///
 44    /// assert!(cs.is_satisfied().unwrap());
 45    /// # Ok(())
 46    /// # }
 47    /// ```
 48    #[tracing::instrument(target = "r1cs", skip(self, other))]
 49    fn bitxor(self, other: Self) -> Self::Output {
 50        self._xor(other).unwrap()
 51    }
 52}
 53
 54impl<'a, F: Field> BitXor<&'a Self> for Boolean<F> {
 55    type Output = Boolean<F>;
 56
 57    #[tracing::instrument(target = "r1cs", skip(self, other))]
 58    fn bitxor(self, other: &Self) -> Self::Output {
 59        self._xor(&other).unwrap()
 60    }
 61}
 62
 63impl<'a, F: Field> BitXor<Boolean<F>> for &'a Boolean<F> {
 64    type Output = Boolean<F>;
 65
 66    #[tracing::instrument(target = "r1cs", skip(self, other))]
 67    fn bitxor(self, other: Boolean<F>) -> Self::Output {
 68        self._xor(&other).unwrap()
 69    }
 70}
 71
 72impl<F: Field> BitXor<Self> for Boolean<F> {
 73    type Output = Self;
 74
 75    #[tracing::instrument(target = "r1cs", skip(self, other))]
 76    fn bitxor(self, other: Self) -> Self::Output {
 77        self._xor(&other).unwrap()
 78    }
 79}
 80
 81impl<F: Field> BitXorAssign<Self> for Boolean<F> {
 82    /// Sets `self = self ^ other`.
 83    #[tracing::instrument(target = "r1cs", skip(self, other))]
 84    fn bitxor_assign(&mut self, other: Self) {
 85        let result = self._xor(&other).unwrap();
 86        *self = result;
 87    }
 88}
 89
 90impl<'a, F: Field> BitXorAssign<&'a Self> for Boolean<F> {
 91    /// Sets `self = self ^ other`.
 92    #[tracing::instrument(target = "r1cs", skip(self, other))]
 93    fn bitxor_assign(&mut self, other: &'a Self) {
 94        let result = self._xor(other).unwrap();
 95        *self = result;
 96    }
 97}
 98
 99#[cfg(test)]
100mod tests {
101    use super::*;
102    use crate::{
103        alloc::{AllocVar, AllocationMode},
104        boolean::test_utils::run_binary_exhaustive,
105        prelude::EqGadget,
106        R1CSVar,
107    };
108    use ark_test_curves::bls12_381::Fr;
109
110    #[test]
111    fn xor() {
112        run_binary_exhaustive::<Fr>(|a, b| {
113            let cs = a.cs().or(b.cs());
114            let both_constant = a.is_constant() && b.is_constant();
115            let computed = &a ^ &b;
116            let expected_mode = if both_constant {
117                AllocationMode::Constant
118            } else {
119                AllocationMode::Witness
120            };
121            let expected =
122                Boolean::new_variable(cs.clone(), || Ok(a.value()? ^ b.value()?), expected_mode)?;
123            assert_eq!(expected.value(), computed.value());
124            expected.enforce_equal(&computed)?;
125            if !both_constant {
126                assert!(cs.is_satisfied().unwrap());
127            }
128            Ok(())
129        })
130        .unwrap()
131    }
132}