implicit arrays and multiple definitions

This commit is contained in:
collin 2020-05-18 15:17:17 -07:00
parent d0c88a08be
commit aa63cf1dbb
8 changed files with 102 additions and 17 deletions

View File

@ -1,3 +1,10 @@
function main() { function test(mut a: u32) {
let a: u32 = if true ? 1 : 5; a = 0;
}
function main() -> u32 {
let a = 1;
test(a);
return a // <- returns 1
} }

View File

@ -142,6 +142,9 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => { (ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
Ok(self.enforce_field_mul(cs, fe_1, fe_2)?) Ok(self.enforce_field_mul(cs, fe_1, fe_2)?)
} }
// (ConstrainedValue::GroupElement(group), ConstrainedValue::FieldElement(scalar)) => {
// Ok(Self::evaluate_group_mul(group, scalar))
// }
(ConstrainedValue::Mutable(val_1), val_2) => { (ConstrainedValue::Mutable(val_1), val_2) => {
self.enforce_mul_expression(cs, *val_1, val_2) self.enforce_mul_expression(cs, *val_1, val_2)
} }
@ -439,9 +442,20 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: Vec<Type<F, G>>, mut expected_types: Vec<Type<F, G>>,
array: Vec<Box<SpreadOrExpression<F, G>>>, array: Vec<Box<SpreadOrExpression<F, G>>>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Check explicit array type dimension if given
let expected_dimensions = vec![];
if !expected_types.is_empty() {
match expected_types[0] {
Type::Array(ref _type, ref dimensions) => {
expected_types = vec![expected_types[0].inner_dimension(dimensions)];
}
ref _type => return Err(ExpressionError::IncompatibleTypes(_type.to_string())),
}
}
let mut result = vec![]; let mut result = vec![];
for element in array.into_iter() { for element in array.into_iter() {
match *element { match *element {
@ -471,6 +485,17 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
} }
} }
} }
// Check expected_dimensions if given
if !expected_dimensions.is_empty() {
if expected_dimensions[expected_dimensions.len() - 1] != result.len() {
return Err(ExpressionError::InvalidLength(
expected_dimensions[expected_dimensions.len() - 1],
result.len(),
));
}
}
Ok(ConstrainedValue::Array(result)) Ok(ConstrainedValue::Array(result))
} }
@ -484,6 +509,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
) -> Result<usize, ExpressionError> { ) -> Result<usize, ExpressionError> {
match self.enforce_expression(cs, file_scope, function_scope, expected_types, index)? { match self.enforce_expression(cs, file_scope, function_scope, expected_types, index)? {
ConstrainedValue::Integer(number) => Ok(number.to_usize()), ConstrainedValue::Integer(number) => Ok(number.to_usize()),
ConstrainedValue::Unresolved(string) => Ok(string.parse::<usize>()?),
value => Err(ExpressionError::InvalidIndex(value.to_string())), value => Err(ExpressionError::InvalidIndex(value.to_string())),
} }
} }

View File

