diff --git a/compiler/src/expression/array/access.rs b/compiler/src/expression/array/access.rs index 58544548b7..bbaf1929e0 100644 --- a/compiler/src/expression/array/access.rs +++ b/compiler/src/expression/array/access.rs @@ -37,6 +37,33 @@ use snarkvm_gadgets::utilities::{ use snarkvm_r1cs::ConstraintSystem; impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { + pub fn array_bounds_check>( + &mut self, + cs: &mut CS, + index_resolved: &Integer, + array_len: u32, + span: &Span, + ) -> Result<(), ExpressionError> { + let bounds_check = evaluate_lt::( + cs, + ConstrainedValue::Integer(index_resolved.clone()), + ConstrainedValue::Integer(Integer::new( + &ConstInt::U32(array_len).cast_to(&index_resolved.get_type()), + )), + span, + )?; + let bounds_check = match bounds_check { + ConstrainedValue::Boolean(b) => b, + _ => unimplemented!("illegal non-Integer returned from lt"), + }; + let namespace_string = format!("evaluate array access bounds {}:{}", span.line_start, span.col_start); + let mut unique_namespace = cs.ns(|| namespace_string); + bounds_check + .enforce_equal(&mut unique_namespace, &Boolean::Constant(true)) + .map_err(|e| ExpressionError::cannot_enforce("array bounds check".to_string(), e, span))?; + Ok(()) + } + #[allow(clippy::too_many_arguments)] pub fn enforce_array_access>( &mut self, @@ -65,21 +92,7 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { .len() .try_into() .map_err(|_| ExpressionError::array_length_out_of_bounds(span))?; - let bounds_check = evaluate_lt::( - cs, - ConstrainedValue::Integer(index_resolved.clone()), - ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array_len))), - span, - )?; - let bounds_check = match bounds_check { - ConstrainedValue::Boolean(b) => b, - _ => unimplemented!("illegal non-Integer returned from lt"), - }; - let namespace_string = format!("evaluate array access bounds {}:{}", span.line_start, span.col_start); - let mut unique_namespace = cs.ns(|| namespace_string); - bounds_check - .enforce_equal(&mut unique_namespace, &Boolean::Constant(true)) - .map_err(|e| ExpressionError::cannot_enforce("array bounds check".to_string(), e, span))?; + self.array_bounds_check(cs, &&index_resolved, array_len, span)?; } let mut current_value = array.pop().unwrap(); diff --git a/compiler/src/statement/assign/assignee/array_index.rs b/compiler/src/statement/assign/assignee/array_index.rs index 14cee72017..be35e5f1ac 100644 --- a/compiler/src/statement/assign/assignee/array_index.rs +++ b/compiler/src/statement/assign/assignee/array_index.rs @@ -25,7 +25,7 @@ use crate::{ GroupType, Integer, }; -use leo_asg::{ConstInt, Expression}; +use leo_asg::{ConstInt, Expression, Node}; use snarkvm_fields::PrimeField; use snarkvm_gadgets::utilities::{eq::EvaluateEqGadget, select::CondSelectGadget}; @@ -65,25 +65,34 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { } } } else { + let span = index.span().cloned().unwrap_or_default(); + { + let array_len: u32 = input + .len() + .try_into() + .map_err(|_| ExpressionError::array_length_out_of_bounds(&span))?; + self.array_bounds_check(cs, &&index_resolved, array_len, &span)?; + } + for (i, item) in input.iter_mut().enumerate() { let namespace_string = format!( "evaluate dyn array assignment eq {} {}:{}", - i, context.span.line_start, context.span.col_start + i, span.line_start, span.col_start ); let eq_namespace = cs.ns(|| namespace_string); let index_bounded = i .try_into() - .map_err(|_| ExpressionError::array_index_out_of_legal_bounds(&context.span))?; + .map_err(|_| ExpressionError::array_index_out_of_legal_bounds(&span))?; let const_index = ConstInt::U32(index_bounded).cast_to(&index_resolved.get_type()); let index_comparison = index_resolved .evaluate_equal(eq_namespace, &Integer::new(&const_index)) - .map_err(|_| ExpressionError::cannot_evaluate("==".to_string(), &context.span))?; + .map_err(|_| ExpressionError::cannot_evaluate("==".to_string(), &span))?; let unique_namespace = cs.ns(|| { format!( "select array dyn assignment {} {}:{}", - i, context.span.line_start, context.span.col_start + i, span.line_start, span.col_start ) }); let value = ConstrainedValue::conditionally_select( @@ -92,7 +101,7 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { &context.target_value, &item, ) - .map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, &context.span))?; + .map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, &span))?; *item = value; } Ok(())