impl compiler error handling

This commit is contained in:
collin 2020-05-08 16:35:00 -07:00
parent dee7b2782e
commit 36018853a7
36 changed files with 2211 additions and 1553 deletions

22
Cargo.lock generated
View File

@ -514,7 +514,6 @@ dependencies = [
name = "leo-compiler"
version = "0.1.0"
dependencies = [
"failure",
"from-pest",
"hex",
"lazy_static",
@ -529,6 +528,7 @@ dependencies = [
"snarkos-errors",
"snarkos-gadgets",
"snarkos-models",
"thiserror",
]
[[package]]
@ -1128,6 +1128,26 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d12a1dae4add0f0d568eebc7bf142f145ba1aa2544cafb195c76f0f409091b60"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f34e0c1caaa462fd840ec6b768946ea1e7842620d94fe29d5b847138f521269"
dependencies = [
"proc-macro2 1.0.9",
"quote 1.0.3",
"syn 1.0.16",
]
[[package]]
name = "thread_local"
version = "1.0.1"

View File

@ -1,7 +1,17 @@
struct Foo {
b: u32
}
function main() {
let a = 1u8 + 1u8;
let c = 1u16 + 1u16;
let b = 1u32 + 1;
let d = 1u64 + 1u64;
let e = 1u128 + 1u128;
let f = true && false;
let g = 5fe + 10fe;
let h: u32[2] = [1, 2];
let i = Foo { b: 5 };
let j = [1, 4, 5];
}

View File

@ -1,4 +1,4 @@
use leo_compiler::{self, ast, errors::CompilerError, ParameterValue, Program};
use leo_compiler::{self, ast, errors::CompilerError, InputValue, Program};
use from_pest::FromPest;
use rand::thread_rng;
@ -20,7 +20,7 @@ use std::{
#[derive(Clone)]
pub struct Benchmark<F: Field + PrimeField> {
program: Program<F>,
parameters: Vec<Option<ParameterValue<F>>>,
parameters: Vec<Option<InputValue<F>>>,
_engine: PhantomData<F>,
}
@ -60,7 +60,7 @@ impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Benchmark<F> {
cs: &mut CS,
) -> Result<(), SynthesisError> {
let _res =
leo_compiler::ConstrainedProgram::generate_constraints(cs, self.program, self.parameters);
leo_compiler::generate_constraints(cs, self.program, self.parameters).unwrap();
println!(" Result: {}", _res);
// Write results to file or something

View File

@ -11,7 +11,7 @@ snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0" }
snarkos-gadgets = { path = "../../snarkOS/gadgets", version = "0.8.0" }
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0" }
failure = { version = "0.1.5" }
thiserror = { version = "1.0" }
from-pest = { version = "0.3.1" }
hex = { version = "0.4.2" }
lazy_static = { version = "1.3.0" }

View File

@ -1,7 +1,10 @@
//! Compiles a Leo program from a file path.
use crate::{
ast, errors::CompilerError, ConstrainedProgram, ConstrainedValue, ParameterValue, Program,
ast,
constraints::{generate_constraints, ConstrainedValue},
errors::CompilerError,
InputValue, Program,
};
use snarkos_errors::gadgets::SynthesisError;
@ -19,7 +22,7 @@ pub struct Compiler<F: Field + PrimeField> {
package_name: String,
main_file_path: PathBuf,
program: Program<F>,
parameters: Vec<Option<ParameterValue<F>>>,
program_inputs: Vec<Option<InputValue<F>>>,
output: Option<ConstrainedValue<F>>,
_engine: PhantomData<F>,
}
@ -30,7 +33,7 @@ impl<F: Field + PrimeField> Compiler<F> {
package_name,
main_file_path,
program: Program::new(),
parameters: vec![],
program_inputs: vec![],
output: None,
_engine: PhantomData,
}
@ -80,7 +83,7 @@ impl<F: Field + PrimeField> Compiler<F> {
let package_name = self.package_name.clone();
self.program = Program::<F>::from(syntax_tree, package_name);
self.parameters = vec![None; self.program.num_parameters];
self.program_inputs = vec![None; self.program.num_parameters];
log::debug!("Compilation complete\n{:#?}", self.program);
@ -93,7 +96,7 @@ impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Compiler<F> {
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {
let _res = ConstrainedProgram::generate_constraints(cs, self.program, self.parameters);
let _res = generate_constraints(cs, self.program, self.program_inputs).unwrap();
// Write results to file or something

View File

@ -2,7 +2,8 @@
use crate::{
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
types::{ParameterModel, ParameterValue, Variable},
errors::BooleanError,
types::{InputModel, InputValue, Variable},
};
use snarkos_errors::gadgets::SynthesisError;
@ -19,27 +20,31 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
parameter_model: InputModel<F>,
parameter_value: Option<InputValue<F>>,
) -> Result<Variable<F>, BooleanError> {
// Check that the parameter value is the correct type
let bool_value = parameter_value.map(|parameter| match parameter {
ParameterValue::Boolean(b) => b,
value => unimplemented!("expected boolean parameter, got {}", value),
});
let bool_value = match parameter_value {
Some(parameter) => {
if let InputValue::Boolean(bool) = parameter {
Some(bool)
} else {
return Err(BooleanError::InvalidBoolean(parameter.to_string()));
}
}
None => None,
};
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let number = if parameter_model.private {
Boolean::alloc(cs.ns(|| name), || {
bool_value.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
})?
} else {
Boolean::alloc_input(cs.ns(|| name), || {
bool_value.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
})?
};
let parameter_variable = new_variable_from_variable(scope, &parameter_model.variable);
@ -50,16 +55,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::Boolean(number),
);
parameter_variable
Ok(parameter_variable)
}
pub(crate) fn boolean_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
_parameter_model: InputModel<F>,
_parameter_value: Option<InputValue<F>>,
) -> Result<Variable<F>, BooleanError> {
unimplemented!("Cannot enforce boolean array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
@ -83,14 +88,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
// parameter_variable
}
pub(crate) fn get_boolean_constant(bool: bool) -> ConstrainedValue<F> {
ConstrainedValue::Boolean(Boolean::Constant(bool))
pub(crate) fn get_boolean_constant(bool: Boolean) -> ConstrainedValue<F> {
ConstrainedValue::Boolean(bool)
}
pub(crate) fn evaluate_not(value: ConstrainedValue<F>) -> ConstrainedValue<F> {
pub(crate) fn evaluate_not(
value: ConstrainedValue<F>,
) -> Result<ConstrainedValue<F>, BooleanError> {
match value {
ConstrainedValue::Boolean(boolean) => ConstrainedValue::Boolean(boolean.not()),
value => unimplemented!("cannot enforce not on non-boolean value {}", value),
ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())),
value => Err(BooleanError::CannotEvaluate(format!("!{}", value))),
}
}
@ -99,16 +106,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, BooleanError> {
match (left, right) {
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => {
ConstrainedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool).unwrap())
}
(left_value, right_value) => unimplemented!(
"cannot enforce or on non-boolean values {} || {}",
left_value,
right_value
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => Ok(
ConstrainedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool)?),
),
(left_value, right_value) => Err(BooleanError::CannotEnforce(format!(
"{} || {}",
left_value, right_value
))),
}
}
@ -117,16 +123,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, BooleanError> {
match (left, right) {
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => {
ConstrainedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool).unwrap())
}
(left_value, right_value) => unimplemented!(
"cannot enforce and on non-boolean values {} && {}",
left_value,
right_value
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => Ok(
ConstrainedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool)?),
),
(left_value, right_value) => Err(BooleanError::CannotEnforce(format!(
"{} && {}",
left_value, right_value
))),
}
}
@ -134,8 +139,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::Boolean(Boolean::Constant(left.eq(&right)))
}
pub(crate) fn enforce_boolean_eq(&mut self, cs: &mut CS, left: Boolean, right: Boolean) {
left.enforce_equal(cs.ns(|| format!("enforce bool equal")), &right)
.unwrap();
pub(crate) fn enforce_boolean_eq(
&mut self,
cs: &mut CS,
left: Boolean,
right: Boolean,
) -> Result<(), BooleanError> {
Ok(left.enforce_equal(cs.ns(|| format!("enforce bool equal")), &right)?)
}
}

View File

@ -5,6 +5,7 @@ use crate::{
new_scope_from_variable, new_variable_from_variable, ConstrainedProgram,
ConstrainedStructMember, ConstrainedValue,
},
errors::ExpressionError,
types::{Expression, RangeOrExpression, SpreadOrExpression, StructMember, Variable},
};
@ -19,19 +20,20 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
scope: String,
unresolved_variable: Variable<F>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
// Evaluate the variable name in the current function scope
let variable_name = new_scope_from_variable(scope, &unresolved_variable);
if self.contains_name(&variable_name) {
// Reassigning variable to another variable
self.get_mut(&variable_name).unwrap().clone()
Ok(self.get_mut(&variable_name).unwrap().clone())
} else if self.contains_variable(&unresolved_variable) {
// Check global scope (function and struct names)
self.get_mut_variable(&unresolved_variable).unwrap().clone()
Ok(self.get_mut_variable(&unresolved_variable).unwrap().clone())
} else {
println!("searched for {}", variable_name);
unimplemented!("variable declaration \"{}\" not found", unresolved_variable)
Err(ExpressionError::UndefinedVariable(
unresolved_variable.to_string(),
))
}
}
@ -41,16 +43,21 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
match (left, right) {
) -> Result<ConstrainedValue<F>, ExpressionError> {
Ok(match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Self::enforce_integer_add(cs, num_1, num_2)
Self::enforce_integer_add(cs, num_1, num_2)?
}
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
self.enforce_field_add(cs, fe_1, fe_2)
self.enforce_field_add(cs, fe_1, fe_2)?
}
(val_1, val_2) => unimplemented!("cannot add {} + {}", val_1, val_2),
}
(val_1, val_2) => {
return Err(ExpressionError::IncompatibleTypes(format!(
"{} + {}",
val_1, val_2,
)))
}
})
}
fn enforce_sub_expression(
@ -58,16 +65,21 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
match (left, right) {
) -> Result<ConstrainedValue<F>, ExpressionError> {
Ok(match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Self::enforce_integer_sub(cs, num_1, num_2)
Self::enforce_integer_sub(cs, num_1, num_2)?
}
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
self.enforce_field_sub(cs, fe_1, fe_2)
self.enforce_field_sub(cs, fe_1, fe_2)?
}
(val_1, val_2) => unimplemented!("cannot subtract {} - {}", val_1, val_2),
}
(val_1, val_2) => {
return Err(ExpressionError::IncompatibleTypes(format!(
"{} - {}",
val_1, val_2,
)))
}
})
}
fn enforce_mul_expression(
@ -75,16 +87,21 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
match (left, right) {
) -> Result<ConstrainedValue<F>, ExpressionError> {
Ok(match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Self::enforce_integer_mul(cs, num_1, num_2)
Self::enforce_integer_mul(cs, num_1, num_2)?
}
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
self.enforce_field_mul(cs, fe_1, fe_2)
self.enforce_field_mul(cs, fe_1, fe_2)?
}
(val_1, val_2) => unimplemented!("cannot multiply {} * {}", val_1, val_2),
}
(val_1, val_2) => {
return Err(ExpressionError::IncompatibleTypes(format!(
"{} * {}",
val_1, val_2,
)))
}
})
}
fn enforce_div_expression(
@ -92,35 +109,45 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
match (left, right) {
) -> Result<ConstrainedValue<F>, ExpressionError> {
Ok(match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Self::enforce_integer_div(cs, num_1, num_2)
Self::enforce_integer_div(cs, num_1, num_2)?
}
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
self.enforce_field_div(cs, fe_1, fe_2)
self.enforce_field_div(cs, fe_1, fe_2)?
}
(val_1, val_2) => unimplemented!("cannot divide {} / {}", val_1, val_2),
}
(val_1, val_2) => {
return Err(ExpressionError::IncompatibleTypes(format!(
"{} / {}",
val_1, val_2,
)))
}
})
}
fn enforce_pow_expression(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
match (left, right) {
) -> Result<ConstrainedValue<F>, ExpressionError> {
Ok(match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Self::enforce_integer_pow(cs, num_1, num_2)
Self::enforce_integer_pow(cs, num_1, num_2)?
}
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::Integer(num_2)) => {
self.enforce_field_pow(cs, fe_1, num_2)
self.enforce_field_pow(cs, fe_1, num_2)?
}
(_, ConstrainedValue::FieldElement(num_2)) => {
unimplemented!("exponent power must be an integer, got field {}", num_2)
return Err(ExpressionError::InvalidExponent(num_2.to_string()))
}
(val_1, val_2) => unimplemented!("cannot enforce exponentiation {} * {}", val_1, val_2),
}
(val_1, val_2) => {
return Err(ExpressionError::IncompatibleTypes(format!(
"{} * {}",
val_1, val_2,
)))
}
})
}
/// Evaluate Boolean operations
@ -128,35 +155,39 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
match (left, right) {
) -> Result<ConstrainedValue<F>, ExpressionError> {
Ok(match (left, right) {
(ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => {
Self::boolean_eq(bool_1, bool_2)
}
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Self::evaluate_integer_eq(num_1, num_2)
Self::evaluate_integer_eq(num_1, num_2)?
}
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_eq(fe_1, fe_2)
// }
(val_1, val_2) => unimplemented!("cannot evaluate {} == {}", val_1, val_2),
}
(val_1, val_2) => {
return Err(ExpressionError::IncompatibleTypes(format!(
"{} == {}",
val_1, val_2,
)))
}
})
}
fn evaluate_geq_expression(
&mut self,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
match (left, right) {
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_geq(fe_1, fe_2)
// }
(val_1, val_2) => unimplemented!(
"cannot evaluate {} >= {}, values must be fields",
val_1,
val_2
),
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
"{} >= {}, values must be fields",
val_1, val_2
))),
}
}
@ -164,16 +195,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
match (left, right) {
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_gt(fe_1, fe_2)
// }
(val_1, val_2) => unimplemented!(
"cannot evaluate {} > {}, values must be fields",
val_1,
val_2
),
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
"{} > {}, values must be fields",
val_1, val_2
))),
}
}
@ -181,16 +211,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
match (left, right) {
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_leq(fe_1, fe_2)
// }
(val_1, val_2) => unimplemented!(
"cannot evaluate {} <= {}, values must be fields",
val_1,
val_2
),
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
"{} <= {}, values must be fields",
val_1, val_2
))),
}
}
@ -198,16 +227,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
match (left, right) {
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
// Self::field_lt(fe_1, fe_2)
// }
(val_1, val_2) => unimplemented!(
"cannot evaluate {} < {}, values must be fields",
val_1,
val_2
),
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
"{} < {}, values must be fields",
val_1, val_2,
))),
}
}
@ -218,37 +246,36 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
file_scope: String,
function_scope: String,
array: Vec<Box<SpreadOrExpression<F>>>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
let mut result = vec![];
array.into_iter().for_each(|element| match *element {
SpreadOrExpression::Spread(spread) => match spread {
Expression::Variable(variable) => {
let array_name = new_scope_from_variable(function_scope.clone(), &variable);
match self.get(&array_name) {
Some(value) => match value {
ConstrainedValue::Array(array) => result.extend(array.clone()),
value => {
unimplemented!("spreads only implemented for arrays, got {}", value)
}
},
None => unimplemented!(
"cannot copy elements from array that does not exist {}",
variable.name
),
for element in array.into_iter() {
match *element {
SpreadOrExpression::Spread(spread) => match spread {
Expression::Variable(variable) => {
let array_name = new_scope_from_variable(function_scope.clone(), &variable);
match self.get(&array_name) {
Some(value) => match value {
ConstrainedValue::Array(array) => result.extend(array.clone()),
value => {
return Err(ExpressionError::InvalidSpread(value.to_string()));
}
},
None => return Err(ExpressionError::UndefinedArray(variable.name)),
}
}
value => return Err(ExpressionError::InvalidSpread(value.to_string())),
},
SpreadOrExpression::Expression(expression) => {
result.push(self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
)?);
}
value => unimplemented!("spreads only implemented for arrays, got {}", value),
},
SpreadOrExpression::Expression(expression) => {
result.push(self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
));
}
});
ConstrainedValue::Array(result)
}
Ok(ConstrainedValue::Array(result))
}
pub(crate) fn enforce_index(
@ -257,10 +284,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
file_scope: String,
function_scope: String,
index: Expression<F>,
) -> usize {
match self.enforce_expression(cs, file_scope, function_scope, index) {
ConstrainedValue::Integer(number) => number.get_value() as usize,
value => unimplemented!("From index must resolve to an integer, got {}", value),
) -> Result<usize, ExpressionError> {
match self.enforce_expression(cs, file_scope, function_scope, index)? {
ConstrainedValue::Integer(number) => Ok(number.to_usize()),
value => Err(ExpressionError::InvalidIndex(value.to_string())),
}
}
@ -271,8 +298,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
array: Box<Expression<F>>,
index: RangeOrExpression<F>,
) -> ConstrainedValue<F> {
match self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *array) {
) -> Result<ConstrainedValue<F>, ExpressionError> {
match self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *array)? {
ConstrainedValue::Array(array) => {
match index {
RangeOrExpression::Range(from, to) => {
@ -284,16 +311,18 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
Some(to_index) => to_index.to_usize(),
None => array.len(), // Array slice ends at array length
};
ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned())
Ok(ConstrainedValue::Array(
array[from_resolved..to_resolved].to_owned(),
))
}
RangeOrExpression::Expression(index) => {
let index_resolved =
self.enforce_index(cs, file_scope, function_scope, index);
array[index_resolved].to_owned()
self.enforce_index(cs, file_scope, function_scope, index)?;
Ok(array[index_resolved].to_owned())
}
}
}
value => unimplemented!("Cannot access element of untyped array {}", value),
value => Err(ExpressionError::InvalidArrayAccess(value.to_string())),
}
}
@ -304,42 +333,42 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
variable: Variable<F>,
members: Vec<StructMember<F>>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
let struct_name = new_variable_from_variable(file_scope.clone(), &variable);
if let Some(resolved_value) = self.get_mut_variable(&struct_name) {
match resolved_value {
ConstrainedValue::StructDefinition(struct_definition) => {
let resolved_members = struct_definition
.fields
.clone()
.iter()
.zip(members.clone().into_iter())
.map(|(field, member)| {
if field.variable != member.variable {
unimplemented!("struct field variables do not match")
}
// Resolve and enforce struct fields
let member_value = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
member.expression,
);
ConstrainedStructMember(member.variable, member_value)
})
.collect();
ConstrainedValue::StructExpression(variable, resolved_members)
if let Some(ConstrainedValue::StructDefinition(struct_definition)) =
self.get_mut_variable(&struct_name)
{
let mut resolved_members = vec![];
for (field, member) in struct_definition
.fields
.clone()
.into_iter()
.zip(members.clone().into_iter())
{
if field.variable != member.variable {
return Err(ExpressionError::InvalidStructField(
field.variable.name,
member.variable.name,
));
}
_ => unimplemented!("Inline struct type is not defined as a struct"),
// Resolve and enforce struct fields
let member_value = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
member.expression,
)?;
resolved_members.push(ConstrainedStructMember(member.variable, member_value))
}
Ok(ConstrainedValue::StructExpression(
variable,
resolved_members,
))
} else {
unimplemented!(
"Struct {} must be declared before it is used in an inline expression",
struct_name
)
Err(ExpressionError::UndefinedStruct(variable.to_string()))
}
}
@ -350,16 +379,18 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
struct_variable: Box<Expression<F>>,
struct_member: Variable<F>,
) -> ConstrainedValue<F> {
match self.enforce_expression(cs, file_scope, function_scope, *struct_variable) {
) -> Result<ConstrainedValue<F>, ExpressionError> {
match self.enforce_expression(cs, file_scope, function_scope, *struct_variable)? {
ConstrainedValue::StructExpression(_name, members) => {
let matched_member = members.into_iter().find(|member| member.0 == struct_member);
match matched_member {
Some(member) => member.1,
None => unimplemented!("Cannot access struct member {}", struct_member.name),
Some(member) => Ok(member.1),
None => Err(ExpressionError::UndefinedStructField(
struct_member.to_string(),
)),
}
}
value => unimplemented!("Cannot access element of untyped struct {}", value),
value => Err(ExpressionError::InvalidStructAccess(value.to_string())),
}
}
@ -370,31 +401,23 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
function: Variable<F>,
arguments: Vec<Expression<F>>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
let function_name = new_variable_from_variable(file_scope.clone(), &function);
match self.get_mut_variable(&function_name) {
Some(value) => match value.clone() {
ConstrainedValue::Function(function) => {
// this function call is inline so we unwrap the return value
match self.enforce_function(cs, file_scope, function_scope, function, arguments)
{
ConstrainedValue::Return(return_values) => {
if return_values.len() == 1 {
return_values[0].clone()
} else {
ConstrainedValue::Return(return_values)
}
}
value => unimplemented!(
"function {} has no return value {}",
function_name,
value
),
}
let function_call = match self.get(&function_name.to_string()) {
Some(ConstrainedValue::Function(function)) => function.clone(),
_ => return Err(ExpressionError::UndefinedFunction(function.to_string())),
};
match self.enforce_function(cs, file_scope, function_scope, function_call, arguments) {
Ok(ConstrainedValue::Return(return_values)) => {
if return_values.len() == 1 {
Ok(return_values[0].clone())
} else {
Ok(ConstrainedValue::Return(return_values))
}
value => unimplemented!("Cannot make function call to {}", value),
},
None => unimplemented!("Cannot call unknown function {}", function_name),
}
Ok(_) => Err(ExpressionError::FunctionDidNotReturn(function.to_string())),
Err(error) => Err(ExpressionError::from(Box::new(error))),
}
}
@ -404,7 +427,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
file_scope: String,
function_scope: String,
expression: Expression<F>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, ExpressionError> {
match expression {
// Variables
Expression::Variable(unresolved_variable) => {
@ -412,114 +435,162 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
}
// Values
Expression::Integer(integer) => Self::get_integer_constant(integer),
Expression::FieldElement(fe) => Self::get_field_element_constant(fe),
Expression::Boolean(bool) => Self::get_boolean_constant(bool),
Expression::Integer(integer) => Ok(Self::get_integer_constant(integer)),
Expression::FieldElement(fe) => Ok(Self::get_field_element_constant(fe)),
Expression::Boolean(bool) => Ok(Self::get_boolean_constant(bool)),
// Binary operations
Expression::Add(left, right) => {
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*right,
)?;
self.enforce_pow_expression(cs, resolved_left, resolved_right)
}
// Boolean operations
Expression::Not(expression) => Self::evaluate_not(self.enforce_expression(
Expression::Not(expression) => Ok(Self::evaluate_not(self.enforce_expression(
cs,
file_scope,
function_scope,
*expression,
)),
)?)?),
Expression::Or(left, right) => {
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*right,
)?;
self.enforce_or(cs, resolved_left, resolved_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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*right,
)?;
self.enforce_and(cs, resolved_left, resolved_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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*right,
)?;
self.evaluate_eq_expression(resolved_left, resolved_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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*right,
)?;
self.evaluate_geq_expression(resolved_left, resolved_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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*right,
)?;
self.evaluate_gt_expression(resolved_left, resolved_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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*right,
)?;
self.evaluate_leq_expression(resolved_left, resolved_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(), *left);
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *left)?;
let resolved_right = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
*right,
)?;
self.evaluate_lt_expression(resolved_left, resolved_right)
Ok(self.evaluate_lt_expression(resolved_left, resolved_right)?)
}
// Conditionals
@ -529,9 +600,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
file_scope.clone(),
function_scope.clone(),
*first,
) {
)? {
ConstrainedValue::Boolean(resolved) => resolved,
_ => unimplemented!("if else conditional must resolve to boolean"),
value => return Err(ExpressionError::IfElseConditional(value.to_string())),
};
if resolved_first.eq(&Boolean::Constant(true)) {
@ -569,7 +640,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope,
function,
arguments,
), // _ => unimplemented!(),
),
}
}
}

