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