From cff3be9d0103c16e62940bde1ea2f2f6010d7ad5 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 22 Jun 2020 13:11:01 -0700 Subject: [PATCH] add unique namespaces to statement gadget calls --- compiler/src/constraints/boolean.rs | 24 ++++++--- compiler/src/constraints/field.rs | 26 +++++++--- compiler/src/constraints/group.rs | 26 +++++++--- compiler/src/constraints/statement.rs | 75 +++++++++++++++++++-------- compiler/src/constraints/value.rs | 25 ++++++--- 5 files changed, 125 insertions(+), 51 deletions(-) diff --git a/compiler/src/constraints/boolean.rs b/compiler/src/constraints/boolean.rs index d654c9d345..d32d787f15 100644 --- a/compiler/src/constraints/boolean.rs +++ b/compiler/src/constraints/boolean.rs @@ -20,6 +20,21 @@ pub(crate) fn new_bool_constant(string: String, span: Span) -> Result>( + cs: &mut CS, + name: String, + option: Option, + span: Span, +) -> Result { + 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, CS: ConstraintSystem>( cs: &mut CS, name: String, @@ -27,7 +42,7 @@ pub(crate) fn bool_from_input, CS: Constr span: Span, ) -> Result, BooleanError> { // Check that the input value is the correct type - let bool_value = match input_value { + let option = match input_value { Some(input) => { if let InputValue::Boolean(bool) = input { Some(bool) @@ -38,12 +53,7 @@ pub(crate) fn bool_from_input, CS: Constr None => None, }; - let boolean_name = format!("{}: bool", name); - let boolean_name_unique = format!("`{}` {}:{}", boolean_name, span.line, span.start); - let number = Boolean::alloc(cs.ns(|| boolean_name_unique), || { - bool_value.ok_or(SynthesisError::AssignmentMissing) - }) - .map_err(|_| BooleanError::missing_boolean(boolean_name, span))?; + let number = allocate_bool(cs, name, option, span)?; Ok(ConstrainedValue::Boolean(number)) } diff --git a/compiler/src/constraints/field.rs b/compiler/src/constraints/field.rs index 343a917006..fe036a1e95 100644 --- a/compiler/src/constraints/field.rs +++ b/compiler/src/constraints/field.rs @@ -9,6 +9,21 @@ use snarkos_models::{ gadgets::{r1cs::ConstraintSystem, utilities::alloc::AllocGadget}, }; +pub(crate) fn allocate_field>( + cs: &mut CS, + name: String, + option: Option, + span: Span, +) -> Result, 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, CS: ConstraintSystem>( cs: &mut CS, name: String, @@ -16,7 +31,7 @@ pub(crate) fn field_from_input, CS: Const span: Span, ) -> Result, 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) @@ -27,12 +42,7 @@ pub(crate) fn field_from_input, CS: Const None => None, }; - let field_name = format!("{}: field", name); - let field_name_unique = format!("`{}` {}:{}", field_name, span.line, span.start); - let field_value = FieldType::alloc(cs.ns(|| field_name_unique), || { - field_option.ok_or(SynthesisError::AssignmentMissing) - }) - .map_err(|_| FieldError::missing_field(field_name, span))?; + let field = allocate_field(cs, name, option, span)?; - Ok(ConstrainedValue::Field(field_value)) + Ok(ConstrainedValue::Field(field)) } diff --git a/compiler/src/constraints/group.rs b/compiler/src/constraints/group.rs index aaf3f4d29c..fd717392e8 100644 --- a/compiler/src/constraints/group.rs +++ b/compiler/src/constraints/group.rs @@ -7,6 +7,21 @@ use snarkos_models::{ gadgets::r1cs::ConstraintSystem, }; +pub(crate) fn allocate_group, CS: ConstraintSystem>( + cs: &mut CS, + name: String, + option: Option, + span: Span, +) -> Result { + 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, CS: ConstraintSystem>( cs: &mut CS, name: String, @@ -14,7 +29,7 @@ pub(crate) fn group_from_input, CS: Const span: Span, ) -> Result, 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) @@ -25,12 +40,7 @@ pub(crate) fn group_from_input, CS: Const None => None, }; - let group_name = format!("{}: group", name); - let group_name_unique = format!("`{}` {}:{}", group_name, span.line, span.start); - let group_value = G::alloc(cs.ns(|| group_name_unique), || { - group_option.ok_or(SynthesisError::AssignmentMissing) - }) - .map_err(|_| GroupError::missing_group(group_name, span))?; + let group = allocate_group(cs, name, option, span)?; - Ok(ConstrainedValue::Group(group_value)) + Ok(ConstrainedValue::Group(group)) } diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index f71bea1657..b935efff7a 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -76,10 +76,17 @@ impl> ConstrainedProgram { ConstrainedValue::Array(old) => { new_value.resolve_type(&vec![old[index].to_type()], 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 mut unique_namespace = + cs.ns(|| format!("select {} {}:{}", new_value.to_string(), span.line, span.start)); + let selected_value = ConstrainedValue::conditionally_select( + &mut unique_namespace, + &condition, + &new_value, + &old[index], + ) + .map_err(|_| { + StatementError::select_fail(new_value.to_string(), old[index].to_string(), span) + })?; old[index] = selected_value; } @@ -107,8 +114,12 @@ impl> ConstrainedProgram { } _ => 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 mut unique_namespace = + cs.ns(|| format!("select {} {}:{}", new_array.to_string(), span.line, span.start)); + let selected_array = + ConstrainedValue::conditionally_select(&mut unique_namespace, &condition, &new_array, old_array) + .map_err(|_| StatementError::select_fail(new_array.to_string(), old_array.to_string(), span))?; + *old_array = selected_array; } } @@ -146,10 +157,17 @@ impl> ConstrainedProgram { _ => { new_value.resolve_type(&vec![object.1.to_type()], 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 mut unique_namespace = + cs.ns(|| format!("select {} {}:{}", new_value.to_string(), span.line, span.start)); + let selected_value = ConstrainedValue::conditionally_select( + &mut unique_namespace, + &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 +203,14 @@ impl> ConstrainedProgram { 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()], span.clone())?; - 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))?; + + let mut unique_namespace = + cs.ns(|| format!("select {} {}:{}", new_value.to_string(), span.line, span.start)); + let selected_value = + ConstrainedValue::conditionally_select(&mut unique_namespace, &condition, &new_value, old_value) + .map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span))?; *old_value = selected_value; @@ -391,9 +414,9 @@ impl> ConstrainedProgram { value => return Err(StatementError::conditional_boolean(value.to_string(), span)), }; - // Determine nested branch selection + // Determine nested branch 1 selection let branch_1_indicator = Boolean::and( - &mut cs.ns(|| format!("statement branch 1 indicator {}", statement_string)), + &mut cs.ns(|| format!("branch indicator 1 {} {}:{}", statement_string, span.line, span.start)), &outer_indicator, &inner_indicator, )?; @@ -408,13 +431,14 @@ impl> ConstrainedProgram { return_types.clone(), )?; - // Execute branch 2 + // Determine nested branch 2 selection let branch_2_indicator = Boolean::and( - &mut cs.ns(|| format!("statement branch 2 indicator {}", statement_string)), + &mut cs.ns(|| format!("branch indicator 2 {} {}:{}", statement_string, span.line, span.start)), &outer_indicator, &inner_indicator.not(), )?; + // Execute branch 2 match statement.next { Some(next) => match next { ConditionalNestedOrEndStatement::Nested(nested) => self.enforce_conditional_statement( @@ -435,7 +459,7 @@ impl> ConstrainedProgram { 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), } } @@ -450,7 +474,7 @@ impl> ConstrainedProgram { stop: Integer, statements: Vec, return_types: Vec, - _span: Span, + span: Span, ) -> Result>, StatementError> { let mut res = None; @@ -463,11 +487,11 @@ impl> ConstrainedProgram { ConstrainedValue::Integer(Integer::U32(UInt32::constant(i as u32))), ); - cs.ns(|| format!("loop {} = {}", index.to_string(), i)); + let mut unique_namespace = cs.ns(|| format!("for loop iteration {} {}:{}", i, span.line, span.start)); // Evaluate statements and possibly return early if let Some(early_return) = self.evaluate_branch( - cs, + &mut unique_namespace, file_scope.clone(), function_scope.clone(), indicator, @@ -491,7 +515,16 @@ impl> ConstrainedProgram { span: Span, ) -> Result<(), StatementError> { let condition = indicator.unwrap_or(Boolean::Constant(true)); - let result = left.conditional_enforce_equal(cs, right, &condition); + let unique_namespace = cs.ns(|| { + format!( + "assert {} == {} {}:{}", + left.to_string(), + right.to_string(), + span.line, + span.start + ) + }); + let result = left.conditional_enforce_equal(unique_namespace, right, &condition); Ok(result.map_err(|_| StatementError::assertion_failed(left.to_string(), right.to_string(), span))?) } diff --git a/compiler/src/constraints/value.rs b/compiler/src/constraints/value.rs index 1d502fb524..fa194cfb3c 100644 --- a/compiler/src/constraints/value.rs +++ b/compiler/src/constraints/value.rs @@ -1,6 +1,14 @@ //! The in memory stored value for a defined name in a resolved Leo program. -use crate::{errors::ValueError, new_bool_constant, FieldType, GroupType}; +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; @@ -8,7 +16,7 @@ use snarkos_models::{ curves::{Field, PrimeField}, gadgets::{ r1cs::ConstraintSystem, - utilities::{alloc::AllocGadget, boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget}, + utilities::{boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget}, }, }; use std::fmt; @@ -104,25 +112,28 @@ impl> ConstrainedValue { // 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, 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) => {