add address ternary and equal functionality and tests

This commit is contained in:
collin 2020-07-06 20:25:14 -07:00
parent 2e1a1c3075
commit 4529c56fd2
6 changed files with 97 additions and 50 deletions

View File

@ -31,7 +31,7 @@ use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{boolean::Boolean, eq::EvaluateEqGadget, select::CondSelectGadget},
utilities::{eq::EvaluateEqGadget, select::CondSelectGadget},
},
};
@ -236,6 +236,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
) -> 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)
}
@ -425,23 +428,32 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
conditional: Expression,
first: Expression,
second: Expression,
third: Expression,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let resolved_first = match self.enforce_expression(
let conditional_value = match self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
&vec![Type::Boolean],
first,
conditional,
)? {
ConstrainedValue::Boolean(resolved) => resolved,
value => return Err(ExpressionError::conditional_boolean(value.to_string(), span)),
};
let resolved_second = self.enforce_expression_value(
let first_value = self.enforce_expression_value(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
first,
span.clone(),
)?;
let second_value = self.enforce_expression_value(
cs,
file_scope.clone(),
function_scope.clone(),
@ -449,46 +461,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
second,
span.clone(),
)?;
let resolved_third =
self.enforce_expression_value(cs, file_scope, function_scope, expected_types, third, span.clone())?;
let unique_namespace = cs.ns(|| {
format!(
"select {} or {} {}:{}",
resolved_second, resolved_third, span.line, span.start
first_value, second_value, span.line, span.start
)
});
match (resolved_second, resolved_third) {
(ConstrainedValue::Boolean(bool_2), ConstrainedValue::Boolean(bool_3)) => {
let result = Boolean::conditionally_select(unique_namespace, &resolved_first, &bool_2, &bool_3)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?;
Ok(ConstrainedValue::Boolean(result))
}
(ConstrainedValue::Integer(integer_2), ConstrainedValue::Integer(integer_3)) => {
let result = Integer::conditionally_select(unique_namespace, &resolved_first, &integer_2, &integer_3)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?;
Ok(ConstrainedValue::Integer(result))
}
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
let result = FieldType::conditionally_select(unique_namespace, &resolved_first, &field_1, &field_2)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?;
Ok(ConstrainedValue::Field(result))
}
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
let result = G::conditionally_select(unique_namespace, &resolved_first, &point_1, &point_2)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?;
Ok(ConstrainedValue::Group(result))
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
format!("ternary between {} and {}", val_1, val_2),
span,
)),
}
ConstrainedValue::conditionally_select(unique_namespace, &conditional_value, &first_value, &second_value)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))
}
/// Enforce array expressions
@ -1113,14 +1095,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
// Conditionals
Expression::IfElse(first, second, third, span) => self.enforce_conditional_expression(
Expression::IfElse(conditional, first, second, span) => self.enforce_conditional_expression(
cs,
file_scope,
function_scope,
expected_types,
*conditional,
*first,
*second,
*third,
span,
),

View File

@ -231,11 +231,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
) -> Result<ConstrainedValue<F, G>, FunctionError> {
match _type {
Type::Address => Ok(Address::from_input(cs, name, input_value, span)?),
Type::Boolean => {
let bool = bool_from_input(cs, name, input_value, span)?;
println!("bool {}", bool);
Ok(bool)
}
Type::Boolean => Ok(bool_from_input(cs, name, input_value, span)?),
Type::Field => Ok(field_from_input(cs, name, input_value, span)?),
Type::Group => Ok(group_from_input(cs, name, input_value, span)?),
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::from_input(

View File

@ -0,0 +1,3 @@
function main(first: address, second: address) -> bool {
return first == second
}

View File

@ -1,6 +1,32 @@
use crate::{get_error, get_output, parse_program};
use crate::{
boolean::{output_false, output_true},
get_error,
get_output,
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,
};
use leo_compiler::{Address, ConstrainedValue};
use leo_types::InputValue;
use snarkos_dpc::base_dpc::instantiated::Components;
use snarkos_objects::AccountPublicKey;
use std::str::FromStr;
static TEST_ADDRESS_1: &'static str = "aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8";
static TEST_ADDRESS_2: &'static str = "aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r";
fn output_test_address(program: EdwardsTestCompiler, address: &str) {
let output = get_output(program);
let address_1 = AccountPublicKey::<Components>::from_str(address).unwrap();
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Address(Address(Some(address_1)))]).to_string(),
output.to_string()
);
}
#[test]
fn test_valid() {
let bytes = include_bytes!("valid.leo");
@ -54,9 +80,7 @@ fn test_input_pass() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Address(
"aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8".to_string(),
))]);
program.set_inputs(vec![Some(InputValue::Address(TEST_ADDRESS_1.to_string()))]);
let _output = get_output(program);
}
@ -70,3 +94,39 @@ fn test_input_fail_bool() {
let _err = get_error(program);
}
#[test]
fn test_ternary() {
let bytes = include_bytes!("ternary.leo");
let mut program_1 = parse_program(bytes).unwrap();
let mut program_2 = program_1.clone();
program_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
output_test_address(program_1, TEST_ADDRESS_1);
program_2.set_inputs(vec![Some(InputValue::Boolean(false))]);
output_test_address(program_2, TEST_ADDRESS_2);
}
#[test]
fn test_equal() {
let bytes = include_bytes!("equal.leo");
let mut program_1 = parse_program(bytes).unwrap();
let mut program_2 = program_1.clone();
program_1.set_inputs(vec![
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
]);
output_true(program_1);
program_2.set_inputs(vec![
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
Some(InputValue::Address(TEST_ADDRESS_2.to_string())),
]);
output_false(program_2);
}

View File

@ -0,0 +1,6 @@
function main(cond: bool) -> address {
let first = address(aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8);
let second = address(aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r);
return if cond ? first : second
}

View File

@ -52,7 +52,7 @@ pub enum Expression {
Lt(Box<Expression>, Box<Expression>, Span),
// Conditionals
IfElse(Box<Expression>, Box<Expression>, Box<Expression>, Span),
IfElse(Box<Expression>, Box<Expression>, Box<Expression>, Span), // (conditional, first_value, second_value)
// Arrays
Array(Vec<Box<SpreadOrExpression>>, Span),