mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-25 13:53:29 +03:00
impl compiler error handling
This commit is contained in:
parent
dee7b2782e
commit
36018853a7
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -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"
|
||||
|
@ -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];
|
||||
}
|
@ -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
|
||||
|
@ -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" }
|
||||
|
@ -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
|
||||
|
||||
|
@ -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, ¶meter_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)?)
|
||||
}
|
||||
}
|
||||
|
@ -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!(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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, ¶meter_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))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
260
compiler/src/constraints/function.rs
Normal file
260
compiler/src/constraints/function.rs
Normal 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(())
|
||||
}
|
||||
}
|
113
compiler/src/constraints/import.rs
Normal file
113
compiler/src/constraints/import.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
}
|
@ -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 ¶meter_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
|
||||
)))
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -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, ¶meter_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, ¶meter.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, ¶meter.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()
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
@ -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, ¶meter_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, ¶meter.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, ¶meter.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()
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
@ -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, ¶meter_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, ¶meter.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, ¶meter.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()
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
@ -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, ¶meter_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, ¶meter.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, ¶meter.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()
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
@ -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, ¶meter_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, ¶meter.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, ¶meter.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()
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
¶meter.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(),
|
||||
¶meter.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(),
|
||||
¶meter.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"),
|
||||
}
|
||||
}
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
31
compiler/src/errors/constraints/boolean.rs
Normal file
31
compiler/src/errors/constraints/boolean.rs
Normal 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)
|
||||
}
|
||||
}
|
106
compiler/src/errors/constraints/expression.rs
Normal file
106
compiler/src/errors/constraints/expression.rs
Normal 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)
|
||||
}
|
||||
}
|
25
compiler/src/errors/constraints/field_element.rs
Normal file
25
compiler/src/errors/constraints/field_element.rs
Normal 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)
|
||||
}
|
||||
}
|
69
compiler/src/errors/constraints/function.rs
Normal file
69
compiler/src/errors/constraints/function.rs
Normal 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)
|
||||
}
|
||||
}
|
20
compiler/src/errors/constraints/import.rs
Normal file
20
compiler/src/errors/constraints/import.rs
Normal 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))
|
||||
}
|
||||
}
|
34
compiler/src/errors/constraints/integer.rs
Normal file
34
compiler/src/errors/constraints/integer.rs
Normal 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)
|
||||
}
|
||||
}
|
25
compiler/src/errors/constraints/mod.rs
Normal file
25
compiler/src/errors/constraints/mod.rs
Normal 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::*;
|
88
compiler/src/errors/constraints/statement.rs
Normal file
88
compiler/src/errors/constraints/statement.rs
Normal 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)
|
||||
}
|
||||
}
|
34
compiler/src/errors/constraints/value.rs
Normal file
34
compiler/src/errors/constraints/value.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -1,2 +1,5 @@
|
||||
pub mod compiler;
|
||||
pub use self::compiler::*;
|
||||
|
||||
pub mod constraints;
|
||||
pub use self::constraints::*;
|
||||
|
@ -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;
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
@ -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<_>>()
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user