Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,9 @@ pub fn core_libfunc_ap_change<InfoProvider: InvocationApChangeInfoProvider>(
vec![ApChange::Known(ap_change), ApChange::Known(ap_change)]
}
BoundedIntConcreteLibfunc::IsZero(_) => vec![ApChange::Known(0), ApChange::Known(0)],
BoundedIntConcreteLibfunc::WrapNonZero(_) => {
vec![ApChange::Known(0)]
}
BoundedIntConcreteLibfunc::WrapNonZero(_) => vec![ApChange::Known(0)],
BoundedIntConcreteLibfunc::ToGuarantee(_) => vec![ApChange::Known(0)],
BoundedIntConcreteLibfunc::GuaranteeContent(_) => vec![ApChange::Known(0)],
BoundedIntConcreteLibfunc::GuaranteeVerify(libfunc) => {
let ap_change = if libfunc.range.lower.is_zero() { 0 } else { 1 }
+ if &libfunc.range.upper - 1 == u128::MAX.into() { 0 } else { 1 };
Expand Down
6 changes: 3 additions & 3 deletions crates/cairo-lang-sierra-gas/src/core_libfunc_cost_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,9 +551,9 @@ pub fn core_libfunc_cost(
BoundedIntConcreteLibfunc::IsZero(_) => {
vec![ConstCost::steps(1).into(), ConstCost::steps(1).into()]
}
BoundedIntConcreteLibfunc::WrapNonZero(_) => {
vec![ConstCost::steps(0).into()]
}
BoundedIntConcreteLibfunc::WrapNonZero(_) => vec![ConstCost::steps(0).into()],
BoundedIntConcreteLibfunc::ToGuarantee(_) => vec![ConstCost::steps(0).into()],
BoundedIntConcreteLibfunc::GuaranteeContent(_) => vec![ConstCost::steps(0).into()],
BoundedIntConcreteLibfunc::GuaranteeVerify(libfunc) => {
let u128_bound = BigInt::one().shl(128);
let range_checks = if libfunc.range.size() == u128_bound { 1 } else { 2 };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use num_traits::{One, Zero};
use crate::invocations::casts::{validate_ge, validate_lt};
use crate::invocations::felt252::build_felt252_op_with_var;
use crate::invocations::int::u128_bound;
use crate::invocations::misc::{build_identity, build_is_zero};
use crate::invocations::misc::{build_dup, build_identity, build_is_zero};
use crate::invocations::{
BuiltinInfo, CompiledInvocation, CompiledInvocationBuilder, CostValidationInfo,
InvocationError, add_input_variables, get_non_fallthrough_statement_id,
Expand Down Expand Up @@ -47,6 +47,8 @@ pub fn build(
}
BoundedIntConcreteLibfunc::IsZero(_) => build_is_zero(builder),
BoundedIntConcreteLibfunc::WrapNonZero(_) => build_identity(builder),
BoundedIntConcreteLibfunc::ToGuarantee(_) => build_identity(builder),
BoundedIntConcreteLibfunc::GuaranteeContent(_) => build_dup(builder),
BoundedIntConcreteLibfunc::GuaranteeVerify(libfunc) => {
build_guarantee_verify(builder, libfunc)
}
Expand Down
68 changes: 68 additions & 0 deletions crates/cairo-lang-sierra/src/extensions/modules/bounded_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ define_libfunc_hierarchy! {
TrimMax(BoundedIntTrimLibfunc<true>),
IsZero(BoundedIntIsZeroLibfunc),
WrapNonZero(BoundedIntWrapNonZeroLibfunc),
ToGuarantee(BoundedIntToGuaranteeLibfunc),
GuaranteeContent(BoundedIntGuaranteeContentLibfunc),
GuaranteeVerify(BoundedIntGuaranteeVerifyLibfunc),
U128ToU32Guarantees(U128ToU32GuaranteesLibfunc),
}, BoundedIntConcreteLibfunc
Expand Down Expand Up @@ -552,6 +554,72 @@ impl SignatureOnlyGenericLibfunc for BoundedIntWrapNonZeroLibfunc {
}
}

/// Libfunc for converting a bounded int into a guarantee - used for converting into interfaces
/// expecting guarantees.
#[derive(Default)]
pub struct BoundedIntToGuaranteeLibfunc {}
impl SignatureOnlyGenericLibfunc for BoundedIntToGuaranteeLibfunc {
const STR_ID: &'static str = "bounded_int_to_guarantee";

fn specialize_signature(
&self,
context: &dyn SignatureSpecializationContext,
args: &[GenericArg],
) -> Result<LibfuncSignature, SpecializationError> {
let (min, max) = extract_bounds(args)?;
// Currently only u32 guarantees are supported.
require(is_valid_guarantee_range(min, max))
.ok_or(SpecializationError::UnsupportedGenericArg)?;

Ok(LibfuncSignature::new_non_branch_ex(
vec![
ParamSignature::new(bounded_int_ty(context, min.clone(), max.clone())?)
.with_allow_all(),
],
vec![OutputVarInfo {
ty: bounded_int_guarantee_ty(context, min.clone(), max.clone())?,
ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
}],
SierraApChange::Known { new_vars_only: false },
))
}
}

/// Libfunc for extracting a bounded int from its corresponding guarantee - used to read its
/// internal value, while deferring the validation into further down the Sierra program.
#[derive(Default)]
pub struct BoundedIntGuaranteeContentLibfunc {}
impl SignatureOnlyGenericLibfunc for BoundedIntGuaranteeContentLibfunc {
const STR_ID: &'static str = "bounded_int_guarantee_content";

fn specialize_signature(
&self,
context: &dyn SignatureSpecializationContext,
args: &[GenericArg],
) -> Result<LibfuncSignature, SpecializationError> {
let (min, max) = extract_bounds(args)?;
// Currently only u32 guarantees are supported.
require(is_valid_guarantee_range(min, max))
.ok_or(SpecializationError::UnsupportedGenericArg)?;
let guarantee_ty = bounded_int_guarantee_ty(context, min.clone(), max.clone())?;

Ok(LibfuncSignature::new_non_branch_ex(
vec![ParamSignature::new(guarantee_ty.clone()).with_allow_all()],
vec![
OutputVarInfo {
ty: guarantee_ty,
ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
},
OutputVarInfo {
ty: bounded_int_ty(context, min.clone(), max.clone())?,
ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
},
],
SierraApChange::Known { new_vars_only: false },
))
}
}

/// Libfunc for verifying a BoundedIntGuarantee.
/// Consumes the guarantee and returns the underlying value as a BoundedInt.
/// Generic args: [min, max] - the bounds of the guarantee.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@
"bounded_int_add",
"bounded_int_constrain",
"bounded_int_div_rem",
"bounded_int_guarantee_content",
"bounded_int_guarantee_verify",
"bounded_int_is_zero",
"bounded_int_mul",
"bounded_int_sub",
"bounded_int_to_guarantee",
"bounded_int_trim_max",
"bounded_int_trim_min",
"bounded_int_wrap_non_zero",
Expand Down
166 changes: 166 additions & 0 deletions tests/e2e_test_data/libfuncs/bounded_int
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,172 @@ test::foo: SmallOrderedMap({Const: 400})

//! > ==========================================================================

//! > bounded_int_to_guarantee libfunc for u32.

//! > test_runner_name
SmallE2ETestRunner

//! > cairo_code
extern type BoundedInt<const MIN: felt252, const MAX: felt252>;
extern type BoundedIntGuarantee<const MIN: felt252, const MAX: felt252>;
extern fn bounded_int_to_guarantee<const MIN: felt252, const MAX: felt252>(
value: BoundedInt<MIN, MAX>,
) -> BoundedIntGuarantee<MIN, MAX> implicits() nopanic;

fn foo(value: BoundedInt<0, 0xffffffff>) -> BoundedIntGuarantee<0, 0xffffffff> {
bounded_int_to_guarantee(value)
}

//! > casm
[ap + 0] = [fp + -3], ap++;
ret;

//! > sierra_code
type BoundedInt<0, 4294967295> = BoundedInt<0, 4294967295> [storable: true, drop: true, dup: true, zero_sized: false];
type BoundedIntGuarantee<0, 4294967295> = BoundedIntGuarantee<0, 4294967295> [storable: true, drop: false, dup: false, zero_sized: false];

libfunc bounded_int_to_guarantee<0, 4294967295> = bounded_int_to_guarantee<0, 4294967295>;
libfunc store_temp<BoundedIntGuarantee<0, 4294967295>> = store_temp<BoundedIntGuarantee<0, 4294967295>>;

F0:
bounded_int_to_guarantee<0, 4294967295>([0]) -> ([1]);
store_temp<BoundedIntGuarantee<0, 4294967295>>([1]) -> ([1]);
return([1]);

test::foo@F0([0]: BoundedInt<0, 4294967295>) -> (BoundedIntGuarantee<0, 4294967295>);

//! > function_costs
test::foo: SmallOrderedMap({Const: 100})

//! > ==========================================================================

//! > bounded_int_to_guarantee libfunc for u128.

//! > test_runner_name
SmallE2ETestRunner

//! > cairo_code
extern type BoundedInt<const MIN: felt252, const MAX: felt252>;
extern type BoundedIntGuarantee<const MIN: felt252, const MAX: felt252>;
extern fn bounded_int_to_guarantee<const MIN: felt252, const MAX: felt252>(
value: BoundedInt<MIN, MAX>,
) -> BoundedIntGuarantee<MIN, MAX> implicits() nopanic;

fn foo(
value: BoundedInt<0, 0xffffffffffffffffffffffffffffffff>,
) -> BoundedIntGuarantee<0, 0xffffffffffffffffffffffffffffffff> {
bounded_int_to_guarantee(value)
}

//! > casm
[ap + 0] = [fp + -3], ap++;
ret;

//! > sierra_code
type BoundedInt<0, 340282366920938463463374607431768211455> = BoundedInt<0, 340282366920938463463374607431768211455> [storable: true, drop: true, dup: true, zero_sized: false];
type BoundedIntGuarantee<0, 340282366920938463463374607431768211455> = BoundedIntGuarantee<0, 340282366920938463463374607431768211455> [storable: true, drop: false, dup: false, zero_sized: false];

libfunc bounded_int_to_guarantee<0, 340282366920938463463374607431768211455> = bounded_int_to_guarantee<0, 340282366920938463463374607431768211455>;
libfunc store_temp<BoundedIntGuarantee<0, 340282366920938463463374607431768211455>> = store_temp<BoundedIntGuarantee<0, 340282366920938463463374607431768211455>>;

F0:
bounded_int_to_guarantee<0, 340282366920938463463374607431768211455>([0]) -> ([1]);
store_temp<BoundedIntGuarantee<0, 340282366920938463463374607431768211455>>([1]) -> ([1]);
return([1]);

test::foo@F0([0]: BoundedInt<0, 340282366920938463463374607431768211455>) -> (BoundedIntGuarantee<0, 340282366920938463463374607431768211455>);

//! > function_costs
test::foo: SmallOrderedMap({Const: 100})

//! > ==========================================================================

//! > bounded_int_guarantee_content libfunc for u32.

//! > test_runner_name
SmallE2ETestRunner

//! > cairo_code
extern type BoundedInt<const MIN: felt252, const MAX: felt252>;
extern type BoundedIntGuarantee<const MIN: felt252, const MAX: felt252>;
extern fn bounded_int_guarantee_content<const MIN: felt252, const MAX: felt252>(
ref value: BoundedIntGuarantee<MIN, MAX>,
) -> BoundedInt<MIN, MAX> implicits() nopanic;

fn foo(ref value: BoundedIntGuarantee<0, 0xffffffff>) -> BoundedInt<0, 0xffffffff> {
bounded_int_guarantee_content(ref value)
}

//! > casm
[ap + 0] = [fp + -3], ap++;
[ap + 0] = [fp + -3], ap++;
ret;

//! > sierra_code
type BoundedIntGuarantee<0, 4294967295> = BoundedIntGuarantee<0, 4294967295> [storable: true, drop: false, dup: false, zero_sized: false];
type BoundedInt<0, 4294967295> = BoundedInt<0, 4294967295> [storable: true, drop: true, dup: true, zero_sized: false];

libfunc bounded_int_guarantee_content<0, 4294967295> = bounded_int_guarantee_content<0, 4294967295>;
libfunc store_temp<BoundedIntGuarantee<0, 4294967295>> = store_temp<BoundedIntGuarantee<0, 4294967295>>;
libfunc store_temp<BoundedInt<0, 4294967295>> = store_temp<BoundedInt<0, 4294967295>>;

F0:
bounded_int_guarantee_content<0, 4294967295>([0]) -> ([1], [2]);
store_temp<BoundedIntGuarantee<0, 4294967295>>([1]) -> ([1]);
store_temp<BoundedInt<0, 4294967295>>([2]) -> ([2]);
return([1], [2]);

test::foo@F0([0]: BoundedIntGuarantee<0, 4294967295>) -> (BoundedIntGuarantee<0, 4294967295>, BoundedInt<0, 4294967295>);

//! > function_costs
test::foo: SmallOrderedMap({Const: 200})

//! > ==========================================================================

//! > bounded_int_guarantee_content libfunc for u128.

//! > test_runner_name
SmallE2ETestRunner

//! > cairo_code
extern type BoundedInt<const MIN: felt252, const MAX: felt252>;
extern type BoundedIntGuarantee<const MIN: felt252, const MAX: felt252>;
extern fn bounded_int_guarantee_content<const MIN: felt252, const MAX: felt252>(
ref value: BoundedIntGuarantee<MIN, MAX>,
) -> BoundedInt<MIN, MAX> implicits() nopanic;

fn foo(
ref value: BoundedIntGuarantee<0, 0xffffffffffffffffffffffffffffffff>,
) -> BoundedInt<0, 0xffffffffffffffffffffffffffffffff> {
bounded_int_guarantee_content(ref value)
}

//! > casm
[ap + 0] = [fp + -3], ap++;
[ap + 0] = [fp + -3], ap++;
ret;

//! > sierra_code
type BoundedIntGuarantee<0, 340282366920938463463374607431768211455> = BoundedIntGuarantee<0, 340282366920938463463374607431768211455> [storable: true, drop: false, dup: false, zero_sized: false];
type BoundedInt<0, 340282366920938463463374607431768211455> = BoundedInt<0, 340282366920938463463374607431768211455> [storable: true, drop: true, dup: true, zero_sized: false];

libfunc bounded_int_guarantee_content<0, 340282366920938463463374607431768211455> = bounded_int_guarantee_content<0, 340282366920938463463374607431768211455>;
libfunc store_temp<BoundedIntGuarantee<0, 340282366920938463463374607431768211455>> = store_temp<BoundedIntGuarantee<0, 340282366920938463463374607431768211455>>;
libfunc store_temp<BoundedInt<0, 340282366920938463463374607431768211455>> = store_temp<BoundedInt<0, 340282366920938463463374607431768211455>>;

F0:
bounded_int_guarantee_content<0, 340282366920938463463374607431768211455>([0]) -> ([1], [2]);
store_temp<BoundedIntGuarantee<0, 340282366920938463463374607431768211455>>([1]) -> ([1]);
store_temp<BoundedInt<0, 340282366920938463463374607431768211455>>([2]) -> ([2]);
return([1], [2]);

test::foo@F0([0]: BoundedIntGuarantee<0, 340282366920938463463374607431768211455>) -> (BoundedIntGuarantee<0, 340282366920938463463374607431768211455>, BoundedInt<0, 340282366920938463463374607431768211455>);

//! > function_costs
test::foo: SmallOrderedMap({Const: 200})

//! > ==========================================================================

//! > bounded_int_guarantee_verify libfunc for u32.

//! > test_runner_name
Expand Down
Loading