@ -127,7 +127,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Allocate each value in the current row // Allocate each value in the current row
for (i, value) in arr.into_iter().enumerate() { for (i, value) in arr.into_iter().enumerate() {
let value_name = new_scope(name.clone(), i.to_string()); let value_name = new_scope(name.clone(), i.to_string());
let value_type = array_type.next_dimension(&array_dimensions); let value_type = array_type.outer_dimension(&array_dimensions);
array_value.push(self.allocate_main_function_input( array_value.push(self.allocate_main_function_input(
cs, cs,
@ -142,7 +142,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Allocate all row values as none // Allocate all row values as none
for i in 0..expected_length { for i in 0..expected_length {
let value_name = new_scope(name.clone(), i.to_string()); let value_name = new_scope(name.clone(), i.to_string());
let value_type = array_type.next_dimension(&array_dimensions); let value_type = array_type.outer_dimension(&array_dimensions);
array_value.push( array_value.push(
self.allocate_main_function_input( self.allocate_main_function_input(

View File

@ -17,4 +17,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub fn evaluate_group_sub(group_element_1: G, group_element_2: G) -> ConstrainedValue<F, G> { pub fn evaluate_group_sub(group_element_1: G, group_element_2: G) -> ConstrainedValue<F, G> {
ConstrainedValue::GroupElement(group_element_1.sub(&group_element_2)) ConstrainedValue::GroupElement(group_element_1.sub(&group_element_2))
} }
//
// pub fn evaluate_group_mul(group_element: G, scalar_field: G::ScalarField) -> ConstrainedValue<F, G> {
// ConstrainedValue::GroupElement(group_element.mul(&scalar_field))
// }
} }

View File

@ -51,27 +51,30 @@ impl<F: Field + PrimeField, G: Group> ConstrainedValue<F, G> {
} }
pub(crate) fn from_type(value: String, _type: &Type<F, G>) -> Result<Self, ValueError> { pub(crate) fn from_type(value: String, _type: &Type<F, G>) -> Result<Self, ValueError> {
Ok(match _type { match _type {
Type::IntegerType(integer_type) => ConstrainedValue::Integer(match integer_type { Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(match integer_type {
IntegerType::U8 => Integer::U8(UInt8::constant(value.parse::<u8>()?)), IntegerType::U8 => Integer::U8(UInt8::constant(value.parse::<u8>()?)),
IntegerType::U16 => Integer::U16(UInt16::constant(value.parse::<u16>()?)), IntegerType::U16 => Integer::U16(UInt16::constant(value.parse::<u16>()?)),
IntegerType::U32 => Integer::U32(UInt32::constant(value.parse::<u32>()?)), IntegerType::U32 => Integer::U32(UInt32::constant(value.parse::<u32>()?)),
IntegerType::U64 => Integer::U64(UInt64::constant(value.parse::<u64>()?)), IntegerType::U64 => Integer::U64(UInt64::constant(value.parse::<u64>()?)),
IntegerType::U128 => Integer::U128(UInt128::constant(value.parse::<u128>()?)), IntegerType::U128 => Integer::U128(UInt128::constant(value.parse::<u128>()?)),
}), })),
Type::FieldElement => ConstrainedValue::FieldElement(FieldElement::Constant( Type::FieldElement => Ok(ConstrainedValue::FieldElement(FieldElement::Constant(
F::from_str(&value).unwrap_or_default(), F::from_str(&value).unwrap_or_default(),
)), ))),
Type::GroupElement => ConstrainedValue::GroupElement({ Type::GroupElement => Ok(ConstrainedValue::GroupElement({
use std::str::FromStr; use std::str::FromStr;
let scalar = G::ScalarField::from_str(&value).unwrap_or_default(); let scalar = G::ScalarField::from_str(&value).unwrap_or_default();
let point = G::default().mul(&scalar); let point = G::default().mul(&scalar);
point point
}), })),
Type::Boolean => ConstrainedValue::Boolean(Boolean::Constant(value.parse::<bool>()?)), Type::Boolean => Ok(ConstrainedValue::Boolean(Boolean::Constant(
_ => ConstrainedValue::Unresolved(value), value.parse::<bool>()?,
}) ))),
Type::Array(ref _type, _dimensions) => ConstrainedValue::from_type(value, _type),
_ => Ok(ConstrainedValue::Unresolved(value)),
}
} }
pub(crate) fn to_type(&self) -> Type<F, G> { pub(crate) fn to_type(&self) -> Type<F, G> {

View File

@ -1,6 +1,7 @@
use crate::errors::{BooleanError, FieldElementError, FunctionError, IntegerError, ValueError}; use crate::errors::{BooleanError, FieldElementError, FunctionError, IntegerError, ValueError};
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
use std::num::ParseIntError;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ExpressionError { pub enum ExpressionError {
@ -21,6 +22,9 @@ pub enum ExpressionError {
#[error("{}", _0)] #[error("{}", _0)]
IntegerError(IntegerError), IntegerError(IntegerError),
#[error("{}", _0)]
ParseIntError(ParseIntError),
#[error("{}", _0)] #[error("{}", _0)]
FieldElementError(FieldElementError), FieldElementError(FieldElementError),
@ -46,6 +50,9 @@ pub enum ExpressionError {
#[error("Index must resolve to an integer, got {}", _0)] #[error("Index must resolve to an integer, got {}", _0)]
InvalidIndex(String), InvalidIndex(String),
#[error("Expected array length {}, got {}", _0, _1)]
InvalidLength(usize, usize),
// Circuits // Circuits
#[error( #[error(
"Circuit {} must be declared before it is used in an inline expression", "Circuit {} must be declared before it is used in an inline expression",
@ -110,6 +117,12 @@ impl From<IntegerError> for ExpressionError {
} }
} }
impl From<ParseIntError> for ExpressionError {
fn from(error: ParseIntError) -> Self {
ExpressionError::ParseIntError(error)
}
}
impl From<FieldElementError> for ExpressionError { impl From<FieldElementError> for ExpressionError {
fn from(error: FieldElementError) -> Self { fn from(error: FieldElementError) -> Self {
ExpressionError::FieldElementError(error) ExpressionError::FieldElementError(error)

View File

@ -156,7 +156,7 @@ pub enum Type<F: Field + PrimeField, G: Group> {
} }
impl<F: Field + PrimeField, G: Group> Type<F, G> { impl<F: Field + PrimeField, G: Group> Type<F, G> {
pub fn next_dimension(&self, dimensions: &Vec<usize>) -> Self { pub fn outer_dimension(&self, dimensions: &Vec<usize>) -> Self {
let _type = self.clone(); let _type = self.clone();
if dimensions.len() > 1 { if dimensions.len() > 1 {
@ -168,6 +168,19 @@ impl<F: Field + PrimeField, G: Group> Type<F, G> {
_type _type
} }
pub fn inner_dimension(&self, dimensions: &Vec<usize>) -> Self {
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);
}
_type
}
} }
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]

View File

@ -61,6 +61,12 @@ impl<'ast> types::Integer {
)), )),
} }
} }
pub(crate) fn from_implicit(number: String) -> Self {
types::Integer::U128(UInt128::constant(
number.parse::<u128>().expect("unable to parse u128"),
))
}
} }
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Integer<'ast>> for types::Expression<F, G> { impl<'ast, F: Field + PrimeField, G: Group> From<ast::Integer<'ast>> for types::Expression<F, G> {
@ -79,6 +85,9 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::RangeOrExpression<'ast>>
.from .from
.map(|from| match types::Expression::<F, G>::from(from.0) { .map(|from| match types::Expression::<F, G>::from(from.0) {
types::Expression::Integer(number) => number, types::Expression::Integer(number) => number,
types::Expression::Implicit(string) => {
types::Integer::from_implicit(string)
}
expression => { expression => {
unimplemented!("Range bounds should be integers, found {}", expression) unimplemented!("Range bounds should be integers, found {}", expression)
} }
@ -87,6 +96,9 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::RangeOrExpression<'ast>>
.to .to
.map(|to| match types::Expression::<F, G>::from(to.0) { .map(|to| match types::Expression::<F, G>::from(to.0) {
types::Expression::Integer(number) => number, types::Expression::Integer(number) => number,
types::Expression::Implicit(string) => {
types::Integer::from_implicit(string)
}
expression => { expression => {
unimplemented!("Range bounds should be integers, found {}", expression) unimplemented!("Range bounds should be integers, found {}", expression)
} }
@ -375,7 +387,12 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Expression<'ast>>
impl<'ast, F: Field + PrimeField, G: Group> types::Expression<F, G> { impl<'ast, F: Field + PrimeField, G: Group> types::Expression<F, G> {
fn get_count(count: ast::Value<'ast>) -> usize { fn get_count(count: ast::Value<'ast>) -> usize {
match count { match count {
ast::Value::Integer(f) => f ast::Value::Integer(integer) => integer
.number
.value
.parse::<usize>()
.expect("Unable to read array size"),
ast::Value::Implicit(number) => number
.number .number
.value .value
.parse::<usize>() .parse::<usize>()
@ -590,10 +607,12 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::ForStatement<'ast>>
fn from(statement: ast::ForStatement<'ast>) -> Self { fn from(statement: ast::ForStatement<'ast>) -> Self {
let from = match types::Expression::<F, G>::from(statement.start) { let from = match types::Expression::<F, G>::from(statement.start) {
types::Expression::Integer(number) => number, types::Expression::Integer(number) => number,
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
expression => unimplemented!("Range bounds should be integers, found {}", expression), expression => unimplemented!("Range bounds should be integers, found {}", expression),
}; };
let to = match types::Expression::<F, G>::from(statement.stop) { let to = match types::Expression::<F, G>::from(statement.stop) {
types::Expression::Integer(number) => number, types::Expression::Integer(number) => number,
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
expression => unimplemented!("Range bounds should be integers, found {}", expression), expression => unimplemented!("Range bounds should be integers, found {}", expression),
}; };