mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-29 11:43:28 +03:00
add address ternary and equal functionality and tests
This commit is contained in:
parent
2e1a1c3075
commit
4529c56fd2
@ -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,
|
||||
),
|
||||
|
||||
|
@ -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(
|
||||
|
3
compiler/tests/address/equal.leo
Normal file
3
compiler/tests/address/equal.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(first: address, second: address) -> bool {
|
||||
return first == second
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
6
compiler/tests/address/ternary.leo
Normal file
6
compiler/tests/address/ternary.leo
Normal file
@ -0,0 +1,6 @@
|
||||
function main(cond: bool) -> address {
|
||||
let first = address(aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8);
|
||||
let second = address(aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r);
|
||||
|
||||
return if cond ? first : second
|
||||
}
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user