/ circuit / types / string / src / equal.rs
equal.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm 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  
 16  use super::*;
 17  
 18  impl<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)]
 40  mod tests {
 41      use super::*;
 42      use alphavm_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  }