Merge pull request #70 from AleoHQ/fix/namespace

Fix/namespace
This commit is contained in:
Collin Chin 2020-06-24 17:04:59 -07:00 committed by GitHub
commit d9583d0b13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 1616 additions and 864 deletions

41
Cargo.lock generated
View File

@ -64,6 +64,18 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base58"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
[[package]]
name = "bech32"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c"
[[package]]
name = "bincode"
version = "1.2.1"
@ -327,7 +339,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.31",
"syn 1.0.33",
]
[[package]]
@ -395,7 +407,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.31",
"syn 1.0.33",
"synstructure",
]
@ -837,7 +849,7 @@ dependencies = [
"pest_meta",
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.31",
"syn 1.0.33",
]
[[package]]
@ -1062,22 +1074,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.112"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243"
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.112"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57"
checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.31",
"syn 1.0.33",
]
[[package]]
@ -1185,13 +1197,15 @@ version = "0.1.0"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.31",
"syn 1.0.33",
]
[[package]]
name = "snarkos-errors"
version = "0.8.0"
dependencies = [
"base58",
"bech32",
"bincode",
"curl",
"hex",
@ -1235,6 +1249,7 @@ version = "0.8.0"
name = "snarkos-utilities"
version = "0.8.0"
dependencies = [
"bincode",
"rand",
"snarkos-derives",
"snarkos-errors",
@ -1277,9 +1292,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.31"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
@ -1294,7 +1309,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.31",
"syn 1.0.33",
"unicode-xid 0.2.0",
]
@ -1333,7 +1348,7 @@ checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.31",
"syn 1.0.33",
]
[[package]]

View File

@ -21,7 +21,7 @@ LINE_END = { ";" ~ NEWLINE* }
mutable = { "mut" }
// Declared in common/range.rs
range = { from_expression? ~ ".." ~ to_expression }
range = { from_expression? ~ ".." ~ to_expression? }
from_expression = { expression }
to_expression = { expression }

View File

@ -29,11 +29,11 @@ pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
}
impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
pub fn new() -> Self {
pub fn new(package_name: String) -> Self {
Self {
package_name: "".to_string(),
package_name: package_name.clone(),
main_file_path: PathBuf::new(),
program: Program::new(),
program: Program::new(package_name),
program_inputs: Inputs::new(),
output: None,
_engine: PhantomData,
@ -41,14 +41,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
}
pub fn init(package_name: String, main_file_path: PathBuf) -> Result<Self, CompilerError> {
let mut program = Self {
package_name,
main_file_path,
program: Program::new(),
program_inputs: Inputs::new(),
output: None,
_engine: PhantomData,
};
let mut program = Self::new(package_name);
program.set_path(main_file_path);
// Generate the abstract syntax tree and assemble the program
let program_string = program.load_program()?;
@ -57,6 +51,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
Ok(program)
}
pub fn set_path(&mut self, main_file_path: PathBuf) {
self.main_file_path = main_file_path
}
pub fn set_inputs(&mut self, program_inputs: Vec<Option<InputValue>>) {
self.program_inputs.set_inputs(program_inputs);
}
@ -78,7 +76,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
self,
cs: &mut CS,
) -> Result<ConstrainedValue<F, G>, CompilerError> {
generate_constraints(cs, self.program, self.program_inputs.get_inputs())
let path = self.main_file_path;
generate_constraints(cs, self.program, self.program_inputs.get_inputs()).map_err(|mut error| {
error.set_path(path);
error
})
}
pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem<F>) -> Result<(), CompilerError> {
@ -117,13 +120,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for Compiler<F, G> {
fn generate_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
let _result =
let result =
generate_constraints::<_, G, _>(cs, self.program, self.program_inputs.get_inputs()).map_err(|e| {
log::error!("{}", e);
SynthesisError::Unsatisfiable
})?;
// Write results to file or something
log::info!("{}", result);
Ok(())
}

View File

@ -1,11 +1,7 @@
//! Methods to enforce constraints on booleans in a resolved Leo program.
use crate::{
constraints::{ConstrainedProgram, ConstrainedValue},
errors::BooleanError,
GroupType,
};
use leo_types::InputValue;
use crate::{constraints::ConstrainedValue, errors::BooleanError, GroupType};
use leo_types::{InputValue, Span};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
@ -16,68 +12,96 @@ use snarkos_models::{
},
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub(crate) fn bool_from_input<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
name: String,
input_value: Option<InputValue>,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
// Check that the input value is the correct type
let bool_value = match input_value {
Some(input) => {
if let InputValue::Boolean(bool) = input {
Some(bool)
} else {
return Err(BooleanError::SynthesisError(SynthesisError::AssignmentMissing));
}
pub(crate) fn new_bool_constant(string: String, span: Span) -> Result<Boolean, BooleanError> {
let boolean = string
.parse::<bool>()
.map_err(|_| BooleanError::invalid_boolean(string, span))?;
Ok(Boolean::constant(boolean))
}
pub(crate) fn allocate_bool<F: Field + PrimeField, CS: ConstraintSystem<F>>(
cs: &mut CS,
name: String,
option: Option<bool>,
span: Span,
) -> Result<Boolean, BooleanError> {
let boolean_name = format!("{}: bool", name);
let boolean_name_unique = format!("`{}` {}:{}", boolean_name, span.line, span.start);
Boolean::alloc(cs.ns(|| boolean_name_unique), || {
option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| BooleanError::missing_boolean(boolean_name, span))
}
pub(crate) fn bool_from_input<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
cs: &mut CS,
name: String,
input_value: Option<InputValue>,
span: Span,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
// Check that the input value is the correct type
let option = match input_value {
Some(input) => {
if let InputValue::Boolean(bool) = input {
Some(bool)
} else {
return Err(BooleanError::invalid_boolean(name, span));
}
None => None,
};
let number = Boolean::alloc(cs.ns(|| name), || bool_value.ok_or(SynthesisError::AssignmentMissing))?;
Ok(ConstrainedValue::Boolean(number))
}
pub(crate) fn evaluate_not(value: ConstrainedValue<F, G>) -> Result<ConstrainedValue<F, G>, BooleanError> {
match value {
ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())),
value => Err(BooleanError::CannotEvaluate(format!("!{}", value))),
}
}
None => None,
};
pub(crate) fn enforce_or<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match (left, right) {
(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
))),
}
}
let number = allocate_bool(cs, name, option, span)?;
pub(crate) fn enforce_and<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match (left, right) {
(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
))),
}
Ok(ConstrainedValue::Boolean(number))
}
pub(crate) fn evaluate_not<F: Field + PrimeField, G: GroupType<F>>(
value: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match value {
ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())),
value => Err(BooleanError::cannot_evaluate(format!("!{}", value), span)),
}
}
pub(crate) fn enforce_or<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
let name = format!("{} || {}", left, right);
if let (ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) = (left, right) {
let name_unique = format!("{} {}:{}", name, span.line, span.start);
let result = Boolean::or(cs.ns(|| name_unique), &left_bool, &right_bool)
.map_err(|e| BooleanError::cannot_enforce(format!("||"), e, span))?;
return Ok(ConstrainedValue::Boolean(result));
}
Err(BooleanError::cannot_evaluate(name, span))
}
pub(crate) fn enforce_and<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
cs: &mut CS,
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
let name = format!("{} && {}", left, right);
if let (ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) = (left, right) {
let name_unique = format!("{} {}:{}", name, span.line, span.start);
let result = Boolean::and(cs.ns(|| name_unique), &left_bool, &right_bool)
.map_err(|e| BooleanError::cannot_enforce(format!("&&"), e, span))?;
return Ok(ConstrainedValue::Boolean(result));
}
Err(BooleanError::cannot_evaluate(name, span))
}

View File

@ -2,7 +2,10 @@
use crate::{
constraints::{ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue},
enforce_and,
enforce_or,
errors::ExpressionError,
evaluate_not,
new_scope,
FieldType,
GroupType,
@ -51,7 +54,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
return Err(ExpressionError::undefined_identifier(unresolved_identifier));
};
result_value.resolve_type(expected_types)?;
result_value.resolve_type(expected_types, unresolved_identifier.span.clone())?;
Ok(result_value)
}
@ -66,20 +69,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.add(cs, num_2)?))
Ok(ConstrainedValue::Integer(num_1.add(cs, num_2, span)?))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
Ok(ConstrainedValue::Field(fe_1.add(cs, &fe_2)?))
Ok(ConstrainedValue::Field(fe_1.add(cs, &fe_2, span)?))
}
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
Ok(ConstrainedValue::Group(ge_1.add(cs, &ge_2)?))
Ok(ConstrainedValue::Group(ge_1.add(cs, &ge_2, span)?))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.enforce_add_expression(cs, val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.enforce_add_expression(cs, val_1, val_2, span)
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
@ -98,20 +101,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.sub(cs, num_2)?))
Ok(ConstrainedValue::Integer(num_1.sub(cs, num_2, span)?))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
Ok(ConstrainedValue::Field(fe_1.sub(cs, &fe_2)?))
Ok(ConstrainedValue::Field(fe_1.sub(cs, &fe_2, span)?))
}
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
Ok(ConstrainedValue::Group(ge_1.sub(cs, &ge_2)?))
Ok(ConstrainedValue::Group(ge_1.sub(cs, &ge_2, span)?))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.enforce_sub_expression(cs, val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.enforce_sub_expression(cs, val_1, val_2, span)
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
@ -130,17 +133,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.mul(cs, num_2)?))
Ok(ConstrainedValue::Integer(num_1.mul(cs, num_2, span)?))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
Ok(ConstrainedValue::Field(fe_1.mul(cs, &fe_2)?))
Ok(ConstrainedValue::Field(fe_1.mul(cs, &fe_2, span)?))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.enforce_mul_expression(cs, val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.enforce_mul_expression(cs, val_1, val_2, span)
}
(val_1, val_2) => {
@ -161,17 +164,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.div(cs, num_2)?))
Ok(ConstrainedValue::Integer(num_1.div(cs, num_2, span)?))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
Ok(ConstrainedValue::Field(fe_1.div(cs, &fe_2)?))
Ok(ConstrainedValue::Field(fe_1.div(cs, &fe_2, span)?))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.enforce_div_expression(cs, val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.enforce_div_expression(cs, val_1, val_2, span)
}
(val_1, val_2) => {
@ -192,14 +195,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.pow(cs, num_2)?))
Ok(ConstrainedValue::Integer(num_1.pow(cs, num_2, span)?))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.enforce_pow_expression(cs, val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.enforce_pow_expression(cs, val_1, val_2, span)
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
@ -217,27 +220,27 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
right: ConstrainedValue<F, G>,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let mut expression_namespace = cs.ns(|| format!("evaluate {} == {}", left.to_string(), right.to_string()));
let result_bool = match (left, right) {
let mut unique_namespace = cs.ns(|| format!("evaluate {} == {} {}:{}", left, right, span.line, span.start));
let constraint_result = match (left, right) {
(ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => {
bool_1.evaluate_equal(expression_namespace, &bool_2)?
bool_1.evaluate_equal(unique_namespace, &bool_2)
}
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
num_1.evaluate_equal(expression_namespace, &num_2)?
num_1.evaluate_equal(unique_namespace, &num_2)
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
fe_1.evaluate_equal(expression_namespace, &fe_2)?
fe_1.evaluate_equal(unique_namespace, &fe_2)
}
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
ge_1.evaluate_equal(expression_namespace, &ge_2)?
ge_1.evaluate_equal(unique_namespace, &ge_2)
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
return self.evaluate_eq_expression(&mut expression_namespace, val_1, val_2, span);
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
return self.evaluate_eq_expression(&mut unique_namespace, val_1, val_2, span);
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
return self.evaluate_eq_expression(&mut expression_namespace, val_1, val_2, span);
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
return self.evaluate_eq_expression(&mut unique_namespace, val_1, val_2, span);
}
(val_1, val_2) => {
return Err(ExpressionError::incompatible_types(
@ -247,7 +250,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
};
Ok(ConstrainedValue::Boolean(result_bool))
let boolean =
constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate equals"), e, span))?;
Ok(ConstrainedValue::Boolean(boolean))
}
//TODO: unsafe for allocated values
@ -267,11 +273,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.evaluate_ge_expression(val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.evaluate_ge_expression(val_1, val_2, span)
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
@ -298,11 +304,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.evaluate_gt_expression(val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.evaluate_gt_expression(val_1, val_2, span)
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
@ -329,11 +335,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.evaluate_le_expression(val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.evaluate_le_expression(val_1, val_2, span)
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
@ -360,11 +366,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.evaluate_lt_expression(val_1, val_2, span)
}
(val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.evaluate_lt_expression(val_1, val_2, span)
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
@ -397,25 +403,47 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
value => return Err(ExpressionError::conditional_boolean(value.to_string(), span)),
};
let resolved_second =
self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), expected_types, second)?;
let resolved_third = self.enforce_expression_value(cs, file_scope, function_scope, expected_types, third)?;
let resolved_second = self.enforce_expression_value(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
second,
span.clone(),
)?;
let resolved_third =
self.enforce_expression_value(cs, file_scope, function_scope, expected_types, third, span.clone())?;
let unique_namespace = cs.ns(|| {
format!(
"select {} or {} {}:{}",
resolved_second, resolved_third, span.line, span.start
)
});
match (resolved_second, resolved_third) {
(ConstrainedValue::Boolean(bool_2), ConstrainedValue::Boolean(bool_3)) => {
let result = Boolean::conditionally_select(cs, &resolved_first, &bool_2, &bool_3)?;
let result = Boolean::conditionally_select(unique_namespace, &resolved_first, &bool_2, &bool_3)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?;
Ok(ConstrainedValue::Boolean(result))
}
(ConstrainedValue::Integer(integer_2), ConstrainedValue::Integer(integer_3)) => {
let result = Integer::conditionally_select(cs, &resolved_first, &integer_2, &integer_3)?;
let result = Integer::conditionally_select(unique_namespace, &resolved_first, &integer_2, &integer_3)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?;
Ok(ConstrainedValue::Integer(result))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = FieldType::conditionally_select(cs, &resolved_first, &fe_1, &fe_2)?;
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
let result = FieldType::conditionally_select(unique_namespace, &resolved_first, &field_1, &field_2)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?;
Ok(ConstrainedValue::Field(result))
}
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
let result = G::conditionally_select(cs, &resolved_first, &ge_1, &ge_2)?;
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
let result = G::conditionally_select(unique_namespace, &resolved_first, &point_1, &point_2)
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))?;
Ok(ConstrainedValue::Group(result))
}
(val_1, val_2) => Err(ExpressionError::incompatible_types(
@ -507,8 +535,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span: Span,
) -> Result<usize, ExpressionError> {
let expected_types = vec![Type::IntegerType(IntegerType::U32)];
match self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), &expected_types, index)? {
ConstrainedValue::Integer(number) => Ok(number.to_usize()),
match self.enforce_expression_value(
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
index,
span.clone(),
)? {
ConstrainedValue::Integer(number) => Ok(number.to_usize(span.clone())?),
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
}
}
@ -529,6 +564,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(),
expected_types,
*array,
span.clone(),
)? {
ConstrainedValue::Array(array) => array,
value => return Err(ExpressionError::undefined_array(value.to_string(), span)),
@ -537,11 +573,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
match index {
RangeOrExpression::Range(from, to) => {
let from_resolved = match from {
Some(from_index) => from_index.to_usize(),
Some(from_index) => from_index.to_usize(span.clone())?,
None => 0usize, // Array slice starts at index 0
};
let to_resolved = match to {
Some(to_index) => to_index.to_usize(),
Some(to_index) => to_index.to_usize(span.clone())?,
None => array.len(), // Array slice ends at array length
};
Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned()))
@ -633,6 +669,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(),
expected_types,
*circuit_identifier.clone(),
span.clone(),
)? {
ConstrainedValue::CircuitExpression(name, members) => (name, members),
value => return Err(ExpressionError::undefined_circuit(value.to_string(), span)),
@ -757,7 +794,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
value => return Err(ExpressionError::undefined_function(value.to_string(), span)),
};
match self.enforce_function(cs, outer_scope, function_scope, function_call, arguments) {
let name_unique = format!(
"function call {} {}:{}",
function_call.get_name(),
span.line,
span.start,
);
match self.enforce_function(
&mut cs.ns(|| name_unique),
outer_scope,
function_scope,
function_call,
arguments,
) {
Ok(ConstrainedValue::Return(return_values)) => {
if return_values.len() == 1 {
Ok(return_values[0].clone())
@ -773,9 +823,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub(crate) fn enforce_number_implicit(
expected_types: &Vec<Type>,
value: String,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
if expected_types.len() == 1 {
return Ok(ConstrainedValue::from_type(value, &expected_types[0])?);
return Ok(ConstrainedValue::from_type(value, &expected_types[0], span)?);
}
Ok(ConstrainedValue::Unresolved(value))
@ -791,11 +842,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String,
expected_types: &Vec<Type>,
expression: Expression,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_types, expression)?;
branch.get_inner_mut();
branch.resolve_type(expected_types)?;
branch.resolve_type(expected_types, span)?;
Ok(branch)
}
@ -808,13 +860,26 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
expected_types: &Vec<Type>,
left: Expression,
right: Expression,
span: Span,
) -> Result<(ConstrainedValue<F, G>, ConstrainedValue<F, G>), ExpressionError> {
let mut resolved_left =
self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), expected_types, left)?;
let mut resolved_right =
self.enforce_expression_value(cs, file_scope.clone(), function_scope.clone(), expected_types, right)?;
let mut resolved_left = self.enforce_expression_value(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
left,
span.clone(),
)?;
let mut resolved_right = self.enforce_expression_value(
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
right,
span.clone(),
)?;
resolved_left.resolve_types(&mut resolved_right, expected_types)?;
resolved_left.resolve_types(&mut resolved_right, expected_types, span)?;
Ok((resolved_left, resolved_right))
}
@ -835,10 +900,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Values
Expression::Integer(integer) => Ok(ConstrainedValue::Integer(integer)),
Expression::Field(field) => Ok(ConstrainedValue::Field(FieldType::constant(field)?)),
Expression::Group(group_affine) => Ok(ConstrainedValue::Group(G::constant(group_affine)?)),
Expression::Field(field, span) => Ok(ConstrainedValue::Field(FieldType::constant(field, span)?)),
Expression::Group(group_affine, span) => Ok(ConstrainedValue::Group(G::constant(group_affine, span)?)),
Expression::Boolean(bool) => Ok(ConstrainedValue::Boolean(bool)),
Expression::Implicit(value) => Self::enforce_number_implicit(expected_types, value),
Expression::Implicit(value, span) => Self::enforce_number_implicit(expected_types, value, span),
// Binary operations
Expression::Add(left, right, span) => {
@ -849,6 +914,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
expected_types,
*left,
*right,
span.clone(),
)?;
self.enforce_add_expression(cs, resolved_left, resolved_right, span)
@ -861,6 +927,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
expected_types,
*left,
*right,
span.clone(),
)?;
self.enforce_sub_expression(cs, resolved_left, resolved_right, span)
@ -873,6 +940,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
expected_types,
*left,
*right,
span.clone(),
)?;
self.enforce_mul_expression(cs, resolved_left, resolved_right, span)
@ -885,6 +953,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
expected_types,
*left,
*right,
span.clone(),
)?;
self.enforce_div_expression(cs, resolved_left, resolved_right, span)
@ -897,20 +966,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
expected_types,
*left,
*right,
span.clone(),
)?;
self.enforce_pow_expression(cs, resolved_left, resolved_right, span)
}
// Boolean operations
Expression::Not(expression) => Ok(Self::evaluate_not(self.enforce_expression(
cs,
file_scope,
function_scope,
expected_types,
*expression,
)?)?),
Expression::Or(left, right, _span) => {
Expression::Not(expression, span) => Ok(evaluate_not(
self.enforce_expression(cs, file_scope, function_scope, expected_types, *expression)?,
span,
)?),
Expression::Or(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
@ -918,11 +985,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
expected_types,
*left,
*right,
span.clone(),
)?;
Ok(self.enforce_or(cs, resolved_left, resolved_right)?)
Ok(enforce_or(cs, resolved_left, resolved_right, span)?)
}
Expression::And(left, right, _span) => {
Expression::And(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(
cs,
file_scope.clone(),
@ -930,9 +998,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
expected_types,
*left,
*right,
span.clone(),
)?;
Ok(self.enforce_and(cs, resolved_left, resolved_right)?)
Ok(enforce_and(cs, resolved_left, resolved_right, span)?)
}
Expression::Eq(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression(
@ -942,6 +1011,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
&vec![],
*left,
*right,
span.clone(),
)?;
Ok(self.evaluate_eq_expression(cs, resolved_left, resolved_right, span)?)
@ -954,6 +1024,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
&vec![],
*left,
*right,
span.clone(),
)?;
Ok(self.evaluate_ge_expression(resolved_left, resolved_right, span)?)
@ -966,6 +1037,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
&vec![],
*left,
*right,
span.clone(),
)?;
Ok(self.evaluate_gt_expression(resolved_left, resolved_right, span)?)
@ -978,6 +1050,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
&vec![],
*left,
*right,
span.clone(),
)?;
Ok(self.evaluate_le_expression(resolved_left, resolved_right, span)?)
@ -990,6 +1063,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
&vec![],
*left,
*right,
span.clone(),
)?;
Ok(self.evaluate_lt_expression(resolved_left, resolved_right, span)?)

