From 8a668677d9c1533fdb832333685ca85347e9974c Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Fri, 14 Nov 2025 16:21:11 -0300 Subject: [PATCH 1/3] Fix is_zero for bounded ints --- src/libfuncs/bounded_int.rs | 69 +++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index b8b1e358f..8478a9edf 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -796,11 +796,19 @@ fn build_is_zero<'ctx, 'this>( _metadata: &mut MetadataStorage, info: &SignatureOnlyConcreteLibfunc, ) -> Result<()> { - let src_value: Value = entry.arg(0)?; + let mut src_value: Value = entry.arg(0)?; let src_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; let src_range = src_ty.integer_range(registry)?; + if src_ty.is_bounded_int(registry)? { + let ty = IntegerType::new(context, src_range.offset_bit_width()).into(); + let lower_bound = + entry.const_int_from_type(context, location, src_range.lower.clone(), ty)?; + src_value = entry.extui(src_value, ty, location)?; + src_value = entry.addi(src_value, lower_bound, location)?; + } + native_assert!( src_range.lower <= BigInt::ZERO && BigInt::ZERO < src_range.upper, "value can never be zero" @@ -854,8 +862,11 @@ mod test { use cairo_vm::Felt252; use crate::{ - context::NativeContext, execution_result::ExecutionResult, executor::JitNativeExecutor, - utils::test::load_cairo, OptLevel, Value, + context::NativeContext, + execution_result::ExecutionResult, + executor::JitNativeExecutor, + utils::test::{load_cairo, run_program}, + OptLevel, Value, }; #[test] @@ -989,4 +1000,56 @@ mod test { }; assert_eq!(value, Felt252::from(0)); } + + fn assert_bool_output(result: Value, expected_tag: usize) { + if let Value::Enum { tag, value, .. } = result { + assert_eq!(tag, 0); + if let Value::Struct { fields, .. } = *value { + if let Value::Enum { tag, .. } = fields[0] { + assert_eq!(tag, expected_tag) + } + } + } + } + + #[test] + fn test_is_zero() { + let program = load_cairo! { + #[feature("bounded-int-utils")] + use core::internal::bounded_int::{self, BoundedInt, is_zero}; + use core::zeroable::IsZeroResult; + + fn run_test_1(a: felt252) -> bool { + let bi: BoundedInt<0, 5> = a.try_into().unwrap(); + match is_zero(bi) { + IsZeroResult::Zero => true, + IsZeroResult::NonZero(_) => false, + } + } + + fn run_test_2(a: felt252) -> bool { + let bi: BoundedInt<-5, 5> = a.try_into().unwrap(); + match is_zero(bi) { + IsZeroResult::Zero => true, + IsZeroResult::NonZero(_) => false, + } + } + }; + + let result = + run_program(&program, "run_test_1", &[Value::Felt252(Felt252::from(0))]).return_value; + assert_bool_output(result, 1); + + let result = + run_program(&program, "run_test_1", &[Value::Felt252(Felt252::from(5))]).return_value; + assert_bool_output(result, 0); + + let result = + run_program(&program, "run_test_2", &[Value::Felt252(Felt252::from(0))]).return_value; + assert_bool_output(result, 1); + + let result = + run_program(&program, "run_test_2", &[Value::Felt252(Felt252::from(-5))]).return_value; + assert_bool_output(result, 0); + } } From 2bea204e4face7ca8d28a57bac746acc8b4add1e Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Fri, 14 Nov 2025 18:25:23 -0300 Subject: [PATCH 2/3] Refactor --- src/libfuncs/bounded_int.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 8478a9edf..a19532c9c 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -796,25 +796,21 @@ fn build_is_zero<'ctx, 'this>( _metadata: &mut MetadataStorage, info: &SignatureOnlyConcreteLibfunc, ) -> Result<()> { - let mut src_value: Value = entry.arg(0)?; + let src_value: Value = entry.arg(0)?; let src_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; let src_range = src_ty.integer_range(registry)?; - if src_ty.is_bounded_int(registry)? { - let ty = IntegerType::new(context, src_range.offset_bit_width()).into(); - let lower_bound = - entry.const_int_from_type(context, location, src_range.lower.clone(), ty)?; - src_value = entry.extui(src_value, ty, location)?; - src_value = entry.addi(src_value, lower_bound, location)?; - } - native_assert!( src_range.lower <= BigInt::ZERO && BigInt::ZERO < src_range.upper, "value can never be zero" ); - let k0 = entry.const_int_from_type(context, location, 0, src_value.r#type())?; + let k0 = if src_ty.is_bounded_int(registry)? { + entry.const_int_from_type(context, location, 0 - src_range.lower, src_value.r#type())? + } else { + entry.const_int_from_type(context, location, 0, src_value.r#type())? + }; let src_is_zero = entry.cmpi(context, CmpiPredicate::Eq, src_value, k0, location)?; helper.cond_br( From 6cbd14c6c9c902a31fdf3e033d25d57b21505a8e Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Fri, 14 Nov 2025 19:10:38 -0300 Subject: [PATCH 3/3] Add comment --- src/libfuncs/bounded_int.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index a19532c9c..78e93e2ee 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -807,6 +807,8 @@ fn build_is_zero<'ctx, 'this>( ); let k0 = if src_ty.is_bounded_int(registry)? { + // We can do the substraction since the lower bound of the bounded int will + // always be less or equal than 0. entry.const_int_from_type(context, location, 0 - src_range.lower, src_value.r#type())? } else { entry.const_int_from_type(context, location, 0, src_value.r#type())?