snarkvm_circuit_types_boolean/
lib.rs1#![forbid(unsafe_code)]
17#![allow(clippy::too_many_arguments)]
18#![cfg_attr(test, allow(clippy::assertions_on_result_states))]
19
20extern crate snarkvm_console_types_boolean as console;
21
22mod helpers;
23
24pub mod and;
25pub mod equal;
26pub mod nand;
27pub mod nor;
28pub mod not;
29pub mod or;
30pub mod ternary;
31pub mod xor;
32
33#[cfg(test)]
34use snarkvm_circuit_environment::{assert_count, assert_output_mode, assert_scope, count, output_mode};
35
36use snarkvm_circuit_environment::prelude::*;
37
38use core::ops::Deref;
39
40#[derive(Clone)]
41pub struct Boolean<E: Environment>(LinearCombination<E::BaseField>);
42
43impl<E: Environment> BooleanTrait for Boolean<E> {}
44
45impl<E: Environment> Boolean<E> {
46 pub fn from_variable(var: Variable<E::BaseField>) -> Self {
50 debug_assert!(var.value().is_zero() || var.value().is_one(), "Boolean variable is not well-formed");
52 Boolean(var.into())
54 }
55}
56
57impl<E: Environment> Inject for Boolean<E> {
58 type Primitive = bool;
59
60 fn new(mode: Mode, value: Self::Primitive) -> Self {
62 let variable = E::new_variable(mode, match value {
63 true => E::BaseField::one(),
64 false => E::BaseField::zero(),
65 });
66
67 E::enforce(|| (E::one() - &variable, &variable, E::zero()));
70
71 Self(variable.into())
72 }
73
74 fn constant(value: Self::Primitive) -> Self {
76 match value {
77 true => Self(E::one()),
78 false => Self(E::zero()),
79 }
80 }
81}
82
83impl<E: Environment> Eject for Boolean<E> {
84 type Primitive = bool;
85
86 fn eject_mode(&self) -> Mode {
88 match self.0.is_boolean_type() {
90 true => self.0.mode(),
91 false => E::halt("Boolean variable is not well-formed"),
92 }
93 }
94
95 fn eject_value(&self) -> Self::Primitive {
97 let value = self.0.value();
98 debug_assert!(value.is_zero() || value.is_one());
99 value.is_one()
100 }
101}
102
103impl<E: Environment> Parser for Boolean<E> {
104 #[inline]
106 fn parse(string: &str) -> ParserResult<Self> {
107 let (string, boolean) = console::Boolean::<E::Network>::parse(string)?;
109 let (string, mode) = opt(pair(tag("."), Mode::parse))(string)?;
111
112 match mode {
113 Some((_, mode)) => Ok((string, Boolean::new(mode, *boolean))),
114 None => Ok((string, Boolean::new(Mode::Constant, *boolean))),
115 }
116 }
117}
118
119impl<E: Environment> FromStr for Boolean<E> {
120 type Err = Error;
121
122 #[inline]
124 fn from_str(string: &str) -> Result<Self> {
125 match Self::parse(string) {
126 Ok((remainder, object)) => {
127 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
129 Ok(object)
131 }
132 Err(error) => bail!("Failed to parse string. {error}"),
133 }
134 }
135}
136
137impl<E: Environment> TypeName for Boolean<E> {
138 #[inline]
140 fn type_name() -> &'static str {
141 console::Boolean::<E::Network>::type_name()
142 }
143}
144
145impl<E: Environment> Debug for Boolean<E> {
146 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147 Display::fmt(self, f)
148 }
149}
150
151impl<E: Environment> Display for Boolean<E> {
152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153 write!(f, "{}.{}", self.eject_value(), self.eject_mode())
154 }
155}
156
157impl<E: Environment> Deref for Boolean<E> {
158 type Target = LinearCombination<E::BaseField>;
159
160 fn deref(&self) -> &Self::Target {
161 &self.0
162 }
163}
164
165impl<E: Environment> From<Boolean<E>> for LinearCombination<E::BaseField> {
166 fn from(boolean: Boolean<E>) -> Self {
167 boolean.0
168 }
169}
170
171impl<E: Environment> From<&Boolean<E>> for LinearCombination<E::BaseField> {
172 fn from(boolean: &Boolean<E>) -> Self {
173 boolean.0.clone()
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use snarkvm_circuit_environment::Circuit;
181
182 #[test]
183 fn test_new_constant() {
184 Circuit::scope("test_new_constant", || {
185 let candidate = Boolean::<Circuit>::new(Mode::Constant, false);
186 assert!(!candidate.eject_value()); assert_scope!(1, 0, 0, 0);
188
189 let candidate = Boolean::<Circuit>::new(Mode::Constant, true);
190 assert!(candidate.eject_value()); assert_scope!(2, 0, 0, 0);
192 });
193 }
194
195 #[test]
196 fn test_new_public() {
197 Circuit::scope("test_new_public", || {
198 let candidate = Boolean::<Circuit>::new(Mode::Public, false);
199 assert!(!candidate.eject_value()); assert_scope!(0, 1, 0, 1);
201
202 let candidate = Boolean::<Circuit>::new(Mode::Public, true);
203 assert!(candidate.eject_value()); assert_scope!(0, 2, 0, 2);
205 });
206 }
207
208 #[test]
209 fn test_new_private() {
210 Circuit::scope("test_new_private", || {
211 let candidate = Boolean::<Circuit>::new(Mode::Private, false);
212 assert!(!candidate.eject_value()); assert_scope!(0, 0, 1, 1);
214
215 let candidate = Boolean::<Circuit>::new(Mode::Private, true);
216 assert!(candidate.eject_value()); assert_scope!(0, 0, 2, 2);
218 });
219 }
220
221 #[test]
222 fn test_new_fail() {
223 let one = <Circuit as Environment>::BaseField::one();
224 let two = one + one;
225 {
226 let candidate = Circuit::new_variable(Mode::Constant, two);
227
228 assert!(
231 std::panic::catch_unwind(|| Circuit::enforce(|| (
232 Circuit::one() - &candidate,
233 candidate,
234 Circuit::zero()
235 )))
236 .is_err()
237 );
238 assert_eq!(0, Circuit::num_constraints());
239
240 Circuit::reset();
241 }
242 {
243 let candidate = Circuit::new_variable(Mode::Public, two);
244
245 Circuit::enforce(|| (Circuit::one() - &candidate, candidate, Circuit::zero()));
248 assert!(!Circuit::is_satisfied());
249
250 Circuit::reset();
251 }
252 {
253 let candidate = Circuit::new_variable(Mode::Private, two);
254
255 Circuit::enforce(|| (Circuit::one() - &candidate, candidate, Circuit::zero()));
258 assert!(!Circuit::is_satisfied());
259
260 Circuit::reset();
261 }
262 }
263
264 #[test]
265 fn test_parser() {
266 let (_, candidate) = Boolean::<Circuit>::parse("true").unwrap();
267 assert!(candidate.eject_value());
268 assert!(candidate.is_constant());
269
270 let (_, candidate) = Boolean::<Circuit>::parse("false").unwrap();
271 assert!(!candidate.eject_value());
272 assert!(candidate.is_constant());
273
274 let (_, candidate) = Boolean::<Circuit>::parse("true.constant").unwrap();
275 assert!(candidate.eject_value());
276 assert!(candidate.is_constant());
277
278 let (_, candidate) = Boolean::<Circuit>::parse("false.constant").unwrap();
279 assert!(!candidate.eject_value());
280 assert!(candidate.is_constant());
281
282 let (_, candidate) = Boolean::<Circuit>::parse("true.public").unwrap();
283 assert!(candidate.eject_value());
284 assert!(candidate.is_public());
285
286 let (_, candidate) = Boolean::<Circuit>::parse("false.public").unwrap();
287 assert!(!candidate.eject_value());
288 assert!(candidate.is_public());
289
290 let (_, candidate) = Boolean::<Circuit>::parse("true.private").unwrap();
291 assert!(candidate.eject_value());
292 assert!(candidate.is_private());
293
294 let (_, candidate) = Boolean::<Circuit>::parse("false.private").unwrap();
295 assert!(!candidate.eject_value());
296 assert!(candidate.is_private());
297
298 for mode in [Mode::Constant, Mode::Public, Mode::Private] {
299 for value in [true, false] {
300 let expected = Boolean::<Circuit>::new(mode, value);
301
302 let (_, candidate) = Boolean::<Circuit>::parse(&format!("{expected}")).unwrap();
303 assert_eq!(expected.eject_value(), candidate.eject_value());
304 assert_eq!(mode, candidate.eject_mode());
305 }
306 }
307 }
308
309 #[test]
310 fn test_display() {
311 let candidate = Boolean::<Circuit>::new(Mode::Constant, false);
312 assert_eq!("false.constant", format!("{candidate}"));
313
314 let candidate = Boolean::<Circuit>::new(Mode::Constant, true);
315 assert_eq!("true.constant", format!("{candidate}"));
316
317 let candidate = Boolean::<Circuit>::new(Mode::Public, false);
318 assert_eq!("false.public", format!("{candidate}"));
319
320 let candidate = Boolean::<Circuit>::new(Mode::Public, true);
321 assert_eq!("true.public", format!("{candidate}"));
322
323 let candidate = Boolean::<Circuit>::new(Mode::Private, false);
324 assert_eq!("false.private", format!("{candidate}"));
325
326 let candidate = Boolean::<Circuit>::new(Mode::Private, true);
327 assert_eq!("true.private", format!("{candidate}"));
328 }
329}