snarkvm_console_program/data/plaintext/
equal.rs

1// Copyright 2024-2025 Aleo Network Foundation
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<N: Network> Eq for Plaintext<N> {}
19
20impl<N: Network> PartialEq for Plaintext<N> {
21    /// Returns `true` if `self` and `other` are equal.
22    fn eq(&self, other: &Self) -> bool {
23        *self.is_equal(other)
24    }
25}
26
27impl<N: Network> Equal<Self> for Plaintext<N> {
28    type Output = Boolean<N>;
29
30    /// Returns `true` if `self` and `other` are equal.
31    fn is_equal(&self, other: &Self) -> Self::Output {
32        match (self, other) {
33            (Self::Literal(a, _), Self::Literal(b, _)) => a.is_equal(b),
34            (Self::Struct(a, _), Self::Struct(b, _)) => match a.len() == b.len() {
35                true => {
36                    // Recursively check each member for equality.
37                    Boolean::new(a.iter().zip_eq(b.iter()).all(|((name_a, plaintext_a), (name_b, plaintext_b))| {
38                        *name_a.is_equal(name_b) && *plaintext_a.is_equal(plaintext_b)
39                    }))
40                }
41                false => Boolean::new(false),
42            },
43            (Self::Array(a, _), Self::Array(b, _)) => match a.len() == b.len() {
44                true => {
45                    // Recursively check each element for equality.
46                    Boolean::new(
47                        a.iter().zip_eq(b.iter()).all(|(plaintext_a, plaintext_b)| *plaintext_a.is_equal(plaintext_b)),
48                    )
49                }
50                false => Boolean::new(false),
51            },
52            (Self::Literal(..), _) | (Self::Struct(..), _) | (Self::Array(..), _) => Boolean::new(false),
53        }
54    }
55
56    /// Returns `true` if `self` and `other` are *not* equal.
57    fn is_not_equal(&self, other: &Self) -> Self::Output {
58        match (self, other) {
59            (Self::Literal(a, _), Self::Literal(b, _)) => a.is_not_equal(b),
60            (Self::Struct(a, _), Self::Struct(b, _)) => match a.len() == b.len() {
61                true => {
62                    // Recursively check each member for equality.
63                    Boolean::new(a.iter().zip_eq(b.iter()).any(|((name_a, plaintext_a), (name_b, plaintext_b))| {
64                        *(name_a.is_not_equal(name_b) | plaintext_a.is_not_equal(plaintext_b))
65                    }))
66                }
67                false => Boolean::new(true),
68            },
69            (Self::Array(a, _), Self::Array(b, _)) => match a.len() == b.len() {
70                true => {
71                    // Recursively check each element for equality.
72                    Boolean::new(
73                        a.iter()
74                            .zip_eq(b.iter())
75                            .any(|(plaintext_a, plaintext_b)| *plaintext_a.is_not_equal(plaintext_b)),
76                    )
77                }
78                false => Boolean::new(true),
79            },
80            (Self::Literal(..), _) | (Self::Struct(..), _) | (Self::Array(..), _) => Boolean::new(true),
81        }
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use snarkvm_console_network::MainnetV0;
89
90    type CurrentNetwork = MainnetV0;
91
92    fn sample_plaintext() -> Plaintext<CurrentNetwork> {
93        Plaintext::<CurrentNetwork>::from_str(
94            r"{
95    a: true,
96    b: 123456789field,
97    c: 0group,
98    d: {
99        e: true,
100        f: 123456789field,
101        g: 0group
102    }
103}",
104        )
105        .unwrap()
106    }
107
108    fn sample_mismatched_plaintext() -> Plaintext<CurrentNetwork> {
109        Plaintext::<CurrentNetwork>::from_str(
110            r"{
111    a: false,
112    b: 123456789field,
113    c: 0group,
114    d: {
115        e: true,
116        f: 123456789field,
117        g: 0group
118    }
119}",
120        )
121        .unwrap()
122    }
123
124    fn check_is_equal() {
125        // Sample the plaintext.
126        let plaintext = sample_plaintext();
127        let mismatched_plaintext = sample_mismatched_plaintext();
128
129        let candidate = plaintext.is_equal(&plaintext);
130        assert!(*candidate);
131
132        let candidate = plaintext.is_equal(&mismatched_plaintext);
133        assert!(!*candidate);
134    }
135
136    fn check_is_not_equal() {
137        // Sample the plaintext.
138        let plaintext = sample_plaintext();
139        let mismatched_plaintext = sample_mismatched_plaintext();
140
141        let candidate = plaintext.is_not_equal(&mismatched_plaintext);
142        assert!(*candidate);
143
144        let candidate = plaintext.is_not_equal(&plaintext);
145        assert!(!*candidate);
146    }
147
148    #[test]
149    fn test_is_equal() {
150        check_is_equal()
151    }
152
153    #[test]
154    fn test_is_not_equal() {
155        check_is_not_equal()
156    }
157}