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