impl mutability tests. simplify mut expression evaluation

This commit is contained in:
collin 2020-05-19 12:01:19 -07:00
parent 9309f95a89
commit a9a8cb95c6
14 changed files with 292 additions and 259 deletions

View File

@ -4,7 +4,7 @@ use crate::{
ast,
constraints::{generate_constraints, ConstrainedValue},
errors::CompilerError,
InputValue, Program
InputValue, Program,
};
use snarkos_errors::gadgets::SynthesisError;
@ -44,6 +44,10 @@ impl<F: Field + PrimeField, G: Group> Compiler<F, G> {
Ok(program)
}
pub fn set_inputs(&mut self, program_inputs: Vec<Option<InputValue<F, G>>>) {
self.program_inputs = program_inputs;
}
pub fn checksum(&self) -> Result<String, CompilerError> {
// Read in the main file as string
let unparsed_file = fs::read_to_string(&self.main_file_path)
@ -60,12 +64,8 @@ impl<F: Field + PrimeField, G: Group> Compiler<F, G> {
pub fn compile_constraints<CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
) -> Result<ConstrainedValue<F, G>, SynthesisError> {
let result = generate_constraints(cs, self.program, self.program_inputs).unwrap();
// Write results to file or something
Ok(result)
) -> Result<ConstrainedValue<F, G>, CompilerError> {
generate_constraints(cs, self.program, self.program_inputs)
}
// pub fn compile(&self) -> Result<ast::File, CompilerError> {

View File

@ -10,7 +10,7 @@ use crate::{
CircuitFieldDefinition, CircuitMember, Expression, Identifier, RangeOrExpression,
SpreadOrExpression,
},
Integer, Type,
Integer, IntegerType, Type,
};
use snarkos_models::{
@ -27,14 +27,14 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
&mut self,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
unresolved_identifier: Identifier<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Evaluate the identifier name in the current function scope
let variable_name = new_scope(function_scope, unresolved_identifier.to_string());
let identifier_name = new_scope(file_scope, unresolved_identifier.to_string());
let result_value = if let Some(value) = self.get(&variable_name) {
let mut result_value = if let Some(value) = self.get(&variable_name) {
// Reassigning variable to another variable
value.clone()
} else if let Some(value) = self.get(&identifier_name) {
@ -46,12 +46,9 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
));
};
match result_value {
ConstrainedValue::Unresolved(string) => {
Self::enforce_number_implicit(expected_types, string)
}
value => Ok(value),
}
result_value.resolve_type(expected_types)?;
Ok(result_value)
}
/// Enforce numerical operations
@ -71,12 +68,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
(ConstrainedValue::GroupElement(ge_1), ConstrainedValue::GroupElement(ge_2)) => {
Ok(Self::evaluate_group_add(ge_1, ge_2))
}
(ConstrainedValue::Mutable(val_1), val_2) => {
self.enforce_add_expression(cs, *val_1, val_2)
}
(val_1, ConstrainedValue::Mutable(val_2)) => {
self.enforce_add_expression(cs, val_1, *val_2)
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.enforce_add_expression(cs, val_1, val_2)
@ -108,12 +99,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
(ConstrainedValue::GroupElement(ge_1), ConstrainedValue::GroupElement(ge_2)) => {
Ok(Self::evaluate_group_sub(ge_1, ge_2))
}
(ConstrainedValue::Mutable(val_1), val_2) => {
self.enforce_sub_expression(cs, *val_1, val_2)
}
(val_1, ConstrainedValue::Mutable(val_2)) => {
self.enforce_sub_expression(cs, val_1, *val_2)
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.enforce_sub_expression(cs, val_1, val_2)
@ -145,12 +130,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// (ConstrainedValue::GroupElement(group), ConstrainedValue::FieldElement(scalar)) => {
// Ok(Self::evaluate_group_mul(group, scalar))
// }
(ConstrainedValue::Mutable(val_1), val_2) => {
self.enforce_mul_expression(cs, *val_1, val_2)
}
(val_1, ConstrainedValue::Mutable(val_2)) => {
self.enforce_mul_expression(cs, val_1, *val_2)
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.enforce_mul_expression(cs, val_1, val_2)
@ -181,12 +160,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
Ok(self.enforce_field_div(cs, fe_1, fe_2)?)
}
(ConstrainedValue::Mutable(val_1), val_2) => {
self.enforce_div_expression(cs, *val_1, val_2)
}
(val_1, ConstrainedValue::Mutable(val_2)) => {
self.enforce_div_expression(cs, val_1, *val_2)
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.enforce_div_expression(cs, val_1, val_2)
@ -216,12 +189,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::Integer(num_2)) => {
Ok(self.enforce_field_pow(cs, fe_1, num_2)?)
}
(ConstrainedValue::Mutable(val_1), val_2) => {
self.enforce_pow_expression(cs, *val_1, val_2)
}
(val_1, ConstrainedValue::Mutable(val_2)) => {
self.enforce_pow_expression(cs, val_1, *val_2)
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.enforce_pow_expression(cs, val_1, val_2)
@ -259,8 +226,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
(ConstrainedValue::GroupElement(ge_1), ConstrainedValue::GroupElement(ge_2)) => {
Ok(Self::evaluate_group_eq(ge_1, ge_2))
}
(ConstrainedValue::Mutable(val_1), val_2) => self.evaluate_eq_expression(*val_1, val_2),
(val_1, ConstrainedValue::Mutable(val_2)) => self.evaluate_eq_expression(val_1, *val_2),
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_eq_expression(val_1, val_2)
@ -285,12 +250,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_geq(fe_1, fe_2)
// }
(ConstrainedValue::Mutable(val_1), val_2) => {
self.evaluate_geq_expression(*val_1, val_2)
}
(val_1, ConstrainedValue::Mutable(val_2)) => {
self.evaluate_geq_expression(val_1, *val_2)
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_geq_expression(val_1, val_2)
@ -315,8 +274,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_gt(fe_1, fe_2)
// }
(ConstrainedValue::Mutable(val_1), val_2) => self.evaluate_gt_expression(*val_1, val_2),
(val_1, ConstrainedValue::Mutable(val_2)) => self.evaluate_gt_expression(val_1, *val_2),
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_gt_expression(val_1, val_2)
@ -341,12 +298,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_leq(fe_1, fe_2)
// }
(ConstrainedValue::Mutable(val_1), val_2) => {
self.evaluate_leq_expression(*val_1, val_2)
}
(val_1, ConstrainedValue::Mutable(val_2)) => {
self.evaluate_leq_expression(val_1, *val_2)
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_leq_expression(val_1, val_2)
@ -371,8 +322,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_lt(fe_1, fe_2)
// }
(ConstrainedValue::Mutable(val_1), val_2) => self.evaluate_lt_expression(*val_1, val_2),
(val_1, ConstrainedValue::Mutable(val_2)) => self.evaluate_lt_expression(val_1, *val_2),
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
self.evaluate_lt_expression(val_1, val_2)
@ -394,7 +343,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
first: Expression<F, G>,
second: Expression<F, G>,
third: Expression<F, G>,
@ -403,22 +352,22 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
vec![Type::Boolean],
&vec![Type::Boolean],
first,
)? {
ConstrainedValue::Boolean(resolved) => resolved,
value => return Err(ExpressionError::IfElseConditional(value.to_string())),
};
let resolved_second = self.enforce_expression(
let resolved_second = self.enforce_branch(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
expected_types,
second,
)?;
let resolved_third =
self.enforce_expression(cs, file_scope, function_scope, expected_types, third)?;
self.enforce_branch(cs, file_scope, function_scope, expected_types, third)?;
match (resolved_second, resolved_third) {
(ConstrainedValue::Boolean(bool_2), ConstrainedValue::Boolean(bool_3)) => {
@ -442,11 +391,13 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
mut expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
array: Vec<Box<SpreadOrExpression<F, G>>>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Check explicit array type dimension if given
let mut expected_types = expected_types.clone();
let expected_dimensions = vec![];
if !expected_types.is_empty() {
match expected_types[0] {
Type::Array(ref _type, ref dimensions) => {
@ -479,7 +430,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
&expected_types,
expression,
)?);
}
@ -504,12 +455,17 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
index: Expression<F, G>,
) -> Result<usize, ExpressionError> {
match self.enforce_expression(cs, file_scope, function_scope, expected_types, index)? {
let expected_types = vec![Type::IntegerType(IntegerType::U32)];
match self.enforce_branch(
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
index,
)? {
ConstrainedValue::Integer(number) => Ok(number.to_usize()),
ConstrainedValue::Unresolved(string) => Ok(string.parse::<usize>()?),
value => Err(ExpressionError::InvalidIndex(value.to_string())),
}
}
@ -519,7 +475,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
array: Box<Expression<F, G>>,
index: RangeOrExpression<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
@ -527,14 +483,10 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
expected_types,
*array,
)? {
ConstrainedValue::Array(array) => array,
ConstrainedValue::Mutable(value) => match *value {
ConstrainedValue::Array(array) => array,
value => return Err(ExpressionError::InvalidArrayAccess(value.to_string())),
},
value => return Err(ExpressionError::InvalidArrayAccess(value.to_string())),
};
@ -553,8 +505,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
))
}
RangeOrExpression::Expression(index) => {
let index_resolved =
self.enforce_index(cs, file_scope, function_scope, expected_types, index)?;
let index_resolved = self.enforce_index(cs, file_scope, function_scope, index)?;
Ok(array[index_resolved].to_owned())
}
}
@ -593,7 +544,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
vec![_type.clone()],
&vec![_type.clone()],
field.expression,
)?;
@ -639,22 +590,18 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
circuit_identifier: Box<Expression<F, G>>,
circuit_member: Identifier<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let (circuit_name, members) = match self.enforce_expression(
let (circuit_name, members) = match self.enforce_branch(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
expected_types,
*circuit_identifier.clone(),
)? {
ConstrainedValue::CircuitExpression(name, members) => (name, members),
ConstrainedValue::Mutable(value) => match *value {
ConstrainedValue::CircuitExpression(name, members) => (name, members),
value => return Err(ExpressionError::InvalidCircuitAccess(value.to_string())),
},
value => return Err(ExpressionError::InvalidCircuitAccess(value.to_string())),
};
@ -700,7 +647,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
circuit_identifier: Box<Expression<F, G>>,
circuit_member: Identifier<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
@ -709,7 +656,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
expected_types,
*circuit_identifier.clone(),
)? {
ConstrainedValue::CircuitDefinition(circuit_definition) => circuit_definition,
@ -752,7 +699,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
function: Box<Expression<F, G>>,
arguments: Vec<Expression<F, G>>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
@ -760,7 +707,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
expected_types,
*function.clone(),
)?;
@ -791,7 +738,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
}
pub(crate) fn enforce_number_implicit(
expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
value: String,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
if expected_types.len() == 1 {
@ -801,12 +748,59 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
Ok(ConstrainedValue::Unresolved(value))
}
/// Enforce a branch of a binary expression.
/// We don't care about mutability because we are not changing any variables.
/// We try to resolve unresolved types here if the type is given explicitly.
pub(crate) fn enforce_branch(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type<F, G>>,
expression: Expression<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let mut branch =
self.enforce_expression(cs, file_scope, function_scope, expected_types, expression)?;
branch.get_inner_mut();
branch.resolve_type(expected_types)?;
Ok(branch)
}
pub(crate) fn enforce_binary_expression(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type<F, G>>,
left: Expression<F, G>,
right: Expression<F, G>,
) -> Result<(ConstrainedValue<F, G>, ConstrainedValue<F, G>), ExpressionError> {
let resolved_left = self.enforce_branch(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
left,
)?;
let resolved_right = self.enforce_branch(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
right,
)?;
Ok((resolved_left, resolved_right))
}
pub(crate) fn enforce_expression(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
expected_types: &Vec<Type<F, G>>,
expression: Expression<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match expression {
@ -827,90 +821,60 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Binary operations
Expression::Add(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
self.enforce_add_expression(cs, resolved_left, resolved_right)
}
Expression::Sub(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
self.enforce_sub_expression(cs, resolved_left, resolved_right)
}
Expression::Mul(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
self.enforce_mul_expression(cs, resolved_left, resolved_right)
}
Expression::Div(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
self.enforce_div_expression(cs, resolved_left, resolved_right)
}
Expression::Pow(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
@ -926,126 +890,84 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
*expression,
)?)?),
Expression::Or(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
Ok(self.enforce_or(cs, resolved_left, resolved_right)?)
}
Expression::And(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
Ok(self.enforce_and(cs, resolved_left, resolved_right)?)
}
Expression::Eq(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
Ok(self.evaluate_eq_expression(resolved_left, resolved_right)?)
}
Expression::Geq(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
Ok(self.evaluate_geq_expression(resolved_left, resolved_right)?)
}
Expression::Gt(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
Ok(self.evaluate_gt_expression(resolved_left, resolved_right)?)
}
Expression::Leq(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;
Ok(self.evaluate_leq_expression(resolved_left, resolved_right)?)
}
Expression::Lt(left, right) => {
let resolved_left = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types.clone(),
*left,
)?;
let resolved_right = self.enforce_expression(
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
*left,
*right,
)?;

View File

@ -37,12 +37,16 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
Expression::Identifier(identifier) => Ok(self.evaluate_identifier(
caller_scope,
function_name,
expected_types,
&expected_types,
identifier,
)?),
expression => {
Ok(self.enforce_expression(cs, scope, function_name, expected_types, expression)?)
}
expression => Ok(self.enforce_expression(
cs,
scope,
function_name,
&expected_types,
expression,
)?),
}
}
@ -202,7 +206,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
function.inputs.clone().into_iter().zip(inputs.into_iter())
{
let input_name = new_scope(function_name.clone(), input_model.identifier.name.clone());
let mut input_value = self.allocate_main_function_input(
let input_value = self.allocate_main_function_input(
cs,
input_model._type,
input_name.clone(),
@ -210,14 +214,12 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
input_option,
)?;
if input_model.mutable {
input_value = ConstrainedValue::Mutable(Box::new(input_value))
}
// Store a new variable for every allocated main function input
self.store(input_name.clone(), input_value);
input_variables.push(Expression::Identifier(Identifier::new(input_name)));
input_variables.push(Expression::Identifier(Identifier::new(
input_model.identifier.name.clone(),
)));
}
self.enforce_function(cs, scope, function_name, function, input_variables)

View File

@ -55,6 +55,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
}
pub(crate) fn store(&mut self, name: String, value: ConstrainedValue<F, G>) {
println!("storing {}", name);
self.identifiers.insert(name, value);
}

