ark_r1cs_std/boolean/
xor.rs1use 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 #[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 #[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 #[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}