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}