From 3f83786871c2755cb4b29d6d1d30ad7108d46d2a Mon Sep 17 00:00:00 2001 From: collin Date: Tue, 14 Apr 2020 17:50:26 -0700 Subject: [PATCH] constraints array initializer --- simple.program | 8 ++- src/aleo_program/constraints.rs | 109 +++++++++++++++++++----------- src/aleo_program/types.rs | 2 - src/aleo_program/types_display.rs | 32 ++++++++- src/aleo_program/types_from.rs | 80 ++++++++++++++++------ 5 files changed, 163 insertions(+), 68 deletions(-) diff --git a/simple.program b/simple.program index 1666f0bbc3..c4ab5a5061 100644 --- a/simple.program +++ b/simple.program @@ -1,3 +1,7 @@ -field[3] a = [1, 2, 3] -//b = 2 + 2 +bool[2] a = [true, false] +bool[2] b = [true; 2] + +field[4] c = [1, 2, 3, 4] +field[3] d = [1; 3] + return a \ No newline at end of file diff --git a/src/aleo_program/constraints.rs b/src/aleo_program/constraints.rs index 0e098c8768..d81141d9ee 100644 --- a/src/aleo_program/constraints.rs +++ b/src/aleo_program/constraints.rs @@ -25,6 +25,17 @@ pub enum ResolvedValue { impl fmt::Display for ResolvedValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { + ResolvedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()), + ResolvedValue::BooleanArray(ref array) => { + write!(f, "[")?; + for (i, e) in array.iter().enumerate() { + write!(f, "{}", e.get_value().unwrap())?; + if i < array.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, "]") + } ResolvedValue::FieldElement(ref value) => write!(f, "{}", value.value.unwrap()), ResolvedValue::FieldElementArray(ref array) => { write!(f, "[")?; @@ -112,7 +123,10 @@ impl ResolvedProgram { match expression { BooleanExpression::Variable(variable) => self.bool_from_variable(cs, variable), BooleanExpression::Value(value) => Boolean::Constant(value), - expression => self.enforce_boolean_expression(cs, expression), + expression => match self.enforce_boolean_expression(cs, expression) { + ResolvedValue::Boolean(value) => value, + _ => unimplemented!("boolean expression did not resolve to boolean"), + }, } } @@ -126,7 +140,7 @@ impl ResolvedProgram { FieldExpression::Number(number) => UInt32::constant(number), field => match self.enforce_field_expression(cs, field) { ResolvedValue::FieldElement(value) => value, - _ => unimplemented!("value not resolved"), + _ => unimplemented!("field expression did not resolve to field"), }, } } @@ -203,27 +217,54 @@ impl ResolvedProgram { &mut self, cs: &mut CS, expression: BooleanExpression, - ) -> Boolean { + ) -> ResolvedValue { match expression { - BooleanExpression::Variable(variable) => self.bool_from_variable(cs, variable), - BooleanExpression::Value(value) => Boolean::Constant(value), - BooleanExpression::Not(expression) => self.enforce_not(cs, *expression), - BooleanExpression::Or(left, right) => self.enforce_or(cs, *left, *right), - BooleanExpression::And(left, right) => self.enforce_and(cs, *left, *right), - BooleanExpression::BoolEq(left, right) => self.enforce_bool_equality(cs, *left, *right), + BooleanExpression::Variable(variable) => { + ResolvedValue::Boolean(self.bool_from_variable(cs, variable)) + } + BooleanExpression::Value(value) => ResolvedValue::Boolean(Boolean::Constant(value)), + BooleanExpression::Not(expression) => { + ResolvedValue::Boolean(self.enforce_not(cs, *expression)) + } + BooleanExpression::Or(left, right) => { + ResolvedValue::Boolean(self.enforce_or(cs, *left, *right)) + } + BooleanExpression::And(left, right) => { + ResolvedValue::Boolean(self.enforce_and(cs, *left, *right)) + } + BooleanExpression::BoolEq(left, right) => { + ResolvedValue::Boolean(self.enforce_bool_equality(cs, *left, *right)) + } BooleanExpression::FieldEq(left, right) => { - self.enforce_field_equality(cs, *left, *right) + ResolvedValue::Boolean(self.enforce_field_equality(cs, *left, *right)) } BooleanExpression::IfElse(first, second, third) => { - if self - .enforce_boolean_expression(cs, *first) - .eq(&Boolean::Constant(true)) - { + let resolved_first = match self.enforce_boolean_expression(cs, *first) { + ResolvedValue::Boolean(resolved) => resolved, + _ => unimplemented!("if else conditional must resolve to boolean"), + }; + if resolved_first.eq(&Boolean::Constant(true)) { self.enforce_boolean_expression(cs, *second) } else { self.enforce_boolean_expression(cs, *third) } } + BooleanExpression::Array(array) => ResolvedValue::BooleanArray( + array + .into_iter() + .map(|element| match *element { + BooleanSpreadOrExpression::Spread(_spread) => { + unimplemented!("spreads not enforced yet") + } + BooleanSpreadOrExpression::BooleanExpression(expression) => { + match self.enforce_boolean_expression(cs, expression) { + ResolvedValue::Boolean(value) => value, + _ => unimplemented!("cannot resolve boolean"), + } + } + }) + .collect::>(), + ), _ => unimplemented!(), } } @@ -345,10 +386,12 @@ impl ResolvedProgram { ResolvedValue::FieldElement(self.enforce_pow(cs, *left, *right)) } FieldExpression::IfElse(first, second, third) => { - if self - .enforce_boolean_expression(cs, *first) - .eq(&Boolean::Constant(true)) - { + let resolved_first = match self.enforce_boolean_expression(cs, *first) { + ResolvedValue::Boolean(resolved) => resolved, + _ => unimplemented!("if else conditional must resolve to boolean"), + }; + + if resolved_first.eq(&Boolean::Constant(true)) { self.enforce_field_expression(cs, *second) } else { self.enforce_field_expression(cs, *third) @@ -358,12 +401,11 @@ impl ResolvedProgram { array .into_iter() .map(|element| match *element { - FieldSpreadOrExpression::Spread(spread) => { + FieldSpreadOrExpression::Spread(_spread) => { unimplemented!("spreads not enforced yet") } FieldSpreadOrExpression::FieldExpression(expression) => { - let resolved = self.enforce_field_expression(cs, expression); - match resolved { + match self.enforce_field_expression(cs, expression) { ResolvedValue::FieldElement(value) => value, _ => unimplemented!("cannot resolve field"), } @@ -383,12 +425,8 @@ impl ResolvedProgram { Statement::Definition(variable, expression) => match expression { Expression::Boolean(boolean_expression) => { let res = self.enforce_boolean_expression(cs, boolean_expression); - println!( - " variable boolean result: {} = {}", - variable.0, - res.get_value().unwrap() - ); - self.insert(variable, ResolvedValue::Boolean(res)); + println!(" variable boolean result: {} = {}", variable.0, res); + self.insert(variable, res); } Expression::FieldElement(field_expression) => { let res = self.enforce_field_expression(cs, field_expression); @@ -441,24 +479,17 @@ impl ResolvedProgram { .for_each(|expression| match expression { Expression::Boolean(boolean_expression) => { let res = self.enforce_boolean_expression(cs, boolean_expression); - println!("\n Boolean result = {}", res.get_value().unwrap()); + println!("\n Boolean result = {}", res); } Expression::FieldElement(field_expression) => { let res = self.enforce_field_expression(cs, field_expression); println!("\n Field result = {}", res); } Expression::Variable(variable) => { - match self.resolved_variables.get_mut(&variable).unwrap().clone() { - ResolvedValue::Boolean(boolean) => println!( - "\n Variable result = {}", - boolean.get_value().unwrap() - ), - ResolvedValue::FieldElement(field_element) => println!( - "\n Variable field result = {}", - field_element.value.unwrap() - ), - _ => {} - } + println!( + "\n Return = {}", + self.resolved_variables.get_mut(&variable).unwrap().clone() + ); } }); } diff --git a/src/aleo_program/types.rs b/src/aleo_program/types.rs index a682dc41a2..e3def75898 100644 --- a/src/aleo_program/types.rs +++ b/src/aleo_program/types.rs @@ -90,8 +90,6 @@ pub enum Expression { /// Program statement that defines some action (or expression) to be carried out. #[derive(Clone)] pub enum Statement { - /// A statement that could be directly translated to a R1CS constraint a * b = c to be enforced - // Constraint(QuadraticCombination, LinearCombination), // Declaration(Variable), Definition(Variable, Expression), Return(Vec), diff --git a/src/aleo_program/types_display.rs b/src/aleo_program/types_display.rs index aead6d9b7d..23248871d4 100644 --- a/src/aleo_program/types_display.rs +++ b/src/aleo_program/types_display.rs @@ -5,8 +5,8 @@ //! @date 2020 use crate::aleo_program::{ - BooleanExpression, Expression, FieldExpression, FieldSpread, FieldSpreadOrExpression, - Statement, Struct, StructField, Type, Variable, + BooleanExpression, BooleanSpread, BooleanSpreadOrExpression, Expression, FieldExpression, + FieldSpread, FieldSpreadOrExpression, Statement, Struct, StructField, Type, Variable, }; use std::fmt; @@ -59,6 +59,23 @@ impl<'ast> fmt::Display for FieldExpression { } } +impl fmt::Display for BooleanSpread { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "...{}", self.0) + } +} + +impl fmt::Display for BooleanSpreadOrExpression { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + BooleanSpreadOrExpression::Spread(ref spread) => write!(f, "{}", spread), + BooleanSpreadOrExpression::BooleanExpression(ref expression) => { + write!(f, "{}", expression) + } + } + } +} + impl<'ast> fmt::Display for BooleanExpression { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -77,7 +94,16 @@ impl<'ast> fmt::Display for BooleanExpression { BooleanExpression::IfElse(ref a, ref b, ref c) => { write!(f, "if {} then {} else {} fi", a, b, c) } - _ => unimplemented!(), + BooleanExpression::Array(ref array) => { + write!(f, "[")?; + for (i, e) in array.iter().enumerate() { + write!(f, "{}", e)?; + if i < array.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, "]") + } } } } diff --git a/src/aleo_program/types_from.rs b/src/aleo_program/types_from.rs index 3210cdd75a..c25dc40966 100644 --- a/src/aleo_program/types_from.rs +++ b/src/aleo_program/types_from.rs @@ -286,9 +286,12 @@ impl<'ast> From> for types::Expression { ast::Expression::Not(expression) => types::Expression::from(expression), ast::Expression::Binary(expression) => types::Expression::from(expression), ast::Expression::Ternary(expression) => types::Expression::from(expression), - ast::Expression::ArrayInline(expression) => { + ast::Expression::ArrayInline(_expression) => { unimplemented!("unknown type for inline array expression") } + ast::Expression::ArrayInitializer(_expression) => { + unimplemented!("unknown type for array initializer expression") + } _ => unimplemented!(), } } @@ -313,12 +316,13 @@ impl<'ast> From> for types::BooleanSpread { } } -impl<'ast> From> for types::FieldSpread { - fn from(spread: ast::Spread<'ast>) -> Self { - let field_expression = types::Expression::from(spread.expression); - match field_expression { - types::Expression::FieldElement(expression) => types::FieldSpread(expression), - _ => unimplemented!("cannot create field spread from boolean type"), +impl<'ast> From> for types::BooleanSpreadOrExpression { + fn from(expression: ast::Expression<'ast>) -> Self { + match types::Expression::from(expression) { + types::Expression::Boolean(expression) => { + types::BooleanSpreadOrExpression::BooleanExpression(expression) + } + _ => unimplemented!("cannot create boolean expression from field type"), } } } @@ -330,8 +334,7 @@ impl<'ast> From> for types::BooleanSpreadOrExpress types::BooleanSpreadOrExpression::Spread(types::BooleanSpread::from(spread)) } ast::SpreadOrExpression::Expression(expression) => { - let boolean_expression = types::Expression::from(expression); - match boolean_expression { + match types::Expression::from(expression) { types::Expression::Boolean(expression) => { types::BooleanSpreadOrExpression::BooleanExpression(expression) } @@ -342,6 +345,27 @@ impl<'ast> From> for types::BooleanSpreadOrExpress } } +impl<'ast> From> for types::FieldSpread { + fn from(spread: ast::Spread<'ast>) -> Self { + let field_expression = types::Expression::from(spread.expression); + match field_expression { + types::Expression::FieldElement(expression) => types::FieldSpread(expression), + _ => unimplemented!("cannot create field spread from boolean type"), + } + } +} + +impl<'ast> From> for types::FieldSpreadOrExpression { + fn from(expression: ast::Expression<'ast>) -> Self { + match types::Expression::from(expression) { + types::Expression::FieldElement(expression) => { + types::FieldSpreadOrExpression::FieldExpression(expression) + } + _ => unimplemented!("cannot create field expression from boolean type"), + } + } +} + impl<'ast> From> for types::FieldSpreadOrExpression { fn from(s_or_e: ast::SpreadOrExpression<'ast>) -> Self { match s_or_e { @@ -349,20 +373,14 @@ impl<'ast> From> for types::FieldSpreadOrExpressio types::FieldSpreadOrExpression::Spread(types::FieldSpread::from(spread)) } ast::SpreadOrExpression::Expression(expression) => { - let field_expression = types::Expression::from(expression); - match field_expression { - types::Expression::FieldElement(expression) => { - types::FieldSpreadOrExpression::FieldExpression(expression) - } - _ => unimplemented!("cannot create field expression from boolean type"), - } + types::FieldSpreadOrExpression::from(expression) } } } } impl<'ast> types::Expression { - fn from_basic(ty: ast::BasicType<'ast>, expression: ast::Expression<'ast>) -> Self { + fn from_basic(_ty: ast::BasicType<'ast>, _expression: ast::Expression<'ast>) -> Self { unimplemented!("from basic not impl"); } @@ -375,8 +393,17 @@ impl<'ast> types::Expression { .into_iter() .map(|s_or_e| Box::new(types::BooleanSpreadOrExpression::from(s_or_e))) .collect(), - ast::Expression::ArrayInitializer(expression) => { - unimplemented!("no array init yet") + ast::Expression::ArrayInitializer(array) => { + let count = match array.count { + ast::Value::Field(f) => { + f.value.parse::().expect("Unable to read array size") + } + _ => unimplemented!("Array size should be an integer"), + }; + let expression = + Box::new(types::BooleanSpreadOrExpression::from(*array.expression)); + + vec![expression; count] } _ => unimplemented!("expected array after array type"), }; @@ -389,8 +416,17 @@ impl<'ast> types::Expression { .into_iter() .map(|s_or_e| Box::new(types::FieldSpreadOrExpression::from(s_or_e))) .collect(), - ast::Expression::ArrayInitializer(expression) => { - unimplemented!("array init not yet") + ast::Expression::ArrayInitializer(array) => { + let count = match array.count { + ast::Value::Field(f) => { + f.value.parse::().expect("Unable to read array size") + } + _ => unimplemented!("Array size should be an integer"), + }; + let expression = + Box::new(types::FieldSpreadOrExpression::from(*array.expression)); + + vec![expression; count] } _ => unimplemented!("expected array after array type"), }; @@ -399,7 +435,7 @@ impl<'ast> types::Expression { } } - fn from_struct(ty: ast::StructType<'ast>, expression: ast::Expression<'ast>) -> Self { + fn from_struct(_ty: ast::StructType<'ast>, _expression: ast::Expression<'ast>) -> Self { unimplemented!("from struct not impl"); }