@@ -3,7 +3,7 @@ use std::ops::Shl;
33use cairo_lang_utils:: require;
44use itertools:: Itertools ;
55use num_bigint:: { BigInt , ToBigInt } ;
6- use num_traits:: { One , Signed , Zero } ;
6+ use num_traits:: { One , Signed , ToPrimitive , Zero } ;
77use starknet_types_core:: felt:: Felt as Felt252 ;
88
99use super :: non_zero:: { NonZeroType , nonzero_ty} ;
@@ -37,30 +37,34 @@ impl NamedType for BoundedIntType {
3737 _context : & dyn TypeSpecializationContext ,
3838 args : & [ GenericArg ] ,
3939 ) -> Result < Self :: Concrete , SpecializationError > {
40- let ( min, max) = match args {
41- [ GenericArg :: Value ( min) , GenericArg :: Value ( max) ] => ( min. clone ( ) , max. clone ( ) ) ,
42- [ _, _] => return Err ( SpecializationError :: UnsupportedGenericArg ) ,
43- _ => return Err ( SpecializationError :: WrongNumberOfGenericArgs ) ,
44- } ;
45-
46- let prime: BigInt = Felt252 :: prime ( ) . into ( ) ;
47- if !( -& prime < min && min <= max && max < prime && & max - & min < prime) {
48- return Err ( SpecializationError :: UnsupportedGenericArg ) ;
49- }
40+ specialize_bounded_int_type ( Self :: ID , args, true , true )
41+ }
42+ }
5043
51- let long_id = Self :: concrete_type_long_id ( args) ;
52- let ty_info = TypeInfo {
53- long_id,
54- zero_sized : false ,
55- storable : true ,
56- droppable : true ,
57- duplicatable : true ,
58- } ;
44+ /// Type for BoundedIntGuarantee.
45+ /// A guarantee that a value is within the specified bounds.
46+ /// Unlike BoundedInt, this type is non-duplicatable and non-droppable.
47+ /// It must be verified via `bounded_int_guarantee_verify` to be consumed.
48+ /// Currently only supports u32 bounds (0 to 2^32-1).
49+ #[ derive( Default ) ]
50+ pub struct BoundedIntGuaranteeType { }
51+ impl NamedType for BoundedIntGuaranteeType {
52+ type Concrete = BoundedIntConcreteType ;
5953
60- Ok ( Self :: Concrete { info : ty_info, range : Range :: closed ( min, max) } )
54+ const ID : GenericTypeId = GenericTypeId :: new_inline ( "BoundedIntGuarantee" ) ;
55+ fn specialize (
56+ & self ,
57+ _context : & dyn TypeSpecializationContext ,
58+ args : & [ GenericArg ] ,
59+ ) -> Result < Self :: Concrete , SpecializationError > {
60+ let ( min, max) = extract_bounds ( args) ?;
61+ // Currently only u32 guarantees are supported.
62+ require ( is_u32_range ( min, max) ) . ok_or ( SpecializationError :: UnsupportedGenericArg ) ?;
63+ specialize_bounded_int_type ( Self :: ID , args, false , false )
6164 }
6265}
6366
67+ /// Shared concrete type for BoundedInt and BoundedIntGuarantee.
6468pub struct BoundedIntConcreteType {
6569 pub info : TypeInfo ,
6670 /// The range bounds for a value of this type.
@@ -83,6 +87,7 @@ define_libfunc_hierarchy! {
8387 TrimMax ( BoundedIntTrimLibfunc <true >) ,
8488 IsZero ( BoundedIntIsZeroLibfunc ) ,
8589 WrapNonZero ( BoundedIntWrapNonZeroLibfunc ) ,
90+ GuaranteeVerify ( BoundedIntGuaranteeVerifyLibfunc ) ,
8691 } , BoundedIntConcreteLibfunc
8792}
8893
@@ -544,6 +549,63 @@ impl SignatureOnlyGenericLibfunc for BoundedIntWrapNonZeroLibfunc {
544549 }
545550}
546551
552+ /// Libfunc for verifying a BoundedIntGuarantee.
553+ /// Consumes the guarantee and returns the underlying value as a BoundedInt.
554+ /// Generic args: [min, max] - the bounds of the guarantee.
555+ /// Currently only supports u32 bounds (0 to 2^32-1).
556+ #[ derive( Default ) ]
557+ pub struct BoundedIntGuaranteeVerifyLibfunc { }
558+ impl NamedLibfunc for BoundedIntGuaranteeVerifyLibfunc {
559+ type Concrete = BoundedIntGuaranteeVerifyConcreteLibfunc ;
560+
561+ const STR_ID : & ' static str = "bounded_int_guarantee_verify" ;
562+
563+ fn specialize_signature (
564+ & self ,
565+ context : & dyn SignatureSpecializationContext ,
566+ args : & [ GenericArg ] ,
567+ ) -> Result < LibfuncSignature , SpecializationError > {
568+ let ( min, max) = extract_bounds ( args) ?;
569+ // Currently only u32 guarantees are supported.
570+ require ( is_u32_range ( min, max) ) . ok_or ( SpecializationError :: UnsupportedGenericArg ) ?;
571+
572+ let range_check_ty = context. get_concrete_type ( RangeCheckType :: ID , & [ ] ) ?;
573+ let guarantee_ty = bounded_int_guarantee_ty ( context, min. clone ( ) , max. clone ( ) ) ?;
574+
575+ Ok ( LibfuncSignature :: new_non_branch_ex (
576+ vec ! [
577+ ParamSignature :: new( range_check_ty. clone( ) ) . with_allow_add_const( ) ,
578+ ParamSignature :: new( guarantee_ty) ,
579+ ] ,
580+ vec ! [ OutputVarInfo :: new_builtin( range_check_ty) ] ,
581+ SierraApChange :: Known { new_vars_only : false } ,
582+ ) )
583+ }
584+
585+ fn specialize (
586+ & self ,
587+ context : & dyn SpecializationContext ,
588+ args : & [ GenericArg ] ,
589+ ) -> Result < Self :: Concrete , SpecializationError > {
590+ let ( min, max) = extract_bounds ( args) ?;
591+ // Currently only u32 guarantees are supported.
592+ require ( is_u32_range ( min, max) ) . ok_or ( SpecializationError :: UnsupportedGenericArg ) ?;
593+
594+ let range = Range :: closed ( min. clone ( ) , max. clone ( ) ) ;
595+ Ok ( Self :: Concrete { range, signature : self . specialize_signature ( context, args) ? } )
596+ }
597+ }
598+
599+ pub struct BoundedIntGuaranteeVerifyConcreteLibfunc {
600+ pub range : Range ,
601+ signature : LibfuncSignature ,
602+ }
603+ impl SignatureBasedConcreteLibfunc for BoundedIntGuaranteeVerifyConcreteLibfunc {
604+ fn signature ( & self ) -> & LibfuncSignature {
605+ & self . signature
606+ }
607+ }
608+
547609/// Returns the concrete type for a BoundedInt<min, max>.
548610pub fn bounded_int_ty (
549611 context : & dyn SignatureSpecializationContext ,
@@ -552,3 +614,49 @@ pub fn bounded_int_ty(
552614) -> Result < ConcreteTypeId , SpecializationError > {
553615 context. get_concrete_type ( BoundedIntType :: ID , & [ GenericArg :: Value ( min) , GenericArg :: Value ( max) ] )
554616}
617+
618+ /// Returns the concrete type for a BoundedIntGuarantee<min, max>.
619+ pub fn bounded_int_guarantee_ty (
620+ context : & dyn SignatureSpecializationContext ,
621+ min : BigInt ,
622+ max : BigInt ,
623+ ) -> Result < ConcreteTypeId , SpecializationError > {
624+ context. get_concrete_type (
625+ BoundedIntGuaranteeType :: ID ,
626+ & [ GenericArg :: Value ( min) , GenericArg :: Value ( max) ] ,
627+ )
628+ }
629+
630+ /// Extracts min and max values from generic args.
631+ fn extract_bounds ( args : & [ GenericArg ] ) -> Result < ( & BigInt , & BigInt ) , SpecializationError > {
632+ match args {
633+ [ GenericArg :: Value ( min) , GenericArg :: Value ( max) ] => Ok ( ( min, max) ) ,
634+ [ _, _] => Err ( SpecializationError :: UnsupportedGenericArg ) ,
635+ _ => Err ( SpecializationError :: WrongNumberOfGenericArgs ) ,
636+ }
637+ }
638+
639+ /// Checks if the given bounds match the u32 range.
640+ fn is_u32_range ( min : & BigInt , max : & BigInt ) -> bool {
641+ min. is_zero ( ) && max. to_u32 ( ) == Some ( u32:: MAX )
642+ }
643+
644+ /// Helper to specialize bounded int types.
645+ fn specialize_bounded_int_type (
646+ generic_id : GenericTypeId ,
647+ args : & [ GenericArg ] ,
648+ droppable : bool ,
649+ duplicatable : bool ,
650+ ) -> Result < BoundedIntConcreteType , SpecializationError > {
651+ let ( min, max) = extract_bounds ( args) ?;
652+
653+ let prime: BigInt = Felt252 :: prime ( ) . into ( ) ;
654+ if !( -& prime < * min && min <= max && max < & prime && max - min < prime) {
655+ return Err ( SpecializationError :: UnsupportedGenericArg ) ;
656+ }
657+
658+ let long_id = crate :: program:: ConcreteTypeLongId { generic_id, generic_args : args. to_vec ( ) } ;
659+ let ty_info = TypeInfo { long_id, zero_sized : false , storable : true , droppable, duplicatable } ;
660+
661+ Ok ( BoundedIntConcreteType { info : ty_info, range : Range :: closed ( min. clone ( ) , max. clone ( ) ) } )
662+ }
0 commit comments