bounds check

This commit is contained in:
Protryon 2021-06-04 07:35:50 -07:00
parent dc91b07e5c
commit e6b7f0fce3
2 changed files with 43 additions and 21 deletions

View File

@ -37,6 +37,33 @@ use snarkvm_gadgets::utilities::{
use snarkvm_r1cs::ConstraintSystem; use snarkvm_r1cs::ConstraintSystem;
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> { impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
pub fn array_bounds_check<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
index_resolved: &Integer,
array_len: u32,
span: &Span,
) -> Result<(), ExpressionError> {
let bounds_check = evaluate_lt::<F, G, CS>(
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)] #[allow(clippy::too_many_arguments)]
pub fn enforce_array_access<CS: ConstraintSystem<F>>( pub fn enforce_array_access<CS: ConstraintSystem<F>>(
&mut self, &mut self,
@ -65,21 +92,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
.len() .len()
.try_into() .try_into()
.map_err(|_| ExpressionError::array_length_out_of_bounds(span))?; .map_err(|_| ExpressionError::array_length_out_of_bounds(span))?;
let bounds_check = evaluate_lt::<F, G, CS>( self.array_bounds_check(cs, &&index_resolved, array_len, span)?;
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))?;
} }
let mut current_value = array.pop().unwrap(); let mut current_value = array.pop().unwrap();

View File

@ -25,7 +25,7 @@ use crate::{
GroupType, GroupType,
Integer, Integer,
}; };
use leo_asg::{ConstInt, Expression}; use leo_asg::{ConstInt, Expression, Node};
use snarkvm_fields::PrimeField; use snarkvm_fields::PrimeField;
use snarkvm_gadgets::utilities::{eq::EvaluateEqGadget, select::CondSelectGadget}; use snarkvm_gadgets::utilities::{eq::EvaluateEqGadget, select::CondSelectGadget};
@ -65,25 +65,34 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
} }
} }
} else { } 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() { for (i, item) in input.iter_mut().enumerate() {
let namespace_string = format!( let namespace_string = format!(
"evaluate dyn array assignment eq {} {}:{}", "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 eq_namespace = cs.ns(|| namespace_string);
let index_bounded = i let index_bounded = i
.try_into() .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 const_index = ConstInt::U32(index_bounded).cast_to(&index_resolved.get_type());
let index_comparison = index_resolved let index_comparison = index_resolved
.evaluate_equal(eq_namespace, &Integer::new(&const_index)) .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(|| { let unique_namespace = cs.ns(|| {
format!( format!(
"select array dyn assignment {} {}:{}", "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( let value = ConstrainedValue::conditionally_select(
@ -92,7 +101,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
&context.target_value, &context.target_value,
&item, &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; *item = value;
} }
Ok(()) Ok(())