View File

@ -1,9 +1,9 @@
//! Methods to enforce constraints on field elements in a resolved Leo program.
use crate::{
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue, FieldElement},
types::{ParameterModel, ParameterValue, Variable},
ConstrainedInteger,
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
errors::FieldElementError,
types::{FieldElement, InputModel, InputValue, Integer, Variable},
};
use snarkos_errors::gadgets::SynthesisError;
@ -17,14 +17,20 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
parameter_model: InputModel<F>,
parameter_value: Option<InputValue<F>>,
) -> Result<Variable<F>, FieldElementError> {
// Check that the parameter value is the correct type
let field_option = parameter_value.map(|parameter| match parameter {
ParameterValue::Field(f) => f,
value => unimplemented!("expected field parameter, got {}", value),
});
let field_option = match parameter_value {
Some(parameter) => {
if let InputValue::Field(fe) = parameter {
Some(fe)
} else {
return Err(FieldElementError::InvalidField(parameter.to_string()));
}
}
None => None,
};
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
@ -32,14 +38,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs.alloc(
|| name,
|| field_option.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap()
)?
} else {
cs.alloc_input(
|| name,
|| field_option.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap()
)?
};
let parameter_variable = new_variable_from_variable(scope, &parameter_model.variable);
@ -50,16 +54,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::FieldElement(FieldElement::Allocated(field_option, field_value)),
);
parameter_variable
Ok(parameter_variable)
}
pub(crate) fn field_element_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
_parameter_model: InputModel<F>,
_parameter_value: Option<InputValue<F>>,
) -> Result<Variable<F>, FieldElementError> {
unimplemented!("Cannot enforce field element array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
@ -81,8 +85,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
// parameter_variable
}
pub(crate) fn get_field_element_constant(fe: F) -> ConstrainedValue<F> {
ConstrainedValue::FieldElement(FieldElement::Constant(fe))
pub(crate) fn get_field_element_constant(fe: FieldElement<F>) -> ConstrainedValue<F> {
ConstrainedValue::FieldElement(fe)
}
// pub(crate) fn field_eq(fe1: F, fe2: F) -> ResolvedValue<F> {
@ -154,8 +158,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
fe_1: FieldElement<F>,
fe_2: FieldElement<F>,
) -> ConstrainedValue<F> {
match (fe_1, fe_2) {
) -> Result<ConstrainedValue<F>, FieldElementError> {
Ok(match (fe_1, fe_2) {
// if both constants, then return a constant result
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
ConstrainedValue::FieldElement(FieldElement::Constant(
@ -168,12 +172,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
FieldElement::Constant(fe_2_constant),
) => {
let sum_value: Option<F> = fe_1_value.map(|v| v.add(&fe_2_constant));
let sum_variable: R1CSVariable = cs
.alloc(
|| "field addition",
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let sum_variable: R1CSVariable = cs.alloc(
|| "field addition",
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "sum = 1 * (fe_1 + fe2)",
@ -189,12 +191,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
FieldElement::Allocated(fe_2_value, fe_2_variable),
) => {
let sum_value: Option<F> = fe_2_value.map(|v| fe_1_constant.add(&v));
let sum_variable: R1CSVariable = cs
.alloc(
|| "field addition",
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let sum_variable: R1CSVariable = cs.alloc(
|| "field addition",
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "sum = 1 * (fe_1 + fe_2)",
@ -213,12 +213,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.add(&fe_2_value)),
(_, _) => None,
};
let sum_variable: R1CSVariable = cs
.alloc(
|| "field addition",
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let sum_variable: R1CSVariable = cs.alloc(
|| "field addition",
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "sum = 1 * (fe_1 + fe_2)",
@ -229,7 +227,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
}
}
})
}
pub(crate) fn enforce_field_sub(
@ -237,8 +235,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
fe_1: FieldElement<F>,
fe_2: FieldElement<F>,
) -> ConstrainedValue<F> {
match (fe_1, fe_2) {
) -> Result<ConstrainedValue<F>, FieldElementError> {
Ok(match (fe_1, fe_2) {
// if both constants, then return a constant result
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
ConstrainedValue::FieldElement(FieldElement::Constant(
@ -251,12 +249,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
FieldElement::Constant(fe_2_constant),
) => {
let sub_value: Option<F> = fe_1_value.map(|v| v.sub(&fe_2_constant));
let sub_variable: R1CSVariable = cs
.alloc(
|| "field subtraction",
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let sub_variable: R1CSVariable = cs.alloc(
|| "field subtraction",
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "sub = 1 * (fe_1 - fe2)",
@ -272,12 +268,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
FieldElement::Allocated(fe_2_value, fe_2_variable),
) => {
let sub_value: Option<F> = fe_2_value.map(|v| fe_1_constant.sub(&v));
let sub_variable: R1CSVariable = cs
.alloc(
|| "field subtraction",
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let sub_variable: R1CSVariable = cs.alloc(
|| "field subtraction",
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "sub = 1 * (fe_1 - fe_2)",
@ -296,12 +290,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.sub(&fe_2_value)),
(_, _) => None,
};
let sub_variable: R1CSVariable = cs
.alloc(
|| "field subtraction",
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let sub_variable: R1CSVariable = cs.alloc(
|| "field subtraction",
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "sub = 1 * (fe_1 - fe_2)",
@ -312,7 +304,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
}
}
})
}
pub(crate) fn enforce_field_mul(
@ -320,8 +312,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
fe_1: FieldElement<F>,
fe_2: FieldElement<F>,
) -> ConstrainedValue<F> {
match (fe_1, fe_2) {
) -> Result<ConstrainedValue<F>, FieldElementError> {
Ok(match (fe_1, fe_2) {
// if both constants, then return a constant result
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
ConstrainedValue::FieldElement(FieldElement::Constant(
@ -334,12 +326,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
FieldElement::Constant(fe_2_constant),
) => {
let mul_value: Option<F> = fe_1_value.map(|v| v.mul(&fe_2_constant));
let mul_variable: R1CSVariable = cs
.alloc(
|| "field multiplication",
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let mul_variable: R1CSVariable = cs.alloc(
|| "field multiplication",
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "mul = fe_1 * fe_2",
@ -355,12 +345,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
FieldElement::Allocated(fe_2_value, fe_2_variable),
) => {
let mul_value: Option<F> = fe_2_value.map(|v| fe_1_constant.mul(&v));
let mul_variable: R1CSVariable = cs
.alloc(
|| "field multiplication",
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let mul_variable: R1CSVariable = cs.alloc(
|| "field multiplication",
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "mul = fe_1 * fe_2",
@ -379,12 +367,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.mul(&fe_2_value)),
(_, _) => None,
};
let mul_variable: R1CSVariable = cs
.alloc(
|| "field multiplication",
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let mul_variable: R1CSVariable = cs.alloc(
|| "field multiplication",
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "mul = fe_1 * fe_2",
@ -395,7 +381,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
}
}
})
}
pub(crate) fn enforce_field_div(
@ -403,8 +389,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
fe_1: FieldElement<F>,
fe_2: FieldElement<F>,
) -> ConstrainedValue<F> {
match (fe_1, fe_2) {
) -> Result<ConstrainedValue<F>, FieldElementError> {
Ok(match (fe_1, fe_2) {
// if both constants, then return a constant result
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
ConstrainedValue::FieldElement(FieldElement::Constant(
@ -417,12 +403,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
FieldElement::Constant(fe_2_constant),
) => {
let div_value: Option<F> = fe_1_value.map(|v| v.div(&fe_2_constant));
let div_variable: R1CSVariable = cs
.alloc(
|| "field division",
|| div_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let div_variable: R1CSVariable = cs.alloc(
|| "field division",
|| div_value.ok_or(SynthesisError::AssignmentMissing),
)?;
let fe_2_inverse_value = fe_2_constant.inverse().unwrap();
cs.enforce(
@ -439,19 +423,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
FieldElement::Allocated(fe_2_value, _fe_2_variable),
) => {
let div_value: Option<F> = fe_2_value.map(|v| fe_1_constant.div(&v));
let div_variable: R1CSVariable = cs
.alloc(
|| "field division",
|| div_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let div_variable: R1CSVariable = cs.alloc(
|| "field division",
|| div_value.ok_or(SynthesisError::AssignmentMissing),
)?;
let fe_2_inverse_value = fe_2_value.map(|v| v.inverse().unwrap());
let fe_2_inverse_variable = cs
.alloc(
|| "field inverse",
|| fe_2_inverse_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let fe_2_inverse_variable = cs.alloc(
|| "field inverse",
|| fe_2_inverse_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "div = fe_1 * fe_2^-1",
@ -470,19 +450,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.div(&fe_2_value)),
(_, _) => None,
};
let div_variable: R1CSVariable = cs
.alloc(
|| "field division",
|| div_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let div_variable: R1CSVariable = cs.alloc(
|| "field division",
|| div_value.ok_or(SynthesisError::AssignmentMissing),
)?;
let fe_2_inverse_value = fe_2_value.map(|v| v.inverse().unwrap());
let fe_2_inverse_variable = cs
.alloc(
|| "field inverse",
|| fe_2_inverse_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let fe_2_inverse_variable = cs.alloc(
|| "field inverse",
|| fe_2_inverse_value.ok_or(SynthesisError::AssignmentMissing),
)?;
cs.enforce(
|| "div = fe_1 * fe_2^-1",
@ -493,29 +469,27 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
}
}
})
}
pub(crate) fn enforce_field_pow(
&mut self,
cs: &mut CS,
fe_1: FieldElement<F>,
num: ConstrainedInteger,
) -> ConstrainedValue<F> {
match fe_1 {
num: Integer,
) -> Result<ConstrainedValue<F>, FieldElementError> {
Ok(match fe_1 {
// if both constants, then return a constant result
FieldElement::Constant(fe_1_constant) => ConstrainedValue::FieldElement(
FieldElement::Constant(fe_1_constant.pow(&[num.get_value() as u64])),
FieldElement::Constant(fe_1_constant.pow(&[num.to_usize() as u64])),
),
// else, return an allocated result
FieldElement::Allocated(fe_1_value, _fe_1_variable) => {
let pow_value: Option<F> = fe_1_value.map(|v| v.pow(&[num.get_value() as u64]));
let pow_variable: R1CSVariable = cs
.alloc(
|| "field exponentiation",
|| pow_value.ok_or(SynthesisError::AssignmentMissing),
)
.unwrap();
let pow_value: Option<F> = fe_1_value.map(|v| v.pow(&[num.to_usize() as u64]));
let pow_variable: R1CSVariable = cs.alloc(
|| "field exponentiation",
|| pow_value.ok_or(SynthesisError::AssignmentMissing),
)?;
// cs.enforce( //todo: find a linear combination for this
// || "pow = 1 + fe_1^num",
@ -525,6 +499,6 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::FieldElement(FieldElement::Allocated(pow_value, pow_variable))
}
}
})
}
}

View File

@ -0,0 +1,260 @@
//! Methods to enforce functions with arguments in
//! a resolved Leo program.
use crate::{
constraints::{
new_scope, new_scope_from_variable, new_variable_from_variables, ConstrainedProgram,
ConstrainedValue,
},
errors::{FunctionError, ImportError},
types::{Expression, Function, InputValue, Program, Type},
};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
fn check_inputs_length(expected: usize, actual: usize) -> Result<(), FunctionError> {
// Make sure we are given the correct number of arguments
if expected != actual {
Err(FunctionError::InputsLength(expected, actual))
} else {
Ok(())
}
}
fn enforce_input(
&mut self,
cs: &mut CS,
scope: String,
caller_scope: String,
function_name: String,
input: Expression<F>,
) -> Result<ConstrainedValue<F>, FunctionError> {
match input {
Expression::Variable(variable) => Ok(self.enforce_variable(caller_scope, variable)?),
expression => Ok(self.enforce_expression(cs, scope, function_name, expression)?),
}
}
pub(crate) fn enforce_function(
&mut self,
cs: &mut CS,
scope: String,
caller_scope: String,
function: Function<F>,
inputs: Vec<Expression<F>>,
) -> Result<ConstrainedValue<F>, FunctionError> {
let function_name = new_scope(scope.clone(), function.get_name());
// Make sure we are given the correct number of arguments
Self::check_inputs_length(function.inputs.len(), inputs.len())?;
// Store argument values as new variables in resolved program
for (input_model, input_expression) in
function.inputs.clone().iter().zip(inputs.into_iter())
{
// Check that argument is correct type
match input_model._type.clone() {
Type::IntegerType(integer_type) => {
match self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
input_expression,
)? {
ConstrainedValue::Integer(number) => {
number.expect_type(&integer_type)?;
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function_name.clone(),
&input_model.variable,
);
self.store(variable_name, ConstrainedValue::Integer(number));
}
argument => {
return Err(FunctionError::InvalidInput(
integer_type.to_string(),
argument.to_string(),
))
}
}
}
Type::FieldElement => {
match self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
input_expression,
)? {
ConstrainedValue::FieldElement(fe) => {
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function_name.clone(),
&input_model.variable,
);
self.store(variable_name, ConstrainedValue::FieldElement(fe));
}
argument => {
return Err(FunctionError::InvalidInput(
Type::<F>::FieldElement.to_string(),
argument.to_string(),
))
}
}
}
Type::Boolean => {
match self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
input_expression,
)? {
ConstrainedValue::Boolean(bool) => {
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function_name.clone(),
&input_model.variable,
);
self.store(variable_name, ConstrainedValue::Boolean(bool));
}
argument => {
return Err(FunctionError::InvalidInput(
Type::<F>::Boolean.to_string(),
argument.to_string(),
))
}
}
}
ty => return Err(FunctionError::UndefinedInput(ty.to_string())),
}
}
// Evaluate function statements
let mut return_values = ConstrainedValue::Return(vec![]);
for statement in function.statements.iter() {
if let Some(returned) = self.enforce_statement(
cs,
scope.clone(),
function_name.clone(),
statement.clone(),
function.returns.clone(),
)? {
return_values = returned;
break;
}
}
Ok(return_values)
}
pub(crate) fn enforce_main_function(
&mut self,
cs: &mut CS,
scope: String,
function: Function<F>,
inputs: Vec<Option<InputValue<F>>>,
) -> Result<ConstrainedValue<F>, FunctionError> {
let function_name = new_scope(scope.clone(), function.get_name());
// Make sure we are given the correct number of arguments
Self::check_inputs_length(function.inputs.len(), inputs.len())?;
// Iterate over main function inputs and allocate new passed-by variable values
let mut input_variables = vec![];
for (input_model, input_value) in
function.inputs.clone().into_iter().zip(inputs.into_iter())
{
// append each variable to inputs vector
let variable = match input_model._type {
Type::IntegerType(ref _integer_type) => self.integer_from_parameter(
cs,
function_name.clone(),
input_model,
input_value,
)?,
Type::FieldElement => self.field_element_from_parameter(
cs,
function_name.clone(),
input_model,
input_value,
)?,
Type::Boolean => {
self.bool_from_parameter(cs, function_name.clone(), input_model, input_value)?
}
Type::Array(ref ty, _length) => match *ty.clone() {
Type::IntegerType(_type) => self.integer_array_from_parameter(
cs,
function_name.clone(),
input_model,
input_value,
)?,
Type::FieldElement => self.field_element_array_from_parameter(
cs,
function_name.clone(),
input_model,
input_value,
)?,
Type::Boolean => self.boolean_array_from_parameter(
cs,
function_name.clone(),
input_model,
input_value,
)?,
_type => return Err(FunctionError::UndefinedInput(_type.to_string())),
},
_type => return Err(FunctionError::UndefinedInput(_type.to_string())),
};
input_variables.push(Expression::Variable(variable));
}
self.enforce_function(cs, scope, function_name, function, input_variables)
}
pub(crate) fn resolve_definitions(
&mut self,
cs: &mut CS,
program: Program<F>,
) -> Result<(), ImportError> {
let program_name = program.name.clone();
// evaluate and store all imports
program
.imports
.into_iter()
.map(|import| self.enforce_import(cs, program_name.name.clone(), import))
.collect::<Result<Vec<_>, ImportError>>()?;
// evaluate and store all struct definitions
program
.structs
.into_iter()
.for_each(|(variable, struct_def)| {
let resolved_struct_name =
new_variable_from_variables(&program_name.clone(), &variable);
self.store_variable(
resolved_struct_name,
ConstrainedValue::StructDefinition(struct_def),
);
});
// evaluate and store all function definitions
program
.functions
.into_iter()
.for_each(|(function_name, function)| {
let resolved_function_name = new_scope(program_name.name.clone(), function_name.0);
self.store(resolved_function_name, ConstrainedValue::Function(function));
});
Ok(())
}
}

View File

@ -0,0 +1,113 @@
use crate::{
ast,
constraints::{new_variable_from_variables, ConstrainedProgram, ConstrainedValue},
errors::constraints::ImportError,
types::Program,
Import,
};
use from_pest::FromPest;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
use std::fs;
use std::path::Path;
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
pub fn enforce_import(
&mut self,
cs: &mut CS,
scope: String,
import: Import<F>,
) -> Result<(), ImportError> {
// Resolve program file path
let unparsed_file = fs::read_to_string(Path::new(&import.path_string_full()))
.map_err(|_| ImportError::FileReadError(import.path_string_full()))?;
let mut file = ast::parse(&unparsed_file).map_err(|_| ImportError::FileParsingError)?;
// generate ast from file
let syntax_tree =
ast::File::from_pest(&mut file).map_err(|_| ImportError::SyntaxTreeError)?;
// generate aleo program from file
let mut program = Program::from(syntax_tree, import.path_string.clone());
// Use same namespace as calling function for imported symbols
program = program.name(scope);
// * -> import all imports, structs, functions in the current scope
if import.is_star() {
// recursively evaluate program statements
self.resolve_definitions(cs, program).unwrap();
Ok(())
} else {
let program_name = program.name.clone();
// match each import symbol to a symbol in the imported file
import.symbols.into_iter().for_each(|symbol| {
// see if the imported symbol is a struct
let matched_struct = program
.structs
.clone()
.into_iter()
.find(|(struct_name, _struct_def)| symbol.symbol == *struct_name);
match matched_struct {
Some((_struct_name, struct_def)) => {
// take the alias if it is present
let resolved_name = symbol.alias.unwrap_or(symbol.symbol);
let resolved_struct_name =
new_variable_from_variables(&program_name.clone(), &resolved_name);
// store imported struct under resolved name
self.store_variable(
resolved_struct_name,
ConstrainedValue::StructDefinition(struct_def),
);
}
None => {
// see if the imported symbol is a function
let matched_function = program.functions.clone().into_iter().find(
|(function_name, _function)| symbol.symbol.name == *function_name.0,
);
match matched_function {
Some((_function_name, function)) => {
// take the alias if it is present
let resolved_name = symbol.alias.unwrap_or(symbol.symbol);
let resolved_function_name = new_variable_from_variables(
&program_name.clone(),
&resolved_name,
);
// store imported function under resolved name
self.store_variable(
resolved_function_name,
ConstrainedValue::Function(function),
)
}
None => unimplemented!(
"cannot find imported symbol {} in imported file {}",
symbol,
program_name.clone()
),
}
}
}
});
// evaluate all import statements in imported file
program
.imports
.into_iter()
.map(|nested_import| {
self.enforce_import(cs, program_name.name.clone(), nested_import)
})
.collect::<Result<Vec<_>, ImportError>>()?;
Ok(())
}
}
}

View File

@ -2,142 +2,76 @@
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
types::{Integer, ParameterModel, ParameterValue, Type, Variable},
errors::IntegerError,
types::{InputModel, InputValue, Integer, Type, Variable},
IntegerType,
};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
uint8::UInt8,
},
},
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
};
use std::fmt;
#[derive(Clone, PartialEq, Eq)]
pub enum ConstrainedInteger {
U8(UInt8),
U16(UInt16),
U32(UInt32),
U64(UInt64),
U128(UInt128),
}
impl ConstrainedInteger {
pub(crate) fn get_value(&self) -> usize {
match self {
ConstrainedInteger::U8(u8) => u8.value.unwrap() as usize,
ConstrainedInteger::U16(u16) => u16.value.unwrap() as usize,
ConstrainedInteger::U32(u32) => u32.value.unwrap() as usize,
ConstrainedInteger::U64(u64) => u64.value.unwrap() as usize,
ConstrainedInteger::U128(u128) => u128.value.unwrap() as usize,
}
}
pub(crate) fn get_type(&self) -> IntegerType {
match self {
ConstrainedInteger::U8(u8) => IntegerType::U8,
ConstrainedInteger::U16(u16) => IntegerType::U16,
ConstrainedInteger::U32(u32) => IntegerType::U32,
ConstrainedInteger::U64(u64) => IntegerType::U64,
ConstrainedInteger::U128(u128) => IntegerType::U128,
}
}
pub(crate) fn expect_type(&self, integer_type: &IntegerType) {
match (self, integer_type) {
(ConstrainedInteger::U8(_u8), IntegerType::U8) => {}
(ConstrainedInteger::U16(_u16), IntegerType::U16) => {}
(ConstrainedInteger::U32(_u32), IntegerType::U32) => {}
(ConstrainedInteger::U64(_u64), IntegerType::U64) => {}
(ConstrainedInteger::U128(_u128), IntegerType::U128) => {}
(actual, expected) => {
unimplemented!("expected integer type {}, got {}", expected, actual)
}
}
}
}
impl fmt::Display for ConstrainedInteger {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ConstrainedInteger::U8(u8) => write!(f, "{}u8", u8.value.unwrap()),
ConstrainedInteger::U16(u16) => write!(f, "{}u16", u16.value.unwrap()),
ConstrainedInteger::U32(u32) => write!(f, "{}u32", u32.value.unwrap()),
ConstrainedInteger::U64(u64) => write!(f, "{}u64", u64.value.unwrap()),
ConstrainedInteger::U128(u128) => write!(f, "{}u128", u128.value.unwrap()),
}
}
}
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
pub(crate) fn get_integer_constant(integer: Integer) -> ConstrainedValue<F> {
ConstrainedValue::Integer(match integer {
Integer::U8(u8_value) => ConstrainedInteger::U8(UInt8::constant(u8_value)),
Integer::U16(u16_value) => ConstrainedInteger::U16(UInt16::constant(u16_value)),
Integer::U32(u32_value) => ConstrainedInteger::U32(UInt32::constant(u32_value)),
Integer::U64(u64_value) => ConstrainedInteger::U64(UInt64::constant(u64_value)),
Integer::U128(u128_value) => ConstrainedInteger::U128(UInt128::constant(u128_value)),
})
ConstrainedValue::Integer(integer)
}
pub(crate) fn evaluate_integer_eq(
left: ConstrainedInteger,
right: ConstrainedInteger,
) -> ConstrainedValue<F> {
ConstrainedValue::Boolean(Boolean::Constant(match (left, right) {
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
left_u8.eq(&right_u8)
}
(ConstrainedInteger::U16(left_u16), ConstrainedInteger::U16(right_u16)) => {
left_u16.eq(&right_u16)
}
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
left_u32.eq(&right_u32)
}
(ConstrainedInteger::U64(left_u64), ConstrainedInteger::U64(right_u64)) => {
left_u64.eq(&right_u64)
}
(ConstrainedInteger::U128(left_u128), ConstrainedInteger::U128(right_u128)) => {
left_u128.eq(&right_u128)
}
(left, right) => unimplemented!(
"cannot evaluate integer equality between {} == {}",
left,
right
),
}))
left: Integer,
right: Integer,
) -> Result<ConstrainedValue<F>, IntegerError> {
Ok(ConstrainedValue::Boolean(Boolean::Constant(
match (left, right) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => left_u8.eq(&right_u8),
(Integer::U16(left_u16), Integer::U16(right_u16)) => left_u16.eq(&right_u16),
(Integer::U32(left_u32), Integer::U32(right_u32)) => left_u32.eq(&right_u32),
(Integer::U64(left_u64), Integer::U64(right_u64)) => left_u64.eq(&right_u64),
(Integer::U128(left_u128), Integer::U128(right_u128)) => left_u128.eq(&right_u128),
(left, right) => {
return Err(IntegerError::CannotEvaluate(format!(
"{} == {}",
left, right
)))
}
},
)))
}
pub(crate) fn integer_from_parameter(
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
parameter_model: InputModel<F>,
parameter_value: Option<InputValue<F>>,
) -> Result<Variable<F>, IntegerError> {
let integer_type = match &parameter_model._type {
Type::IntegerType(integer_type) => integer_type,
_type => unimplemented!("expected integer parameter, got {}", _type),
_type => return Err(IntegerError::InvalidType(_type.to_string())),
};
// Check that the parameter value is the correct type
let integer_option = match parameter_value {
Some(parameter) => {
if let InputValue::Integer(integer) = parameter {
Some(integer)
} else {
return Err(IntegerError::InvalidInteger(
parameter_model._type.to_string(),
parameter.to_string(),
));
}
}
None => None,
};
match integer_type {
IntegerType::U8 => self.u8_from_parameter(cs, scope, parameter_model, parameter_value),
IntegerType::U16 => {
self.u16_from_parameter(cs, scope, parameter_model, parameter_value)
}
IntegerType::U32 => {
self.u32_from_parameter(cs, scope, parameter_model, parameter_value)
}
IntegerType::U64 => {
self.u64_from_parameter(cs, scope, parameter_model, parameter_value)
}
IntegerType::U8 => self.u8_from_parameter(cs, scope, parameter_model, integer_option),
IntegerType::U16 => self.u16_from_parameter(cs, scope, parameter_model, integer_option),
IntegerType::U32 => self.u32_from_parameter(cs, scope, parameter_model, integer_option),
IntegerType::U64 => self.u64_from_parameter(cs, scope, parameter_model, integer_option),
IntegerType::U128 => {
self.u128_from_parameter(cs, scope, parameter_model, parameter_value)
self.u128_from_parameter(cs, scope, parameter_model, integer_option)
}
}
}
@ -146,9 +80,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
_parameter_model: InputModel<F>,
_parameter_value: Option<InputValue<F>>,
) -> Result<Variable<F>, IntegerError> {
unimplemented!("Cannot enforce integer array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
@ -174,171 +108,165 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
pub(crate) fn enforce_integer_eq(
cs: &mut CS,
left: ConstrainedInteger,
right: ConstrainedInteger,
) {
left: Integer,
right: Integer,
) -> Result<(), IntegerError> {
match (left, right) {
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
Self::enforce_u8_eq(cs, left_u8, right_u8)
}
(ConstrainedInteger::U16(left_u16), ConstrainedInteger::U16(right_u16)) => {
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
Self::enforce_u16_eq(cs, left_u16, right_u16)
}
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
Self::enforce_u32_eq(cs, left_u32, right_u32)
}
(ConstrainedInteger::U64(left_u64), ConstrainedInteger::U64(right_u64)) => {
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
Self::enforce_u64_eq(cs, left_u64, right_u64)
}
(ConstrainedInteger::U128(left_u128), ConstrainedInteger::U128(right_u128)) => {
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
Self::enforce_u128_eq(cs, left_u128, right_u128)
}
(left, right) => unimplemented!(
"cannot enforce integer equality between {} == {}",
left,
right
),
(left, right) => {
return Err(IntegerError::CannotEnforce(format!(
"{} == {}",
left, right
)))
}
}
}
pub(crate) fn enforce_integer_add(
cs: &mut CS,
left: ConstrainedInteger,
right: ConstrainedInteger,
) -> ConstrainedValue<F> {
ConstrainedValue::Integer(match (left, right) {
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
ConstrainedInteger::U8(Self::enforce_u8_add(cs, left_u8, right_u8))
left: Integer,
right: Integer,
) -> Result<ConstrainedValue<F>, IntegerError> {
Ok(ConstrainedValue::Integer(match (left, right) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
Integer::U8(Self::enforce_u8_add(cs, left_u8, right_u8)?)
}
(ConstrainedInteger::U16(left_u16), ConstrainedInteger::U16(right_u16)) => {
ConstrainedInteger::U16(Self::enforce_u16_add(cs, left_u16, right_u16))
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
Integer::U16(Self::enforce_u16_add(cs, left_u16, right_u16)?)
}
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
ConstrainedInteger::U32(Self::enforce_u32_add(cs, left_u32, right_u32))
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
Integer::U32(Self::enforce_u32_add(cs, left_u32, right_u32)?)
}
(ConstrainedInteger::U64(left_u64), ConstrainedInteger::U64(right_u64)) => {
ConstrainedInteger::U64(Self::enforce_u64_add(cs, left_u64, right_u64))
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
Integer::U64(Self::enforce_u64_add(cs, left_u64, right_u64)?)
}
(ConstrainedInteger::U128(left_u128), ConstrainedInteger::U128(right_u128)) => {
ConstrainedInteger::U128(Self::enforce_u128_add(cs, left_u128, right_u128))
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
Integer::U128(Self::enforce_u128_add(cs, left_u128, right_u128)?)
}
(left, right) => unimplemented!(
"cannot enforce integer addition between {} + {}",
left,
right
),
})
(left, right) => {
return Err(IntegerError::CannotEnforce(format!("{} + {}", left, right)))
}
}))
}
pub(crate) fn enforce_integer_sub(
cs: &mut CS,
left: ConstrainedInteger,
right: ConstrainedInteger,
) -> ConstrainedValue<F> {
ConstrainedValue::Integer(match (left, right) {
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
ConstrainedInteger::U8(Self::enforce_u8_sub(cs, left_u8, right_u8))
left: Integer,
right: Integer,
) -> Result<ConstrainedValue<F>, IntegerError> {
Ok(ConstrainedValue::Integer(match (left, right) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
Integer::U8(Self::enforce_u8_sub(cs, left_u8, right_u8)?)
}
(ConstrainedInteger::U16(left_u16), ConstrainedInteger::U16(right_u16)) => {
ConstrainedInteger::U16(Self::enforce_u16_sub(cs, left_u16, right_u16))
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
Integer::U16(Self::enforce_u16_sub(cs, left_u16, right_u16)?)
}
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
ConstrainedInteger::U32(Self::enforce_u32_sub(cs, left_u32, right_u32))
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
Integer::U32(Self::enforce_u32_sub(cs, left_u32, right_u32)?)
}
(ConstrainedInteger::U64(left_u64), ConstrainedInteger::U64(right_u64)) => {
ConstrainedInteger::U64(Self::enforce_u64_sub(cs, left_u64, right_u64))
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
Integer::U64(Self::enforce_u64_sub(cs, left_u64, right_u64)?)
}
(ConstrainedInteger::U128(left_u128), ConstrainedInteger::U128(right_u128)) => {
ConstrainedInteger::U128(Self::enforce_u128_sub(cs, left_u128, right_u128))
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
Integer::U128(Self::enforce_u128_sub(cs, left_u128, right_u128)?)
}
(left, right) => unimplemented!(
"cannot enforce integer subtraction between {} - {}",
left,
right
),
})
(left, right) => {
return Err(IntegerError::CannotEnforce(format!("{} - {}", left, right)))
}
}))
}
pub(crate) fn enforce_integer_mul(
cs: &mut CS,
left: ConstrainedInteger,
right: ConstrainedInteger,
) -> ConstrainedValue<F> {
ConstrainedValue::Integer(match (left, right) {
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
ConstrainedInteger::U8(Self::enforce_u8_mul(cs, left_u8, right_u8))
left: Integer,
right: Integer,
) -> Result<ConstrainedValue<F>, IntegerError> {
Ok(ConstrainedValue::Integer(match (left, right) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
Integer::U8(Self::enforce_u8_mul(cs, left_u8, right_u8)?)
}
(ConstrainedInteger::U16(left_u16), ConstrainedInteger::U16(right_u16)) => {
ConstrainedInteger::U16(Self::enforce_u16_mul(cs, left_u16, right_u16))
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
Integer::U16(Self::enforce_u16_mul(cs, left_u16, right_u16)?)
}
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
ConstrainedInteger::U32(Self::enforce_u32_mul(cs, left_u32, right_u32))
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
Integer::U32(Self::enforce_u32_mul(cs, left_u32, right_u32)?)
}
(ConstrainedInteger::U64(left_u64), ConstrainedInteger::U64(right_u64)) => {
ConstrainedInteger::U64(Self::enforce_u64_mul(cs, left_u64, right_u64))
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
Integer::U64(Self::enforce_u64_mul(cs, left_u64, right_u64)?)
}
(ConstrainedInteger::U128(left_u128), ConstrainedInteger::U128(right_u128)) => {
ConstrainedInteger::U128(Self::enforce_u128_mul(cs, left_u128, right_u128))
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
Integer::U128(Self::enforce_u128_mul(cs, left_u128, right_u128)?)
}
(left, right) => unimplemented!(
"cannot enforce integer multiplication between {} * {}",
left,
right
),
})
(left, right) => {
return Err(IntegerError::CannotEnforce(format!("{} * {}", left, right)))
}
}))
}
pub(crate) fn enforce_integer_div(
cs: &mut CS,
left: ConstrainedInteger,
right: ConstrainedInteger,
) -> ConstrainedValue<F> {
ConstrainedValue::Integer(match (left, right) {
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
ConstrainedInteger::U8(Self::enforce_u8_div(cs, left_u8, right_u8))
left: Integer,
right: Integer,
) -> Result<ConstrainedValue<F>, IntegerError> {
Ok(ConstrainedValue::Integer(match (left, right) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
Integer::U8(Self::enforce_u8_div(cs, left_u8, right_u8)?)
}
(ConstrainedInteger::U16(left_u16), ConstrainedInteger::U16(right_u16)) => {
ConstrainedInteger::U16(Self::enforce_u16_div(cs, left_u16, right_u16))
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
Integer::U16(Self::enforce_u16_div(cs, left_u16, right_u16)?)
}
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
ConstrainedInteger::U32(Self::enforce_u32_div(cs, left_u32, right_u32))
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
Integer::U32(Self::enforce_u32_div(cs, left_u32, right_u32)?)
}
(ConstrainedInteger::U64(left_u64), ConstrainedInteger::U64(right_u64)) => {
ConstrainedInteger::U64(Self::enforce_u64_div(cs, left_u64, right_u64))
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
Integer::U64(Self::enforce_u64_div(cs, left_u64, right_u64)?)
}
(ConstrainedInteger::U128(left_u128), ConstrainedInteger::U128(right_u128)) => {
ConstrainedInteger::U128(Self::enforce_u128_div(cs, left_u128, right_u128))
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
Integer::U128(Self::enforce_u128_div(cs, left_u128, right_u128)?)
}
(left, right) => unimplemented!(
"cannot enforce integer division between {} / {}",
left,
right
),
})
(left, right) => {
return Err(IntegerError::CannotEnforce(format!("{} / {}", left, right)))
}
}))
}
pub(crate) fn enforce_integer_pow(
cs: &mut CS,
left: ConstrainedInteger,
right: ConstrainedInteger,
) -> ConstrainedValue<F> {
ConstrainedValue::Integer(match (left, right) {
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
ConstrainedInteger::U8(Self::enforce_u8_pow(cs, left_u8, right_u8))
left: Integer,
right: Integer,
) -> Result<ConstrainedValue<F>, IntegerError> {
Ok(ConstrainedValue::Integer(match (left, right) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
Integer::U8(Self::enforce_u8_pow(cs, left_u8, right_u8)?)
}
(ConstrainedInteger::U16(left_u16), ConstrainedInteger::U16(right_u16)) => {
ConstrainedInteger::U16(Self::enforce_u16_pow(cs, left_u16, right_u16))
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
Integer::U16(Self::enforce_u16_pow(cs, left_u16, right_u16)?)
}
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
ConstrainedInteger::U32(Self::enforce_u32_pow(cs, left_u32, right_u32))
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
Integer::U32(Self::enforce_u32_pow(cs, left_u32, right_u32)?)
}
(ConstrainedInteger::U64(left_u64), ConstrainedInteger::U64(right_u64)) => {
ConstrainedInteger::U64(Self::enforce_u64_pow(cs, left_u64, right_u64))
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
Integer::U64(Self::enforce_u64_pow(cs, left_u64, right_u64)?)
}
(ConstrainedInteger::U128(left_u128), ConstrainedInteger::U128(right_u128)) => {
ConstrainedInteger::U128(Self::enforce_u128_pow(cs, left_u128, right_u128))
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
Integer::U128(Self::enforce_u128_pow(cs, left_u128, right_u128)?)
}
(left, right) => unimplemented!(
"cannot enforce integer exponentiation between {} ** {}",
left,
right
),
})
(left, right) => {
return Err(IntegerError::CannotEnforce(format!(
"{} ** {}",
left, right
)))
}
}))
}
}

