test field comparators

This commit is contained in:
collin 2020-06-02 16:56:11 -07:00
parent 82ba9560be
commit c8229cef18
14 changed files with 206 additions and 69 deletions

View File

@ -90,10 +90,10 @@ pub enum BinaryOperator {
Or,
And,
Eq,
Neq,
Geq,
Ne,
Ge,
Gt,
Leq,
Le,
Lt,
Add,
Sub,
@ -812,10 +812,10 @@ fn precedence_climber() -> PrecClimber<Rule> {
Operator::new(Rule::operation_or, Assoc::Left),
Operator::new(Rule::operation_and, Assoc::Left),
Operator::new(Rule::operation_eq, Assoc::Left)
| Operator::new(Rule::operation_neq, Assoc::Left),
Operator::new(Rule::operation_geq, Assoc::Left)
| Operator::new(Rule::operation_ne, Assoc::Left),
Operator::new(Rule::operation_ge, Assoc::Left)
| Operator::new(Rule::operation_gt, Assoc::Left)
| Operator::new(Rule::operation_leq, Assoc::Left)
| Operator::new(Rule::operation_le, Assoc::Left)
| Operator::new(Rule::operation_lt, Assoc::Left),
Operator::new(Rule::operation_add, Assoc::Left)
| Operator::new(Rule::operation_sub, Assoc::Left),
@ -927,10 +927,10 @@ fn binary_expression<'ast>(
Rule::operation_or => Expression::binary(BinaryOperator::Or, lhs, rhs, span),
Rule::operation_and => Expression::binary(BinaryOperator::And, lhs, rhs, span),
Rule::operation_eq => Expression::binary(BinaryOperator::Eq, lhs, rhs, span),
Rule::operation_neq => Expression::binary(BinaryOperator::Neq, lhs, rhs, span),
Rule::operation_geq => Expression::binary(BinaryOperator::Geq, lhs, rhs, span),
Rule::operation_ne => Expression::binary(BinaryOperator::Ne, lhs, rhs, span),
Rule::operation_ge => Expression::binary(BinaryOperator::Ge, lhs, rhs, span),
Rule::operation_gt => Expression::binary(BinaryOperator::Gt, lhs, rhs, span),
Rule::operation_leq => Expression::binary(BinaryOperator::Leq, lhs, rhs, span),
Rule::operation_le => Expression::binary(BinaryOperator::Le, lhs, rhs, span),
Rule::operation_lt => Expression::binary(BinaryOperator::Lt, lhs, rhs, span),
Rule::operation_add => Expression::binary(BinaryOperator::Add, lhs, rhs, span),
Rule::operation_sub => Expression::binary(BinaryOperator::Sub, lhs, rhs, span),

View File

@ -230,22 +230,23 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
}
}
fn evaluate_geq_expression(
fn evaluate_ge_expression(
&mut self,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_geq(fe_1, fe_2)
// }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = fe_1.ge(&fe_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_geq_expression(val_1, val_2)
self.evaluate_ge_expression(val_1, val_2)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
self.evaluate_geq_expression(val_1, val_2)
self.evaluate_ge_expression(val_1, val_2)
}
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
"{} >= {}, values must be fields",
@ -260,9 +261,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_gt(fe_1, fe_2)
// }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = fe_1.gt(&fe_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_gt_expression(val_1, val_2)
@ -278,22 +280,23 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
}
}
fn evaluate_leq_expression(
fn evaluate_le_expression(
&mut self,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_leq(fe_1, fe_2)
// }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = fe_1.le(&fe_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_leq_expression(val_1, val_2)
self.evaluate_le_expression(val_1, val_2)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
self.evaluate_leq_expression(val_1, val_2)
self.evaluate_le_expression(val_1, val_2)
}
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
"{} <= {}, values must be fields",
@ -308,9 +311,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_lt(fe_1, fe_2)
// }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = fe_1.lt(&fe_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_lt_expression(val_1, val_2)
@ -930,7 +934,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
Ok(self.evaluate_eq_expression(resolved_left, resolved_right)?)
}
Expression::Geq(left, right) => {
Expression::Ge(left, right) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
@ -940,7 +944,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
*right,
)?;
Ok(self.evaluate_geq_expression(resolved_left, resolved_right)?)
Ok(self.evaluate_ge_expression(resolved_left, resolved_right)?)
}
Expression::Gt(left, right) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(
@ -954,7 +958,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
Ok(self.evaluate_gt_expression(resolved_left, resolved_right)?)
}
Expression::Leq(left, right) => {
Expression::Le(left, right) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
@ -964,7 +968,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
*right,
)?;
Ok(self.evaluate_leq_expression(resolved_left, resolved_right)?)
Ok(self.evaluate_le_expression(resolved_left, resolved_right)?)
}
Expression::Lt(left, right) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(

View File

@ -433,10 +433,6 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
val_1,
val_2
)
// return Err(StatementError::AssertEq(
// val_1.to_string(),
// val_2.to_string(),
// ))
}
})
}

