add relational expression module

This commit is contained in:
collin 2020-07-07 23:07:35 -07:00
parent f29fac883f
commit d5017c7666
8 changed files with 296 additions and 202 deletions

View File

@ -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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Ok(result_value)
}
/// Evaluate Boolean operations
fn evaluate_eq_expression<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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<CS: ConstraintSystem<F>>(
&mut self,

View File

@ -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::*;

View File

@ -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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
/// Evaluate Boolean operations
pub fn evaluate_eq_expression<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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))
}
}

View File

@ -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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn evaluate_ge_expression<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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))
}
}

View File

@ -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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn evaluate_gt_expression<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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))
}
}

View File

@ -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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn evaluate_le_expression<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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))
}
}

View File

@ -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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn evaluate_lt_expression<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, 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))
}
}

View File

@ -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::*;