arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/eq.rs
r1cs-std/src/eq.rsRaw
  1use crate::{prelude::*, Vec};
  2use algebra::Field;
  3use r1cs_core::SynthesisError;
  4
  5/// Specifies how to generate constraints that check for equality for two variables of type `Self`.
  6pub trait EqGadget<F: Field> {
  7    /// Output a `Boolean` value representing whether `self.value() == other.value()`.
  8    fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError>;
  9
 10    /// Output a `Boolean` value representing whether `self.value() != other.value()`.
 11    ///
 12    /// By default, this is defined as `self.is_eq(other)?.not()`.
 13    fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
 14        Ok(self.is_eq(other)?.not())
 15    }
 16
 17    /// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
 18    /// enforce a vacuously true statement.
 19    ///
 20    /// A safe default implementation is provided that generates the following constraints:
 21    /// `self.is_eq(other)?.conditional_enforce_equal(&Boolean::TRUE, should_enforce)`.
 22    ///
 23    /// More efficient specialized implementation may be possible; implementors
 24    /// are encouraged to carefully analyze the efficiency and safety of these.
 25    #[tracing::instrument(target = "r1cs", skip(self, other))]
 26    fn conditional_enforce_equal(
 27        &self,
 28        other: &Self,
 29        should_enforce: &Boolean<F>,
 30    ) -> Result<(), SynthesisError> {
 31        self.is_eq(&other)?
 32            .conditional_enforce_equal(&Boolean::constant(true), should_enforce)
 33    }
 34
 35    /// Enforce that `self` and `other` are equal.
 36    ///
 37    /// A safe default implementation is provided that generates the following constraints:
 38    /// `self.conditional_enforce_equal(other, &Boolean::TRUE)`.
 39    ///
 40    /// More efficient specialized implementation may be possible; implementors
 41    /// are encouraged to carefully analyze the efficiency and safety of these.
 42    #[tracing::instrument(target = "r1cs", skip(self, other))]
 43    fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> {
 44        self.conditional_enforce_equal(other, &Boolean::constant(true))
 45    }
 46
 47    /// If `should_enforce == true`, enforce that `self` and `other` are *not* equal; else,
 48    /// enforce a vacuously true statement.
 49    ///
 50    /// A safe default implementation is provided that generates the following constraints:
 51    /// `self.is_neq(other)?.conditional_enforce_equal(&Boolean::TRUE, should_enforce)`.
 52    ///
 53    /// More efficient specialized implementation may be possible; implementors
 54    /// are encouraged to carefully analyze the efficiency and safety of these.
 55    #[tracing::instrument(target = "r1cs", skip(self, other))]
 56    fn conditional_enforce_not_equal(
 57        &self,
 58        other: &Self,
 59        should_enforce: &Boolean<F>,
 60    ) -> Result<(), SynthesisError> {
 61        self.is_neq(&other)?
 62            .conditional_enforce_equal(&Boolean::constant(true), should_enforce)
 63    }
 64
 65    /// Enforce that `self` and `other` are *not* equal.
 66    ///
 67    /// A safe default implementation is provided that generates the following constraints:
 68    /// `self.conditional_enforce_not_equal(other, &Boolean::TRUE)`.
 69    ///
 70    /// More efficient specialized implementation may be possible; implementors
 71    /// are encouraged to carefully analyze the efficiency and safety of these.
 72    #[tracing::instrument(target = "r1cs", skip(self, other))]
 73    fn enforce_not_equal(&self, other: &Self) -> Result<(), SynthesisError> {
 74        self.conditional_enforce_not_equal(other, &Boolean::constant(true))
 75    }
 76}
 77
 78impl<T: EqGadget<F> + R1CSVar<F>, F: Field> EqGadget<F> for [T] {
 79    #[tracing::instrument(target = "r1cs", skip(self, other))]
 80    fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
 81        assert_eq!(self.len(), other.len());
 82        assert!(!self.is_empty());
 83        let mut results = Vec::with_capacity(self.len());
 84        for (a, b) in self.iter().zip(other) {
 85            results.push(a.is_eq(b)?);
 86        }
 87        Boolean::kary_and(&results)
 88    }
 89
 90    #[tracing::instrument(target = "r1cs", skip(self, other))]
 91    fn conditional_enforce_equal(
 92        &self,
 93        other: &Self,
 94        condition: &Boolean<F>,
 95    ) -> Result<(), SynthesisError> {
 96        assert_eq!(self.len(), other.len());
 97        for (a, b) in self.iter().zip(other) {
 98            a.conditional_enforce_equal(b, condition)?;
 99        }
100        Ok(())
101    }
102
103    #[tracing::instrument(target = "r1cs", skip(self, other))]
104    fn conditional_enforce_not_equal(
105        &self,
106        other: &Self,
107        should_enforce: &Boolean<F>,
108    ) -> Result<(), SynthesisError> {
109        assert_eq!(self.len(), other.len());
110        let some_are_different = self.is_neq(other)?;
111        if [&some_are_different, should_enforce].is_constant() {
112            assert!(some_are_different.value().unwrap());
113            Ok(())
114        } else {
115            let cs = [&some_are_different, should_enforce].cs();
116            cs.enforce_constraint(
117                some_are_different.lc(),
118                should_enforce.lc(),
119                should_enforce.lc(),
120            )
121        }
122    }
123}