snarkvm_circuit_types_string/
equal.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18impl<E: Environment> Equal<Self> for StringType<E> {
19    type Output = Boolean<E>;
20
21    /// Returns `true` if `self` and `other` are equal.
22    fn is_equal(&self, other: &Self) -> Self::Output {
23        // Convert each string type into fields.
24        let this = self.to_fields();
25        let that = other.to_fields();
26
27        // Check that the size in bytes of the two strings are equal.
28        self.size_in_bytes.is_equal(&other.size_in_bytes)
29            // Check that the string contents are equal.
30            & this.iter().zip(&that).fold(Boolean::constant(true), |acc, (a, b)| acc & a.is_equal(b))
31    }
32
33    /// Returns `true` if `self` and `other` are *not* equal.
34    fn is_not_equal(&self, other: &Self) -> Self::Output {
35        !self.is_equal(other)
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42    use snarkvm_circuit_environment::Circuit;
43
44    fn sample_string(mode: Mode, rng: &mut TestRng) -> StringType<Circuit> {
45        // Sample a random string. Take 1/4th to ensure we fit for all code points.
46        let given = rng.next_string(Circuit::MAX_STRING_BYTES / 4, true);
47        StringType::<Circuit>::new(mode, console::StringType::new(&given))
48    }
49
50    fn check_is_equal(
51        mode: Mode,
52        num_constants: u64,
53        num_public: u64,
54        num_private: u64,
55        num_constraints: u64,
56    ) -> Result<()> {
57        let mut rng = TestRng::default();
58
59        // Sample two strings.
60        let string_a = sample_string(mode, &mut rng);
61        let string_b = sample_string(mode, &mut rng);
62
63        Circuit::scope(format!("{mode}"), || {
64            let candidate = string_a.is_equal(&string_a);
65            assert!(candidate.eject_value());
66            assert_scope!(<=num_constants, <=num_public, <=num_private, <=num_constraints);
67        });
68
69        Circuit::scope(format!("{mode}"), || {
70            let candidate = string_a.is_equal(&string_b);
71            assert!(!candidate.eject_value());
72            assert_scope!(<=num_constants, <=num_public, <=num_private, <=num_constraints);
73        });
74
75        Circuit::reset();
76        Ok(())
77    }
78
79    fn check_is_not_equal(
80        mode: Mode,
81        num_constants: u64,
82        num_public: u64,
83        num_private: u64,
84        num_constraints: u64,
85    ) -> Result<()> {
86        let mut rng = TestRng::default();
87
88        // Sample two strings.
89        let string_a = sample_string(mode, &mut rng);
90        let string_b = sample_string(mode, &mut rng);
91
92        Circuit::scope(format!("{mode}"), || {
93            let candidate = string_a.is_not_equal(&string_b);
94            assert!(candidate.eject_value());
95            assert_scope!(<=num_constants, <=num_public, <=num_private, <=num_constraints);
96        });
97
98        Circuit::scope(format!("{mode}"), || {
99            let candidate = string_a.is_not_equal(&string_a);
100            assert!(!candidate.eject_value());
101            assert_scope!(<=num_constants, <=num_public, <=num_private, <=num_constraints);
102        });
103
104        Circuit::reset();
105        Ok(())
106    }
107
108    #[test]
109    fn test_is_equal_constant() -> Result<()> {
110        check_is_equal(Mode::Constant, 9, 0, 0, 0)
111    }
112
113    #[test]
114    fn test_is_equal_public() -> Result<()> {
115        check_is_equal(Mode::Public, 9, 0, 26, 26)
116    }
117
118    #[test]
119    fn test_is_equal_private() -> Result<()> {
120        check_is_equal(Mode::Private, 9, 0, 26, 26)
121    }
122
123    #[test]
124    fn test_is_not_equal_constant() -> Result<()> {
125        check_is_not_equal(Mode::Constant, 9, 0, 0, 0)
126    }
127
128    #[test]
129    fn test_is_not_equal_public() -> Result<()> {
130        check_is_not_equal(Mode::Public, 9, 0, 26, 26)
131    }
132
133    #[test]
134    fn test_is_not_equal_private() -> Result<()> {
135        check_is_not_equal(Mode::Private, 9, 0, 26, 36)
136    }
137}