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
 5pub trait EqGadget<F: Field> {
 6    /// Output a `Boolean` value representing whether `self.value() == other.value()`.
 7    fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError>;
 8
 9    /// Output a `Boolean` value representing whether `self.value() != other.value()`.
10    fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
11        Ok(self.is_eq(other)?.not())
12    }
13
14    /// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
15    /// enforce a vacuously true statement.
16    #[tracing::instrument(target = "r1cs", skip(self, other))]
17    fn conditional_enforce_equal(
18        &self,
19        other: &Self,
20        should_enforce: &Boolean<F>,
21    ) -> Result<(), SynthesisError> {
22        self.is_eq(&other)?
23            .conditional_enforce_equal(&Boolean::constant(true), should_enforce)
24    }
25
26    /// Enforce that `self` and `other` are equal.
27    #[tracing::instrument(target = "r1cs", skip(self, other))]
28    fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> {
29        self.conditional_enforce_equal(other, &Boolean::constant(true))
30    }
31
32    /// If `should_enforce == true`, enforce that `self` and `other` are not equal; else,
33    /// enforce a vacuously true statement.
34    #[tracing::instrument(target = "r1cs", skip(self, other))]
35    fn conditional_enforce_not_equal(
36        &self,
37        other: &Self,
38        should_enforce: &Boolean<F>,
39    ) -> Result<(), SynthesisError> {
40        self.is_neq(&other)?
41            .conditional_enforce_equal(&Boolean::constant(true), should_enforce)
42    }
43
44    /// Enforce that `self` and `other` are not equal.
45    #[tracing::instrument(target = "r1cs", skip(self, other))]
46    fn enforce_not_equal(&self, other: &Self) -> Result<(), SynthesisError> {
47        self.conditional_enforce_not_equal(other, &Boolean::constant(true))
48    }
49}
50
51impl<T: EqGadget<F> + R1CSVar<F>, F: Field> EqGadget<F> for [T] {
52    #[tracing::instrument(target = "r1cs", skip(self, other))]
53    fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
54        assert_eq!(self.len(), other.len());
55        assert!(!self.is_empty());
56        let mut results = Vec::with_capacity(self.len());
57        for (a, b) in self.iter().zip(other) {
58            results.push(a.is_eq(b)?);
59        }
60        Boolean::kary_and(&results)
61    }
62
63    #[tracing::instrument(target = "r1cs", skip(self, other))]
64    fn conditional_enforce_equal(
65        &self,
66        other: &Self,
67        condition: &Boolean<F>,
68    ) -> Result<(), SynthesisError> {
69        assert_eq!(self.len(), other.len());
70        for (a, b) in self.iter().zip(other) {
71            a.conditional_enforce_equal(b, condition)?;
72        }
73        Ok(())
74    }
75
76    #[tracing::instrument(target = "r1cs", skip(self, other))]
77    fn conditional_enforce_not_equal(
78        &self,
79        other: &Self,
80        should_enforce: &Boolean<F>,
81    ) -> Result<(), SynthesisError> {
82        assert_eq!(self.len(), other.len());
83        let some_are_different = self.is_neq(other)?;
84        if let Some(cs) = some_are_different.cs().or(should_enforce.cs()) {
85            cs.enforce_constraint(
86                some_are_different.lc(),
87                should_enforce.lc(),
88                should_enforce.lc(),
89            )
90        } else {
91            // `some_are_different` and `should_enforce` are both constants
92            assert!(some_are_different.value().unwrap());
93            Ok(())
94        }
95    }
96}