View File

@ -2,8 +2,8 @@
use crate::{
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
types::{ParameterModel, ParameterValue, Variable},
ConstrainedInteger,
errors::IntegerError,
types::{InputModel, Integer, Variable},
};
use snarkos_errors::gadgets::SynthesisError;
@ -20,27 +20,23 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
// Check that the parameter value is the correct type
let integer_option = parameter_value.map(|parameter| match parameter {
ParameterValue::Integer(i) => i as u128,
value => unimplemented!("expected integer parameter, got {}", value),
});
parameter_model: InputModel<F>,
integer_option: Option<usize>,
) -> Result<Variable<F>, IntegerError> {
// Type cast to u128 in rust.
// If this fails should we return our own error?
let u128_option = integer_option.map(|integer| integer as u128);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer = if parameter_model.private {
UInt128::alloc(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u128_option.ok_or(SynthesisError::AssignmentMissing)
})?
} else {
UInt128::alloc_input(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u128_option.ok_or(SynthesisError::AssignmentMissing)
})?
};
let parameter_variable = new_variable_from_variable(scope, &parameter_model.variable);
@ -48,79 +44,98 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
// store each argument as variable in resolved program
self.store_variable(
parameter_variable.clone(),
ConstrainedValue::Integer(ConstrainedInteger::U128(integer)),
ConstrainedValue::Integer(Integer::U128(integer)),
);
parameter_variable
Ok(parameter_variable)
}
pub(crate) fn u128_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
unimplemented!("Cannot enforce integer array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
// let name = parameter.variable.name.clone();
// for argument in argument_array {
// let number = if parameter.private {
// UInt128::alloc(cs.ns(|| name), Some(argument)).unwrap()
// } else {
// UInt128::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// };
//
// array_value.push(number);
// }
//
//
// let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
//
// // store array as variable in resolved program
// self.store_variable(parameter_variable.clone(), ResolvedValue::U128Array(array_value));
//
// parameter_variable
// pub(crate) fn u128_array_from_parameter(
// &mut self,
// _cs: &mut CS,
// _scope: String,
// _parameter_model: ParameterModel<F>,
// _parameter_value: Option<ParameterValue<F>>,
// ) -> Result<Variable<F>, IntegerError> {
// unimplemented!("Cannot enforce integer array as parameter")
// // // Check visibility of parameter
// // let mut array_value = vec![];
// // let name = parameter.variable.name.clone();
// // for argument in argument_array {
// // let number = if parameter.private {
// // UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
// // } else {
// // UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// // };
// //
// // array_value.push(number);
// // }
// //
// //
// // let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
// //
// // // store array as variable in resolved program
// // self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
// //
// // parameter_variable
// }
pub(crate) fn enforce_u128_eq(
cs: &mut CS,
left: UInt128,
right: UInt128,
) -> Result<(), IntegerError> {
Ok(left.enforce_equal(cs.ns(|| format!("enforce u128 equal")), &right)?)
}
pub(crate) fn enforce_u128_eq(cs: &mut CS, left: UInt128, right: UInt128) {
left.enforce_equal(cs.ns(|| format!("enforce u128 equal")), &right)
.unwrap();
}
pub(crate) fn enforce_u128_add(cs: &mut CS, left: UInt128, right: UInt128) -> UInt128 {
UInt128::addmany(
pub(crate) fn enforce_u128_add(
cs: &mut CS,
left: UInt128,
right: UInt128,
) -> Result<UInt128, IntegerError> {
Ok(UInt128::addmany(
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
&[left, right],
)
.unwrap()
)?)
}
pub(crate) fn enforce_u128_sub(cs: &mut CS, left: UInt128, right: UInt128) -> UInt128 {
left.sub(
pub(crate) fn enforce_u128_sub(
cs: &mut CS,
left: UInt128,
right: UInt128,
) -> Result<UInt128, IntegerError> {
Ok(left.sub(
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u128_mul(cs: &mut CS, left: UInt128, right: UInt128) -> UInt128 {
left.mul(
pub(crate) fn enforce_u128_mul(
cs: &mut CS,
left: UInt128,
right: UInt128,
) -> Result<UInt128, IntegerError> {
Ok(left.mul(
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u128_div(cs: &mut CS, left: UInt128, right: UInt128) -> UInt128 {
left.div(
pub(crate) fn enforce_u128_div(
cs: &mut CS,
left: UInt128,
right: UInt128,
) -> Result<UInt128, IntegerError> {
Ok(left.div(
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u128_pow(cs: &mut CS, left: UInt128, right: UInt128) -> UInt128 {
left.pow(
pub(crate) fn enforce_u128_pow(
cs: &mut CS,
left: UInt128,
right: UInt128,
) -> Result<UInt128, IntegerError> {
Ok(left.pow(
cs.ns(|| {
format!(
"enforce {} ** {}",
@ -129,7 +144,6 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
)
}),
&right,
)
.unwrap()
)?)
}
}

View File

@ -2,8 +2,8 @@
use crate::{
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
types::{ParameterModel, ParameterValue, Variable},
ConstrainedInteger,
errors::IntegerError,
types::{InputModel, Integer, Variable},
};
use snarkos_errors::gadgets::SynthesisError;
@ -20,27 +20,23 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
// Check that the parameter value is the correct type
let integer_option = parameter_value.map(|parameter| match parameter {
ParameterValue::Integer(i) => i as u16,
value => unimplemented!("expected integer parameter, got {}", value),
});
parameter_model: InputModel<F>,
integer_option: Option<usize>,
) -> Result<Variable<F>, IntegerError> {
// Type cast to u16 in rust.
// If this fails should we return our own error?
let u16_option = integer_option.map(|integer| integer as u16);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer = if parameter_model.private {
UInt16::alloc(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u16_option.ok_or(SynthesisError::AssignmentMissing)
})?
} else {
UInt16::alloc_input(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u16_option.ok_or(SynthesisError::AssignmentMissing)
})?
};
let parameter_variable = new_variable_from_variable(scope, &parameter_model.variable);
@ -48,79 +44,98 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
// store each argument as variable in resolved program
self.store_variable(
parameter_variable.clone(),
ConstrainedValue::Integer(ConstrainedInteger::U16(integer)),
ConstrainedValue::Integer(Integer::U16(integer)),
);
parameter_variable
Ok(parameter_variable)
}
pub(crate) fn u16_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
unimplemented!("Cannot enforce integer array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
// let name = parameter.variable.name.clone();
// for argument in argument_array {
// let number = if parameter.private {
// UInt16::alloc(cs.ns(|| name), Some(argument)).unwrap()
// } else {
// UInt16::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// };
//
// array_value.push(number);
// }
//
//
// let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
//
// // store array as variable in resolved program
// self.store_variable(parameter_variable.clone(), ResolvedValue::U16Array(array_value));
//
// parameter_variable
// pub(crate) fn u16_array_from_parameter(
// &mut self,
// _cs: &mut CS,
// _scope: String,
// _parameter_model: ParameterModel<F>,
// _parameter_value: Option<ParameterValue<F>>,
// ) -> Result<Variable<F>, IntegerError> {
// unimplemented!("Cannot enforce integer array as parameter")
// // // Check visibility of parameter
// // let mut array_value = vec![];
// // let name = parameter.variable.name.clone();
// // for argument in argument_array {
// // let number = if parameter.private {
// // UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
// // } else {
// // UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// // };
// //
// // array_value.push(number);
// // }
// //
// //
// // let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
// //
// // // store array as variable in resolved program
// // self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
// //
// // parameter_variable
// }
pub(crate) fn enforce_u16_eq(
cs: &mut CS,
left: UInt16,
right: UInt16,
) -> Result<(), IntegerError> {
Ok(left.enforce_equal(cs.ns(|| format!("enforce u16 equal")), &right)?)
}
pub(crate) fn enforce_u16_eq(cs: &mut CS, left: UInt16, right: UInt16) {
left.enforce_equal(cs.ns(|| format!("enforce u16 equal")), &right)
.unwrap();
}
pub(crate) fn enforce_u16_add(cs: &mut CS, left: UInt16, right: UInt16) -> UInt16 {
UInt16::addmany(
pub(crate) fn enforce_u16_add(
cs: &mut CS,
left: UInt16,
right: UInt16,
) -> Result<UInt16, IntegerError> {
Ok(UInt16::addmany(
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
&[left, right],
)
.unwrap()
)?)
}
pub(crate) fn enforce_u16_sub(cs: &mut CS, left: UInt16, right: UInt16) -> UInt16 {
left.sub(
pub(crate) fn enforce_u16_sub(
cs: &mut CS,
left: UInt16,
right: UInt16,
) -> Result<UInt16, IntegerError> {
Ok(left.sub(
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u16_mul(cs: &mut CS, left: UInt16, right: UInt16) -> UInt16 {
left.mul(
pub(crate) fn enforce_u16_mul(
cs: &mut CS,
left: UInt16,
right: UInt16,
) -> Result<UInt16, IntegerError> {
Ok(left.mul(
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u16_div(cs: &mut CS, left: UInt16, right: UInt16) -> UInt16 {
left.div(
pub(crate) fn enforce_u16_div(
cs: &mut CS,
left: UInt16,
right: UInt16,
) -> Result<UInt16, IntegerError> {
Ok(left.div(
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u16_pow(cs: &mut CS, left: UInt16, right: UInt16) -> UInt16 {
left.pow(
pub(crate) fn enforce_u16_pow(
cs: &mut CS,
left: UInt16,
right: UInt16,
) -> Result<UInt16, IntegerError> {
Ok(left.pow(
cs.ns(|| {
format!(
"enforce {} ** {}",
@ -129,7 +144,6 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
)
}),
&right,
)
.unwrap()
)?)
}
}

View File

@ -2,8 +2,8 @@
use crate::{
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
types::{ParameterModel, ParameterValue, Variable},
ConstrainedInteger,
errors::IntegerError,
types::{InputModel, Integer, Variable},
};
use snarkos_errors::gadgets::SynthesisError;
@ -20,27 +20,23 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
// Check that the parameter value is the correct type
let integer_option = parameter_value.map(|parameter| match parameter {
ParameterValue::Integer(i) => i as u32,
value => unimplemented!("expected integer parameter, got {}", value),
});
parameter_model: InputModel<F>,
integer_option: Option<usize>,
) -> Result<Variable<F>, IntegerError> {
// Type cast to u32 in rust.
// If this fails should we return our own error?
let u32_option = integer_option.map(|integer| integer as u32);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer = if parameter_model.private {
UInt32::alloc(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u32_option.ok_or(SynthesisError::AssignmentMissing)
})?
} else {
UInt32::alloc_input(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u32_option.ok_or(SynthesisError::AssignmentMissing)
})?
};
let parameter_variable = new_variable_from_variable(scope, &parameter_model.variable);
@ -48,79 +44,98 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
// store each argument as variable in resolved program
self.store_variable(
parameter_variable.clone(),
ConstrainedValue::Integer(ConstrainedInteger::U32(integer)),
ConstrainedValue::Integer(Integer::U32(integer)),
);
parameter_variable
Ok(parameter_variable)
}
pub(crate) fn u32_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
unimplemented!("Cannot enforce integer array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
// let name = parameter.variable.name.clone();
// for argument in argument_array {
// let number = if parameter.private {
// UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
// } else {
// UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// };
//
// array_value.push(number);
// }
//
//
// let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
//
// // store array as variable in resolved program
// self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
//
// parameter_variable
// pub(crate) fn u32_array_from_parameter(
// &mut self,
// _cs: &mut CS,
// _scope: String,
// _parameter_model: ParameterModel<F>,
// _parameter_value: Option<ParameterValue<F>>,
// ) -> Result<Variable<F>, IntegerError> {
// unimplemented!("Cannot enforce integer array as parameter")
// // // Check visibility of parameter
// // let mut array_value = vec![];
// // let name = parameter.variable.name.clone();
// // for argument in argument_array {
// // let number = if parameter.private {
// // UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
// // } else {
// // UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// // };
// //
// // array_value.push(number);
// // }
// //
// //
// // let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
// //
// // // store array as variable in resolved program
// // self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
// //
// // parameter_variable
// }
pub(crate) fn enforce_u32_eq(
cs: &mut CS,
left: UInt32,
right: UInt32,
) -> Result<(), IntegerError> {
Ok(left.enforce_equal(cs.ns(|| format!("enforce u32 equal")), &right)?)
}
pub(crate) fn enforce_u32_eq(cs: &mut CS, left: UInt32, right: UInt32) {
left.enforce_equal(cs.ns(|| format!("enforce u32 equal")), &right)
.unwrap();
}
pub(crate) fn enforce_u32_add(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
UInt32::addmany(
pub(crate) fn enforce_u32_add(
cs: &mut CS,
left: UInt32,
right: UInt32,
) -> Result<UInt32, IntegerError> {
Ok(UInt32::addmany(
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
&[left, right],
)
.unwrap()
)?)
}
pub(crate) fn enforce_u32_sub(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
left.sub(
pub(crate) fn enforce_u32_sub(
cs: &mut CS,
left: UInt32,
right: UInt32,
) -> Result<UInt32, IntegerError> {
Ok(left.sub(
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u32_mul(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
left.mul(
pub(crate) fn enforce_u32_mul(
cs: &mut CS,
left: UInt32,
right: UInt32,
) -> Result<UInt32, IntegerError> {
Ok(left.mul(
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u32_div(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
left.div(
pub(crate) fn enforce_u32_div(
cs: &mut CS,
left: UInt32,
right: UInt32,
) -> Result<UInt32, IntegerError> {
Ok(left.div(
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u32_pow(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
left.pow(
pub(crate) fn enforce_u32_pow(
cs: &mut CS,
left: UInt32,
right: UInt32,
) -> Result<UInt32, IntegerError> {
Ok(left.pow(
cs.ns(|| {
format!(
"enforce {} ** {}",
@ -129,7 +144,6 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
)
}),
&right,
)
.unwrap()
)?)
}
}

View File

@ -2,8 +2,8 @@
use crate::{
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
types::{ParameterModel, ParameterValue, Variable},
ConstrainedInteger,
errors::IntegerError,
types::{InputModel, Integer, Variable},
};
use snarkos_errors::gadgets::SynthesisError;
@ -20,27 +20,23 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
// Check that the parameter value is the correct type
let integer_option = parameter_value.map(|parameter| match parameter {
ParameterValue::Integer(i) => i as u64,
value => unimplemented!("expected integer parameter, got {}", value),
});
parameter_model: InputModel<F>,
integer_option: Option<usize>,
) -> Result<Variable<F>, IntegerError> {
// Type cast to u64 in rust.
// If this fails should we return our own error?
let u64_option = integer_option.map(|integer| integer as u64);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer = if parameter_model.private {
UInt64::alloc(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u64_option.ok_or(SynthesisError::AssignmentMissing)
})?
} else {
UInt64::alloc_input(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u64_option.ok_or(SynthesisError::AssignmentMissing)
})?
};
let parameter_variable = new_variable_from_variable(scope, &parameter_model.variable);
@ -48,79 +44,98 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
// store each argument as variable in resolved program
self.store_variable(
parameter_variable.clone(),
ConstrainedValue::Integer(ConstrainedInteger::U64(integer)),
ConstrainedValue::Integer(Integer::U64(integer)),
);
parameter_variable
Ok(parameter_variable)
}
pub(crate) fn u64_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
unimplemented!("Cannot enforce integer array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
// let name = parameter.variable.name.clone();
// for argument in argument_array {
// let number = if parameter.private {
// UInt64::alloc(cs.ns(|| name), Some(argument)).unwrap()
// } else {
// UInt64::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// };
//
// array_value.push(number);
// }
//
//
// let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
//
// // store array as variable in resolved program
// self.store_variable(parameter_variable.clone(), ResolvedValue::U64Array(array_value));
//
// parameter_variable
// pub(crate) fn u64_array_from_parameter(
// &mut self,
// _cs: &mut CS,
// _scope: String,
// _parameter_model: ParameterModel<F>,
// _parameter_value: Option<ParameterValue<F>>,
// ) -> Result<Variable<F>, IntegerError> {
// unimplemented!("Cannot enforce integer array as parameter")
// // // Check visibility of parameter
// // let mut array_value = vec![];
// // let name = parameter.variable.name.clone();
// // for argument in argument_array {
// // let number = if parameter.private {
// // UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
// // } else {
// // UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// // };
// //
// // array_value.push(number);
// // }
// //
// //
// // let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
// //
// // // store array as variable in resolved program
// // self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
// //
// // parameter_variable
// }
pub(crate) fn enforce_u64_eq(
cs: &mut CS,
left: UInt64,
right: UInt64,
) -> Result<(), IntegerError> {
Ok(left.enforce_equal(cs.ns(|| format!("enforce u64 equal")), &right)?)
}
pub(crate) fn enforce_u64_eq(cs: &mut CS, left: UInt64, right: UInt64) {
left.enforce_equal(cs.ns(|| format!("enforce u64 equal")), &right)
.unwrap();
}
pub(crate) fn enforce_u64_add(cs: &mut CS, left: UInt64, right: UInt64) -> UInt64 {
UInt64::addmany(
pub(crate) fn enforce_u64_add(
cs: &mut CS,
left: UInt64,
right: UInt64,
) -> Result<UInt64, IntegerError> {
Ok(UInt64::addmany(
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
&[left, right],
)
.unwrap()
)?)
}
pub(crate) fn enforce_u64_sub(cs: &mut CS, left: UInt64, right: UInt64) -> UInt64 {
left.sub(
pub(crate) fn enforce_u64_sub(
cs: &mut CS,
left: UInt64,
right: UInt64,
) -> Result<UInt64, IntegerError> {
Ok(left.sub(
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u64_mul(cs: &mut CS, left: UInt64, right: UInt64) -> UInt64 {
left.mul(
pub(crate) fn enforce_u64_mul(
cs: &mut CS,
left: UInt64,
right: UInt64,
) -> Result<UInt64, IntegerError> {
Ok(left.mul(
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u64_div(cs: &mut CS, left: UInt64, right: UInt64) -> UInt64 {
left.div(
pub(crate) fn enforce_u64_div(
cs: &mut CS,
left: UInt64,
right: UInt64,
) -> Result<UInt64, IntegerError> {
Ok(left.div(
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u64_pow(cs: &mut CS, left: UInt64, right: UInt64) -> UInt64 {
left.pow(
pub(crate) fn enforce_u64_pow(
cs: &mut CS,
left: UInt64,
right: UInt64,
) -> Result<UInt64, IntegerError> {
Ok(left.pow(
cs.ns(|| {
format!(
"enforce {} ** {}",
@ -129,7 +144,6 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
)
}),
&right,
)
.unwrap()
)?)
}
}

View File

@ -2,8 +2,8 @@
use crate::{
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
types::{ParameterModel, ParameterValue, Variable},
ConstrainedInteger,
errors::IntegerError,
types::{InputModel, Integer, Variable},
};
use snarkos_errors::gadgets::SynthesisError;
@ -20,27 +20,23 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
// Check that the parameter value is the correct type
let integer_option = parameter_value.map(|parameter| match parameter {
ParameterValue::Integer(i) => i as u8,
value => unimplemented!("expected integer parameter, got {}", value),
});
parameter_model: InputModel<F>,
integer_option: Option<usize>,
) -> Result<Variable<F>, IntegerError> {
// Type cast to u8 in rust.
// If this fails should we return our own error?
let u8_option = integer_option.map(|integer| integer as u8);
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let integer = if parameter_model.private {
let integer_value = if parameter_model.private {
UInt8::alloc(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u8_option.ok_or(SynthesisError::AssignmentMissing)
})?
} else {
UInt8::alloc_input(cs.ns(|| name), || {
integer_option.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
u8_option.ok_or(SynthesisError::AssignmentMissing)
})?
};
let parameter_variable = new_variable_from_variable(scope, &parameter_model.variable);
@ -48,79 +44,98 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
// store each argument as variable in resolved program
self.store_variable(
parameter_variable.clone(),
ConstrainedValue::Integer(ConstrainedInteger::U8(integer)),
ConstrainedValue::Integer(Integer::U8(integer_value)),
);
parameter_variable
Ok(parameter_variable)
}
pub(crate) fn u8_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
unimplemented!("Cannot enforce integer array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
// let name = parameter.variable.name.clone();
// for argument in argument_array {
// let number = if parameter.private {
// UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
// } else {
// UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// };
//
// array_value.push(number);
// }
//
//
// let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
//
// // store array as variable in resolved program
// self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
//
// parameter_variable
// pub(crate) fn u8_array_from_parameter(
// &mut self,
// _cs: &mut CS,
// _scope: String,
// _parameter_model: ParameterModel<F>,
// _parameter_value: Option<ParameterValue<F>>,
// ) -> Result<Variable<F>, IntegerError> {
// unimplemented!("Cannot enforce integer array as parameter")
// // // Check visibility of parameter
// // let mut array_value = vec![];
// // let name = parameter.variable.name.clone();
// // for argument in argument_array {
// // let number = if parameter.private {
// // UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
// // } else {
// // UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
// // };
// //
// // array_value.push(number);
// // }
// //
// //
// // let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
// //
// // // store array as variable in resolved program
// // self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
// //
// // parameter_variable
// }
pub(crate) fn enforce_u8_eq(
cs: &mut CS,
left: UInt8,
right: UInt8,
) -> Result<(), IntegerError> {
Ok(left.enforce_equal(cs.ns(|| format!("enforce u8 equal")), &right)?)
}
pub(crate) fn enforce_u8_eq(cs: &mut CS, left: UInt8, right: UInt8) {
left.enforce_equal(cs.ns(|| format!("enforce u8 equal")), &right)
.unwrap();
}
pub(crate) fn enforce_u8_add(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
UInt8::addmany(
pub(crate) fn enforce_u8_add(
cs: &mut CS,
left: UInt8,
right: UInt8,
) -> Result<UInt8, IntegerError> {
Ok(UInt8::addmany(
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
&[left, right],
)
.unwrap()
)?)
}
pub(crate) fn enforce_u8_sub(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
left.sub(
pub(crate) fn enforce_u8_sub(
cs: &mut CS,
left: UInt8,
right: UInt8,
) -> Result<UInt8, IntegerError> {
Ok(left.sub(
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u8_mul(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
left.mul(
pub(crate) fn enforce_u8_mul(
cs: &mut CS,
left: UInt8,
right: UInt8,
) -> Result<UInt8, IntegerError> {
Ok(left.mul(
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u8_div(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
left.div(
pub(crate) fn enforce_u8_div(
cs: &mut CS,
left: UInt8,
right: UInt8,
) -> Result<UInt8, IntegerError> {
Ok(left.div(
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
&right,
)
.unwrap()
)?)
}
pub(crate) fn enforce_u8_pow(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
left.pow(
pub(crate) fn enforce_u8_pow(
cs: &mut CS,
left: UInt8,
right: UInt8,
) -> Result<UInt8, IntegerError> {
Ok(left.pow(
cs.ns(|| {
format!(
"enforce {} ** {}",
@ -129,7 +144,6 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
)
}),
&right,
)
.unwrap()
)?)
}
}

View File

@ -1,361 +0,0 @@
//! Methods to enforce the main function with arguments in
//! a resolved Leo program.
use crate::{
ast,
constraints::{
new_scope, new_scope_from_variable, new_variable_from_variables, ConstrainedProgram,
ConstrainedValue,
},
types::{Expression, Function, ParameterValue, Program, Type},
Import,
};
use from_pest::FromPest;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
use std::fs;
use std::path::Path;
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
fn enforce_argument(
&mut self,
cs: &mut CS,
scope: String,
caller_scope: String,
function_name: String,
argument: Expression<F>,
) -> ConstrainedValue<F> {
match argument {
Expression::Variable(variable) => self.enforce_variable(caller_scope, variable),
expression => self.enforce_expression(cs, scope, function_name, expression),
}
}
pub(crate) fn enforce_function(
&mut self,
cs: &mut CS,
scope: String,
caller_scope: String,
function: Function<F>,
arguments: Vec<Expression<F>>,
) -> ConstrainedValue<F> {
let function_name = new_scope(scope.clone(), function.get_name());
// Make sure we are given the correct number of arguments
if function.parameters.len() != arguments.len() {
unimplemented!(
"function expected {} arguments, got {}",
function.parameters.len(),
arguments.len()
)
}
// Store argument values as new variables in resolved program
function
.parameters
.clone()
.iter()
.zip(arguments.clone().into_iter())
.for_each(|(parameter, argument)| {
// Check that argument is correct type
match parameter._type.clone() {
Type::IntegerType(integer_type) => {
match self.enforce_argument(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
argument,
) {
ConstrainedValue::Integer(number) => {
number.expect_type(&integer_type);
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function_name.clone(),
&parameter.variable,
);
self.store(variable_name, ConstrainedValue::Integer(number));
}
argument => {
unimplemented!("expected integer argument got {}", argument)
}
}
}
Type::FieldElement => {
match self.enforce_argument(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
argument,
) {
ConstrainedValue::FieldElement(fe) => {
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function_name.clone(),
&parameter.variable,
);
self.store(variable_name, ConstrainedValue::FieldElement(fe));
}
argument => unimplemented!("expected field argument got {}", argument),
}
}
Type::Boolean => {
match self.enforce_argument(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
argument,
) {
ConstrainedValue::Boolean(bool) => {
// Store argument as variable with {function_name}_{parameter name}
let variable_name = new_scope_from_variable(
function_name.clone(),
&parameter.variable,
);
self.store(variable_name, ConstrainedValue::Boolean(bool));
}
argument => {
unimplemented!("expected boolean argument got {}", argument)
}
}
}
ty => unimplemented!("parameter type {} not matched yet", ty),
}
});
// Evaluate function statements
let mut return_values = ConstrainedValue::Return(vec![]);
for statement in function.statements.iter() {
if let Some(returned) = self.enforce_statement(
cs,
scope.clone(),
function_name.clone(),
statement.clone(),
function.returns.clone(),
) {
return_values = returned;
break;
}
}
return_values
}
fn enforce_main_function(
&mut self,
cs: &mut CS,
scope: String,
function: Function<F>,
parameters: Vec<Option<ParameterValue<F>>>,
) -> ConstrainedValue<F> {
let function_name = new_scope(scope.clone(), function.get_name());
let mut arguments = vec![];
// todo: check parameters length for each
// Iterate over main function parameters
function
.parameters
.clone()
.into_iter()
.zip(parameters.into_iter())
.for_each(|(parameter_model, parameter_value)| {
// append each variable to arguments vector
arguments.push(Expression::Variable(match parameter_model._type {
Type::IntegerType(ref _integer_type) => self.integer_from_parameter(
cs,
function_name.clone(),
parameter_model,
parameter_value,
),
Type::FieldElement => self.field_element_from_parameter(
cs,
function_name.clone(),
parameter_model,
parameter_value,
),
Type::Boolean => self.bool_from_parameter(
cs,
function_name.clone(),
parameter_model,
parameter_value,
),
Type::Array(ref ty, _length) => match *ty.clone() {
Type::IntegerType(_type) => self.integer_array_from_parameter(
cs,
function_name.clone(),
parameter_model,
parameter_value,
),
Type::FieldElement => self.field_element_array_from_parameter(
cs,
function_name.clone(),
parameter_model,
parameter_value,
),
Type::Boolean => self.boolean_array_from_parameter(
cs,
function_name.clone(),
parameter_model,
parameter_value,
),
ty => unimplemented!("parameter type not implemented {}", ty),
},
ty => unimplemented!("parameter type not implemented {}", ty),
}))
});
self.enforce_function(cs, scope, function_name, function, arguments)
}
fn enforce_import(&mut self, cs: &mut CS, scope: String, import: Import<F>) {
// Resolve program file path
let unparsed_file = fs::read_to_string(Path::new(&import.path_string_full())).expect(
&format!("cannot parse import {}", import.path_string_full()),
);
let mut file = ast::parse(&unparsed_file).expect(&format!(
"cannot parse import {}",
import.path_string_full()
));
// generate ast from file
let syntax_tree = ast::File::from_pest(&mut file).expect("infallible");
// generate aleo program from file
let mut program = Program::from(syntax_tree, import.path_string.clone());
// Use same namespace as calling function for imported symbols
program = program.name(scope);
// * -> import all imports, structs, functions in the current scope
if import.is_star() {
// recursively evaluate program statements
self.resolve_definitions(cs, program);
} else {
let program_name = program.name.clone();
// match each import symbol to a symbol in the imported file
import.symbols.into_iter().for_each(|symbol| {
// see if the imported symbol is a struct
let matched_struct = program
.structs
.clone()
.into_iter()
.find(|(struct_name, _struct_def)| symbol.symbol == *struct_name);
match matched_struct {
Some((_struct_name, struct_def)) => {
// take the alias if it is present
let resolved_name = symbol.alias.unwrap_or(symbol.symbol);
let resolved_struct_name =
new_variable_from_variables(&program_name.clone(), &resolved_name);
// store imported struct under resolved name
self.store_variable(
resolved_struct_name,
ConstrainedValue::StructDefinition(struct_def),
);
}
None => {
// see if the imported symbol is a function
let matched_function = program.functions.clone().into_iter().find(
|(function_name, _function)| symbol.symbol.name == *function_name.0,
);
match matched_function {
Some((_function_name, function)) => {
// take the alias if it is present
let resolved_name = symbol.alias.unwrap_or(symbol.symbol);
let resolved_function_name = new_variable_from_variables(
&program_name.clone(),
&resolved_name,
);
// store imported function under resolved name
self.store_variable(
resolved_function_name,
ConstrainedValue::Function(function),
)
}
None => unimplemented!(
"cannot find imported symbol {} in imported file {}",
symbol,
program_name.clone()
),
}
}
}
});
// evaluate all import statements in imported file
program.imports.into_iter().for_each(|nested_import| {
self.enforce_import(cs, program_name.name.clone(), nested_import)
});
}
}
pub fn resolve_definitions(&mut self, cs: &mut CS, program: Program<F>) {
let program_name = program.name.clone();
// evaluate and store all imports
program
.imports
.into_iter()
.for_each(|import| self.enforce_import(cs, program_name.name.clone(), import));
// evaluate and store all struct definitions
program
.structs
.into_iter()
.for_each(|(variable, struct_def)| {
let resolved_struct_name =
new_variable_from_variables(&program_name.clone(), &variable);
self.store_variable(
resolved_struct_name,
ConstrainedValue::StructDefinition(struct_def),
);
});
// evaluate and store all function definitions
program
.functions
.into_iter()
.for_each(|(function_name, function)| {
let resolved_function_name = new_scope(program_name.name.clone(), function_name.0);
self.store(resolved_function_name, ConstrainedValue::Function(function));
});
}
pub fn generate_constraints(
cs: &mut CS,
program: Program<F>,
parameters: Vec<Option<ParameterValue<F>>>,
) -> ConstrainedValue<F> {
let mut resolved_program = ConstrainedProgram::new();
let program_name = program.get_name();
let main_function_name = new_scope(program_name.clone(), "main".into());
resolved_program.resolve_definitions(cs, program);
let main = resolved_program
.get(&main_function_name)
.expect("main function not defined");
match main.clone() {
ConstrainedValue::Function(function) => {
let result =
resolved_program.enforce_main_function(cs, program_name, function, parameters);
log::debug!("{}", result);
result
}
_ => unimplemented!("main must be a function"),
}
}
}

View File

@ -3,23 +3,62 @@
pub mod boolean;
pub use boolean::*;
pub mod main_function;
pub use main_function::*;
pub mod function;
pub use function::*;
pub mod expression;
pub use expression::*;
pub mod import;
pub use import::*;
pub mod integer;
pub use integer::*;
pub mod field_element;
pub use field_element::*;
pub mod constrained_program;
pub use constrained_program::*;
pub mod program;
pub use program::*;
pub mod constrained_value;
pub use constrained_value::*;
pub mod value;
pub use value::*;
pub mod statement;
pub use statement::*;
use crate::{
errors::CompilerError,
types::{InputValue, Program},
};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
pub fn generate_constraints<F: Field + PrimeField, CS: ConstraintSystem<F>>(
cs: &mut CS,
program: Program<F>,
parameters: Vec<Option<InputValue<F>>>,
) -> Result<ConstrainedValue<F>, CompilerError> {
let mut resolved_program = ConstrainedProgram::new();
let program_name = program.get_name();
let main_function_name = new_scope(program_name.clone(), "main".into());
resolved_program.resolve_definitions(cs, program)?;
let main = resolved_program
.get(&main_function_name)
.ok_or_else(|| CompilerError::NoMain)?;
match main.clone() {
ConstrainedValue::Function(function) => {
let result =
resolved_program.enforce_main_function(cs, program_name, function, parameters)?;
log::debug!("{}", result);
Ok(result)
}
_ => Err(CompilerError::NoMainFunction),
}
}

View File

@ -2,11 +2,11 @@
use crate::{
constraints::{new_scope_from_variable, ConstrainedProgram, ConstrainedValue},
errors::StatementError,
types::{
Assignee, ConditionalNestedOrEnd, ConditionalStatement, Expression, Integer,
RangeOrExpression, Statement, Type, Variable,
},
ConstrainedInteger,
};
use snarkos_models::{
@ -32,7 +32,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
assignee: Assignee<F>,
return_value: &mut ConstrainedValue<F>,
) {
) -> Result<(), StatementError> {
match assignee {
Assignee::Variable(name) => {
// Store the variable in the current scope
@ -52,7 +52,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
file_scope.clone(),
function_scope.clone(),
index,
);
)?;
// Modify the single value of the array in place
match self.get_mut(&expected_array_name) {
@ -60,14 +60,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
ConstrainedValue::Array(old) => {
old[index] = return_value.to_owned();
}
_ => {
unimplemented!("Cannot assign single index to array of values ")
}
_ => return Err(StatementError::ArrayAssignIndex),
},
None => unimplemented!(
"tried to assign to unknown array {}",
expected_array_name
),
None => {
return Err(StatementError::UndefinedArray(expected_array_name))
}
}
}
RangeOrExpression::Range(from, to) => {
@ -87,14 +84,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
let to_index = to_index_option.unwrap_or(old.len());
old.splice(from_index..to_index, new.iter().cloned());
}
_ => unimplemented!(
"Cannot assign a range of array values to single value"
),
_ => return Err(StatementError::ArrayAssignRange),
},
None => unimplemented!(
"tried to assign to unknown array {}",
expected_array_name
),
None => {
return Err(StatementError::UndefinedArray(expected_array_name))
}
}
}
}
@ -105,31 +99,25 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
self.resolve_assignee(function_scope.clone(), *struct_variable);
match self.get_mut(&expected_struct_name) {
Some(value) => match value {
ConstrainedValue::StructExpression(_variable, members) => {
// Modify the struct member in place
let matched_member =
members.into_iter().find(|member| member.0 == struct_member);
match matched_member {
Some(mut member) => member.1 = return_value.to_owned(),
None => unimplemented!(
"struct member {} does not exist in {}",
struct_member,
expected_struct_name
),
Some(ConstrainedValue::StructExpression(_variable, members)) => {
// Modify the struct member in place
let matched_member =
members.into_iter().find(|member| member.0 == struct_member);
match matched_member {
Some(mut member) => member.1 = return_value.to_owned(),
None => {
return Err(StatementError::UndefinedStructField(
struct_member.to_string(),
))
}
}
_ => unimplemented!(
"tried to assign to unknown struct {}",
expected_struct_name
),
},
None => {
unimplemented!("tried to assign to unknown struct {}", expected_struct_name)
}
_ => return Err(StatementError::UndefinedStruct(expected_struct_name)),
}
}
}
Ok(())
}
fn enforce_assign_statement(
@ -139,7 +127,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
assignee: Assignee<F>,
expression: Expression<F>,
) {
) -> Result<(), StatementError> {
// Check that assignee exists
let name = self.resolve_assignee(function_scope.clone(), assignee.clone());
@ -150,11 +138,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
file_scope.clone(),
function_scope.clone(),
expression,
);
)?;
self.store_assignment(cs, file_scope, function_scope, assignee, result_value);
self.store_assignment(cs, file_scope, function_scope, assignee, result_value)
}
None => unimplemented!("cannot assign to uninitialized variable {}", assignee),
None => Err(StatementError::UndefinedVariable(assignee.to_string())),
}
}
@ -166,19 +154,19 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
assignee: Assignee<F>,
ty: Option<Type<F>>,
expression: Expression<F>,
) {
) -> Result<(), StatementError> {
let result_value = &mut self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
);
)?;
match ty {
// Explicit type
Some(ty) => {
result_value.expect_type(&ty);
self.store_assignment(cs, file_scope, function_scope, assignee, result_value);
result_value.expect_type(&ty)?;
self.store_assignment(cs, file_scope, function_scope, assignee, result_value)
}
// Implicit type
None => self.store_assignment(cs, file_scope, function_scope, assignee, result_value),
@ -192,30 +180,36 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
assignees: Vec<Assignee<F>>,
function: Expression<F>,
) {
) -> Result<(), StatementError> {
// Expect return values from function
let return_values =
match self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), function)
{
ConstrainedValue::Return(values) => values,
value => unimplemented!(
"multiple assignment only implemented for functions, got {}",
value
),
};
let return_values = match self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
function,
)? {
ConstrainedValue::Return(values) => values,
value => unimplemented!(
"multiple assignment only implemented for functions, got {}",
value
),
};
assignees
.into_iter()
.zip(return_values.into_iter())
.for_each(|(assignee, mut return_value)| {
.map(|(assignee, mut return_value)| {
self.store_assignment(
cs,
file_scope.clone(),
function_scope.clone(),
assignee,
&mut return_value,
);
});
)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(())
}
fn enforce_return_statement(
@ -225,32 +219,29 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
expressions: Vec<Expression<F>>,
return_types: Vec<Type<F>>,
) -> ConstrainedValue<F> {
) -> Result<ConstrainedValue<F>, StatementError> {
// Make sure we return the correct number of values
if return_types.len() != expressions.len() {
unimplemented!(
"function expected {} return values, got {} values",
return Err(StatementError::InvalidNumberOfReturns(
return_types.len(),
expressions.len(),
)
));
}
ConstrainedValue::Return(
expressions
.into_iter()
.zip(return_types.into_iter())
.map(|(expression, ty)| {
let result = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
);
result.expect_type(&ty);
result
})
.collect::<Vec<ConstrainedValue<F>>>(),
)
let mut returns = vec![];
for (expression, ty) in expressions.into_iter().zip(return_types.into_iter()) {
let result = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expression,
)?;
result.expect_type(&ty)?;
returns.push(result);
}
Ok(ConstrainedValue::Return(returns))
}
fn iterate_or_early_return(
@ -260,7 +251,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
statements: Vec<Statement<F>>,
return_types: Vec<Type<F>>,
) -> Option<ConstrainedValue<F>> {
) -> Result<Option<ConstrainedValue<F>>, StatementError> {
let mut res = None;
// Evaluate statements and possibly return early
for statement in statements.iter() {
@ -270,13 +261,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope.clone(),
statement.clone(),
return_types.clone(),
) {
)? {
res = Some(early_return);
break;
}
}
res
Ok(res)
}
fn enforce_conditional_statement(
@ -286,15 +277,15 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
statement: ConditionalStatement<F>,
return_types: Vec<Type<F>>,
) -> Option<ConstrainedValue<F>> {
) -> Result<Option<ConstrainedValue<F>>, StatementError> {
let condition = match self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
statement.condition.clone(),
) {
)? {
ConstrainedValue::Boolean(resolved) => resolved,
value => unimplemented!("if else conditional must resolve to boolean, got {}", value),
value => return Err(StatementError::IfElseConditional(value.to_string())),
};
// use gadget impl
@ -324,7 +315,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
return_types,
),
},
None => None,
None => Ok(None),
}
}
}
@ -339,7 +330,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
stop: Integer,
statements: Vec<Statement<F>>,
return_types: Vec<Type<F>>,
) -> Option<ConstrainedValue<F>> {
) -> Result<Option<ConstrainedValue<F>>, StatementError> {
let mut res = None;
for i in start.to_usize()..stop.to_usize() {
@ -348,7 +339,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
let index_name = new_scope_from_variable(function_scope.clone(), &index);
self.store(
index_name,
ConstrainedValue::Integer(ConstrainedInteger::U32(UInt32::constant(i as u32))),
ConstrainedValue::Integer(Integer::U32(UInt32::constant(i as u32))),
);
// Evaluate statements and possibly return early
@ -358,13 +349,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope.clone(),
statements.clone(),
return_types.clone(),
) {
)? {
res = Some(early_return);
break;
}
}
res
Ok(res)
}
fn enforce_assert_eq_statement(
@ -372,21 +363,24 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
cs: &mut CS,
left: ConstrainedValue<F>,
right: ConstrainedValue<F>,
) {
match (left, right) {
) -> Result<(), StatementError> {
Ok(match (left, right) {
(ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => {
self.enforce_boolean_eq(cs, bool_1, bool_2)
self.enforce_boolean_eq(cs, bool_1, bool_2)?
}
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Self::enforce_integer_eq(cs, num_1, num_2)
Self::enforce_integer_eq(cs, num_1, num_2)?
}
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
self.enforce_field_eq(cs, fe_1, fe_2)
}
(val_1, val_2) => {
unimplemented!("cannot enforce equality between {} == {}", val_1, val_2)
return Err(StatementError::AssertEq(
val_1.to_string(),
val_2.to_string(),
))
}
}
})
}
pub(crate) fn enforce_statement(
@ -396,7 +390,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope: String,
statement: Statement<F>,
return_types: Vec<Type<F>>,
) -> Option<ConstrainedValue<F>> {
) -> Result<Option<ConstrainedValue<F>>, StatementError> {
let mut res = None;
match statement {
Statement::Return(expressions) => {
@ -406,7 +400,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope,
expressions,
return_types,
));
)?);
}
Statement::Definition(assignee, ty, expression) => {
self.enforce_definition_statement(
@ -416,10 +410,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
assignee,
ty,
expression,
);
)?;
}
Statement::Assign(variable, expression) => {
self.enforce_assign_statement(cs, file_scope, function_scope, variable, expression);
self.enforce_assign_statement(
cs,
file_scope,
function_scope,
variable,
expression,
)?;
}
Statement::MultipleAssign(assignees, function) => {
self.enforce_multiple_definition_statement(
@ -428,7 +428,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope,
assignees,
function,
);
)?;
}
Statement::Conditional(statement) => {
if let Some(early_return) = self.enforce_conditional_statement(
@ -437,7 +437,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
function_scope,
statement,
return_types,
) {
)? {
res = Some(early_return)
}
}
@ -451,33 +451,30 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
stop,
statements,
return_types,
) {
)? {
res = Some(early_return)
}
}
Statement::AssertEq(left, right) => {
let resolved_left =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), left);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), left)?;
let resolved_right =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), right);
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), right)?;
self.enforce_assert_eq_statement(cs, resolved_left, resolved_right);
self.enforce_assert_eq_statement(cs, resolved_left, resolved_right)?;
}
Statement::Expression(expression) => {
match self.enforce_expression(cs, file_scope, function_scope, expression.clone()) {
match self.enforce_expression(cs, file_scope, function_scope, expression.clone())? {
ConstrainedValue::Return(values) => {
if !values.is_empty() {
unimplemented!("function return values not assigned {:#?}", values)
return Err(StatementError::Unassigned(expression.to_string()));
}
}
_ => unimplemented!(
"expected assignment of return values for expression {}",
expression
),
_ => return Err(StatementError::Unassigned(expression.to_string())),
}
}
};
res
Ok(res)
}
}

View File

@ -1,43 +1,23 @@
//! The in memory stored value for a defined name in a resolved Leo program.
use crate::{
constraints::ConstrainedInteger,
types::{Function, Struct, Type, Variable},
errors::ValueError,
types::{FieldElement, Function, Struct, Type, Variable},
Integer,
};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{r1cs::Variable as R1CSVariable, utilities::boolean::Boolean},
gadgets::utilities::boolean::Boolean,
};
use std::fmt;
#[derive(Clone, PartialEq, Eq)]
pub struct ConstrainedStructMember<F: Field + PrimeField>(pub Variable<F>, pub ConstrainedValue<F>);
#[derive(Clone, PartialEq, Eq)]
pub enum FieldElement<F: Field + PrimeField> {
Constant(F),
Allocated(Option<F>, R1CSVariable),
}
impl<F: Field + PrimeField> fmt::Display for FieldElement<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldElement::Constant(ref constant) => write!(f, "{}", constant),
FieldElement::Allocated(ref option, ref _r1cs_var) => {
if option.is_some() {
write!(f, "{}", option.unwrap())
} else {
write!(f, "allocated fe")
}
}
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub enum ConstrainedValue<F: Field + PrimeField> {
Integer(ConstrainedInteger),
Integer(Integer),
FieldElement(FieldElement<F>),
Boolean(Boolean),
Array(Vec<ConstrainedValue<F>>),
@ -48,21 +28,24 @@ pub enum ConstrainedValue<F: Field + PrimeField> {
}
impl<F: Field + PrimeField> ConstrainedValue<F> {
pub(crate) fn expect_type(&self, _type: &Type<F>) {
pub(crate) fn expect_type(&self, _type: &Type<F>) -> Result<(), ValueError> {
match (self, _type) {
(ConstrainedValue::Integer(ref integer), Type::IntegerType(ref _type)) => {
integer.expect_type(_type)
integer.expect_type(_type)?;
}
(ConstrainedValue::FieldElement(ref _f), Type::FieldElement) => {}
(ConstrainedValue::Boolean(ref _b), Type::Boolean) => {}
(ConstrainedValue::Array(ref arr), Type::Array(ref ty, ref len)) => {
// check array lengths are equal
if arr.len() != *len {
unimplemented!("array length {} != {}", arr.len(), *len)
return Err(ValueError::ArrayLength(format!(
"Expected array {:?} to be length {}",
arr, len
)));
}
// check each value in array matches
for value in arr {
value.expect_type(ty)
value.expect_type(ty)?;
}
}
(
@ -70,16 +53,26 @@ impl<F: Field + PrimeField> ConstrainedValue<F> {
Type::Struct(ref expected_name),
) => {
if expected_name != actual_name {
unimplemented!("expected struct name {} got {}", expected_name, actual_name)
return Err(ValueError::StructName(format!(
"Expected struct name {} got {}",
expected_name, actual_name
)));
}
}
(ConstrainedValue::Return(ref values), ty) => {
for value in values {
value.expect_type(ty)
value.expect_type(ty)?;
}
}
(value, _type) => unimplemented!("expected type {}, got {}", _type, value),
(value, _type) => {
return Err(ValueError::TypeError(format!(
"expected type {}, got {}",
_type, value
)))
}
}
Ok(())
}
}

View File

@ -1,24 +1,41 @@
use crate::errors::{FunctionError, ImportError, IntegerError};
use std::io;
use std::path::PathBuf;
#[derive(Debug, Fail)]
#[derive(Debug, Error)]
pub enum CompilerError {
#[fail(display = "{}: {}", _0, _1)]
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[fail(display = "creating: {}", _0)]
#[error("creating: {}", _0)]
Creating(io::Error),
#[fail(display = "Cannot read from the provided file path - {:?}", _0)]
#[error("{}", _0)]
ImportError(ImportError),
#[error("{}", _0)]
IntegerError(IntegerError),
#[error("{}", _0)]
FunctionError(FunctionError),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[fail(display = "Cannot parse the file")]
#[error("Syntax error. Cannot parse the file")]
FileParsingError,
#[fail(display = "Unable to construct abstract syntax tree")]
#[error("Main function not found")]
NoMain,
#[error("Main must be a function")]
NoMainFunction,
#[error("Unable to construct abstract syntax tree")]
SyntaxTreeError,
#[fail(display = "writing: {}", _0)]
#[error("writing: {}", _0)]
Writing(io::Error),
}
@ -27,3 +44,21 @@ impl From<std::io::Error> for CompilerError {
CompilerError::Crate("std::io", format!("{}", error))
}
}
impl From<ImportError> for CompilerError {
fn from(error: ImportError) -> Self {
CompilerError::ImportError(error)
}
}
impl From<IntegerError> for CompilerError {
fn from(error: IntegerError) -> Self {
CompilerError::IntegerError(error)
}
}
impl From<FunctionError> for CompilerError {
fn from(error: FunctionError) -> Self {
CompilerError::FunctionError(error)
}
}

View File

@ -0,0 +1,31 @@
use snarkos_errors::gadgets::SynthesisError;
#[derive(Debug, Error)]
pub enum BooleanError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("Expected boolean parameter, got {}", _0)]
InvalidBoolean(String),
#[error("Cannot evaluate {}", _0)]
CannotEvaluate(String),
#[error("Cannot enforce {}", _0)]
CannotEnforce(String),
#[error("{}", _0)]
SynthesisError(SynthesisError),
}
impl From<std::io::Error> for BooleanError {
fn from(error: std::io::Error) -> Self {
BooleanError::Crate("std::io", format!("{}", error))
}
}
impl From<SynthesisError> for BooleanError {
fn from(error: SynthesisError) -> Self {
BooleanError::SynthesisError(error)
}
}

View File

@ -0,0 +1,106 @@
use crate::errors::{BooleanError, FieldElementError, FunctionError, IntegerError};
#[derive(Debug, Error)]
pub enum ExpressionError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
// Variables
#[error("Variable \"{}\" not found", _0)]
UndefinedVariable(String),
// Types
#[error("{}", _0)]
IncompatibleTypes(String),
#[error("{}", _0)]
IntegerError(IntegerError),
#[error("{}", _0)]
FieldElementError(FieldElementError),
#[error("{}", _0)]
BooleanError(BooleanError),
#[error("Exponent must be an integer, got field {}", _0)]
InvalidExponent(String),
// Arrays
#[error(
"Array {} must be declared before it is used in an inline expression",
_0
)]
UndefinedArray(String),
#[error("Cannot access array {}", _0)]
InvalidArrayAccess(String),
#[error("Spread should contain an array, got {}", _0)]
InvalidSpread(String),
#[error("Index must resolve to an integer, got {}", _0)]
InvalidIndex(String),
// Structs
#[error(
"Struct {} must be declared before it is used in an inline expression",
_0
)]
UndefinedStruct(String),
#[error("Struct field {} does not exist", _0)]
UndefinedStructField(String),
#[error("Expected struct field {}, got {}", _0, _1)]
InvalidStructField(String, String),
#[error("Cannot access struct {}", _0)]
InvalidStructAccess(String),
// Functions
#[error(
"Function {} must be declared before it is used in an inline expression",
_0
)]
UndefinedFunction(String),
#[error("Cannot evaluate function call")]
FunctionError(Box<FunctionError>),
#[error("Inline function call to {} did not return", _0)]
FunctionDidNotReturn(String),
// Conditionals
#[error("If, else conditional must resolve to a boolean, got {}", _0)]
IfElseConditional(String),
}
impl From<std::io::Error> for ExpressionError {
fn from(error: std::io::Error) -> Self {
ExpressionError::Crate("std::io", format!("{}", error))
}
}
impl From<IntegerError> for ExpressionError {
fn from(error: IntegerError) -> Self {
ExpressionError::IntegerError(error)
}
}
impl From<FieldElementError> for ExpressionError {
fn from(error: FieldElementError) -> Self {
ExpressionError::FieldElementError(error)
}
}
impl From<BooleanError> for ExpressionError {
fn from(error: BooleanError) -> Self {
ExpressionError::BooleanError(error)
}
}
impl From<Box<FunctionError>> for ExpressionError {
fn from(error: Box<FunctionError>) -> Self {
ExpressionError::FunctionError(error)
}
}

View File

@ -0,0 +1,25 @@
use snarkos_errors::gadgets::SynthesisError;
#[derive(Debug, Error)]
pub enum FieldElementError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("Expected field element parameter, got {}", _0)]
InvalidField(String),
#[error("{}", _0)]
SynthesisError(SynthesisError),
}
impl From<std::io::Error> for FieldElementError {
fn from(error: std::io::Error) -> Self {
FieldElementError::Crate("std::io", format!("{}", error))
}
}
impl From<SynthesisError> for FieldElementError {
fn from(error: SynthesisError) -> Self {
FieldElementError::SynthesisError(error)
}
}

View File

@ -0,0 +1,69 @@
use crate::errors::{
BooleanError, ExpressionError, FieldElementError, IntegerError, StatementError,
};
#[derive(Debug, Error)]
pub enum FunctionError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("Function expected {} inputs, got {}", _0, _1)]
InputsLength(usize, usize),
#[error("Function input type not defined {}", _0)]
UndefinedInput(String),
#[error("Function expected input type {}, got {}", _0, _1)]
InvalidInput(String, String),
#[error("{}", _0)]
IntegerError(IntegerError),
#[error("{}", _0)]
FieldElementError(FieldElementError),
#[error("{}", _0)]
BooleanError(BooleanError),
#[error("{}", _0)]
ExpressionError(ExpressionError),
#[error("{}", _0)]
StatementError(StatementError),
}
impl From<std::io::Error> for FunctionError {
fn from(error: std::io::Error) -> Self {
FunctionError::Crate("std::io", format!("{}", error))
}
}
impl From<IntegerError> for FunctionError {
fn from(error: IntegerError) -> Self {
FunctionError::IntegerError(error)
}
}
impl From<FieldElementError> for FunctionError {
fn from(error: FieldElementError) -> Self {
FunctionError::FieldElementError(error)
}
}
impl From<BooleanError> for FunctionError {
fn from(error: BooleanError) -> Self {
FunctionError::BooleanError(error)
}
}
impl From<ExpressionError> for FunctionError {
fn from(error: ExpressionError) -> Self {
FunctionError::ExpressionError(error)
}
}
impl From<StatementError> for FunctionError {
fn from(error: StatementError) -> Self {
FunctionError::StatementError(error)
}
}

View File

@ -0,0 +1,20 @@
#[derive(Debug, Error)]
pub enum ImportError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("Cannot read from the provided file path - {}", _0)]
FileReadError(String),
#[error("Syntax error. Cannot parse the file")]
FileParsingError,
#[error("Unable to construct abstract syntax tree")]
SyntaxTreeError,
}
impl From<std::io::Error> for ImportError {
fn from(error: std::io::Error) -> Self {
ImportError::Crate("std::io", format!("{}", error))
}
}

View File

@ -0,0 +1,34 @@
use snarkos_errors::gadgets::SynthesisError;
#[derive(Debug, Error)]
pub enum IntegerError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("expected integer parameter type, got {}", _0)]
InvalidType(String),
#[error("Expected integer {} parameter, got {}", _0, _1)]
InvalidInteger(String, String),
#[error("Cannot evaluate {}", _0)]
CannotEvaluate(String),
#[error("Cannot enforce {}", _0)]
CannotEnforce(String),
#[error("{}", _0)]
SynthesisError(SynthesisError),
}
impl From<std::io::Error> for IntegerError {
fn from(error: std::io::Error) -> Self {
IntegerError::Crate("std::io", format!("{}", error))
}
}
impl From<SynthesisError> for IntegerError {
fn from(error: SynthesisError) -> Self {
IntegerError::SynthesisError(error)
}
}

View File

@ -0,0 +1,25 @@
//! Module containing errors returned when enforcing constraints in an Leo program
pub mod boolean;
pub use boolean::*;
pub mod function;
pub use function::*;
pub mod expression;
pub use expression::*;
pub mod import;
pub use import::*;
pub mod integer;
pub use integer::*;
pub mod field_element;
pub use field_element::*;
pub mod value;
pub use value::*;
pub mod statement;
pub use statement::*;

View File

@ -0,0 +1,88 @@
use crate::errors::{BooleanError, ExpressionError, FieldElementError, IntegerError, ValueError};
#[derive(Debug, Error)]
pub enum StatementError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("Attempted to assign to unknown variable {}", _0)]
UndefinedVariable(String),
#[error("{}", _0)]
ExpressionError(ExpressionError),
#[error("{}", _0)]
IntegerError(IntegerError),
#[error("{}", _0)]
FieldElementError(FieldElementError),
#[error("{}", _0)]
BooleanError(BooleanError),
#[error("{}", _0)]
ValueError(ValueError),
#[error("Cannot assign single index to array of values")]
ArrayAssignIndex,
#[error("Cannot assign range of array values to single value")]
ArrayAssignRange,
#[error("Cannot assign to unknown array {}", _0)]
UndefinedArray(String),
#[error("Attempted to assign to unknown struct {}", _0)]
UndefinedStruct(String),
#[error("Attempted to assign to unknown struct field {}", _0)]
UndefinedStructField(String),
#[error("Function return statement expected {} return values, got {}", _0, _1)]
InvalidNumberOfReturns(usize, usize),
#[error("If, else conditional must resolve to a boolean, got {}", _0)]
IfElseConditional(String),
#[error("Cannot assert equality between {} == {}", _0, _1)]
AssertEq(String, String),
#[error("Expected assignment of return values for expression {}", _0)]
Unassigned(String),
}
impl From<std::io::Error> for StatementError {
fn from(error: std::io::Error) -> Self {
StatementError::Crate("std::io", format!("{}", error))
}
}
impl From<ExpressionError> for StatementError {
fn from(error: ExpressionError) -> Self {
StatementError::ExpressionError(error)
}
}
impl From<IntegerError> for StatementError {
fn from(error: IntegerError) -> Self {
StatementError::IntegerError(error)
}
}
impl From<FieldElementError> for StatementError {
fn from(error: FieldElementError) -> Self {
StatementError::FieldElementError(error)
}
}
impl From<BooleanError> for StatementError {
fn from(error: BooleanError) -> Self {
StatementError::BooleanError(error)
}
}
impl From<ValueError> for StatementError {
fn from(error: ValueError) -> Self {
StatementError::ValueError(error)
}
}

View File

@ -0,0 +1,34 @@
use crate::errors::IntegerError;
#[derive(Debug, Error)]
pub enum ValueError {
/// Unexpected array length
#[error("{}", _0)]
ArrayLength(String),
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("{}", _0)]
IntegerError(IntegerError),
/// Unexpected struct name
#[error("{}", _0)]
StructName(String),
/// Unexpected type
#[error("{}", _0)]
TypeError(String),
}
impl From<std::io::Error> for ValueError {
fn from(error: std::io::Error) -> Self {
ValueError::Crate("std::io", format!("{}", error))
}
}
impl From<IntegerError> for ValueError {
fn from(error: IntegerError) -> Self {
ValueError::IntegerError(error)
}
}

View File

@ -1,2 +1,5 @@
pub mod compiler;
pub use self::compiler::*;
pub mod constraints;
pub use self::constraints::*;

View File

@ -1,7 +1,7 @@
//! Module containing structs and types that make up a Leo program.
#[macro_use]
extern crate failure;
extern crate thiserror;
#[macro_use]
extern crate lazy_static;

View File

@ -1,9 +1,16 @@
//! A typed Leo program consists of import, struct, and function definitions.
//! Each defined type consists of typed statements and expressions.
use crate::Import;
use crate::{errors::IntegerError, Import};
use snarkos_models::curves::{Field, PrimeField};
use snarkos_models::gadgets::{
r1cs::Variable as R1CSVariable,
utilities::{
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
uint8::UInt8,
},
};
use std::collections::HashMap;
use std::marker::PhantomData;
@ -17,24 +24,52 @@ pub struct Variable<F: Field + PrimeField> {
/// An integer type enum wrapping the integer value. Used only in expressions.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Integer {
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
U8(UInt8),
U16(UInt16),
U32(UInt32),
U64(UInt64),
U128(UInt128),
}
impl Integer {
pub fn to_usize(&self) -> usize {
match *self {
Integer::U8(num) => num as usize,
Integer::U32(num) => num as usize,
Integer::U16(num) => num as usize,
Integer::U64(num) => num as usize,
Integer::U128(num) => num as usize,
// U64(u64)
match self {
Integer::U8(u8) => u8.value.unwrap() as usize,
Integer::U16(u16) => u16.value.unwrap() as usize,
Integer::U32(u32) => u32.value.unwrap() as usize,
Integer::U64(u64) => u64.value.unwrap() as usize,
Integer::U128(u128) => u128.value.unwrap() as usize,
}
}
pub(crate) fn get_type(&self) -> IntegerType {
match self {
Integer::U8(_u8) => IntegerType::U8,
Integer::U16(_u16) => IntegerType::U16,
Integer::U32(_u32) => IntegerType::U32,
Integer::U64(_u64) => IntegerType::U64,
Integer::U128(_u128) => IntegerType::U128,
}
}
pub(crate) fn expect_type(&self, integer_type: &IntegerType) -> Result<(), IntegerError> {
if self.get_type() != *integer_type {
unimplemented!(
"expected integer type {}, got {}",
self.get_type(),
integer_type
)
}
Ok(())
}
}
/// A constant or allocated element in the field
#[derive(Clone, PartialEq, Eq)]
pub enum FieldElement<F: Field + PrimeField> {
Constant(F),
Allocated(Option<F>, R1CSVariable),
}
/// Range or expression enum
@ -59,8 +94,8 @@ pub enum Expression<F: Field + PrimeField> {
// Values
Integer(Integer),
FieldElement(F),
Boolean(bool),
FieldElement(FieldElement<F>),
Boolean(Boolean),
// Number operations
Add(Box<Expression<F>>, Box<Expression<F>>),
@ -170,14 +205,14 @@ pub struct Struct<F: Field + PrimeField> {
/// Function parameters
#[derive(Clone, PartialEq, Eq)]
pub struct ParameterModel<F: Field + PrimeField> {
pub struct InputModel<F: Field + PrimeField> {
pub private: bool,
pub _type: Type<F>,
pub variable: Variable<F>,
}
#[derive(Clone, PartialEq, Eq)]
pub enum ParameterValue<F: Field + PrimeField> {
pub enum InputValue<F: Field + PrimeField> {
Integer(usize),
Field(F),
Boolean(bool),
@ -190,7 +225,7 @@ pub struct FunctionName(pub String);
#[derive(Clone, PartialEq, Eq)]
pub struct Function<F: Field + PrimeField> {
pub function_name: FunctionName,
pub parameters: Vec<ParameterModel<F>>,
pub inputs: Vec<InputModel<F>>,
pub returns: Vec<Type<F>>,
pub statements: Vec<Statement<F>>,
}

View File

@ -1,9 +1,9 @@
//! Format display functions for Leo types.
use crate::{
Assignee, ConditionalNestedOrEnd, ConditionalStatement, Expression, Function, FunctionName,
Integer, IntegerType, ParameterModel, ParameterValue, RangeOrExpression, SpreadOrExpression,
Statement, Struct, StructField, Type, Variable,
Assignee, ConditionalNestedOrEnd, ConditionalStatement, Expression, FieldElement, Function,
FunctionName, InputModel, InputValue, Integer, IntegerType, RangeOrExpression,
SpreadOrExpression, Statement, Struct, StructField, Type, Variable,
};
use snarkos_models::curves::{Field, PrimeField};
@ -22,16 +22,37 @@ impl<F: Field + PrimeField> fmt::Debug for Variable<F> {
impl fmt::Display for Integer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.to_usize(), self.get_type())
}
}
impl<F: Field + PrimeField> FieldElement<F> {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Integer::U8(ref num) => write!(f, "{}u8", num),
Integer::U16(ref num) => write!(f, "{}u16", num),
Integer::U32(ref num) => write!(f, "{}u32", num),
Integer::U64(ref num) => write!(f, "{}u64", num),
Integer::U128(ref num) => write!(f, "{}u128", num),
FieldElement::Constant(ref constant) => write!(f, "{}", constant),
FieldElement::Allocated(ref option, ref _r1cs_var) => {
if option.is_some() {
write!(f, "{}", option.unwrap())
} else {
write!(f, "allocated fe")
}
}
}
}
}
impl<F: Field + PrimeField> fmt::Display for FieldElement<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl<F: Field + PrimeField> fmt::Debug for FieldElement<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl<'ast, F: Field + PrimeField> fmt::Display for RangeOrExpression<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
@ -68,7 +89,7 @@ impl<'ast, F: Field + PrimeField> fmt::Display for Expression<F> {
// Values
Expression::Integer(ref integer) => write!(f, "{}", integer),
Expression::FieldElement(ref fe) => write!(f, "{}", fe),
Expression::Boolean(ref bool) => write!(f, "{}", bool),
Expression::Boolean(ref bool) => write!(f, "{}", bool.get_value().unwrap()),
// Number operations
Expression::Add(ref left, ref right) => write!(f, "{} + {}", left, right),
@ -273,19 +294,19 @@ impl<F: Field + PrimeField> fmt::Debug for Struct<F> {
}
}
impl<F: Field + PrimeField> fmt::Display for ParameterModel<F> {
impl<F: Field + PrimeField> fmt::Display for InputModel<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let visibility = if self.private { "private" } else { "public" };
write!(f, "{}: {} {}", self.variable, visibility, self._type,)
}
}
impl<F: Field + PrimeField> fmt::Display for ParameterValue<F> {
impl<F: Field + PrimeField> fmt::Display for InputValue<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ParameterValue::Integer(ref integer) => write!(f, "{}", integer),
ParameterValue::Field(ref field) => write!(f, "{}", field),
ParameterValue::Boolean(ref bool) => write!(f, "{}", bool),
InputValue::Integer(ref integer) => write!(f, "{}", integer),
InputValue::Field(ref field) => write!(f, "{}", field),
InputValue::Boolean(ref bool) => write!(f, "{}", bool),
}
}
}
@ -312,7 +333,7 @@ impl<F: Field + PrimeField> Function<F> {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "function {}", self.function_name)?;
let parameters = self
.parameters
.inputs
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()

View File

@ -3,6 +3,10 @@
use crate::{ast, types, Import, ImportSymbol};
use snarkos_models::curves::{Field, PrimeField};
use snarkos_models::gadgets::utilities::{
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
uint8::UInt8,
};
use std::{collections::HashMap, marker::PhantomData};
/// pest ast -> types::Variable
@ -26,21 +30,21 @@ impl<'ast, F: Field + PrimeField> From<ast::Variable<'ast>> for types::Expressio
impl<'ast> types::Integer {
pub(crate) fn from(number: ast::Number<'ast>, _type: ast::IntegerType) -> Self {
match _type {
ast::IntegerType::U8Type(_u8) => {
types::Integer::U8(number.value.parse::<u8>().expect("unable to parse u8"))
}
ast::IntegerType::U16Type(_u16) => {
types::Integer::U16(number.value.parse::<u16>().expect("unable to parse u16"))
}
ast::IntegerType::U32Type(_u32) => {
types::Integer::U32(number.value.parse::<u32>().expect("unable to parse u32"))
}
ast::IntegerType::U64Type(_u64) => {
types::Integer::U64(number.value.parse::<u64>().expect("unable to parse u64"))
}
ast::IntegerType::U128Type(_u128) => {
types::Integer::U128(number.value.parse::<u128>().expect("unable to parse u128"))
}
ast::IntegerType::U8Type(_u8) => types::Integer::U8(UInt8::constant(
number.value.parse::<u8>().expect("unable to parse u8"),
)),
ast::IntegerType::U16Type(_u16) => types::Integer::U16(UInt16::constant(
number.value.parse::<u16>().expect("unable to parse u16"),
)),
ast::IntegerType::U32Type(_u32) => types::Integer::U32(UInt32::constant(
number.value.parse::<u32>().expect("unable to parse u32"),
)),
ast::IntegerType::U64Type(_u64) => types::Integer::U64(UInt64::constant(
number.value.parse::<u64>().expect("unable to parse u64"),
)),
ast::IntegerType::U128Type(_u128) => types::Integer::U128(UInt128::constant(
number.value.parse::<u128>().expect("unable to parse u128"),
)),
}
}
}
@ -50,13 +54,13 @@ impl<'ast, F: Field + PrimeField> From<ast::Integer<'ast>> for types::Expression
types::Expression::Integer(match field._type {
Some(_type) => types::Integer::from(field.number, _type),
// default integer type is u32
None => types::Integer::U32(
None => types::Integer::U32(UInt32::constant(
field
.number
.value
.parse::<u32>()
.expect("unable to parse u32"),
),
)),
})
}
}
@ -78,7 +82,7 @@ impl<'ast, F: Field + PrimeField> From<ast::RangeOrExpression<'ast>>
let to = range.to.map(|to| match types::Expression::<F>::from(to.0) {
types::Expression::Integer(number) => number,
expression => {
unimplemented!("Range bounds should be intgers, found {}", expression)
unimplemented!("Range bounds should be integers, found {}", expression)
}
});
@ -95,7 +99,9 @@ impl<'ast, F: Field + PrimeField> From<ast::RangeOrExpression<'ast>>
impl<'ast, F: Field + PrimeField> From<ast::Field<'ast>> for types::Expression<F> {
fn from(field: ast::Field<'ast>) -> Self {
types::Expression::FieldElement(F::from_str(&field.number.value).unwrap_or_default())
types::Expression::FieldElement(types::FieldElement::Constant(
F::from_str(&field.number.value).unwrap_or_default(),
))
}
}
@ -103,12 +109,12 @@ impl<'ast, F: Field + PrimeField> From<ast::Field<'ast>> for types::Expression<F
impl<'ast, F: Field + PrimeField> From<ast::Boolean<'ast>> for types::Expression<F> {
fn from(boolean: ast::Boolean<'ast>) -> Self {
types::Expression::Boolean(
types::Expression::Boolean(Boolean::Constant(
boolean
.value
.parse::<bool>()
.expect("unable to parse boolean"),
)
))
}
}
@ -652,7 +658,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Struct<'ast>> for types::Struct<F> {
/// pest ast -> function types::Parameters
impl<'ast, F: Field + PrimeField> From<ast::Parameter<'ast>> for types::ParameterModel<F> {
impl<'ast, F: Field + PrimeField> From<ast::Parameter<'ast>> for types::InputModel<F> {
fn from(parameter: ast::Parameter<'ast>) -> Self {
let _type = types::Type::from(parameter._type);
let variable = types::Variable::from(parameter.variable);
@ -662,13 +668,13 @@ impl<'ast, F: Field + PrimeField> From<ast::Parameter<'ast>> for types::Paramete
ast::Visibility::Private(_) => true,
ast::Visibility::Public(_) => false,
};
types::ParameterModel {
types::InputModel {
private,
_type,
variable,
}
} else {
types::ParameterModel {
types::InputModel {
private: true,
_type,
variable,
@ -691,7 +697,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Function<'ast>> for types::Function<
let parameters = function_definition
.parameters
.into_iter()
.map(|parameter| types::ParameterModel::from(parameter))
.map(|parameter| types::InputModel::from(parameter))
.collect();
let returns = function_definition
.returns
@ -706,7 +712,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Function<'ast>> for types::Function<
types::Function {
function_name,
parameters,
inputs: parameters,
returns,
statements,
}
@ -766,7 +772,7 @@ impl<'ast, F: Field + PrimeField> types::Program<F> {
});
if let Some(main_function) = functions.get(&types::FunctionName("main".into())) {
num_parameters = main_function.parameters.len();
num_parameters = main_function.inputs.len();
}
types::Program {