View File

@ -20,6 +20,7 @@ use snarkos_models::{
},
};
use std::borrow::Borrow;
use std::cmp::Ordering;
#[derive(Clone, Debug)]
pub enum FieldType<F: Field + PrimeField> {
@ -185,6 +186,15 @@ impl<F: Field + PrimeField> PartialEq for FieldType<F> {
impl<F: Field + PrimeField> Eq for FieldType<F> {}
impl<F: Field + PrimeField> PartialOrd for FieldType<F> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let self_value = self.get_value();
let other_value = other.get_value();
Option::from(self_value.cmp(&other_value))
}
}
impl<F: Field + PrimeField> EqGadget<F> for FieldType<F> {}
impl<F: Field + PrimeField> ConditionalEqGadget<F> for FieldType<F> {

View File

@ -25,11 +25,11 @@ operation_and = { "&&" }
operation_or = { "||" }
operation_eq = { "==" }
operation_neq = { "!=" }
operation_ne = { "!=" }
operation_geq = { ">=" }
operation_ge = { ">=" }
operation_gt = { ">" }
operation_leq = { "<=" }
operation_le = { "<=" }
operation_lt = { "<" }
operation_add = { "+" }
@ -39,9 +39,9 @@ operation_div = { "/" }
operation_pow = { "**" }
operation_compare = _{
operation_eq | operation_neq |
operation_geq | operation_gt |
operation_leq | operation_lt
operation_eq | operation_ne |
operation_ge | operation_gt |
operation_le | operation_lt
}
operation_binary = _{

View File

@ -82,9 +82,9 @@ pub enum Expression {
Or(Box<Expression>, Box<Expression>),
And(Box<Expression>, Box<Expression>),
Eq(Box<Expression>, Box<Expression>),
Geq(Box<Expression>, Box<Expression>),
Ge(Box<Expression>, Box<Expression>),
Gt(Box<Expression>, Box<Expression>),
Leq(Box<Expression>, Box<Expression>),
Le(Box<Expression>, Box<Expression>),
Lt(Box<Expression>, Box<Expression>),
// Conditionals

View File

@ -93,9 +93,9 @@ impl<'ast> fmt::Display for Expression {
Expression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
Expression::And(ref lhs, ref rhs) => write!(f, "{} && {}", lhs, rhs),
Expression::Eq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
Expression::Geq(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
Expression::Ge(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
Expression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
Expression::Leq(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
Expression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
Expression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
// Conditionals

View File

@ -191,10 +191,10 @@ impl<'ast> From<ast::BinaryExpression<'ast>> for types::Expression {
Box::new(types::Expression::from(*expression.left)),
Box::new(types::Expression::from(*expression.right)),
),
ast::BinaryOperator::Neq => {
ast::BinaryOperator::Ne => {
types::Expression::Not(Box::new(types::Expression::from(expression)))
}
ast::BinaryOperator::Geq => types::Expression::Geq(
ast::BinaryOperator::Ge => types::Expression::Ge(
Box::new(types::Expression::from(*expression.left)),
Box::new(types::Expression::from(*expression.right)),
),
@ -202,7 +202,7 @@ impl<'ast> From<ast::BinaryExpression<'ast>> for types::Expression {
Box::new(types::Expression::from(*expression.left)),
Box::new(types::Expression::from(*expression.right)),
),
ast::BinaryOperator::Leq => types::Expression::Leq(
ast::BinaryOperator::Le => types::Expression::Le(
Box::new(types::Expression::from(*expression.left)),
Box::new(types::Expression::from(*expression.right)),
),

View File

@ -8,22 +8,21 @@ use snarkos_models::gadgets::utilities::boolean::Boolean;
const DIRECTORY_NAME: &str = "tests/boolean/";
pub fn output_true(program: EdwardsTestCompiler) {
pub fn output_expected_boolean(program: EdwardsTestCompiler, boolean: bool) {
let output = get_output(program);
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Boolean(Boolean::Constant(true))])
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Boolean(Boolean::Constant(boolean))])
.to_string(),
output.to_string()
);
}
pub fn output_true(program: EdwardsTestCompiler) {
output_expected_boolean(program, true)
}
pub fn output_false(program: EdwardsTestCompiler) {
let output = get_output(program);
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Boolean(Boolean::Constant(false))])
.to_string(),
output.to_string()
);
output_expected_boolean(program, false)
}
fn fail_evaluate(program: EdwardsTestCompiler) {

View File

@ -0,0 +1,3 @@
function main(a: field, b: field) -> bool {
return a >= b
}

View File

@ -0,0 +1,3 @@
function main(a: field, b: field) -> bool {
return a > b
}

View File

@ -0,0 +1,3 @@
function main(a: field, b: field) -> bool {
return a <= b
}

View File

@ -0,0 +1,3 @@
function main(a: field, b: field) -> bool {
return a < b
}

View File

@ -1,4 +1,4 @@
use crate::boolean::{output_false, output_true};
use crate::boolean::{output_false, output_true, output_expected_boolean};
use crate::{compile_program, get_error, get_output, EdwardsConstrainedValue, EdwardsTestCompiler};
use leo_compiler::{
errors::{CompilerError, FieldError, FunctionError},
@ -219,29 +219,23 @@ fn test_div() {
}
#[test]
fn test_eq_true() {
fn test_eq() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let mut program = compile_program(DIRECTORY_NAME, "eq.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_true(program)
}
}
output_true(program);
#[test]
fn test_eq_false() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test not equal
let r2: u64 = rand::random();
if r1 == r2 {
continue;
}
let result = r1.eq(&r2);
let mut program = compile_program(DIRECTORY_NAME, "eq.leo").unwrap();
program.set_inputs(vec![
@ -249,7 +243,129 @@ fn test_eq_false() {
Some(InputValue::Field(r2.to_string())),
]);
output_false(program)
output_expected_boolean(program, result)
}
}
#[test]
fn test_ge() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let mut program = compile_program(DIRECTORY_NAME, "ge.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_true(program);
// test greater than
let r2: u64 = rand::random();
let result = r1.ge(&r2);
let mut program = compile_program(DIRECTORY_NAME, "ge.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
]);
output_expected_boolean(program, result)
}
}
#[test]
fn test_gt() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let mut program = compile_program(DIRECTORY_NAME, "gt.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_false(program);
// test greater than
let r2: u64 = rand::random();
let result = r1.gt(&r2);
let mut program = compile_program(DIRECTORY_NAME, "gt.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
]);
output_expected_boolean(program, result)
}
}
#[test]
fn test_le() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let mut program = compile_program(DIRECTORY_NAME, "le.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_true(program);
// test greater than
let r2: u64 = rand::random();
let result = r1.le(&r2);
let mut program = compile_program(DIRECTORY_NAME, "le.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
]);
output_expected_boolean(program, result)
}
}
#[test]
fn test_lt() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let mut program = compile_program(DIRECTORY_NAME, "lt.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_false(program);
// test greater than
let r2: u64 = rand::random();
let result = r1.lt(&r2);
let mut program = compile_program(DIRECTORY_NAME, "lt.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
]);
output_expected_boolean(program, result)
}
}