View File

@ -53,13 +53,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Resolve index so we know if we are assigning to a single value or a range of values
match range_or_expression {
RangeOrExpression::Expression(index) => {
let index = self.enforce_index(
cs,
file_scope.clone(),
function_scope.clone(),
vec![],
index,
)?;
let index =
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), index)?;
// Modify the single value of the array in place
match self.get_mutable_assignee(name)? {
@ -145,7 +140,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
vec![],
&vec![],
expression,
)?;
@ -206,7 +201,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&expected_types,
expression,
)?;
@ -233,7 +228,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&expected_types,
function,
)? {
ConstrainedValue::Return(values) => values,
@ -275,11 +270,11 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
let mut returns = vec![];
for (expression, ty) in expressions.into_iter().zip(return_types.into_iter()) {
let expected_types = vec![ty.clone()];
let result = self.enforce_expression(
let result = self.enforce_branch(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&expected_types,
expression,
)?;
@ -328,7 +323,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
&expected_types,
statement.condition.clone(),
)? {
ConstrainedValue::Boolean(resolved) => resolved,
@ -516,14 +511,14 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope.clone(),
function_scope.clone(),
vec![],
&vec![],
left,
)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
vec![],
&vec![],
right,
)?;
@ -534,7 +529,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs,
file_scope,
function_scope,
vec![],
&vec![],
expression.clone(),
)? {
ConstrainedValue::Return(values) => {

View File

@ -86,6 +86,22 @@ impl<F: Field + PrimeField, G: Group> ConstrainedValue<F, G> {
_ => unimplemented!("to type only implemented for primitives"),
}
}
pub(crate) fn resolve_type(&mut self, types: &Vec<Type<F, G>>) -> Result<(), ValueError> {
if let ConstrainedValue::Unresolved(ref string) = self {
if !types.is_empty() {
*self = ConstrainedValue::from_type(string.clone(), &types[0])?
}
}
Ok(())
}
pub(crate) fn get_inner_mut(&mut self) {
if let ConstrainedValue::Mutable(inner) = self {
*self = *inner.clone()
}
}
}
impl<F: Field + PrimeField, G: Group> fmt::Display for ConstrainedValue<F, G> {

View File

@ -785,6 +785,7 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::InputModel<'ast>>
for types::InputModel<F, G>
{
fn from(parameter: ast::InputModel<'ast>) -> Self {
println!("{}", parameter.mutable.is_some());
types::InputModel {
identifier: types::Identifier::from(parameter.identifier),
mutable: parameter.mutable.is_some(),

View File

@ -1 +1,31 @@
pub mod mutability;
pub mod u32;
use leo_compiler::{compiler::Compiler, errors::CompilerError};
use snarkos_curves::{bls12_377::Fr, edwards_bls12::EdwardsProjective};
use std::env::current_dir;
pub(crate) fn compile_program(
directory_name: &str,
file_name: &str,
) -> Result<Compiler<Fr, EdwardsProjective>, CompilerError> {
let path = current_dir().map_err(|error| CompilerError::DirectoryError(error))?;
// Sanitize the package path to the test directory
let mut package_path = path.clone();
if package_path.is_file() {
package_path.pop();
}
// Construct the path to the test file in the test directory
let mut main_file_path = package_path.clone();
main_file_path.push(directory_name);
main_file_path.push(file_name);
println!("Compiling file - {:?}", main_file_path);
// Compile from the main file path
Compiler::<Fr, EdwardsProjective>::init(file_name.to_string(), main_file_path)
}

View File

@ -0,0 +1,4 @@
// Function inputs are immutable by default.
function main(a: u32) {
a = 0;
}

View File

@ -0,0 +1,6 @@
// Adding the `mut` keyword makes a function variable mutable.
function main(mut a: u32) -> u32 {
a = 0;
return a
}

View File

@ -0,0 +1,5 @@
// Variables are immutable by default.
function main() {
let a = 1u32;
a = 0;
}

View File

@ -0,0 +1,7 @@
// Adding the `mut` keyword makes a variable mutable.
function main() -> u32 {
let mut a = 1u32;
a = 0;
return a
}

View File

@ -0,0 +1,59 @@
use crate::compile_program;
use leo_compiler::{types::Integer, ConstrainedValue, InputValue};
use snarkos_curves::{bls12_377::Fr, edwards_bls12::EdwardsProjective};
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use snarkos_models::gadgets::utilities::uint32::UInt32;
const DIRECTORY_NAME: &str = "tests/mutability/";
#[test]
fn test_let() {
let mut cs = TestConstraintSystem::<Fr>::new();
let program = compile_program(DIRECTORY_NAME, "let.leo").unwrap();
let output = program.compile_constraints(&mut cs).is_err();
assert!(output);
}
#[test]
fn test_let_mut() {
let mut cs = TestConstraintSystem::<Fr>::new();
let program = compile_program(DIRECTORY_NAME, "let_mut.leo").unwrap();
let output = program.compile_constraints(&mut cs).unwrap();
println!("{}", output);
assert!(cs.is_satisfied());
assert_eq!(
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(
Integer::U32(UInt32::constant(0))
)]),
output
);
}
#[test]
fn test_function_input() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut program = compile_program(DIRECTORY_NAME, "function_input.leo").unwrap();
program.set_inputs(vec![Some(InputValue::Integer(1))]);
let output = program.compile_constraints(&mut cs).is_err();
assert!(output);
}
#[test]
fn test_function_input_mut() {
let mut cs = TestConstraintSystem::<Fr>::new();
let mut program = compile_program(DIRECTORY_NAME, "function_input_mut.leo").unwrap();
program.set_inputs(vec![Some(InputValue::Integer(1))]);
let output = program.compile_constraints(&mut cs).unwrap();
println!("{}", output);
assert!(cs.is_satisfied());
assert_eq!(
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(
Integer::U32(UInt32::constant(0))
)]),
output
);
}

