snarkvm_circuit_types_boolean/
nand.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> Nand<Self> for Boolean<E> {
19    type Output = Boolean<E>;
20
21    /// Returns `NOT (a AND b)`.
22    fn nand(&self, other: &Self) -> Self::Output {
23        // Constant `self`
24        if self.is_constant() {
25            match self.eject_value() {
26                true => !other.clone(),
27                false => !self.clone(),
28            }
29        }
30        // Constant `other`
31        else if other.is_constant() {
32            match other.eject_value() {
33                true => !self.clone(),
34                false => !other.clone(),
35            }
36        }
37        // Variable NAND Variable
38        else {
39            // Declare a new variable with the expected output as witness.
40            // Note: The constraint below will ensure `output` is either 0 or 1,
41            // assuming `self` and `other` are well-formed (they are either 0 or 1).
42            let output = Boolean(
43                E::new_variable(Mode::Private, match !(self.eject_value() & other.eject_value()) {
44                    true => E::BaseField::one(),
45                    false => E::BaseField::zero(),
46                })
47                .into(),
48            );
49
50            // Ensure `self` * `other` = (1 - `output`)
51            // `output` is `1` iff `self` or `other` is `0`, otherwise `output` is `0`.
52            E::enforce(|| (self, other, E::one() - &output.0));
53
54            output
55        }
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use snarkvm_circuit_environment::Circuit;
63
64    fn check_nand(
65        name: &str,
66        expected: bool,
67        a: Boolean<Circuit>,
68        b: Boolean<Circuit>,
69        num_constants: u64,
70        num_public: u64,
71        num_private: u64,
72        num_constraints: u64,
73    ) {
74        Circuit::scope(name, || {
75            let candidate = a.nand(&b);
76            assert_eq!(expected, candidate.eject_value(), "({} NAND {})", a.eject_value(), b.eject_value());
77            assert_scope!(num_constants, num_public, num_private, num_constraints);
78        });
79    }
80
81    #[test]
82    fn test_constant_nand_constant() {
83        // false NAND false
84        let expected = true;
85        let a = Boolean::<Circuit>::new(Mode::Constant, false);
86        let b = Boolean::<Circuit>::new(Mode::Constant, false);
87        check_nand("false NAND false", expected, a, b, 0, 0, 0, 0);
88
89        // false NAND true
90        let expected = true;
91        let a = Boolean::<Circuit>::new(Mode::Constant, false);
92        let b = Boolean::<Circuit>::new(Mode::Constant, true);
93        check_nand("false NAND true", expected, a, b, 0, 0, 0, 0);
94
95        // true NAND false
96        let expected = true;
97        let a = Boolean::<Circuit>::new(Mode::Constant, true);
98        let b = Boolean::<Circuit>::new(Mode::Constant, false);
99        check_nand("true NAND false", expected, a, b, 0, 0, 0, 0);
100
101        // true NAND true
102        let expected = false;
103        let a = Boolean::<Circuit>::new(Mode::Constant, true);
104        let b = Boolean::<Circuit>::new(Mode::Constant, true);
105        check_nand("true NAND true", expected, a, b, 0, 0, 0, 0);
106    }
107
108    #[test]
109    fn test_constant_nand_public() {
110        // false NAND false
111        let expected = true;
112        let a = Boolean::<Circuit>::new(Mode::Constant, false);
113        let b = Boolean::<Circuit>::new(Mode::Public, false);
114        check_nand("false NAND false", expected, a, b, 0, 0, 0, 0);
115
116        // false NAND true
117        let expected = true;
118        let a = Boolean::<Circuit>::new(Mode::Constant, false);
119        let b = Boolean::<Circuit>::new(Mode::Public, true);
120        check_nand("false NAND true", expected, a, b, 0, 0, 0, 0);
121
122        // true NAND false
123        let expected = true;
124        let a = Boolean::<Circuit>::new(Mode::Constant, true);
125        let b = Boolean::<Circuit>::new(Mode::Public, false);
126        check_nand("true NAND false", expected, a, b, 0, 0, 0, 0);
127
128        // true NAND true
129        let expected = false;
130        let a = Boolean::<Circuit>::new(Mode::Constant, true);
131        let b = Boolean::<Circuit>::new(Mode::Public, true);
132        check_nand("true NAND true", expected, a, b, 0, 0, 0, 0);
133    }
134
135    #[test]
136    fn test_constant_nand_private() {
137        // false NAND false
138        let expected = true;
139        let a = Boolean::<Circuit>::new(Mode::Constant, false);
140        let b = Boolean::<Circuit>::new(Mode::Private, false);
141        check_nand("false NAND false", expected, a, b, 0, 0, 0, 0);
142
143        // false NAND true
144        let expected = true;
145        let a = Boolean::<Circuit>::new(Mode::Constant, false);
146        let b = Boolean::<Circuit>::new(Mode::Private, true);
147        check_nand("false NAND true", expected, a, b, 0, 0, 0, 0);
148
149        // true NAND false
150        let expected = true;
151        let a = Boolean::<Circuit>::new(Mode::Constant, true);
152        let b = Boolean::<Circuit>::new(Mode::Private, false);
153        check_nand("true NAND false", expected, a, b, 0, 0, 0, 0);
154
155        // true NAND true
156        let expected = false;
157        let a = Boolean::<Circuit>::new(Mode::Constant, true);
158        let b = Boolean::<Circuit>::new(Mode::Private, true);
159        check_nand("true NAND true", expected, a, b, 0, 0, 0, 0);
160    }
161
162    #[test]
163    fn test_public_nand_constant() {
164        // false NAND false
165        let expected = true;
166        let a = Boolean::<Circuit>::new(Mode::Public, false);
167        let b = Boolean::<Circuit>::new(Mode::Constant, false);
168        check_nand("false NAND false", expected, a, b, 0, 0, 0, 0);
169
170        // false NAND true
171        let expected = true;
172        let a = Boolean::<Circuit>::new(Mode::Public, false);
173        let b = Boolean::<Circuit>::new(Mode::Constant, true);
174        check_nand("false NAND true", expected, a, b, 0, 0, 0, 0);
175
176        // true NAND false
177        let expected = true;
178        let a = Boolean::<Circuit>::new(Mode::Public, true);
179        let b = Boolean::<Circuit>::new(Mode::Constant, false);
180        check_nand("true NAND false", expected, a, b, 0, 0, 0, 0);
181
182        // true NAND true
183        let expected = false;
184        let a = Boolean::<Circuit>::new(Mode::Public, true);
185        let b = Boolean::<Circuit>::new(Mode::Constant, true);
186        check_nand("true NAND true", expected, a, b, 0, 0, 0, 0);
187    }
188
189    #[test]
190    fn test_public_nand_public() {
191        // false NAND false
192        let expected = true;
193        let a = Boolean::<Circuit>::new(Mode::Public, false);
194        let b = Boolean::<Circuit>::new(Mode::Public, false);
195        check_nand("false NAND false", expected, a, b, 0, 0, 1, 1);
196
197        // false NAND true
198        let expected = true;
199        let a = Boolean::<Circuit>::new(Mode::Public, false);
200        let b = Boolean::<Circuit>::new(Mode::Public, true);
201        check_nand("false NAND true", expected, a, b, 0, 0, 1, 1);
202
203        // true NAND false
204        let expected = true;
205        let a = Boolean::<Circuit>::new(Mode::Public, true);
206        let b = Boolean::<Circuit>::new(Mode::Public, false);
207        check_nand("true NAND false", expected, a, b, 0, 0, 1, 1);
208
209        // true NAND true
210        let expected = false;
211        let a = Boolean::<Circuit>::new(Mode::Public, true);
212        let b = Boolean::<Circuit>::new(Mode::Public, true);
213        check_nand("true NAND true", expected, a, b, 0, 0, 1, 1);
214    }
215
216    #[test]
217    fn test_public_nand_private() {
218        // false NAND false
219        let expected = true;
220        let a = Boolean::<Circuit>::new(Mode::Public, false);
221        let b = Boolean::<Circuit>::new(Mode::Private, false);
222        check_nand("false NAND false", expected, a, b, 0, 0, 1, 1);
223
224        // false NAND true
225        let expected = true;
226        let a = Boolean::<Circuit>::new(Mode::Public, false);
227        let b = Boolean::<Circuit>::new(Mode::Private, true);
228        check_nand("false NAND true", expected, a, b, 0, 0, 1, 1);
229
230        // true NAND false
231        let expected = true;
232        let a = Boolean::<Circuit>::new(Mode::Public, true);
233        let b = Boolean::<Circuit>::new(Mode::Private, false);
234        check_nand("true NAND false", expected, a, b, 0, 0, 1, 1);
235
236        // true NAND true
237        let expected = false;
238        let a = Boolean::<Circuit>::new(Mode::Public, true);
239        let b = Boolean::<Circuit>::new(Mode::Private, true);
240        check_nand("true NAND true", expected, a, b, 0, 0, 1, 1);
241    }
242
243    #[test]
244    fn test_private_nand_constant() {
245        // false NAND false
246        let expected = true;
247        let a = Boolean::<Circuit>::new(Mode::Private, false);
248        let b = Boolean::<Circuit>::new(Mode::Constant, false);
249        check_nand("false NAND false", expected, a, b, 0, 0, 0, 0);
250
251        // false NAND true
252        let expected = true;
253        let a = Boolean::<Circuit>::new(Mode::Private, false);
254        let b = Boolean::<Circuit>::new(Mode::Constant, true);
255        check_nand("false NAND true", expected, a, b, 0, 0, 0, 0);
256
257        // true NAND false
258        let expected = true;
259        let a = Boolean::<Circuit>::new(Mode::Private, true);
260        let b = Boolean::<Circuit>::new(Mode::Constant, false);
261        check_nand("true NAND false", expected, a, b, 0, 0, 0, 0);
262
263        // true NAND true
264        let expected = false;
265        let a = Boolean::<Circuit>::new(Mode::Private, true);
266        let b = Boolean::<Circuit>::new(Mode::Constant, true);
267        check_nand("true NAND true", expected, a, b, 0, 0, 0, 0);
268    }
269
270    #[test]
271    fn test_private_nand_public() {
272        // false NAND false
273        let expected = true;
274        let a = Boolean::<Circuit>::new(Mode::Private, false);
275        let b = Boolean::<Circuit>::new(Mode::Public, false);
276        check_nand("false NAND false", expected, a, b, 0, 0, 1, 1);
277
278        // false NAND true
279        let expected = true;
280        let a = Boolean::<Circuit>::new(Mode::Private, false);
281        let b = Boolean::<Circuit>::new(Mode::Public, true);
282        check_nand("false NAND true", expected, a, b, 0, 0, 1, 1);
283
284        // true NAND false
285        let expected = true;
286        let a = Boolean::<Circuit>::new(Mode::Private, true);
287        let b = Boolean::<Circuit>::new(Mode::Public, false);
288        check_nand("true NAND false", expected, a, b, 0, 0, 1, 1);
289
290        // true NAND true
291        let expected = false;
292        let a = Boolean::<Circuit>::new(Mode::Private, true);
293        let b = Boolean::<Circuit>::new(Mode::Public, true);
294        check_nand("true NAND true", expected, a, b, 0, 0, 1, 1);
295    }
296
297    #[test]
298    fn test_private_nand_private() {
299        // false NAND false
300        let expected = true;
301        let a = Boolean::<Circuit>::new(Mode::Private, false);
302        let b = Boolean::<Circuit>::new(Mode::Private, false);
303        check_nand("false NAND false", expected, a, b, 0, 0, 1, 1);
304
305        // false NAND true
306        let expected = true;
307        let a = Boolean::<Circuit>::new(Mode::Private, false);
308        let b = Boolean::<Circuit>::new(Mode::Private, true);
309        check_nand("false NAND true", expected, a, b, 0, 0, 1, 1);
310
311        // true NAND false
312        let expected = true;
313        let a = Boolean::<Circuit>::new(Mode::Private, true);
314        let b = Boolean::<Circuit>::new(Mode::Private, false);
315        check_nand("true NAND false", expected, a, b, 0, 0, 1, 1);
316
317        // true NAND true
318        let expected = false;
319        let a = Boolean::<Circuit>::new(Mode::Private, true);
320        let b = Boolean::<Circuit>::new(Mode::Private, true);
321        check_nand("true NAND true", expected, a, b, 0, 0, 1, 1);
322    }
323}