View File

@ -1,7 +1,7 @@
//! Methods to enforce constraints on field elements in a resolved Leo program.
use crate::{constraints::ConstrainedValue, errors::FieldError, FieldType, GroupType};
use leo_types::InputValue;
use leo_types::{InputValue, Span};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
@ -9,24 +9,40 @@ use snarkos_models::{
gadgets::{r1cs::ConstraintSystem, utilities::alloc::AllocGadget},
};
pub(crate) fn allocate_field<F: Field + PrimeField, CS: ConstraintSystem<F>>(
cs: &mut CS,
name: String,
option: Option<String>,
span: Span,
) -> Result<FieldType<F>, FieldError> {
let field_name = format!("{}: field", name);
let field_name_unique = format!("`{}` {}:{}", field_name, span.line, span.start);
FieldType::alloc(cs.ns(|| field_name_unique), || {
option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| FieldError::missing_field(field_name, span))
}
pub(crate) fn field_from_input<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
cs: &mut CS,
name: String,
input_value: Option<InputValue>,
span: Span,
) -> Result<ConstrainedValue<F, G>, FieldError> {
// Check that the parameter value is the correct type
let field_option = match input_value {
let option = match input_value {
Some(input) => {
if let InputValue::Field(string) = input {
Some(string)
} else {
return Err(FieldError::Invalid(input.to_string()));
return Err(FieldError::invalid_field(input.to_string(), span));
}
}
None => None,
};
let field_value = FieldType::alloc(cs.ns(|| name), || field_option.ok_or(SynthesisError::AssignmentMissing))?;
let field = allocate_field(cs, name, option, span)?;
Ok(ConstrainedValue::Field(field_value))
Ok(ConstrainedValue::Field(field))
}

View File

@ -2,6 +2,7 @@
//! a resolved Leo program.
use crate::{
bool_from_input,
constraints::{new_scope, ConstrainedProgram, ConstrainedValue},
errors::{FunctionError, ImportError},
field_from_input,
@ -169,10 +170,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
integer_type,
name,
input_value,
span,
)?)),
Type::Field => Ok(field_from_input(cs, name, input_value)?),
Type::Group => Ok(group_from_input(cs, name, input_value)?),
Type::Boolean => Ok(self.bool_from_input(cs, name, input_value)?),
Type::Field => Ok(field_from_input(cs, name, input_value, span)?),
Type::Group => Ok(group_from_input(cs, name, input_value, span)?),
Type::Boolean => Ok(bool_from_input(cs, name, input_value, span)?),
Type::Array(_type, dimensions) => self.allocate_array(cs, name, *_type, dimensions, input_value, span),
_ => unimplemented!("main function input not implemented for type"),
}
@ -193,16 +195,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Iterate over main function inputs and allocate new passed-by variable values
let mut input_variables = vec![];
for (input_model, input_option) in function.inputs.clone().into_iter().zip(inputs.into_iter()) {
let input_name = new_scope(function_name.clone(), input_model.identifier.name.clone());
let input_value = self.allocate_main_function_input(
cs,
input_model._type,
input_name.clone(),
input_model.identifier.name.clone(),
input_option,
function.span.clone(),
)?;
// Store a new variable for every allocated main function input
let input_name = new_scope(function_name.clone(), input_model.identifier.name.clone());
self.store(input_name.clone(), input_value);
input_variables.push(Expression::Identifier(input_model.identifier));
@ -211,18 +213,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
self.enforce_function(cs, scope, function_name, function, input_variables)
}
pub(crate) fn resolve_definitions<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
program: Program,
) -> Result<(), ImportError> {
pub(crate) fn resolve_definitions(&mut self, program: Program) -> 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.clone(), import))
.map(|import| self.enforce_import(program_name.clone(), import))
.collect::<Result<Vec<_>, ImportError>>()?;
// evaluate and store all circuit definitions

View File

@ -1,5 +1,5 @@
use crate::{errors::GroupError, ConstrainedValue, GroupType};
use leo_types::InputValue;
use leo_types::{InputValue, Span};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
@ -7,24 +7,40 @@ use snarkos_models::{
gadgets::r1cs::ConstraintSystem,
};
pub(crate) fn allocate_group<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
cs: &mut CS,
name: String,
option: Option<String>,
span: Span,
) -> Result<G, GroupError> {
let group_name = format!("{}: group", name);
let group_name_unique = format!("`{}` {}:{}", group_name, span.line, span.start);
G::alloc(cs.ns(|| group_name_unique), || {
option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| GroupError::missing_group(group_name, span))
}
pub(crate) fn group_from_input<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
cs: &mut CS,
name: String,
input_value: Option<InputValue>,
span: Span,
) -> Result<ConstrainedValue<F, G>, GroupError> {
// Check that the parameter value is the correct type
let group_option = match input_value {
let option = match input_value {
Some(input) => {
if let InputValue::Group(string) = input {
Some(string)
} else {
return Err(GroupError::Invalid(input.to_string()));
return Err(GroupError::invalid_group(input.to_string(), span));
}
}
None => None,
};
let group_value = G::alloc(cs.ns(|| name), || group_option.ok_or(SynthesisError::AssignmentMissing))?;
let group = allocate_group(cs, name, option, span)?;
Ok(ConstrainedValue::Group(group_value))
Ok(ConstrainedValue::Group(group))
}

View File

@ -7,20 +7,12 @@ use crate::{
use leo_ast::LeoParser;
use leo_types::{Import, Program};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
use snarkos_models::curves::{Field, PrimeField};
use std::env::current_dir;
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn enforce_import<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
scope: String,
import: Import,
) -> Result<(), ImportError> {
let path = current_dir().map_err(|error| ImportError::DirectoryError(error))?;
pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> {
let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?;
// Sanitize the package path to the imports directory
let mut package_path = path.clone();
@ -48,9 +40,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// * -> import all imports, circuits, functions in the current scope
if import.is_star() {
// recursively evaluate program statements
self.resolve_definitions(cs, program).unwrap();
Ok(())
self.resolve_definitions(program)
} else {
let program_name = program.name.clone();
@ -75,11 +65,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
match matched_function {
Some((_function_name, function)) => ConstrainedValue::Function(None, function),
None => unimplemented!(
"cannot find imported symbol {} in imported file {}",
symbol,
program_name.clone()
),
None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)),
}
}
};
@ -96,7 +82,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
program
.imports
.into_iter()
.map(|nested_import| self.enforce_import(cs, program_name.clone(), nested_import))
.map(|nested_import| self.enforce_import(program_name.clone(), nested_import))
.collect::<Result<Vec<_>, ImportError>>()?;
Ok(())

View File

@ -1,7 +1,7 @@
//! Module containing methods to enforce constraints in an Leo program
pub mod boolean;
pub use boolean::*;
pub(crate) mod boolean;
pub(crate) use boolean::*;
pub mod function;
pub use function::*;
@ -44,7 +44,7 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
let program_name = program.get_name();
let main_function_name = new_scope(program_name.clone(), "main".into());
resolved_program.resolve_definitions(cs, program)?;
resolved_program.resolve_definitions(program)?;
let main = resolved_program
.get(&main_function_name)
@ -69,7 +69,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
let tests = program.tests.clone();
resolved_program.resolve_definitions(cs, program)?;
resolved_program.resolve_definitions(program)?;
log::info!("Running {} tests", tests.len());

View File