View File

@ -1,36 +1,13 @@
use leo_compiler::{compiler::Compiler, errors::CompilerError, types::Integer, ConstrainedValue};
use crate::compile_program;
use snarkos_curves::{
bls12_377::{Bls12_377, Fr},
edwards_bls12::EdwardsProjective
};
use snarkos_models::gadgets::r1cs::{ConstraintSynthesizer, TestConstraintSystem};
use leo_compiler::{types::Integer, ConstrainedValue};
use snarkos_curves::{bls12_377::Fr, edwards_bls12::EdwardsProjective};
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use snarkos_models::gadgets::utilities::uint32::UInt32;
use std::env::current_dir;
const DIRECTORY_NAME: &str = "tests/u32/";
fn compile_program(directory_name: &str, file_name: &str) -> Result<Compiler<Fr, EdwardsProjective>, CompilerError> {
let path = current_dir().map_err(|error| CompilerError::DirectoryError(error))?;
// Sanitize the package path to the test directory
let mut package_path = path.clone();
if package_path.is_file() {
package_path.pop();
}
// Construct the path to the test file in the test directory
let mut main_file_path = package_path.clone();
main_file_path.push(directory_name);
main_file_path.push(file_name);
println!("Compiling file - {:?}", main_file_path);
// Compile from the main file path
Compiler::<Fr, EdwardsProjective>::init(file_name.to_string(), main_file_path)
}
#[test]
fn test_zero() {
let mut cs = TestConstraintSystem::<Fr>::new();
@ -40,7 +17,9 @@ fn test_zero() {
assert!(cs.is_satisfied());
assert_eq!(
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(Integer::U32(UInt32::constant(0)))]),
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(
Integer::U32(UInt32::constant(0))
)]),
output
);
}
@ -54,7 +33,9 @@ fn test_one() {
assert!(cs.is_satisfied());
assert_eq!(
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(Integer::U32(UInt32::constant(1)))]),
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(
Integer::U32(UInt32::constant(1))
)]),
output
);
}
@ -68,7 +49,9 @@ fn test_1_plus_1() {
assert!(cs.is_satisfied());
assert_eq!(
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(Integer::U32(UInt32::constant(2)))]),
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(
Integer::U32(UInt32::constant(2))
)]),
output
);
}
@ -82,17 +65,19 @@ fn test_1_minus_1() {
assert!(cs.is_satisfied());
assert_eq!(
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(Integer::U32(UInt32::constant(0)))]),
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::Integer(
Integer::U32(UInt32::constant(0))
)]),
output
);
}
#[test]
fn test_1_minus_2_should_fail() {
// TODO (howardwu): Catch panic from subtraction overflow
let mut cs = TestConstraintSystem::<Fr>::new();
let program = compile_program(DIRECTORY_NAME, "1-2.leo").unwrap();
let output = program.compile_constraints(&mut cs);
assert!(output.is_err());
}
// #[test]
// fn test_1_minus_2_should_fail() {
// // TODO (howardwu): Catch panic from subtraction overflow
//
// let mut cs = TestConstraintSystem::<Fr>::new();
// let program = compile_program(DIRECTORY_NAME, "1-2.leo").unwrap();
// let output = program.compile_constraints(&mut cs);
// assert!(output.is_err());
// }