diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs index 9fcdeced7c..8222496e6f 100644 --- a/compiler/src/expression/expression.rs +++ b/compiler/src/expression/expression.rs @@ -1,7 +1,6 @@ //! Methods to enforce constraints on expressions in a compiled Leo program. use crate::{ - comparator::{ComparatorGadget, EvaluateLtGadget}, errors::ExpressionError, program::{new_scope, ConstrainedProgram}, value::{ @@ -31,10 +30,7 @@ use leo_types::{ use snarkos_models::{ curves::{Field, PrimeField}, - gadgets::{ - r1cs::ConstraintSystem, - utilities::{eq::EvaluateEqGadget, select::CondSelectGadget}, - }, + gadgets::{r1cs::ConstraintSystem, utilities::select::CondSelectGadget}, }; static SELF_KEYWORD: &'static str = "self"; @@ -75,201 +71,6 @@ impl> ConstrainedProgram { Ok(result_value) } - /// Evaluate Boolean operations - fn evaluate_eq_expression>( - &mut self, - cs: &mut CS, - left: ConstrainedValue, - right: ConstrainedValue, - span: Span, - ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} == {} {}:{}", left, right, span.line, span.start)); - let constraint_result = match (left, right) { - (ConstrainedValue::Address(address_1), ConstrainedValue::Address(address_2)) => { - address_1.evaluate_equal(unique_namespace, &address_2) - } - (ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => { - bool_1.evaluate_equal(unique_namespace, &bool_2) - } - (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - num_1.evaluate_equal(unique_namespace, &num_2) - } - (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { - field_1.evaluate_equal(unique_namespace, &field_2) - } - (ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => { - point_1.evaluate_equal(unique_namespace, &point_2) - } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; - return self.evaluate_eq_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; - return self.evaluate_eq_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, val_2) => { - return Err(ExpressionError::incompatible_types( - format!("{} == {}", val_1, val_2,), - span, - )); - } - }; - - let boolean = - constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate equal"), e, span))?; - - Ok(ConstrainedValue::Boolean(boolean)) - } - - fn evaluate_ge_expression>( - &mut self, - cs: &mut CS, - left: ConstrainedValue, - right: ConstrainedValue, - span: Span, - ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} >= {} {}:{}", left, right, span.line, span.start)); - let constraint_result = match (left, right) { - (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - num_1.greater_than_or_equal(unique_namespace, &num_2) - } - (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { - field_1.greater_than_or_equal(unique_namespace, &field_2) - } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; - return self.evaluate_ge_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; - return self.evaluate_ge_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, val_2) => { - return Err(ExpressionError::incompatible_types( - format!("{} >= {}", val_1, val_2), - span, - )); - } - }; - - let boolean = constraint_result - .map_err(|e| ExpressionError::cannot_enforce(format!("evaluate greater than or equal"), e, span))?; - - Ok(ConstrainedValue::Boolean(boolean)) - } - - fn evaluate_gt_expression>( - &mut self, - cs: &mut CS, - left: ConstrainedValue, - right: ConstrainedValue, - span: Span, - ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} > {} {}:{}", left, right, span.line, span.start)); - let constraint_result = match (left, right) { - (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - num_1.greater_than(unique_namespace, &num_2) - } - (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { - field_1.greater_than(unique_namespace, &field_2) - } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; - return self.evaluate_gt_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; - return self.evaluate_gt_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, val_2) => { - return Err(ExpressionError::incompatible_types( - format!("{} > {}", val_1, val_2), - span, - )); - } - }; - - let boolean = constraint_result - .map_err(|e| ExpressionError::cannot_enforce(format!("evaluate greater than"), e, span))?; - - Ok(ConstrainedValue::Boolean(boolean)) - } - - fn evaluate_le_expression>( - &mut self, - cs: &mut CS, - left: ConstrainedValue, - right: ConstrainedValue, - span: Span, - ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} <= {} {}:{}", left, right, span.line, span.start)); - let constraint_result = match (left, right) { - (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - num_1.less_than_or_equal(unique_namespace, &num_2) - } - (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { - field_1.less_than_or_equal(unique_namespace, &field_2) - } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; - return self.evaluate_le_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; - return self.evaluate_le_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, val_2) => { - return Err(ExpressionError::incompatible_types( - format!("{} <= {}", val_1, val_2), - span, - )); - } - }; - - let boolean = constraint_result - .map_err(|e| ExpressionError::cannot_enforce(format!("evaluate less than or equal"), e, span))?; - - Ok(ConstrainedValue::Boolean(boolean)) - } - - fn evaluate_lt_expression>( - &mut self, - cs: &mut CS, - left: ConstrainedValue, - right: ConstrainedValue, - span: Span, - ) -> Result, ExpressionError> { - let mut unique_namespace = cs.ns(|| format!("evaluate {} < {} {}:{}", left, right, span.line, span.start)); - let constraint_result = match (left, right) { - (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { - num_1.less_than(unique_namespace, &num_2) - } - (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { - field_1.less_than(unique_namespace, &field_2) - } - (ConstrainedValue::Unresolved(string), val_2) => { - let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; - return self.evaluate_lt_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, ConstrainedValue::Unresolved(string)) => { - let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; - return self.evaluate_lt_expression(&mut unique_namespace, val_1, val_2, span); - } - (val_1, val_2) => { - return Err(ExpressionError::incompatible_types( - format!("{} < {}", val_1, val_2), - span, - )); - } - }; - - let boolean = - constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate less than"), e, span))?; - - Ok(ConstrainedValue::Boolean(boolean)) - } - /// Enforce ternary conditional expression fn enforce_conditional_expression>( &mut self, diff --git a/compiler/src/expression/mod.rs b/compiler/src/expression/mod.rs index d690f05491..1030078e72 100644 --- a/compiler/src/expression/mod.rs +++ b/compiler/src/expression/mod.rs @@ -1,7 +1,10 @@ //! Methods to enforce expressions in a compiled Leo program. pub mod arithmetic; -pub use arithmetic::*; +pub use self::arithmetic::*; pub mod expression; -pub use expression::*; +pub use self::expression::*; + +pub mod relational; +pub use self::relational::*; diff --git a/compiler/src/expression/relational/eq.rs b/compiler/src/expression/relational/eq.rs new file mode 100644 index 0000000000..0c953879e7 --- /dev/null +++ b/compiler/src/expression/relational/eq.rs @@ -0,0 +1,58 @@ +//! Methods to enforce constraints on `==` comparison expressions in a compiled Leo program. + +use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use leo_types::Span; + +use snarkos_models::{ + curves::{Field, PrimeField}, + gadgets::{r1cs::ConstraintSystem, utilities::eq::EvaluateEqGadget}, +}; + +impl> ConstrainedProgram { + /// Evaluate Boolean operations + pub fn evaluate_eq_expression>( + &mut self, + cs: &mut CS, + left: ConstrainedValue, + right: ConstrainedValue, + span: Span, + ) -> Result, ExpressionError> { + let mut unique_namespace = cs.ns(|| format!("evaluate {} == {} {}:{}", left, right, span.line, span.start)); + let constraint_result = match (left, right) { + (ConstrainedValue::Address(address_1), ConstrainedValue::Address(address_2)) => { + address_1.evaluate_equal(unique_namespace, &address_2) + } + (ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => { + bool_1.evaluate_equal(unique_namespace, &bool_2) + } + (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { + num_1.evaluate_equal(unique_namespace, &num_2) + } + (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { + field_1.evaluate_equal(unique_namespace, &field_2) + } + (ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => { + point_1.evaluate_equal(unique_namespace, &point_2) + } + (ConstrainedValue::Unresolved(string), val_2) => { + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; + return self.evaluate_eq_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, ConstrainedValue::Unresolved(string)) => { + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; + return self.evaluate_eq_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, val_2) => { + return Err(ExpressionError::incompatible_types( + format!("{} == {}", val_1, val_2,), + span, + )); + } + }; + + let boolean = + constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate equal"), e, span))?; + + Ok(ConstrainedValue::Boolean(boolean)) + } +} diff --git a/compiler/src/expression/relational/ge.rs b/compiler/src/expression/relational/ge.rs new file mode 100644 index 0000000000..ac69d617b8 --- /dev/null +++ b/compiler/src/expression/relational/ge.rs @@ -0,0 +1,54 @@ +//! Methods to enforce constraints on `>=` comparison expressions in a compiled Leo program. + +use crate::{ + comparator::ComparatorGadget, + errors::ExpressionError, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, +}; +use leo_types::Span; + +use snarkos_models::{ + curves::{Field, PrimeField}, + gadgets::r1cs::ConstraintSystem, +}; + +impl> ConstrainedProgram { + pub fn evaluate_ge_expression>( + &mut self, + cs: &mut CS, + left: ConstrainedValue, + right: ConstrainedValue, + span: Span, + ) -> Result, ExpressionError> { + let mut unique_namespace = cs.ns(|| format!("evaluate {} >= {} {}:{}", left, right, span.line, span.start)); + let constraint_result = match (left, right) { + (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { + num_1.greater_than_or_equal(unique_namespace, &num_2) + } + (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { + field_1.greater_than_or_equal(unique_namespace, &field_2) + } + (ConstrainedValue::Unresolved(string), val_2) => { + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; + return self.evaluate_ge_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, ConstrainedValue::Unresolved(string)) => { + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; + return self.evaluate_ge_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, val_2) => { + return Err(ExpressionError::incompatible_types( + format!("{} >= {}", val_1, val_2), + span, + )); + } + }; + + let boolean = constraint_result + .map_err(|e| ExpressionError::cannot_enforce(format!("evaluate greater than or equal"), e, span))?; + + Ok(ConstrainedValue::Boolean(boolean)) + } +} diff --git a/compiler/src/expression/relational/gt.rs b/compiler/src/expression/relational/gt.rs new file mode 100644 index 0000000000..2e4b29e32a --- /dev/null +++ b/compiler/src/expression/relational/gt.rs @@ -0,0 +1,54 @@ +//! Methods to enforce constraints on `>` comparison expressions in a compiled Leo program. + +use crate::{ + comparator::ComparatorGadget, + errors::ExpressionError, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, +}; +use leo_types::Span; + +use snarkos_models::{ + curves::{Field, PrimeField}, + gadgets::r1cs::ConstraintSystem, +}; + +impl> ConstrainedProgram { + pub fn evaluate_gt_expression>( + &mut self, + cs: &mut CS, + left: ConstrainedValue, + right: ConstrainedValue, + span: Span, + ) -> Result, ExpressionError> { + let mut unique_namespace = cs.ns(|| format!("evaluate {} > {} {}:{}", left, right, span.line, span.start)); + let constraint_result = match (left, right) { + (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { + num_1.greater_than(unique_namespace, &num_2) + } + (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { + field_1.greater_than(unique_namespace, &field_2) + } + (ConstrainedValue::Unresolved(string), val_2) => { + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; + return self.evaluate_gt_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, ConstrainedValue::Unresolved(string)) => { + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; + return self.evaluate_gt_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, val_2) => { + return Err(ExpressionError::incompatible_types( + format!("{} > {}", val_1, val_2), + span, + )); + } + }; + + let boolean = constraint_result + .map_err(|e| ExpressionError::cannot_enforce(format!("evaluate greater than"), e, span))?; + + Ok(ConstrainedValue::Boolean(boolean)) + } +} diff --git a/compiler/src/expression/relational/le.rs b/compiler/src/expression/relational/le.rs new file mode 100644 index 0000000000..ff91be3eba --- /dev/null +++ b/compiler/src/expression/relational/le.rs @@ -0,0 +1,54 @@ +//! Methods to enforce constraints on `<=` comparison expressions in a compiled Leo program. + +use crate::{ + comparator::ComparatorGadget, + errors::ExpressionError, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, +}; +use leo_types::Span; + +use snarkos_models::{ + curves::{Field, PrimeField}, + gadgets::r1cs::ConstraintSystem, +}; + +impl> ConstrainedProgram { + pub fn evaluate_le_expression>( + &mut self, + cs: &mut CS, + left: ConstrainedValue, + right: ConstrainedValue, + span: Span, + ) -> Result, ExpressionError> { + let mut unique_namespace = cs.ns(|| format!("evaluate {} <= {} {}:{}", left, right, span.line, span.start)); + let constraint_result = match (left, right) { + (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { + num_1.less_than_or_equal(unique_namespace, &num_2) + } + (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { + field_1.less_than_or_equal(unique_namespace, &field_2) + } + (ConstrainedValue::Unresolved(string), val_2) => { + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; + return self.evaluate_le_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, ConstrainedValue::Unresolved(string)) => { + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; + return self.evaluate_le_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, val_2) => { + return Err(ExpressionError::incompatible_types( + format!("{} <= {}", val_1, val_2), + span, + )); + } + }; + + let boolean = constraint_result + .map_err(|e| ExpressionError::cannot_enforce(format!("evaluate less than or equal"), e, span))?; + + Ok(ConstrainedValue::Boolean(boolean)) + } +} diff --git a/compiler/src/expression/relational/lt.rs b/compiler/src/expression/relational/lt.rs new file mode 100644 index 0000000000..40eb2b032a --- /dev/null +++ b/compiler/src/expression/relational/lt.rs @@ -0,0 +1,54 @@ +//! Methods to enforce constraints on `<` comparison expressions in a compiled Leo program. + +use crate::{ + comparator::EvaluateLtGadget, + errors::ExpressionError, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, +}; +use leo_types::Span; + +use snarkos_models::{ + curves::{Field, PrimeField}, + gadgets::r1cs::ConstraintSystem, +}; + +impl> ConstrainedProgram { + pub fn evaluate_lt_expression>( + &mut self, + cs: &mut CS, + left: ConstrainedValue, + right: ConstrainedValue, + span: Span, + ) -> Result, ExpressionError> { + let mut unique_namespace = cs.ns(|| format!("evaluate {} < {} {}:{}", left, right, span.line, span.start)); + let constraint_result = match (left, right) { + (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { + num_1.less_than(unique_namespace, &num_2) + } + (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => { + field_1.less_than(unique_namespace, &field_2) + } + (ConstrainedValue::Unresolved(string), val_2) => { + let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; + return self.evaluate_lt_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, ConstrainedValue::Unresolved(string)) => { + let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; + return self.evaluate_lt_expression(&mut unique_namespace, val_1, val_2, span); + } + (val_1, val_2) => { + return Err(ExpressionError::incompatible_types( + format!("{} < {}", val_1, val_2), + span, + )); + } + }; + + let boolean = + constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate less than"), e, span))?; + + Ok(ConstrainedValue::Boolean(boolean)) + } +} diff --git a/compiler/src/expression/relational/mod.rs b/compiler/src/expression/relational/mod.rs new file mode 100644 index 0000000000..2bb58dc9c7 --- /dev/null +++ b/compiler/src/expression/relational/mod.rs @@ -0,0 +1,16 @@ +//! Methods to enforce constraints on relational expressions in a compiled Leo program. + +pub mod eq; +pub use self::eq::*; + +pub mod ge; +pub use self::ge::*; + +pub mod gt; +pub use self::gt::*; + +pub mod le; +pub use self::le::*; + +pub mod lt; +pub use self::lt::*;