@ -21,6 +21,7 @@ use leo_types::{
Variable,
};
use crate::errors::ValueError;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
@ -74,12 +75,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Modify the single value of the array in place
match self.get_mutable_assignee(name, span.clone())? {
ConstrainedValue::Array(old) => {
new_value.resolve_type(&vec![old[index].to_type()])?;
new_value.resolve_type(&vec![old[index].to_type(span.clone())?], span.clone())?;
let selected_value =
ConstrainedValue::conditionally_select(cs, &condition, &new_value, &old[index]).map_err(
|_| StatementError::select_fail(new_value.to_string(), old[index].to_string(), span),
)?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value = ConstrainedValue::conditionally_select(
cs.ns(|| name_unique),
&condition,
&new_value,
&old[index],
)
.map_err(|_| {
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span)
})?;
old[index] = selected_value;
}
@ -88,11 +95,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
RangeOrExpression::Range(from, to) => {
let from_index = match from {
Some(integer) => integer.to_usize(),
Some(integer) => integer.to_usize(span.clone())?,
None => 0usize,
};
let to_index_option = match to {
Some(integer) => Some(integer.to_usize()),
Some(integer) => Some(integer.to_usize(span.clone())?),
None => None,
};
@ -107,8 +114,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
_ => return Err(StatementError::array_assign_range(span)),
};
let selected_array = ConstrainedValue::conditionally_select(cs, &condition, &new_array, old_array)
.map_err(|_| StatementError::select_fail(new_array.to_string(), old_array.to_string(), span))?;
let name_unique = format!("select {} {}:{}", new_array, span.line, span.start);
let selected_array =
ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_array, old_array)
.map_err(|_| StatementError::select_fail(new_array.to_string(), old_array.to_string(), span))?;
*old_array = selected_array;
}
}
@ -144,12 +154,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
return Err(StatementError::immutable_circuit_function("static".into(), span));
}
_ => {
new_value.resolve_type(&vec![object.1.to_type()])?;
new_value.resolve_type(&vec![object.1.to_type(span.clone())?], span.clone())?;
let selected_value =
ConstrainedValue::conditionally_select(cs, &condition, &new_value, &object.1).map_err(
|_| StatementError::select_fail(new_value.to_string(), object.1.to_string(), span),
)?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value = ConstrainedValue::conditionally_select(
cs.ns(|| name_unique),
&condition,
&new_value,
&object.1,
)
.map_err(|_| {
StatementError::select_fail(new_value.to_string(), object.1.to_string(), span)
})?;
object.1 = selected_value.to_owned();
}
@ -185,9 +201,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Assignee::Identifier(_identifier) => {
let condition = indicator.unwrap_or(Boolean::Constant(true));
let old_value = self.get_mutable_assignee(variable_name.clone(), span.clone())?;
new_value.resolve_type(&vec![old_value.to_type()])?;
let selected_value = ConstrainedValue::conditionally_select(cs, &condition, &new_value, old_value)
.map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span))?;
new_value.resolve_type(&vec![old_value.to_type(span.clone())?], span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value =
ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_value, old_value)
.map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span))?;
*old_value = selected_value;
@ -235,7 +255,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
declare: Declare,
variable: Variable,
expression: Expression,
_span: Span,
span: Span,
) -> Result<(), StatementError> {
let mut expected_types = vec![];
if let Some(ref _type) = variable._type {
@ -250,7 +270,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
)?;
if let Declare::Let = declare {
value.allocate_value(cs)?;
value.allocate_value(cs, span)?;
}
self.store_definition(function_scope, variable, value)
@ -298,6 +318,27 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Ok(())
}
fn check_return_types(expected: &Vec<Type>, actual: &Vec<Type>, span: Span) -> Result<(), StatementError> {
expected
.iter()
.zip(actual.iter())
.map(|(type_1, type_2)| {
if type_1.ne(type_2) {
// catch return Self type
if type_1.is_self() && type_2.is_circuit() {
Ok(())
} else {
Err(StatementError::arguments_type(type_1, type_2, span.clone()))
}
} else {
Ok(())
}
})
.collect::<Result<Vec<()>, StatementError>>()?;
Ok(())
}
fn enforce_return_statement<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
@ -317,7 +358,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
let mut returns = vec![];
for (expression, ty) in expressions.into_iter().zip(return_types.into_iter()) {
for (expression, ty) in expressions.into_iter().zip(return_types.clone().into_iter()) {
let expected_types = vec![ty.clone()];
let result = self.enforce_expression_value(
cs,
@ -325,11 +366,19 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(),
&expected_types,
expression,
span.clone(),
)?;
returns.push(result);
}
let actual_types = returns
.iter()
.map(|value| value.to_type(span.clone()))
.collect::<Result<Vec<Type>, ValueError>>()?;
Self::check_return_types(&return_types, &actual_types, span)?;
Ok(ConstrainedValue::Return(returns))
}
@ -390,12 +439,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
value => return Err(StatementError::conditional_boolean(value.to_string(), span)),
};
// Determine nested branch selection
// Determine nested branch 1 selection
let outer_indicator_string = outer_indicator
.get_value()
.map(|b| b.to_string())
.unwrap_or(format!("[allocated]"));
let inner_indicator_string = inner_indicator
.get_value()
.map(|b| b.to_string())
.unwrap_or(format!("[allocated]"));
let branch_1_name = format!(
"branch indicator 1 {} && {}",
outer_indicator_string, inner_indicator_string
);
let branch_1_indicator = Boolean::and(
&mut cs.ns(|| format!("statement branch 1 indicator {}", statement_string)),
&mut cs.ns(|| format!("branch 1 {} {}:{}", statement_string, span.line, span.start)),
&outer_indicator,
&inner_indicator,
)?;
)
.map_err(|_| StatementError::indicator_calculation(branch_1_name, span.clone()))?;
// Execute branch 1
self.evaluate_branch(
@ -407,13 +469,24 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
return_types.clone(),
)?;
// Execute branch 2
// Determine nested branch 2 selection
let inner_indicator = inner_indicator.not();
let inner_indicator_string = inner_indicator
.get_value()
.map(|b| b.to_string())
.unwrap_or(format!("[allocated]"));
let branch_2_name = format!(
"branch indicator 2 {} && {}",
outer_indicator_string, inner_indicator_string
);
let branch_2_indicator = Boolean::and(
&mut cs.ns(|| format!("statement branch 2 indicator {}", statement_string)),
&mut cs.ns(|| format!("branch 2 {} {}:{}", statement_string, span.line, span.start)),
&outer_indicator,
&inner_indicator.not(),
)?;
&inner_indicator,
)
.map_err(|_| StatementError::indicator_calculation(branch_2_name, span.clone()))?;
// Execute branch 2
match statement.next {
Some(next) => match next {
ConditionalNestedOrEndStatement::Nested(nested) => self.enforce_conditional_statement(
@ -434,7 +507,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
return_types,
),
},
None => Ok(None), // this is an if with no else, have to pass statements.conditional down to next statements somehow
None => Ok(None),
}
}
@ -449,24 +522,26 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
stop: Integer,
statements: Vec<Statement>,
return_types: Vec<Type>,
_span: Span,
span: Span,
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
let mut res = None;
let from = start.to_usize(span.clone())?;
let to = stop.to_usize(span.clone())?;
for i in start.to_usize()..stop.to_usize() {
for i in from..to {
// Store index in current function scope.
// For loop scope is not implemented.
let index_name = new_scope(function_scope.clone(), index.to_string());
self.store(
index_name,
ConstrainedValue::Integer(Integer::U32(UInt32::constant(i as u32))),
);
cs.ns(|| format!("loop {} = {}", index.to_string(), i));
// Evaluate statements and possibly return early
let name_unique = format!("for loop iteration {} {}:{}", i, span.line, span.start);
if let Some(early_return) = self.evaluate_branch(
cs,
&mut cs.ns(|| name_unique),
file_scope.clone(),
function_scope.clone(),
indicator,
@ -490,7 +565,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span: Span,
) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true));
let result = left.conditional_enforce_equal(cs, right, &condition);
let name_unique = format!("assert {} == {} {}:{}", left, right, span.line, span.start);
let result = left.conditional_enforce_equal(cs.ns(|| name_unique), right, &condition);
Ok(result.map_err(|_| StatementError::assertion_failed(left.to_string(), right.to_string(), span))?)
}
@ -556,7 +632,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
Statement::AssertEq(left, right, span) => {
let (resolved_left, resolved_right) =
self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, right)?;
self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, right, span.clone())?;
self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right, span)?;
}

View File

