From 5a3d1b8d90e1f379e132d45c4ed0850682f61337 Mon Sep 17 00:00:00 2001 From: fmoletta <99273364+fmoletta@users.noreply.github.com> Date: Wed, 26 Apr 2023 00:21:26 +0300 Subject: [PATCH] feat(hints): Implement NewHint#63 & NewHint#65 (#1047) * Implement hint * Add integration test + update changelog * Add unit test * Remaneme hint * Implement v0.8 hint * Integration test * Update changelog * Add unit test --------- Co-authored-by: Mario Rugiero --- CHANGELOG.md | 33 +++++++++ cairo_programs/assert_le_felt_old.cairo | 68 +++++++++++++++++ .../builtin_hint_processor_definition.rs | 6 ++ .../builtin_hint_processor/hint_code.rs | 18 +++++ .../builtin_hint_processor/math_utils.rs | 73 +++++++++++++++++++ src/tests/cairo_run_test.rs | 7 ++ 6 files changed, 205 insertions(+) create mode 100644 cairo_programs/assert_le_felt_old.cairo diff --git a/CHANGELOG.md b/CHANGELOG.md index 53ef5e2c36..4c4f4b9c0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,39 @@ #### Upcoming Changes + +* Implement hint on `assert_le_felt` for versions 0.6.0 and 0.8.2 [#1047](https://github.com/lambdaclass/cairo-rs/pull/1047): + + `BuiltinHintProcessor` now supports the following hints: + + ```python + + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert_integer(ids.b) + assert (ids.a % PRIME) <= (ids.b % PRIME), \ + f'a = {ids.a % PRIME} is not less than or equal to b = {ids.b % PRIME}.' + %} + + ``` + + ```python + + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert_integer(ids.b) + a = ids.a % PRIME + b = ids.b % PRIME + assert a <= b, f'a = {a} is not less than or equal to b = {b}.' + + ids.small_inputs = int( + a < range_check_builtin.bound and (b - a) < range_check_builtin.bound) + %} + + ``` + * Implement hint on ec_recover.json whitelist [#1038](https://github.com/lambdaclass/cairo-rs/pull/1038): `BuiltinHintProcessor` now supports the following hint: diff --git a/cairo_programs/assert_le_felt_old.cairo b/cairo_programs/assert_le_felt_old.cairo new file mode 100644 index 0000000000..50a1868876 --- /dev/null +++ b/cairo_programs/assert_le_felt_old.cairo @@ -0,0 +1,68 @@ +%builtins range_check +from starkware.cairo.common.math import split_felt, assert_le, assert_nn_le + +// Asserts that the unsigned integer lift (as a number in the range [0, PRIME)) of a is lower than +// or equal to that of b. +// See split_felt() for more details. +func assert_le_felt_v_0_6{range_check_ptr}(a, b) { + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert_integer(ids.b) + assert (ids.a % PRIME) <= (ids.b % PRIME), \ + f'a = {ids.a % PRIME} is not less than or equal to b = {ids.b % PRIME}.' + %} + alloc_locals; + let (local a_high, local a_low) = split_felt(a); + let (b_high, b_low) = split_felt(b); + + if (a_high == b_high) { + assert_le(a_low, b_low); + return (); + } + assert_le(a_high, b_high); + return (); +} + +// Asserts that the unsigned integer lift (as a number in the range [0, PRIME)) of a is lower than +// or equal to that of b. +// See split_felt() for more details. +@known_ap_change +func assert_le_felt_v_0_8{range_check_ptr}(a, b) { + alloc_locals; + local small_inputs; + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.a) + assert_integer(ids.b) + a = ids.a % PRIME + b = ids.b % PRIME + assert a <= b, f'a = {a} is not less than or equal to b = {b}.' + + ids.small_inputs = int( + a < range_check_builtin.bound and (b - a) < range_check_builtin.bound) + %} + if (small_inputs != 0) { + assert_nn_le(a, b); + ap += 33; + return (); + } + + let (local a_high, local a_low) = split_felt(a); + let (b_high, b_low) = split_felt(b); + + if (a_high == b_high) { + assert_le(a_low, b_low); + return (); + } + + assert_le(a_high, b_high); + return (); +} + +func main{range_check_ptr}() { + assert_le_felt_v_0_6(7, 17); + assert_le_felt_v_0_8(6, 16); + assert_le_felt_v_0_8(5, -15); + return(); +} diff --git a/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs b/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs index 53ba342d2f..0e3ff2aef3 100644 --- a/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs +++ b/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs @@ -635,6 +635,12 @@ impl HintProcessor for BuiltinHintProcessor { hint_code::EC_RECOVER_SUB_A_B => { ec_recover_sub_a_b(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } + hint_code::ASSERT_LE_FELT_V_0_6 => { + assert_le_felt_v_0_6(vm, &hint_data.ids_data, &hint_data.ap_tracking) + } + hint_code::ASSERT_LE_FELT_V_0_8 => { + assert_le_felt_v_0_8(vm, &hint_data.ids_data, &hint_data.ap_tracking) + } hint_code::EC_RECOVER_PRODUCT_MOD => { ec_recover_product_mod(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index 1ed271b3f8..ab3eaa7c99 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -58,6 +58,24 @@ memory[ids.range_check_ptr + 1], memory[ids.range_check_ptr + 0] = ( memory[ids.range_check_ptr + 3], memory[ids.range_check_ptr + 2] = ( divmod(lengths_and_indices[1][0], ids.PRIME_OVER_2_HIGH))"#; +pub const ASSERT_LE_FELT_V_0_6: &str = + "from starkware.cairo.common.math_utils import assert_integer +assert_integer(ids.a) +assert_integer(ids.b) +assert (ids.a % PRIME) <= (ids.b % PRIME), \\ + f'a = {ids.a % PRIME} is not less than or equal to b = {ids.b % PRIME}.'"; + +pub const ASSERT_LE_FELT_V_0_8: &str = + "from starkware.cairo.common.math_utils import assert_integer +assert_integer(ids.a) +assert_integer(ids.b) +a = ids.a % PRIME +b = ids.b % PRIME +assert a <= b, f'a = {a} is not less than or equal to b = {b}.' + +ids.small_inputs = int( + a < range_check_builtin.bound and (b - a) < range_check_builtin.bound)"; + pub const ASSERT_LE_FELT_EXCLUDED_0: &str = "memory[ap] = 1 if excluded != 0 else 0"; pub const ASSERT_LE_FELT_EXCLUDED_1: &str = "memory[ap] = 1 if excluded != 1 else 0"; pub const ASSERT_LE_FELT_EXCLUDED_2: &str = "assert excluded == 2"; diff --git a/src/hint_processor/builtin_hint_processor/math_utils.rs b/src/hint_processor/builtin_hint_processor/math_utils.rs index 4ed24b95c9..9b9317aa31 100644 --- a/src/hint_processor/builtin_hint_processor/math_utils.rs +++ b/src/hint_processor/builtin_hint_processor/math_utils.rs @@ -145,6 +145,47 @@ pub fn assert_le_felt( Ok(()) } +pub fn assert_le_felt_v_0_6( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + let a = &get_integer_from_var_name("a", vm, ids_data, ap_tracking)?; + let b = &get_integer_from_var_name("b", vm, ids_data, ap_tracking)?; + + if a.as_ref() > b.as_ref() { + return Err(HintError::NonLeFelt252( + a.clone().into_owned(), + b.clone().into_owned(), + )); + } + Ok(()) +} + +pub fn assert_le_felt_v_0_8( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + let a = &get_integer_from_var_name("a", vm, ids_data, ap_tracking)?; + let b = &get_integer_from_var_name("b", vm, ids_data, ap_tracking)?; + + if a.as_ref() > b.as_ref() { + return Err(HintError::NonLeFelt252( + a.clone().into_owned(), + b.clone().into_owned(), + )); + } + let bound = vm + .get_range_check_builtin()? + ._bound + .clone() + .unwrap_or_default(); + let small_inputs = + Felt252::from((a.as_ref() < &bound && b.as_ref() - a.as_ref() < bound) as u8); + insert_value_from_var_name("small_inputs", small_inputs, vm, ids_data, ap_tracking) +} + pub fn assert_le_felt_excluded_2(exec_scopes: &mut ExecutionScopes) -> Result<(), HintError> { let excluded: Felt252 = exec_scopes.get("excluded")?; @@ -2001,6 +2042,38 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_is_assert_le_felt_v_0_6_assertion_fail() { + let mut vm = vm_with_range_check!(); + vm.set_fp(2); + vm.segments = segments![((1, 0), 17), ((1, 1), 7)]; + //Initialize ap + //Create ids_data & hint_data + let ids_data = ids_data!["a", "b"]; + //Execute the hint + assert_matches!( + run_hint!(vm, ids_data, hint_code::ASSERT_LE_FELT_V_0_6), + Err(HintError::NonLeFelt252(a, b)) if a == 17_u32.into() && b == 7_u32.into() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_is_assert_le_felt_v_0_8_assertion_fail() { + let mut vm = vm_with_range_check!(); + vm.set_fp(2); + vm.segments = segments![((1, 0), 17), ((1, 1), 7)]; + //Initialize ap + //Create ids_data & hint_data + let ids_data = ids_data!["a", "b"]; + //Execute the hint + assert_matches!( + run_hint!(vm, ids_data, hint_code::ASSERT_LE_FELT_V_0_8), + Err(HintError::NonLeFelt252(a, b)) if a == 17_u32.into() && b == 7_u32.into() + ); + } + #[cfg(not(target_arch = "wasm32"))] proptest! { #[test] diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index 8ac4532f03..a36b5934fe 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -828,6 +828,13 @@ fn cairo_run_inv_mod_p_uint512() { run_program_simple(program_data.as_slice()); } +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn assert_le_felt_old() { + let program_data = include_bytes!("../../cairo_programs/assert_le_felt_old.json"); + run_program_simple_with_memory_holes(program_data.as_slice(), 35); +} + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn cairo_run_fq_test() {