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}