@ -1,20 +1,22 @@
//! The in memory stored value for a defined name in a resolved Leo program.
use crate::{errors::ValueError, FieldType, GroupType};
use leo_types::{Circuit, Function, Identifier, Integer, IntegerType, Type};
use crate::{
allocate_bool,
allocate_field,
allocate_group,
errors::ValueError,
new_bool_constant,
FieldType,
GroupType,
};
use leo_types::{Circuit, Function, Identifier, Integer, Span, Type};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{
alloc::AllocGadget,
boolean::Boolean,
eq::ConditionalEqGadget,
select::CondSelectGadget,
uint::{UInt128, UInt16, UInt32, UInt64, UInt8},
},
utilities::{boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget},
},
};
use std::fmt;
@ -43,43 +45,55 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
}
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
pub(crate) fn from_other(value: String, other: &ConstrainedValue<F, G>) -> Result<Self, ValueError> {
let other_type = other.to_type();
pub(crate) fn from_other(value: String, other: &ConstrainedValue<F, G>, span: Span) -> Result<Self, ValueError> {
let other_type = other.to_type(span.clone())?;
ConstrainedValue::from_type(value, &other_type)
ConstrainedValue::from_type(value, &other_type, span)
}
pub(crate) fn from_type(value: String, _type: &Type) -> Result<Self, ValueError> {
pub(crate) fn from_type(value: String, _type: &Type, span: Span) -> Result<Self, ValueError> {
match _type {
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(match integer_type {
IntegerType::U8 => Integer::U8(UInt8::constant(value.parse::<u8>()?)),
IntegerType::U16 => Integer::U16(UInt16::constant(value.parse::<u16>()?)),
IntegerType::U32 => Integer::U32(UInt32::constant(value.parse::<u32>()?)),
IntegerType::U64 => Integer::U64(UInt64::constant(value.parse::<u64>()?)),
IntegerType::U128 => Integer::U128(UInt128::constant(value.parse::<u128>()?)),
})),
Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value)?)),
Type::Group => Ok(ConstrainedValue::Group(G::constant(value)?)),
Type::Boolean => Ok(ConstrainedValue::Boolean(Boolean::Constant(value.parse::<bool>()?))),
Type::Array(ref _type, _dimensions) => ConstrainedValue::from_type(value, _type),
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::new_constant(
integer_type,
value,
span,
)?)),
Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)),
Type::Group => Ok(ConstrainedValue::Group(G::constant(value, span)?)),
Type::Boolean => Ok(ConstrainedValue::Boolean(new_bool_constant(value, span)?)),
Type::Array(ref _type, _dimensions) => ConstrainedValue::from_type(value, _type, span),
_ => Ok(ConstrainedValue::Unresolved(value)),
}
}
pub(crate) fn to_type(&self) -> Type {
match self {
pub(crate) fn to_type(&self, span: Span) -> Result<Type, ValueError> {
Ok(match self {
ConstrainedValue::Integer(integer) => Type::IntegerType(integer.get_type()),
ConstrainedValue::Field(_field) => Type::Field,
ConstrainedValue::Group(_group) => Type::Group,
ConstrainedValue::Boolean(_bool) => Type::Boolean,
_ => unimplemented!("to type only implemented for primitives"),
}
ConstrainedValue::Array(types) => {
let array_type = types[0].to_type(span.clone())?;
let count = types.len();
// nested array type
if let Type::Array(inner_type, inner_dimensions) = &array_type {
let mut dimensions = inner_dimensions.clone();
dimensions.push(count);
return Ok(Type::Array(inner_type.clone(), dimensions));
}
Type::Array(Box::new(array_type), vec![count])
}
ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.clone()),
value => return Err(ValueError::implicit(value.to_string(), span)),
})
}
pub(crate) fn resolve_type(&mut self, types: &Vec<Type>) -> Result<(), ValueError> {
pub(crate) fn resolve_type(&mut self, types: &Vec<Type>, span: Span) -> Result<(), ValueError> {
if let ConstrainedValue::Unresolved(ref string) = self {
if !types.is_empty() {
*self = ConstrainedValue::from_type(string.clone(), &types[0])?
*self = ConstrainedValue::from_type(string.clone(), &types[0], span)?
}
}
@ -87,16 +101,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
}
/// Expect both `self` and `other` to resolve to the same type
pub(crate) fn resolve_types(&mut self, other: &mut Self, types: &Vec<Type>) -> Result<(), ValueError> {
pub(crate) fn resolve_types(&mut self, other: &mut Self, types: &Vec<Type>, span: Span) -> Result<(), ValueError> {
if !types.is_empty() {
self.resolve_type(types)?;
return other.resolve_type(types);
self.resolve_type(types, span.clone())?;
return other.resolve_type(types, span);
}
match (&self, &other) {
(ConstrainedValue::Unresolved(_), ConstrainedValue::Unresolved(_)) => Ok(()),
(ConstrainedValue::Unresolved(_), _) => self.resolve_type(&vec![other.to_type()]),
(_, ConstrainedValue::Unresolved(_)) => other.resolve_type(&vec![self.to_type()]),
(ConstrainedValue::Unresolved(_), _) => self.resolve_type(&vec![other.to_type(span.clone())?], span),
(_, ConstrainedValue::Unresolved(_)) => other.resolve_type(&vec![self.to_type(span.clone())?], span),
_ => Ok(()),
}
}
@ -107,37 +121,44 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
}
}
pub(crate) fn allocate_value<CS: ConstraintSystem<F>>(&mut self, mut cs: CS) -> Result<(), ValueError> {
pub(crate) fn allocate_value<CS: ConstraintSystem<F>>(&mut self, mut cs: CS, span: Span) -> Result<(), ValueError> {
match self {
// allocated values
ConstrainedValue::Boolean(boolean) => {
let option = boolean.get_value();
let name = option.map(|b| b.to_string()).unwrap_or(format!("[allocated]"));
*boolean = Boolean::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?;
*boolean = allocate_bool(&mut cs, name, option, span)?;
}
ConstrainedValue::Integer(integer) => {
let integer_type = integer.get_type();
let option = integer.get_value();
let name = format!("clone {}", integer);
let name = option.map(|n| n.to_string()).unwrap_or(format!("[allocated]"));
*integer = Integer::allocate_type(&mut cs, integer_type, name, option)?;
*integer = Integer::allocate_type(&mut cs, integer_type, name, option, span)?;
}
ConstrainedValue::Field(field) => {
let option = field.get_value().map(|v| format!("{}", v));
let name = option.clone().map(|f| f.to_string()).unwrap_or(format!("[allocated]"));
*field = FieldType::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?;
*field = allocate_field(&mut cs, name, option, span)?;
}
ConstrainedValue::Group(group) => {
let string = format!("{}", group); // may need to implement u256 -> decimal formatting
let name = format!("{}", group); // may need to implement u256 -> decimal formatting
let option = Some(name.clone());
*group = G::alloc(cs, || Ok(string))?;
*group = allocate_group(&mut cs, name, option, span)?;
}
// value wrappers
ConstrainedValue::Array(array) => {
array
.iter_mut()
.enumerate()
.map(|(i, value)| value.allocate_value(cs.ns(|| format!("allocate array member {}", i))))
.map(|(i, value)| {
let unique_name = format!("allocate array member {} {}:{}", i, span.line, span.start);
value.allocate_value(cs.ns(|| unique_name), span.clone())
})
.collect::<Result<(), ValueError>>()?;
}
ConstrainedValue::CircuitExpression(_id, members) => {
@ -145,9 +166,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
.iter_mut()
.enumerate()
.map(|(i, member)| {
member
.1
.allocate_value(cs.ns(|| format!("allocate circuit member {}", i)))
let unique_name = format!("allocate circuit member {} {}:{}", i, span.line, span.start);
member.1.allocate_value(cs.ns(|| unique_name), span.clone())
})
.collect::<Result<(), ValueError>>()?;
}
@ -155,20 +176,24 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
array
.iter_mut()
.enumerate()
.map(|(i, value)| value.allocate_value(cs.ns(|| format!("allocate return member {}", i))))
.map(|(i, value)| {
let unique_name = format!("allocate return member {} {}:{}", i, span.line, span.start);
value.allocate_value(cs.ns(|| unique_name), span.clone())
})
.collect::<Result<(), ValueError>>()?;
}
ConstrainedValue::Mutable(value) => {
value.allocate_value(cs)?;
value.allocate_value(cs, span)?;
}
ConstrainedValue::Static(value) => {
value.allocate_value(cs)?;
value.allocate_value(cs, span)?;
}
// empty wrappers
ConstrainedValue::CircuitDefinition(_) => {}
ConstrainedValue::Function(_, _) => {}
ConstrainedValue::Unresolved(_) => {
return Err(ValueError::SynthesisError(SynthesisError::AssignmentMissing));
ConstrainedValue::Unresolved(value) => {
return Err(ValueError::implicit(value.to_string(), span));
}
}
@ -182,7 +207,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
ConstrainedValue::Integer(ref value) => write!(f, "{}", value),
ConstrainedValue::Field(ref value) => write!(f, "{:?}", value),
ConstrainedValue::Group(ref value) => write!(f, "{:?}", value),
ConstrainedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()),
ConstrainedValue::Boolean(ref value) => write!(
f,
"{}",
value
.get_value()
.map(|v| v.to_string())
.unwrap_or(format!("[allocated]"))
),
ConstrainedValue::Array(ref array) => {
write!(f, "[")?;
for (i, e) in array.iter().enumerate() {
@ -213,10 +245,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
}
write!(f, "]")
}
ConstrainedValue::CircuitDefinition(ref _definition) => {
unimplemented!("cannot return circuit definition in program")
ConstrainedValue::CircuitDefinition(ref circuit) => write!(f, "circuit {{ {} }}", circuit.circuit_name),
ConstrainedValue::Function(ref _circuit_option, ref function) => {
write!(f, "function {{ {}() }}", function.function_name)
}
ConstrainedValue::Function(ref _circuit_option, ref function) => write!(f, "{}", function),
ConstrainedValue::Mutable(ref value) => write!(f, "mut {}", value),
ConstrainedValue::Static(ref value) => write!(f, "static {}", value),
ConstrainedValue::Unresolved(ref value) => write!(f, "unresolved {}", value),
@ -238,33 +270,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConditionalEqGadget<F> for Constrai
condition: &Boolean,
) -> Result<(), SynthesisError> {
match (self, other) {
(ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => bool_1.conditional_enforce_equal(
cs.ns(|| format!("{} == {}", self.to_string(), other.to_string())),
bool_2,
&condition,
),
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => num_1.conditional_enforce_equal(
cs.ns(|| format!("{} == {}", self.to_string(), other.to_string())),
num_2,
&condition,
),
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => field_1.conditional_enforce_equal(
cs.ns(|| format!("{} == {}", self.to_string(), other.to_string())),
field_2,
&condition,
),
(ConstrainedValue::Group(group_1), ConstrainedValue::Group(group_2)) => group_1.conditional_enforce_equal(
cs.ns(|| format!("{} == {}", self.to_string(), other.to_string())),
group_2,
&condition,
),
(ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => {
bool_1.conditional_enforce_equal(cs, bool_2, &condition)
}
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
num_1.conditional_enforce_equal(cs, num_2, &condition)
}
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
field_1.conditional_enforce_equal(cs, field_2, &condition)
}
(ConstrainedValue::Group(group_1), ConstrainedValue::Group(group_2)) => {
group_1.conditional_enforce_equal(cs, group_2, &condition)
}
(ConstrainedValue::Array(arr_1), ConstrainedValue::Array(arr_2)) => {
for (i, (left, right)) in arr_1.into_iter().zip(arr_2.into_iter()).enumerate() {
left.conditional_enforce_equal(
cs.ns(|| format!("array[{}] equal {} == {}", i, left.to_string(), right.to_string())),
right,
&condition,
)?;
left.conditional_enforce_equal(cs.ns(|| format!("array[{}]", i)), right, &condition)?;
}
Ok(())
}
@ -286,49 +306,22 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
) -> Result<Self, SynthesisError> {
Ok(match (first, second) {
(ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => {
ConstrainedValue::Boolean(Boolean::conditionally_select(
cs.ns(|| format!("if cond ? {} else {}", first.to_string(), second.to_string())),
cond,
bool_1,
bool_2,
)?)
ConstrainedValue::Boolean(Boolean::conditionally_select(cs, cond, bool_1, bool_2)?)
}
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
ConstrainedValue::Integer(Integer::conditionally_select(
cs.ns(|| format!("if cond ? {} else {}", first.to_string(), second.to_string())),
cond,
num_1,
num_2,
)?)
ConstrainedValue::Integer(Integer::conditionally_select(cs, cond, num_1, num_2)?)
}
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
ConstrainedValue::Field(FieldType::conditionally_select(
cs.ns(|| format!("if cond ? {} else {}", first.to_string(), second.to_string())),
cond,
field_1,
field_2,
)?)
ConstrainedValue::Field(FieldType::conditionally_select(cs, cond, field_1, field_2)?)
}
(ConstrainedValue::Group(group_1), ConstrainedValue::Group(group_2)) => {
ConstrainedValue::Group(G::conditionally_select(
cs.ns(|| format!("if cond ? {} else {}", first.to_string(), second.to_string())),
cond,
group_1,
group_2,
)?)
ConstrainedValue::Group(G::conditionally_select(cs, cond, group_1, group_2)?)
}
(ConstrainedValue::Array(arr_1), ConstrainedValue::Array(arr_2)) => {
let mut array = vec![];
for (i, (first, second)) in arr_1.into_iter().zip(arr_2.into_iter()).enumerate() {
array.push(Self::conditionally_select(
cs.ns(|| {
format!(
"array[{}] = if cond ? {} else {}",
i,
first.to_string(),
second.to_string()
)
}),
cs.ns(|| format!("array[{}]", i,)),
cond,
first,
second,
@ -336,6 +329,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
}
ConstrainedValue::Array(array)
}
(ConstrainedValue::Mutable(first), _) => Self::conditionally_select(cs, cond, first, second)?,
(_, ConstrainedValue::Mutable(second)) => Self::conditionally_select(cs, cond, first, second)?,
(_, _) => return Err(SynthesisError::Unsatisfiable),
})
}

View File

@ -1,51 +1,38 @@
use crate::errors::{FunctionError, ImportError};
use leo_ast::{ParserError, SyntaxError};
use leo_ast::ParserError;
use leo_inputs::InputParserError;
use leo_types::IntegerError;
use std::{io, path::PathBuf};
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum CompilerError {
#[error("creating: {}", _0)]
Creating(io::Error),
#[error("Attempt to access current directory failed - {:?}", _0)]
DirectoryError(io::Error),
#[error("{}", _0)]
ImportError(#[from] ImportError),
#[error("{}", _0)]
InputParserError(#[from] InputParserError),
#[error("{}", _0)]
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
FunctionError(#[from] FunctionError),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("Syntax error. Cannot parse the file")]
FileParsingError,
#[error("Main function not found")]
#[error("`main` function not found")]
NoMain,
#[error("Main must be a function")]
#[error("`main` must be a function")]
NoMainFunction,
#[error("{}", _0)]
ParserError(#[from] ParserError),
#[error("{}", _0)]
SyntaxError(#[from] SyntaxError),
#[error("Unable to construct abstract syntax tree")]
SyntaxTreeError,
#[error("writing: {}", _0)]
Writing(io::Error),
}
impl CompilerError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
CompilerError::FunctionError(error) => error.set_path(path),
_ => {}
}
}
}

View File

@ -1,18 +1,49 @@
use snarkos_errors::gadgets::SynthesisError;
use leo_types::{Error as FormattedError, Span};
use std::str::ParseBoolError;
use snarkos_errors::gadgets::SynthesisError;
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum BooleanError {
#[error("Cannot evaluate {}", _0)]
CannotEvaluate(String),
#[error("Cannot enforce {}", _0)]
CannotEnforce(String),
#[error("{}", _0)]
ParseBoolError(#[from] ParseBoolError),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
Error(#[from] FormattedError),
}
impl BooleanError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
BooleanError::Error(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
BooleanError::Error(FormattedError::new_from_span(message, span))
}
pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self {
let message = format!(
"the boolean operation `{}` failed due to the synthesis error `{}`",
operation, error,
);
Self::new_from_span(message, span)
}
pub fn cannot_evaluate(operation: String, span: Span) -> Self {
let message = format!("no implementation found for `{}`", operation);
Self::new_from_span(message, span)
}
pub fn invalid_boolean(actual: String, span: Span) -> Self {
let message = format!("expected boolean input type, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn missing_boolean(expected: String, span: Span) -> Self {
let message = format!("expected boolean input `{}` not found", expected);
Self::new_from_span(message, span)
}
}

View File

@ -1,8 +1,8 @@
use crate::errors::{BooleanError, Error as FormattedError, FieldError, FunctionError, GroupError, ValueError};
use leo_types::{Identifier, IntegerError, Span};
use crate::errors::{BooleanError, FieldError, FunctionError, GroupError, ValueError};
use leo_types::{Error as FormattedError, Identifier, IntegerError, Span};
use snarkos_errors::gadgets::SynthesisError;
use std::num::ParseIntError;
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum ExpressionError {
@ -12,9 +12,6 @@ pub enum ExpressionError {
#[error("{}", _0)]
Error(#[from] FormattedError),
#[error("{}", _0)]
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
FieldError(#[from] FieldError),
@ -25,28 +22,46 @@ pub enum ExpressionError {
GroupError(#[from] GroupError),
#[error("{}", _0)]
ParseIntError(#[from] ParseIntError),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
ValueError(#[from] ValueError),
}
impl ExpressionError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
ExpressionError::BooleanError(error) => error.set_path(path),
ExpressionError::Error(error) => error.set_path(path),
ExpressionError::FieldError(error) => error.set_path(path),
ExpressionError::FunctionError(error) => error.set_path(path),
ExpressionError::GroupError(error) => error.set_path(path),
ExpressionError::IntegerError(error) => error.set_path(path),
ExpressionError::ValueError(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
ExpressionError::Error(FormattedError::new_from_span(message, span))
}
pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self {
let message = format!(
"the gadget operation `{}` failed due to synthesis error `{}`",
operation, error,
);
Self::new_from_span(message, span)
}
pub fn conditional_boolean(actual: String, span: Span) -> Self {
let message = format!("If, else conditional must resolve to a boolean, found `{}`", actual);
let message = format!("if, else conditional must resolve to a boolean, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn expected_circuit_member(expected: String, span: Span) -> Self {
let message = format!("Expected circuit member `{}`, not found", expected);
let message = format!("expected circuit member `{}`, not found", expected);
Self::new_from_span(message, span)
}
@ -64,50 +79,50 @@ impl ExpressionError {
}
pub fn invalid_index(actual: String, span: Span) -> Self {
let message = format!("Index must resolve to an integer, found `{}`", actual);
let message = format!("index must resolve to an integer, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn invalid_length(expected: usize, actual: usize, span: Span) -> Self {
let message = format!("Expected array length {}, found one with length {}", expected, actual);
let message = format!("expected array length {}, found one with length {}", expected, actual);
Self::new_from_span(message, span)
}
pub fn invalid_spread(actual: String, span: Span) -> Self {
let message = format!("Spread should contain an array, found `{}`", actual);
let message = format!("spread should contain an array, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn invalid_member_access(member: String, span: Span) -> Self {
let message = format!("Non-static member `{}` must be accessed using `.` syntax", member);
let message = format!("non-static member `{}` must be accessed using `.` syntax", member);
Self::new_from_span(message, span)
}
pub fn invalid_static_access(member: String, span: Span) -> Self {
let message = format!("Static member `{}` must be accessed using `::` syntax", member);
let message = format!("static member `{}` must be accessed using `::` syntax", member);
Self::new_from_span(message, span)
}
pub fn function_no_return(function: String, span: Span) -> Self {
let message = format!("Inline function call to `{}` did not return", function);
let message = format!("inline function call to `{}` did not return", function);
Self::new_from_span(message, span)
}
pub fn undefined_array(actual: String, span: Span) -> Self {
let message = format!("Array `{}` must be declared before it is used in an expression", actual);
let message = format!("array `{}` must be declared before it is used in an expression", actual);
Self::new_from_span(message, span)
}
pub fn undefined_circuit(actual: String, span: Span) -> Self {
let message = format!(
"Circuit `{}` must be declared before it is used in an expression",
"circuit `{}` must be declared before it is used in an expression",
actual
);
@ -122,7 +137,7 @@ impl ExpressionError {
pub fn undefined_function(function: String, span: Span) -> Self {
let message = format!(
"Function `{}` must be declared before it is used in an inline expression",
"function `{}` must be declared before it is used in an inline expression",
function
);

View File

@ -1,13 +1,49 @@
use leo_types::{Error as FormattedError, Span};
use snarkos_errors::gadgets::SynthesisError;
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum FieldError {
#[error("Expected field element parameter, got {}", _0)]
Invalid(String),
#[error("No multiplicative inverse found for field {}", _0)]
NoInverse(String),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
Error(#[from] FormattedError),
}
impl FieldError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
FieldError::Error(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
FieldError::Error(FormattedError::new_from_span(message, span))
}
pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self {
let message = format!(
"the field binary operation `{}` failed due to synthesis error `{}`",
operation, error,
);
Self::new_from_span(message, span)
}
pub fn invalid_field(actual: String, span: Span) -> Self {
let message = format!("expected field element input type, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn missing_field(expected: String, span: Span) -> Self {
let message = format!("expected integer input `{}` not found", expected);
Self::new_from_span(message, span)
}
pub fn no_inverse(field: String, span: Span) -> Self {
let message = format!("no multiplicative inverse found for field `{}`", field);
Self::new_from_span(message, span)
}
}

View File

@ -1,13 +1,6 @@
use crate::errors::{
BooleanError,
Error as FormattedError,
ExpressionError,
FieldError,
GroupError,
StatementError,
ValueError,
};
use leo_types::{IntegerError, Span};
use crate::errors::{BooleanError, ExpressionError, FieldError, GroupError, StatementError, ValueError};
use leo_types::{Error as FormattedError, IntegerError, Span};
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum FunctionError {
@ -37,6 +30,19 @@ pub enum FunctionError {
}
impl FunctionError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
FunctionError::BooleanError(error) => error.set_path(path),
FunctionError::ExpressionError(error) => error.set_path(path),
FunctionError::Error(error) => error.set_path(path),
FunctionError::FieldError(error) => error.set_path(path),
FunctionError::GroupError(error) => error.set_path(path),
FunctionError::IntegerError(error) => error.set_path(path),
FunctionError::StatementError(error) => error.set_path(path),
FunctionError::ValueError(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
FunctionError::Error(FormattedError::new_from_span(message, span))
}

View File

@ -1,10 +1,43 @@
use leo_types::{Error as FormattedError, Span};
use snarkos_errors::gadgets::SynthesisError;
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum GroupError {
#[error("Expected affine point, got {}", _0)]
Invalid(String),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
Error(#[from] FormattedError),
}
impl GroupError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
GroupError::Error(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
GroupError::Error(FormattedError::new_from_span(message, span))
}
pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self {
let message = format!(
"the group binary operation `{}` failed due to the synthesis error `{}`",
operation, error,
);
Self::new_from_span(message, span)
}
pub fn invalid_group(actual: String, span: Span) -> Self {
let message = format!("expected group affine point input type, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn missing_group(expected: String, span: Span) -> Self {
let message = format!("expected group input `{}` not found", expected);
Self::new_from_span(message, span)
}
}

View File

@ -1,21 +1,34 @@
use leo_ast::ParserError;
use leo_types::{Error as FormattedError, ImportSymbol, Span};
use std::{io, path::PathBuf};
#[derive(Debug, Error)]
pub enum ImportError {
#[error("Attempt to access current directory failed - {:?}", _0)]
DirectoryError(io::Error),
#[error("Syntax error. Cannot parse the file")]
FileParsingError,
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("{}", _0)]
Error(#[from] FormattedError),
#[error("{}", _0)]
ParserError(#[from] ParserError),
#[error("Unable to construct abstract syntax tree")]
SyntaxTreeError,
}
impl ImportError {
fn new_from_span(message: String, span: Span) -> Self {
ImportError::Error(FormattedError::new_from_span(message, span))
}
pub fn directory_error(error: io::Error, span: Span) -> Self {
let message = format!("attempt to access current directory failed - {:?}", error);
Self::new_from_span(message, span)
}
pub fn unknown_symbol(symbol: ImportSymbol, file: String, file_path: &PathBuf) -> Self {
let message = format!("cannot find imported symbol `{}` in imported file `{}`", symbol, file);
let mut error = FormattedError::new_from_span(message, symbol.span);
error.path = Some(format!("{:?}", file_path));
ImportError::Error(error)
}
}

View File

@ -1,31 +1,46 @@
use crate::errors::{BooleanError, Error as FormattedError, ExpressionError, ValueError};
use leo_types::Span;
use snarkos_errors::gadgets::SynthesisError;
use crate::errors::{BooleanError, ExpressionError, ValueError};
use leo_types::{Error as FormattedError, IntegerError, Span, Type};
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum StatementError {
#[error("{}", _0)]
Error(#[from] FormattedError),
BooleanError(#[from] BooleanError),
#[error("{}", _0)]
BooleanError(#[from] BooleanError),
Error(#[from] FormattedError),
#[error("{}", _0)]
ExpressionError(#[from] ExpressionError),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
ValueError(#[from] ValueError),
}
impl StatementError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
StatementError::BooleanError(error) => error.set_path(path),
StatementError::Error(error) => error.set_path(path),
StatementError::ExpressionError(error) => error.set_path(path),
StatementError::IntegerError(error) => error.set_path(path),
StatementError::ValueError(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
StatementError::Error(FormattedError::new_from_span(message, span))
}
pub fn arguments_type(expected: &Type, actual: &Type, span: Span) -> Self {
let message = format!("expected return argument type `{}`, found type `{}`", expected, actual);
Self::new_from_span(message, span)
}
pub fn array_assign_index(span: Span) -> Self {
let message = format!("Cannot assign single index to array of values");
@ -50,6 +65,27 @@ impl StatementError {
Self::new_from_span(message, span)
}
pub fn immutable_assign(name: String, span: Span) -> Self {
let message = format!("Cannot assign to immutable variable `{}`", name);
Self::new_from_span(message, span)
}
pub fn immutable_circuit_function(name: String, span: Span) -> Self {
let message = format!("Cannot mutate circuit function, `{}`", name);
Self::new_from_span(message, span)
}
pub fn indicator_calculation(name: String, span: Span) -> Self {
let message = format!(
"Constraint system failed to evaluate branch selection indicator `{}`",
name
);
Self::new_from_span(message, span)
}
pub fn invalid_number_of_definitions(expected: usize, actual: usize, span: Span) -> Self {
let message = format!(
"Multiple definition statement expected {} return values, found {} values",
@ -68,18 +104,6 @@ impl StatementError {
Self::new_from_span(message, span)
}
pub fn immutable_assign(name: String, span: Span) -> Self {
let message = format!("Cannot assign to immutable variable `{}`", name);
Self::new_from_span(message, span)
}
pub fn immutable_circuit_function(name: String, span: Span) -> Self {
let message = format!("Cannot mutate circuit function, `{}`", name);
Self::new_from_span(message, span)
}
pub fn select_fail(first: String, second: String, span: Span) -> Self {
let message = format!(
"Conditional select gadget failed to select between `{}` or `{}`",

View File

@ -1,11 +1,15 @@
use crate::errors::{FieldError, GroupError};
use leo_types::IntegerError;
use snarkos_errors::gadgets::SynthesisError;
use std::{num::ParseIntError, str::ParseBoolError};
use crate::errors::{BooleanError, FieldError, GroupError};
use leo_types::{Error as FormattedError, IntegerError, Span};
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum ValueError {
#[error("{}", _0)]
BooleanError(#[from] BooleanError),
#[error("{}", _0)]
Error(#[from] FormattedError),
#[error("{}", _0)]
FieldError(#[from] FieldError),
@ -14,13 +18,26 @@ pub enum ValueError {
#[error("{}", _0)]
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
ParseBoolError(#[from] ParseBoolError),
#[error("{}", _0)]
ParseIntError(#[from] ParseIntError),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
}
impl ValueError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
ValueError::BooleanError(error) => error.set_path(path),
ValueError::Error(error) => error.set_path(path),
ValueError::FieldError(error) => error.set_path(path),
ValueError::GroupError(error) => error.set_path(path),
ValueError::IntegerError(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
ValueError::Error(FormattedError::new_from_span(message, span))
}
pub fn implicit(value: String, span: Span) -> Self {
let message = format!("explicit type needed for `{}`", value);
Self::new_from_span(message, span)
}
}

View File

@ -3,6 +3,3 @@ pub use self::compiler::*;
pub mod constraints;
pub use self::constraints::*;
pub mod error;
pub use self::error::*;

View File

@ -1,6 +1,7 @@
//! A data type that represents a field value
use crate::errors::FieldError;
use leo_types::Span;
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
@ -35,82 +36,100 @@ impl<F: Field + PrimeField> FieldType<F> {
}
}
pub fn constant(string: String) -> Result<Self, FieldError> {
let value = F::from_str(&string).map_err(|_| FieldError::Invalid(string))?;
pub fn constant(string: String, span: Span) -> Result<Self, FieldError> {
let value = F::from_str(&string).map_err(|_| FieldError::invalid_field(string, span))?;
Ok(FieldType::Constant(value))
}
pub fn add<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Self, FieldError> {
pub fn add<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self, span: Span) -> Result<Self, FieldError> {
match (self, other) {
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
Ok(FieldType::Constant(self_value.add(other_value)))
}
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
let result = self_value.add(cs, other_value)?;
Ok(FieldType::Allocated(result))
}
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => {
Ok(FieldType::Allocated(allocated_value.add_constant(cs, constant_value)?))
}
}
}
pub fn sub<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Self, FieldError> {
match (self, other) {
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
Ok(FieldType::Constant(self_value.sub(other_value)))
}
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
let result = self_value.sub(cs, other_value)?;
Ok(FieldType::Allocated(result))
}
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => {
Ok(FieldType::Allocated(allocated_value.sub_constant(cs, constant_value)?))
}
}
}
pub fn mul<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Self, FieldError> {
match (self, other) {
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
Ok(FieldType::Constant(self_value.mul(other_value)))
}
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
let result = self_value.mul(cs, other_value)?;
let result = self_value
.add(cs, other_value)
.map_err(|e| FieldError::cannot_enforce(format!("+"), e, span))?;
Ok(FieldType::Allocated(result))
}
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(FieldType::Allocated(
allocated_value.mul_by_constant(cs, constant_value)?,
allocated_value
.add_constant(cs, constant_value)
.map_err(|e| FieldError::cannot_enforce(format!("+"), e, span))?,
)),
}
}
pub fn div<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Self, FieldError> {
pub fn sub<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self, span: Span) -> Result<Self, FieldError> {
match (self, other) {
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
Ok(FieldType::Constant(self_value.sub(other_value)))
}
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
let result = self_value
.sub(cs, other_value)
.map_err(|e| FieldError::cannot_enforce(format!("-"), e, span))?;
Ok(FieldType::Allocated(result))
}
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(FieldType::Allocated(
allocated_value
.sub_constant(cs, constant_value)
.map_err(|e| FieldError::cannot_enforce(format!("+"), e, span))?,
)),
}
}
pub fn mul<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self, span: Span) -> Result<Self, FieldError> {
match (self, other) {
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
Ok(FieldType::Constant(self_value.mul(other_value)))
}
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
let result = self_value
.mul(cs, other_value)
.map_err(|e| FieldError::cannot_enforce(format!("*"), e, span))?;
Ok(FieldType::Allocated(result))
}
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(FieldType::Allocated(
allocated_value
.mul_by_constant(cs, constant_value)
.map_err(|e| FieldError::cannot_enforce(format!("*"), e, span))?,
)),
}
}
pub fn div<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self, span: Span) -> Result<Self, FieldError> {
let inverse = match other {
FieldType::Constant(constant) => {
let constant_inverse = constant.inverse().ok_or(FieldError::NoInverse(constant.to_string()))?;
let constant_inverse = constant
.inverse()
.ok_or(FieldError::no_inverse(constant.to_string(), span.clone()))?;
FieldType::Constant(constant_inverse)
}
FieldType::Allocated(allocated) => {
let allocated_inverse = allocated.inverse(&mut cs)?;
let allocated_inverse = allocated
.inverse(&mut cs)
.map_err(|e| FieldError::cannot_enforce(format!("+"), e, span.clone()))?;
FieldType::Allocated(allocated_inverse)
}
};
self.mul(cs, &inverse)
self.mul(cs, &inverse, span)
}
pub fn alloc_helper<Fn: FnOnce() -> Result<T, SynthesisError>, T: Borrow<String>>(

View File

@ -1,4 +1,5 @@
use crate::{errors::GroupError, GroupType};
use leo_types::Span;
use snarkos_curves::{
edwards_bls12::{EdwardsAffine, EdwardsParameters, Fq},
@ -31,13 +32,14 @@ pub enum EdwardsGroupType {
}
impl GroupType<Fq> for EdwardsGroupType {
fn constant(string: String) -> Result<Self, GroupError> {
let value = Self::edwards_affine_from_str(string)?;
fn constant(string: String, span: Span) -> Result<Self, GroupError> {
let value =
Self::edwards_affine_from_str(string.clone()).map_err(|_| GroupError::invalid_group(string, span))?;
Ok(EdwardsGroupType::Constant(value))
}
fn add<CS: ConstraintSystem<Fq>>(&self, cs: CS, other: &Self) -> Result<Self, GroupError> {
fn add<CS: ConstraintSystem<Fq>>(&self, cs: CS, other: &Self, span: Span) -> Result<Self, GroupError> {
match (self, other) {
(EdwardsGroupType::Constant(self_value), EdwardsGroupType::Constant(other_value)) => {
Ok(EdwardsGroupType::Constant(self_value.add(other_value)))
@ -48,18 +50,24 @@ impl GroupType<Fq> for EdwardsGroupType {
self_value,
cs,
other_value,
)?;
)
.map_err(|e| GroupError::cannot_enforce(format!("+"), e, span))?;
Ok(EdwardsGroupType::Allocated(result))
}
(EdwardsGroupType::Constant(constant_value), EdwardsGroupType::Allocated(allocated_value))
| (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => Ok(
EdwardsGroupType::Allocated(allocated_value.add_constant(cs, constant_value)?),
),
| (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => {
Ok(EdwardsGroupType::Allocated(
allocated_value
.add_constant(cs, constant_value)
.map_err(|e| GroupError::cannot_enforce(format!("+"), e, span))?,
))
}
}
}
fn sub<CS: ConstraintSystem<Fq>>(&self, cs: CS, other: &Self) -> Result<Self, GroupError> {
fn sub<CS: ConstraintSystem<Fq>>(&self, cs: CS, other: &Self, span: Span) -> Result<Self, GroupError> {
match (self, other) {
(EdwardsGroupType::Constant(self_value), EdwardsGroupType::Constant(other_value)) => {
Ok(EdwardsGroupType::Constant(self_value.sub(other_value)))
@ -70,24 +78,30 @@ impl GroupType<Fq> for EdwardsGroupType {
self_value,
cs,
other_value,
)?;
)
.map_err(|e| GroupError::cannot_enforce(format!("-"), e, span))?;
Ok(EdwardsGroupType::Allocated(result))
}
(EdwardsGroupType::Constant(constant_value), EdwardsGroupType::Allocated(allocated_value))
| (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => Ok(
EdwardsGroupType::Allocated(allocated_value.sub_constant(cs, constant_value)?),
),
| (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => {
Ok(EdwardsGroupType::Allocated(
allocated_value
.sub_constant(cs, constant_value)
.map_err(|e| GroupError::cannot_enforce(format!("-"), e, span))?,
))
}
}
}
}
impl EdwardsGroupType {
pub fn edwards_affine_from_str(string: String) -> Result<EdwardsAffine, GroupError> {
pub fn edwards_affine_from_str(string: String) -> Result<EdwardsAffine, SynthesisError> {
// 0 or (0, 1)
match Fq::from_str(&string).ok() {
Some(x) => EdwardsAffine::get_point_from_x(x, false).ok_or(GroupError::Invalid(string)),
None => EdwardsAffine::from_str(&string).map_err(|_| GroupError::Invalid(string)),
Some(x) => EdwardsAffine::get_point_from_x(x, false).ok_or(SynthesisError::AssignmentMissing),
None => EdwardsAffine::from_str(&string).map_err(|_| SynthesisError::AssignmentMissing),
}
}
@ -102,7 +116,7 @@ impl EdwardsGroupType {
_ => Err(SynthesisError::AssignmentMissing),
}?;
Self::edwards_affine_from_str(affine_string).map_err(|_| SynthesisError::AssignmentMissing)
Self::edwards_affine_from_str(affine_string)
}
pub fn allocated<CS: ConstraintSystem<Fq>>(&self, mut cs: CS) -> Result<EdwardsBlsGadget, SynthesisError> {

View File

@ -1,6 +1,7 @@
//! A data type that represents members in the group formed by the set of affine points on a curve.
use crate::errors::GroupError;
use leo_types::Span;
use snarkos_models::{
curves::Field,
@ -32,9 +33,9 @@ pub trait GroupType<F: Field>:
+ ToBitsGadget<F>
+ ToBytesGadget<F>
{
fn constant(string: String) -> Result<Self, GroupError>;
fn constant(string: String, span: Span) -> Result<Self, GroupError>;
fn add<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Self, GroupError>;
fn add<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self, span: Span) -> Result<Self, GroupError>;
fn sub<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Self, GroupError>;
fn sub<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self, span: Span) -> Result<Self, GroupError>;
}

View File

@ -1,10 +1,17 @@
use crate::{get_error, get_output, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler};
use crate::{
get_error,
get_output,
integers::fail_integer,
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,
};
use leo_compiler::{
errors::{CompilerError, FunctionError},
ConstrainedValue,
};
use leo_inputs::types::{IntegerType, U32Type};
use leo_types::{InputValue, Integer, IntegerError};
use leo_types::{InputValue, Integer};
use snarkos_models::gadgets::utilities::uint::UInt32;
@ -42,14 +49,7 @@ fn output_multi(program: EdwardsTestCompiler) {
fn fail_array(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::Error(_string)) => {}
error => panic!("Expected invalid array error, got {}", error),
}
}
fn fail_synthesis(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::SynthesisError(_string))) => {}
error => panic!("Expected synthesis error, got {}", error),
error => panic!("Expected function error, found {}", error),
}
}
@ -128,5 +128,5 @@ fn test_input_field_none() {
program.set_inputs(vec![None]);
fail_synthesis(program)
fail_integer(program)
}

View File

@ -23,35 +23,19 @@ pub fn output_false(program: EdwardsTestCompiler) {
output_expected_boolean(program, false)
}
fn fail_evaluate(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::BooleanError(BooleanError::CannotEvaluate(_string)),
))) => {}
error => panic!("Expected evaluate error, got {}", error),
}
}
fn fail_enforce(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::BooleanError(BooleanError::CannotEnforce(_string)),
))) => {}
error => panic!("Expected evaluate error, got {}", error),
}
}
fn fail_boolean(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::SynthesisError(_))) => {}
error => panic!("Expected invalid boolean error, got {}", error),
CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::Error(_))) => {}
error => panic!("Expected boolean error, got {}", error),
}
}
fn fail_synthesis(program: EdwardsTestCompiler) {
fn fail_boolean_statement(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::SynthesisError(_string))) => {}
error => panic!("Expected synthesis error, got {}", error),
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::BooleanError(BooleanError::Error(_)),
))) => {}
_ => panic!("Expected boolean error, got {}"),
}
}
@ -88,7 +72,7 @@ fn test_input_bool_none() {
program.set_inputs(vec![None]);
fail_synthesis(program);
fail_boolean(program);
}
// Boolean not !
@ -114,7 +98,7 @@ fn test_not_u32() {
let bytes = include_bytes!("not_u32.leo");
let program = parse_program(bytes).unwrap();
fail_evaluate(program);
fail_boolean_statement(program)
}
// Boolean or ||
@ -148,7 +132,7 @@ fn test_true_or_u32() {
let bytes = include_bytes!("true_or_u32.leo");
let program = parse_program(bytes).unwrap();
fail_enforce(program);
fail_boolean_statement(program);
}
// Boolean and &&
@ -182,7 +166,7 @@ fn test_true_and_u32() {
let bytes = include_bytes!("true_and_u32.leo");
let program = parse_program(bytes).unwrap();
fail_enforce(program);
fail_boolean_statement(program);
}
// All

View File

@ -284,10 +284,12 @@ fn test_self() {
// All
// #[test]
// fn test_pedersen_mock() {
// let bytes = include_bytes!("pedersen_mock.leo");
// let program = parse_program(bytes).unwrap();
//
// output_zero(program);
// }
#[test]
fn test_pedersen_mock() {
use crate::integers::u32::output_zero;
let bytes = include_bytes!("pedersen_mock.leo");
let program = parse_program(bytes).unwrap();
output_zero(program);
}

View File

@ -54,18 +54,11 @@ fn output_one(program: EdwardsTestCompiler) {
fn fail_field(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::FieldError(FieldError::Invalid(_string))) => {}
CompilerError::FunctionError(FunctionError::FieldError(FieldError::Error(_string))) => {}
error => panic!("Expected invalid field error, got {}", error),
}
}
fn fail_synthesis(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::FieldError(FieldError::SynthesisError(_string))) => {}
error => panic!("Expected synthesis error, got {}", error),
}
}
#[test]
fn test_zero() {
let bytes = include_bytes!("zero.leo");
@ -110,7 +103,7 @@ fn test_input_fail_none() {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![None]);
fail_synthesis(program);
fail_field(program);
}
#[test]

View File

@ -0,0 +1,13 @@
function one() -> u32 {
return 1u32
}
function main() -> u32 {
let mut a = 0u32;
for i in 0..10 {
a += one();
}
return a
}

View File

@ -1,7 +1,8 @@
use crate::{
boolean::output_true,
get_error,
get_output,
integers::u32::output_one,
integers::u32::{output_number, output_one},
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,
@ -109,3 +110,28 @@ fn test_multiple_returns_main() {
output_multiple(program);
}
// Repeated calls
#[test]
fn test_repeated_function_call() {
let bytes = include_bytes!("repeated.leo");
let program = parse_program(bytes).unwrap();
output_true(program);
}
#[test]
fn test_iteration() {
let bytes = include_bytes!("iteration.leo");
let program = parse_program(bytes).unwrap();
output_number(program, 10);
}
#[test]
fn test_repeated_iteration() {
let bytes = include_bytes!("repeated_iteration.leo");
let program = parse_program(bytes).unwrap();
output_number(program, 20u32);
}

View File

@ -0,0 +1,7 @@
function test() -> bool {
return true
}
function main() -> bool {
return test() && test()
}

View File

@ -0,0 +1,13 @@
function iteration() -> u32 {
let mut a = 0u32;
for i in 0..10 {
a += 1;
}
return a
}
function main() -> u32 {
return iteration() + iteration()
}

View File

@ -44,7 +44,7 @@ macro_rules! test_uint {
// None input
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![None]);
fail_synthesis(program);
fail_integer(program);
}
fn test_add() {

View File

@ -48,18 +48,11 @@ pub trait IntegerTester {
pub(crate) fn fail_integer(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::InvalidInteger(_string))) => {}
CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::Error(_string))) => {}
error => panic!("Expected invalid boolean error, got {}", error),
}
}
pub(crate) fn fail_synthesis(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::SynthesisError(_string))) => {}
error => panic!("Expected synthesis error, got {}", error),
}
}
// must be below macro definitions!
pub mod u128;
pub mod u16;

View File

@ -2,7 +2,7 @@ use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
integers::{fail_integer, IntegerTester},
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,

View File

@ -2,7 +2,7 @@ use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
integers::{fail_integer, IntegerTester},
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,

View File

@ -2,7 +2,7 @@ use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
integers::{fail_integer, IntegerTester},
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,

View File

@ -2,7 +2,7 @@ use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
integers::{fail_integer, IntegerTester},
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,

View File

@ -2,7 +2,7 @@ use crate::{
boolean::{output_expected_boolean, output_false, output_true},
get_error,
get_output,
integers::{fail_integer, fail_synthesis, IntegerTester},
integers::{fail_integer, IntegerTester},
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,

View File

@ -20,6 +20,7 @@ use leo_compiler::{
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use std::path::PathBuf;
pub type EdwardsTestCompiler = Compiler<Fq, EdwardsGroupType>;
pub type EdwardsConstrainedValue = ConstrainedValue<Fq, EdwardsGroupType>;
@ -43,10 +44,18 @@ pub(crate) fn fail_enforce(program: EdwardsTestCompiler) {
}
}
pub(crate) fn parse_program(bytes: &[u8]) -> Result<EdwardsTestCompiler, CompilerError> {
let program_string = String::from_utf8_lossy(bytes);
fn new_compiler() -> EdwardsTestCompiler {
let program_name = "test".to_string();
let path = PathBuf::from("/test/src/main.leo");
let mut compiler = EdwardsTestCompiler::new(program_name);
compiler.set_path(path);
let mut compiler = EdwardsTestCompiler::new();
compiler
}
pub(crate) fn parse_program(bytes: &[u8]) -> Result<EdwardsTestCompiler, CompilerError> {
let mut compiler = new_compiler();
let program_string = String::from_utf8_lossy(bytes);
compiler.parse_program(&program_string)?;
@ -54,10 +63,9 @@ pub(crate) fn parse_program(bytes: &[u8]) -> Result<EdwardsTestCompiler, Compile
}
pub(crate) fn parse_inputs(bytes: &[u8]) -> Result<EdwardsTestCompiler, CompilerError> {
let mut compiler = new_compiler();
let inputs_string = String::from_utf8_lossy(bytes);
let mut compiler = EdwardsTestCompiler::new();
compiler.parse_inputs(&inputs_string)?;
Ok(compiler)

View File

@ -65,7 +65,5 @@ fn test_num_returns_fail() {
let bytes = include_bytes!("num_returns_fail.leo");
let program = parse_program(bytes).unwrap();
let error = get_error(program);
println!("{}", error);
let _ = get_error(program);
}

View File

@ -28,7 +28,7 @@ fn test_undefined() {
assert_eq!(
format!("{}", error),
vec![
" --> 2:10",
" --> \"/test/src/main.leo\": 2:10",
" |",
" 2 | return a",
" | ^",

View File

View File

@ -1,27 +1,16 @@
function fibonacci(i: u32) -> u32 {
if i == 0 {
return 0
} else if i == 1 {
return 1
} else {
return fibonacci(i - 1) + fibonacci(i - 2)
function fibonacci() -> u32 {
let mut a = 0u32;
let mut b = 1u32;
for i in 0..10 {
a = b;
b = a + b;
}
return a
}
// The 'fibonacci' main function.
function main() -> u32 {
return fibonacci(1)
}
Function mutateNoLet(b: bool) {
let mut a = 5;
if b {
// must be turned into statements.conditional expression
a = 0;
// a = if b ? 0 : a;
} else {
a = 3;
// a = if b ? a : 3;
}
return fibonacci()
}

View File

@ -1,5 +1,5 @@
// The 'hello_world' main function.
function main() -> u32 {
let a = 1 + 1;
let a: u32 = 1 + 1;
return a
}

1
examples/square_root/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
outputs/

View File

@ -0,0 +1,3 @@
[package]
name = "square_root"
version = "0.1.0"

View File

@ -0,0 +1,4 @@
// The program inputs for square_root/src/main.leo
[main]
a: field = 337;
b: field = 113569;

View File

@ -0,0 +1,5 @@
// The 'square_root' main function.
// prove knowledge of the square root `a` of a number `b`:
function main(a: field, b: field) -> bool {
return a * a == b
}

View File

@ -34,7 +34,6 @@ impl LeoInputsParser {
// Build the abstract syntax tree
let syntax_tree = files::File::from_pest(&mut file).map_err(|_| InputParserError::SyntaxTreeError)?;
// println!("{:?}", syntax_tree);
Ok(syntax_tree)
}

View File

@ -3,67 +3,180 @@ use crate::errors::*;
#[derive(Debug, Error)]
pub enum CLIError {
#[error("{}", _0)]
BuildError(#[from] BuildError),
BuildError(BuildError),
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("{}", _0)]
ChecksumFileError(#[from] ChecksumFileError),
ChecksumFileError(ChecksumFileError),
#[error("{}", _0)]
GitignoreError(#[from] GitignoreError),
GitignoreError(GitignoreError),
#[error("{}", _0)]
InitError(#[from] InitError),
InitError(InitError),
#[error("{}", _0)]
InputsDirectoryError(#[from] InputsDirectoryError),
InputsDirectoryError(InputsDirectoryError),
#[error("{}", _0)]
InputsFileError(#[from] InputsFileError),
InputsFileError(InputsFileError),
#[error("{}", _0)]
MainFileError(#[from] MainFileError),
MainFileError(MainFileError),
#[error("{}", _0)]
ManifestError(#[from] ManifestError),
ManifestError(ManifestError),
#[error("{}", _0)]
NewError(#[from] NewError),
NewError(NewError),
#[error("{}", _0)]
OutputsDirectoryError(#[from] OutputsDirectoryError),
OutputsDirectoryError(OutputsDirectoryError),
#[error("{}", _0)]
ProofFileError(#[from] ProofFileError),
ProofFileError(ProofFileError),
#[error("{}", _0)]
ProvingKeyFileError(#[from] ProvingKeyFileError),
ProvingKeyFileError(ProvingKeyFileError),
#[error("{}", _0)]
RunError(#[from] RunError),
RunError(RunError),
#[error("{}", _0)]
SourceDirectoryError(#[from] SourceDirectoryError),
SourceDirectoryError(SourceDirectoryError),
#[error("{}", _0)]
TestError(#[from] TestError),
TestError(TestError),
#[error("{}", _0)]
VerificationKeyFileError(#[from] VerificationKeyFileError),
VerificationKeyFileError(VerificationKeyFileError),
}
impl From<BuildError> for CLIError {
fn from(error: BuildError) -> Self {
log::error!("{}\n", error);
CLIError::BuildError(error)
}
}
impl From<ChecksumFileError> for CLIError {
fn from(error: ChecksumFileError) -> Self {
log::error!("{}\n", error);
CLIError::ChecksumFileError(error)
}
}
impl From<GitignoreError> for CLIError {
fn from(error: GitignoreError) -> Self {
log::error!("{}\n", error);
CLIError::GitignoreError(error)
}
}
impl From<InitError> for CLIError {
fn from(error: InitError) -> Self {
log::error!("{}\n", error);
CLIError::InitError(error)
}
}
impl From<InputsDirectoryError> for CLIError {
fn from(error: InputsDirectoryError) -> Self {
log::error!("{}\n", error);
CLIError::InputsDirectoryError(error)
}
}
impl From<InputsFileError> for CLIError {
fn from(error: InputsFileError) -> Self {
log::error!("{}\n", error);
CLIError::InputsFileError(error)
}
}
impl From<MainFileError> for CLIError {
fn from(error: MainFileError) -> Self {
log::error!("{}\n", error);
CLIError::MainFileError(error)
}
}
impl From<ManifestError> for CLIError {
fn from(error: ManifestError) -> Self {
log::error!("{}\n", error);
CLIError::ManifestError(error)
}
}
impl From<NewError> for CLIError {
fn from(error: NewError) -> Self {
log::error!("{}\n", error);
CLIError::NewError(error)
}
}
impl From<OutputsDirectoryError> for CLIError {
fn from(error: OutputsDirectoryError) -> Self {
log::error!("{}\n", error);
CLIError::OutputsDirectoryError(error)
}
}
impl From<ProofFileError> for CLIError {
fn from(error: ProofFileError) -> Self {
log::error!("{}\n", error);
CLIError::ProofFileError(error)
}
}
impl From<ProvingKeyFileError> for CLIError {
fn from(error: ProvingKeyFileError) -> Self {
log::error!("{}\n", error);
CLIError::ProvingKeyFileError(error)
}
}
impl From<RunError> for CLIError {
fn from(error: RunError) -> Self {
log::error!("{}\n", error);
CLIError::RunError(error)
}
}
impl From<SourceDirectoryError> for CLIError {
fn from(error: SourceDirectoryError) -> Self {
log::error!("{}\n", error);
CLIError::SourceDirectoryError(error)
}
}
impl From<TestError> for CLIError {
fn from(error: TestError) -> Self {
log::error!("{}\n", error);
CLIError::TestError(error)
}
}
impl From<VerificationKeyFileError> for CLIError {
fn from(error: VerificationKeyFileError) -> Self {
log::error!("{}\n", error);
CLIError::VerificationKeyFileError(error)
}
}
impl From<leo_compiler::errors::CompilerError> for CLIError {
fn from(error: leo_compiler::errors::CompilerError) -> Self {
log::error!("{}", error);
log::error!("{}\n", error);
CLIError::Crate("leo_compiler", "Program failed due to previous error".into())
}
}
impl From<leo_inputs::errors::InputParserError> for CLIError {
fn from(error: leo_inputs::errors::InputParserError) -> Self {
CLIError::Crate("leo_inputs", format!("{}", error))
log::error!("{}\n", error);
CLIError::Crate("leo_inputs", "Program failed due to previous error".into())
}
}

View File

@ -16,12 +16,12 @@ impl<'ast> From<AstRangeOrExpression<'ast>> for RangeOrExpression {
AstRangeOrExpression::Range(range) => {
let from = range.from.map(|from| match Expression::from(from.0) {
Expression::Integer(number) => number,
Expression::Implicit(string) => Integer::from_implicit(string),
Expression::Implicit(string, _span) => Integer::from_implicit(string),
expression => unimplemented!("Range bounds should be integers, found {}", expression),
});
let to = range.to.map(|to| match Expression::from(to.0) {
Expression::Integer(number) => number,
Expression::Implicit(string) => Integer::from_implicit(string),
Expression::Implicit(string, _span) => Integer::from_implicit(string),
expression => unimplemented!("Range bounds should be integers, found {}", expression),
});

View File

@ -15,12 +15,16 @@ pub struct Span {
impl<'ast> From<AstSpan<'ast>> for Span {
fn from(span: AstSpan<'ast>) -> Self {
let mut text = " ".to_string();
let line_col = span.start_pos().line_col();
let end = span.end_pos().line_col().1;
text.push_str(span.start_pos().line_of().trim_end());
Self {
text,
line: span.start_pos().line_col().0,
start: find_line_start(&span.start_pos()),
end: find_line_end(&span.end_pos()),
line: line_col.0,
start: line_col.1,
end,
}
}
}

View File

@ -1,6 +1,8 @@
use leo_types::Span;
use crate::Span;
use std::fmt;
use std::{fmt, path::PathBuf};
pub const INDENT: &'static str = " ";
/// Formatted compiler error type
/// --> file.leo 2:8
@ -37,8 +39,11 @@ impl Error {
}
}
pub fn set_path(&mut self, path: PathBuf) {
self.path = Some(format!("{:?}", path));
}
pub fn format(&self) -> String {
let indent = " ".to_string();
let path = self.path.as_ref().map(|path| format!("{}:", path)).unwrap_or_default();
let underline = underline(self.start, self.end);
@ -49,8 +54,8 @@ impl Error {
{indent } | {underline}\n\
{indent } |\n\
{indent } = {message}",
indent = indent,
width = indent.len(),
indent = INDENT,
width = INDENT.len(),
path = path,
line = self.line,
start = self.start,

View File

@ -1,18 +1,59 @@
use snarkos_errors::gadgets::SynthesisError;
use crate::{error::Error as FormattedError, Span};
use std::num::ParseIntError;
use snarkos_errors::gadgets::SynthesisError;
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum IntegerError {
#[error("Cannot enforce {}", _0)]
CannotEnforce(String),
#[error("Expected integer parameter, got {}", _0)]
InvalidInteger(String),
#[error("{}", _0)]
ParseIntError(#[from] ParseIntError),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
Error(#[from] FormattedError),
}
impl IntegerError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
IntegerError::Error(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
IntegerError::Error(FormattedError::new_from_span(message, span))
}
pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self {
let message = format!(
"the integer operation `{}` failed due to the synthesis error `{}`",
operation, error,
);
Self::new_from_span(message, span)
}
pub fn cannot_evaluate(operation: String, span: Span) -> Self {
let message = format!(
"the integer binary operation `{}` can only be enforced on integers of the same type",
operation
);
Self::new_from_span(message, span)
}
pub fn invalid_index(span: Span) -> Self {
let message =
format!("index must be a constant value integer. allocated indices produce a circuit of unknown size");
Self::new_from_span(message, span)
}
pub fn invalid_integer(actual: String, span: Span) -> Self {
let message = format!("expected integer input type, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn missing_integer(expected: String, span: Span) -> Self {
let message = format!("expected integer input `{}` not found", expected);
Self::new_from_span(message, span)
}
}

View File

@ -1,2 +1,5 @@
pub mod error;
pub use error::*;
pub mod integer;
pub use integer::*;

View File

@ -28,10 +28,10 @@ pub enum Expression {
// Values
Integer(Integer),
Field(String),
Group(String),
Field(String, Span),
Group(String, Span),
Boolean(Boolean),
Implicit(String),
Implicit(String, Span),
// Number operations
Add(Box<Expression>, Box<Expression>, Span),
@ -41,7 +41,7 @@ pub enum Expression {
Pow(Box<Expression>, Box<Expression>, Span),
// Boolean operations
Not(Box<Expression>),
Not(Box<Expression>, Span),
Or(Box<Expression>, Box<Expression>, Span),
And(Box<Expression>, Box<Expression>, Span),
Eq(Box<Expression>, Box<Expression>, Span),
@ -66,6 +66,41 @@ pub enum Expression {
FunctionCall(Box<Expression>, Vec<Expression>, Span),
}
impl Expression {
pub fn set_span(&mut self, new_span: &Span) {
match self {
Expression::Field(_, old_span) => *old_span = new_span.clone(),
Expression::Group(_, old_span) => *old_span = new_span.clone(),
Expression::Add(_, _, old_span) => *old_span = new_span.clone(),
Expression::Sub(_, _, old_span) => *old_span = new_span.clone(),
Expression::Mul(_, _, old_span) => *old_span = new_span.clone(),
Expression::Div(_, _, old_span) => *old_span = new_span.clone(),
Expression::Pow(_, _, old_span) => *old_span = new_span.clone(),
Expression::Not(_, old_span) => *old_span = new_span.clone(),
Expression::Or(_, _, old_span) => *old_span = new_span.clone(),
Expression::And(_, _, old_span) => *old_span = new_span.clone(),
Expression::Eq(_, _, old_span) => *old_span = new_span.clone(),
Expression::Ge(_, _, old_span) => *old_span = new_span.clone(),
Expression::Gt(_, _, old_span) => *old_span = new_span.clone(),
Expression::Le(_, _, old_span) => *old_span = new_span.clone(),
Expression::Lt(_, _, old_span) => *old_span = new_span.clone(),
Expression::IfElse(_, _, _, old_span) => *old_span = new_span.clone(),
Expression::Array(_, old_span) => *old_span = new_span.clone(),
Expression::ArrayAccess(_, _, old_span) => *old_span = new_span.clone(),
Expression::Circuit(_, _, old_span) => *old_span = new_span.clone(),
Expression::CircuitMemberAccess(_, _, old_span) => *old_span = new_span.clone(),
Expression::CircuitStaticFunctionAccess(_, _, old_span) => *old_span = new_span.clone(),
Expression::FunctionCall(_, _, old_span) => *old_span = new_span.clone(),
_ => {}
}
}
}
impl<'ast> Expression {
pub(crate) fn get_count(count: Value<'ast>) -> usize {
match count {
@ -88,10 +123,10 @@ impl<'ast> fmt::Display for Expression {
// Values
Expression::Integer(ref integer) => write!(f, "{}", integer),
Expression::Field(ref field) => write!(f, "{}", field),
Expression::Group(ref group) => write!(f, "{}", group),
Expression::Field(ref field, ref _span) => write!(f, "{}", field),
Expression::Group(ref group, ref _span) => write!(f, "{}", group),
Expression::Boolean(ref bool) => write!(f, "{}", bool.get_value().unwrap()),
Expression::Implicit(ref value) => write!(f, "{}", value),
Expression::Implicit(ref value, ref _span) => write!(f, "{}", value),
// Number operations
Expression::Add(ref left, ref right, ref _span) => write!(f, "{} + {}", left, right),
@ -101,7 +136,7 @@ impl<'ast> fmt::Display for Expression {
Expression::Pow(ref left, ref right, ref _span) => write!(f, "{} ** {}", left, right),
// Boolean operations
Expression::Not(ref expression) => write!(f, "!{}", expression),
Expression::Not(ref expression, ref _span) => write!(f, "!{}", expression),
Expression::Or(ref lhs, ref rhs, ref _span) => write!(f, "{} || {}", lhs, rhs),
Expression::And(ref lhs, ref rhs, ref _span) => write!(f, "{} && {}", lhs, rhs),
Expression::Eq(ref lhs, ref rhs, ref _span) => write!(f, "{} == {}", lhs, rhs),
@ -194,15 +229,18 @@ impl<'ast> From<PostfixExpression<'ast>> for Expression {
),
// Handle function calls
Access::Call(function) => Expression::FunctionCall(
Box::new(acc),
function
.expressions
.into_iter()
.map(|expression| Expression::from(expression))
.collect(),
Span::from(function.span),
),
Access::Call(function) => {
let span = Span::from(function.span);
Expression::FunctionCall(
Box::new(acc),
function
.expressions
.into_iter()
.map(|expression| Expression::from(expression))
.collect(),
span,
)
}
// Handle circuit member accesses
Access::Object(circuit_object) => Expression::CircuitMemberAccess(
@ -278,7 +316,10 @@ impl<'ast> From<BinaryExpression<'ast>> for Expression {
Box::new(Expression::from(*expression.right)),
Span::from(expression.span),
),
BinaryOperation::Ne => Expression::Not(Box::new(Expression::from(expression))),
BinaryOperation::Ne => Expression::Not(
Box::new(Expression::from(expression.clone())),
Span::from(expression.span),
),
BinaryOperation::Ge => Expression::Ge(
Box::new(Expression::from(*expression.left)),
Box::new(Expression::from(*expression.right)),
@ -376,19 +417,22 @@ impl<'ast> From<Value<'ast>> for Expression {
impl<'ast> From<NotExpression<'ast>> for Expression {
fn from(expression: NotExpression<'ast>) -> Self {
Expression::Not(Box::new(Expression::from(*expression.expression)))
Expression::Not(
Box::new(Expression::from(*expression.expression)),
Span::from(expression.span),
)
}
}
impl<'ast> From<FieldValue<'ast>> for Expression {
fn from(field: FieldValue<'ast>) -> Self {
Expression::Field(field.number.value)
Expression::Field(field.number.value, Span::from(field.span))
}
}
impl<'ast> From<GroupValue<'ast>> for Expression {
fn from(group: GroupValue<'ast>) -> Self {
Expression::Group(group.to_string())
Expression::Group(group.to_string(), Span::from(group.span))
}
}
@ -402,7 +446,7 @@ impl<'ast> From<BooleanValue<'ast>> for Expression {
impl<'ast> From<NumberImplicitValue<'ast>> for Expression {
fn from(number: NumberImplicitValue<'ast>) -> Self {
Expression::Implicit(number.number.value)
Expression::Implicit(number.number.value, Span::from(number.span))
}
}

View File

@ -1,4 +1,4 @@
use crate::{Identifier, Type};
use crate::{Identifier, Span, Type};
use leo_ast::functions::FunctionInput as AstFunctionInput;
use std::fmt;
@ -8,6 +8,7 @@ pub struct FunctionInput {
pub identifier: Identifier,
pub mutable: bool,
pub _type: Type,
pub span: Span,
}
impl<'ast> From<AstFunctionInput<'ast>> for FunctionInput {
@ -16,6 +17,7 @@ impl<'ast> From<AstFunctionInput<'ast>> for FunctionInput {
identifier: Identifier::from(parameter.identifier),
mutable: parameter.mutable.is_some(),
_type: Type::from(parameter._type),
span: Span::from(parameter.span),
}
}
}

View File

@ -1,6 +1,6 @@
//! The import type for a Leo program.
use crate::ImportSymbol;
use crate::{ImportSymbol, Span};
use leo_ast::imports::Import as AstImport;
use std::fmt;
@ -9,6 +9,7 @@ use std::fmt;
pub struct Import {
pub path_string: String,
pub symbols: Vec<ImportSymbol>,
pub span: Span,
}
impl<'ast> From<AstImport<'ast>> for Import {
@ -20,18 +21,12 @@ impl<'ast> From<AstImport<'ast>> for Import {
.into_iter()
.map(|symbol| ImportSymbol::from(symbol))
.collect(),
span: Span::from(import.span),
}
}
}
impl Import {
pub fn new(source: String, symbols: Vec<ImportSymbol>) -> Import {
Import {
path_string: source,
symbols,
}
}
pub fn path_string_full(&self) -> String {
format!("{}.leo", self.path_string)
}

View File

@ -1,4 +1,4 @@
use crate::Identifier;
use crate::{Identifier, Span};
use leo_ast::imports::ImportSymbol as AstImportSymbol;
use std::fmt;
@ -7,6 +7,7 @@ use std::fmt;
pub struct ImportSymbol {
pub symbol: Identifier,
pub alias: Option<Identifier>,
pub span: Span,
}
impl<'ast> From<AstImportSymbol<'ast>> for ImportSymbol {
@ -14,6 +15,7 @@ impl<'ast> From<AstImportSymbol<'ast>> for ImportSymbol {
ImportSymbol {
symbol: Identifier::from(symbol.value),
alias: symbol.alias.map(|alias| Identifier::from(alias)),
span: Span::from(symbol.span),
}
}
}

View File

@ -1,6 +1,6 @@
//! Conversion of integer declarations to constraints in Leo.
use crate::{errors::IntegerError, InputValue, IntegerType};
use crate::{errors::IntegerError, InputValue, IntegerType, Span};
use leo_ast::{types::IntegerType as AstIntegerType, values::NumberValue};
use snarkos_errors::gadgets::SynthesisError;
@ -58,6 +58,46 @@ impl<'ast> Integer {
}
impl Integer {
pub fn new_constant(integer_type: &IntegerType, string: String, span: Span) -> Result<Self, IntegerError> {
match integer_type {
IntegerType::U8 => {
let number = string
.parse::<u8>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U8(UInt8::constant(number)))
}
IntegerType::U16 => {
let number = string
.parse::<u16>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U16(UInt16::constant(number)))
}
IntegerType::U32 => {
let number = string
.parse::<u32>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U32(UInt32::constant(number)))
}
IntegerType::U64 => {
let number = string
.parse::<u64>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U64(UInt64::constant(number)))
}
IntegerType::U128 => {
let number = string
.parse::<u128>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U128(UInt128::constant(number)))
}
}
}
pub fn get_value(&self) -> Option<u128> {
match self {
Integer::U8(u8) => u8.value.map(|v| v as u128),
@ -68,8 +108,9 @@ impl Integer {
}
}
pub fn to_usize(&self) -> usize {
self.get_value().unwrap() as usize
pub fn to_usize(&self, span: Span) -> Result<usize, IntegerError> {
let value = self.get_value().ok_or(IntegerError::invalid_index(span))?;
Ok(value as usize)
}
pub fn get_type(&self) -> IntegerType {
@ -87,36 +128,61 @@ impl Integer {
integer_type: IntegerType,
name: String,
option: Option<u128>,
span: Span,
) -> Result<Self, IntegerError> {
Ok(match integer_type {
IntegerType::U8 => {
let u8_name = format!("{}: u8", name);
let u8_name_unique = format!("`{}` {}:{}", u8_name, span.line, span.start);
let u8_option = option.map(|integer| integer as u8);
let u8_result = UInt8::alloc(cs.ns(|| name), || u8_option.ok_or(SynthesisError::AssignmentMissing))?;
let u8_result = UInt8::alloc(cs.ns(|| u8_name_unique), || {
u8_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u8_name, span))?;
Integer::U8(u8_result)
}
IntegerType::U16 => {
let u16_name = format!("{}: u16", name);
let u16_name_unique = format!("`{}` {}:{}", u16_name, span.line, span.start);
let u16_option = option.map(|integer| integer as u16);
let u16_result = UInt16::alloc(cs.ns(|| name), || u16_option.ok_or(SynthesisError::AssignmentMissing))?;
let u16_result = UInt16::alloc(cs.ns(|| u16_name_unique), || {
u16_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u16_name, span))?;
Integer::U16(u16_result)
}
IntegerType::U32 => {
let u32_name = format!("{}: u32", name);
let u32_name_unique = format!("`{}` {}:{}", u32_name, span.line, span.start);
let u32_option = option.map(|integer| integer as u32);
let u32_result = UInt32::alloc(cs.ns(|| name), || u32_option.ok_or(SynthesisError::AssignmentMissing))?;
let u32_result = UInt32::alloc(cs.ns(|| u32_name_unique), || {
u32_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u32_name, span))?;
Integer::U32(u32_result)
}
IntegerType::U64 => {
let u64_name = format!("{}: u64", name);
let u64_name_unique = format!("`{}` {}:{}", u64_name, span.line, span.start);
let u64_option = option.map(|integer| integer as u64);
let u64_result = UInt64::alloc(cs.ns(|| name), || u64_option.ok_or(SynthesisError::AssignmentMissing))?;
let u64_result = UInt64::alloc(cs.ns(|| u64_name_unique), || {
u64_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u64_name, span))?;
Integer::U64(u64_result)
}
IntegerType::U128 => {
let u128_name = format!("{}: u128", name);
let u128_name_unique = format!("`{}` {}:{}", u128_name, span.line, span.start);
let u128_option = option.map(|integer| integer as u128);
let u128_result =
UInt128::alloc(cs.ns(|| name), || u128_option.ok_or(SynthesisError::AssignmentMissing))?;
let u128_result = UInt128::alloc(cs.ns(|| u128_name_unique), || {
u128_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u128_name, span))?;
Integer::U128(u128_result)
}
@ -128,6 +194,7 @@ impl Integer {
integer_type: IntegerType,
name: String,
integer_value: Option<InputValue>,
span: Span,
) -> Result<Self, IntegerError> {
// Check that the input value is the correct type
let option = match integer_value {
@ -135,57 +202,55 @@ impl Integer {
if let InputValue::Integer(_type_, number) = input {
Some(number)
} else {
return Err(IntegerError::InvalidInteger(input.to_string()));
return Err(IntegerError::invalid_integer(input.to_string(), span));
}
}
None => None,
};
Self::allocate_type(cs, integer_type, name, option)
Self::allocate_type(cs, integer_type, name, option, span)
}
pub fn add<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} + {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = UInt8::addmany(
cs.ns(|| format!("enforce {} + {}", left_u8.value.unwrap(), right_u8.value.unwrap())),
&[left_u8, right_u8],
)?;
let result = UInt8::addmany(cs.ns(|| unique_namespace), &[left_u8, right_u8])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = UInt16::addmany(
cs.ns(|| format!("enforce {} + {}", left_u16.value.unwrap(), right_u16.value.unwrap())),
&[left_u16, right_u16],
)?;
let result = UInt16::addmany(cs.ns(|| unique_namespace), &[left_u16, right_u16])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = UInt32::addmany(
cs.ns(|| format!("enforce {} + {}", left_u32.value.unwrap(), right_u32.value.unwrap())),
&[left_u32, right_u32],
)?;
let result = UInt32::addmany(cs.ns(|| unique_namespace), &[left_u32, right_u32])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = UInt64::addmany(
cs.ns(|| format!("enforce {} + {}", left_u64.value.unwrap(), right_u64.value.unwrap())),
&[left_u64, right_u64],
)?;
let result = UInt64::addmany(cs.ns(|| unique_namespace), &[left_u64, right_u64])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = UInt128::addmany(
cs.ns(|| format!("enforce {} + {}", left_u128.value.unwrap(), right_u128.value.unwrap())),
&[left_u128, right_u128],
)?;
let result = UInt128::addmany(cs.ns(|| unique_namespace), &[left_u128, right_u128])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U128(result)
}
(left, right) => return Err(IntegerError::CannotEnforce(format!("{} + {}", left, right))),
(_, _) => return Err(IntegerError::cannot_evaluate(format!("+"), span)),
})
}
@ -193,44 +258,47 @@ impl Integer {
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} - {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = left_u8.sub(
cs.ns(|| format!("enforce {} - {}", left_u8.value.unwrap(), right_u8.value.unwrap())),
&right_u8,
)?;
let result = left_u8
.sub(cs.ns(|| unique_namespace), &right_u8)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = left_u16.sub(
cs.ns(|| format!("enforce {} - {}", left_u16.value.unwrap(), right_u16.value.unwrap())),
&right_u16,
)?;
let result = left_u16
.sub(cs.ns(|| unique_namespace), &right_u16)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = left_u32.sub(
cs.ns(|| format!("enforce {} - {}", left_u32.value.unwrap(), right_u32.value.unwrap())),
&right_u32,
)?;
let result = left_u32
.sub(cs.ns(|| unique_namespace), &right_u32)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = left_u64.sub(
cs.ns(|| format!("enforce {} - {}", left_u64.value.unwrap(), right_u64.value.unwrap())),
&right_u64,
)?;
let result = left_u64
.sub(cs.ns(|| unique_namespace), &right_u64)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = left_u128.sub(
cs.ns(|| format!("enforce {} - {}", left_u128.value.unwrap(), right_u128.value.unwrap())),
&right_u128,
)?;
let result = left_u128
.sub(cs.ns(|| unique_namespace), &right_u128)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U128(result)
}
(left, right) => return Err(IntegerError::CannotEnforce(format!("{} - {}", left, right))),
(_, _) => return Err(IntegerError::cannot_evaluate(format!("-"), span)),
})
}
@ -238,44 +306,47 @@ impl Integer {
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} * {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = left_u8.mul(
cs.ns(|| format!("enforce {} * {}", left_u8.value.unwrap(), right_u8.value.unwrap())),
&right_u8,
)?;
let result = left_u8
.mul(cs.ns(|| unique_namespace), &right_u8)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = left_u16.mul(
cs.ns(|| format!("enforce {} * {}", left_u16.value.unwrap(), right_u16.value.unwrap())),
&right_u16,
)?;
let result = left_u16
.mul(cs.ns(|| unique_namespace), &right_u16)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = left_u32.mul(
cs.ns(|| format!("enforce {} * {}", left_u32.value.unwrap(), right_u32.value.unwrap())),
&right_u32,
)?;
let result = left_u32
.mul(cs.ns(|| unique_namespace), &right_u32)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = left_u64.mul(
cs.ns(|| format!("enforce {} * {}", left_u64.value.unwrap(), right_u64.value.unwrap())),
&right_u64,
)?;
let result = left_u64
.mul(cs.ns(|| unique_namespace), &right_u64)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = left_u128.mul(
cs.ns(|| format!("enforce {} * {}", left_u128.value.unwrap(), right_u128.value.unwrap())),
&right_u128,
)?;
let result = left_u128
.mul(cs.ns(|| unique_namespace), &right_u128)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U128(result)
}
(left, right) => return Err(IntegerError::CannotEnforce(format!("{} * {}", left, right))),
(_, _) => return Err(IntegerError::cannot_evaluate(format!("*"), span)),
})
}
@ -283,44 +354,47 @@ impl Integer {
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} ÷ {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = left_u8.div(
cs.ns(|| format!("enforce {} ÷ {}", left_u8.value.unwrap(), right_u8.value.unwrap())),
&right_u8,
)?;
let result = left_u8
.div(cs.ns(|| unique_namespace), &right_u8)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = left_u16.div(
cs.ns(|| format!("enforce {} ÷ {}", left_u16.value.unwrap(), right_u16.value.unwrap())),
&right_u16,
)?;
let result = left_u16
.div(cs.ns(|| unique_namespace), &right_u16)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = left_u32.div(
cs.ns(|| format!("enforce {} ÷ {}", left_u32.value.unwrap(), right_u32.value.unwrap())),
&right_u32,
)?;
let result = left_u32
.div(cs.ns(|| unique_namespace), &right_u32)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = left_u64.div(
cs.ns(|| format!("enforce {} ÷ {}", left_u64.value.unwrap(), right_u64.value.unwrap())),
&right_u64,
)?;
let result = left_u64
.div(cs.ns(|| unique_namespace), &right_u64)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = left_u128.div(
cs.ns(|| format!("enforce {} ÷ {}", left_u128.value.unwrap(), right_u128.value.unwrap())),
&right_u128,
)?;
let result = left_u128
.div(cs.ns(|| unique_namespace), &right_u128)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U128(result)
}
(left, right) => return Err(IntegerError::CannotEnforce(format!("{} ÷ {}", left, right))),
(_, _) => return Err(IntegerError::cannot_evaluate(format!("÷"), span)),
})
}
@ -328,44 +402,47 @@ impl Integer {
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} ** {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = left_u8.pow(
cs.ns(|| format!("enforce {} ** {}", left_u8.value.unwrap(), right_u8.value.unwrap())),
&right_u8,
)?;
let result = left_u8
.pow(cs.ns(|| unique_namespace), &right_u8)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = left_u16.pow(
cs.ns(|| format!("enforce {} ** {}", left_u16.value.unwrap(), right_u16.value.unwrap())),
&right_u16,
)?;
let result = left_u16
.pow(cs.ns(|| unique_namespace), &right_u16)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = left_u32.pow(
cs.ns(|| format!("enforce {} ** {}", left_u32.value.unwrap(), right_u32.value.unwrap())),
&right_u32,
)?;
let result = left_u32
.pow(cs.ns(|| unique_namespace), &right_u32)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = left_u64.pow(
cs.ns(|| format!("enforce {} ** {}", left_u64.value.unwrap(), right_u64.value.unwrap())),
&right_u64,
)?;
let result = left_u64
.pow(cs.ns(|| unique_namespace), &right_u64)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = left_u128.pow(
cs.ns(|| format!("enforce {} ** {}", left_u128.value.unwrap(), right_u128.value.unwrap())),
&right_u128,
)?;
let result = left_u128
.pow(cs.ns(|| unique_namespace), &right_u128)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U128(result)
}
(left, right) => return Err(IntegerError::CannotEnforce(format!("{} ** {}", left, right))),
(_, _) => return Err(IntegerError::cannot_evaluate(format!("**"), span)),
})
}
}
@ -450,11 +527,11 @@ impl<F: Field + PrimeField> CondSelectGadget<F> for Integer {
impl fmt::Display for Integer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let option = match self {
Integer::U8(u8) => u8.value.map(|num| num as usize),
Integer::U16(u16) => u16.value.map(|num| num as usize),
Integer::U32(u32) => u32.value.map(|num| num as usize),
Integer::U64(u64) => u64.value.map(|num| num as usize),
Integer::U128(u128) => u128.value.map(|num| num as usize),
Integer::U8(u8) => u8.value.map(|num| num as u128),
Integer::U16(u16) => u16.value.map(|num| num as u128),
Integer::U32(u32) => u32.value.map(|num| num as u128),
Integer::U64(u64) => u64.value.map(|num| num as u128),
Integer::U128(u128) => u128.value.map(|num| num as u128),
};
match option {
Some(number) => write!(f, "{}{}", number, self.get_type()),

View File

@ -59,9 +59,9 @@ impl<'ast> Program {
}
impl Program {
pub fn new() -> Self {
pub fn new(name: String) -> Self {
Self {
name: "".into(),
name,
expected_inputs: vec![],
imports: vec![],
circuits: HashMap::new(),

View File

@ -30,24 +30,34 @@ pub enum Statement {
impl<'ast> From<ReturnStatement<'ast>> for Statement {
fn from(statement: ReturnStatement<'ast>) -> Self {
let span = Span::from(statement.span);
Statement::Return(
statement
.expressions
.into_iter()
.map(|expression| Expression::from(expression))
.map(|expression| {
let mut expression = Expression::from(expression);
expression.set_span(&span);
expression
})
.collect(),
Span::from(statement.span),
span,
)
}
}
impl<'ast> From<DefinitionStatement<'ast>> for Statement {
fn from(statement: DefinitionStatement<'ast>) -> Self {
let span = Span::from(statement.span);
let mut expression = Expression::from(statement.expression);
expression.set_span(&span);
Statement::Definition(
Declare::from(statement.declare),
Variable::from(statement.variable),
Expression::from(statement.expression),
Span::from(statement.span),
expression,
span,
)
}
}
@ -141,12 +151,12 @@ impl<'ast> From<ForStatement<'ast>> for Statement {
fn from(statement: ForStatement<'ast>) -> Self {
let from = match Expression::from(statement.start) {
Expression::Integer(number) => number,
Expression::Implicit(string) => Integer::from_implicit(string),
Expression::Implicit(string, _span) => Integer::from_implicit(string),
expression => unimplemented!("Range bounds should be integers, found {}", expression),
};
let to = match Expression::from(statement.stop) {
Expression::Integer(number) => number,
Expression::Implicit(string) => Integer::from_implicit(string),
Expression::Implicit(string, _span) => Integer::from_implicit(string),
expression => unimplemented!("Range bounds should be integers, found {}", expression),
};
@ -178,7 +188,12 @@ impl<'ast> From<AssertStatement<'ast>> for Statement {
impl<'ast> From<ExpressionStatement<'ast>> for Statement {
fn from(statement: ExpressionStatement<'ast>) -> Self {
Statement::Expression(Expression::from(statement.expression), Span::from(statement.span))
let span = Span::from(statement.span);
let mut expression = Expression::from(statement.expression);
expression.set_span(&span);
Statement::Expression(expression, span)
}
}

View File

@ -15,6 +15,22 @@ pub enum Type {
SelfType,
}
impl Type {
pub fn is_self(&self) -> bool {
if let Type::SelfType = self {
return true;
}
false
}
pub fn is_circuit(&self) -> bool {
if let Type::Circuit(_) = self {
return true;
}
false
}
}
/// pest ast -> Explicit Type for defining circuit members and function params
impl From<DataType> for Type {
@ -60,29 +76,29 @@ impl<'ast> From<AstType<'ast>> for Type {
impl Type {
pub fn outer_dimension(&self, dimensions: &Vec<usize>) -> Self {
let _type = self.clone();
let type_ = self.clone();
if dimensions.len() > 1 {
let mut next = vec![];
next.extend_from_slice(&dimensions[1..]);
return Type::Array(Box::new(_type), next);
return Type::Array(Box::new(type_), next);
}
_type
type_
}
pub fn inner_dimension(&self, dimensions: &Vec<usize>) -> Self {
let _type = self.clone();
let type_ = self.clone();
if dimensions.len() > 1 {
let mut next = vec![];
next.extend_from_slice(&dimensions[..dimensions.len() - 1]);
return Type::Array(Box::new(_type), next);
return Type::Array(Box::new(type_), next);
}
_type
type_
}
}
@ -93,8 +109,8 @@ impl fmt::Display for Type {
Type::Field => write!(f, "field"),
Type::Group => write!(f, "group"),
Type::Boolean => write!(f, "bool"),
Type::Circuit(ref variable) => write!(f, "{}", variable),
Type::SelfType => write!(f, "Self"),
Type::Circuit(ref variable) => write!(f, "circuit {}", variable),
Type::SelfType => write!(f, "SelfType"),
Type::Array(ref array, ref dimensions) => {
write!(f, "{}", *array)?;
for row in dimensions {