diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea37436f4..30d5ea647a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ #### Upcoming Changes +* Implement hints on uint384 lib (Part 2) [#971](https://github.com/lambdaclass/cairo-rs/pull/971) + + `BuiltinHintProcessor` now supports the following hint: + + ```python + memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0 + ``` + * Add alternative hint code for hint on _block_permutation used by 0.10.3 whitelist [#958](https://github.com/lambdaclass/cairo-rs/pull/958) `BuiltinHintProcessor` now supports the following hint: diff --git a/cairo_programs/uint384.cairo b/cairo_programs/uint384.cairo index ecb135dae8..f578b29eb3 100644 --- a/cairo_programs/uint384.cairo +++ b/cairo_programs/uint384.cairo @@ -97,6 +97,22 @@ namespace uint384_lib { return (res,); } + // Returns 1 if the signed integer is nonnegative. + @known_ap_change + func signed_nn{range_check_ptr}(a: Uint384) -> (res: felt) { + %{ memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0 %} + jmp non_negative if [ap] != 0, ap++; + + assert [range_check_ptr] = a.d2 - 2 ** 127; + let range_check_ptr = range_check_ptr + 1; + return (res=0); + + non_negative: + assert [range_check_ptr] = a.d2 + 2 ** 127; + let range_check_ptr = range_check_ptr + 1; + return (res=1); + } + // Adds two integers. Returns the result as a 384-bit integer and the (1-bit) carry. // Doesn't verify that the result is a proper Uint384, that's now the responsibility of the calling function func _add_no_uint384_check{range_check_ptr}(a: Uint384, b: Uint384) -> ( @@ -523,6 +539,14 @@ func test_uint384_operations{range_check_ptr}() { assert root.d1 = 916102188; assert root.d2 = 0; + let g = Uint384(1, 1, 1); + let (sign_g) = uint384_lib.signed_nn(g); + assert sign_g = 1; + + let h = Uint384(0, 0, 170141183460469231731687303715884105729); + let (sign_h) = uint384_lib.signed_nn(h); + assert sign_h = 0; + 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 60ed30726f..8ae2f7f60e 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 @@ -73,8 +73,8 @@ use crate::hint_processor::builtin_hint_processor::skip_next_instruction::skip_n use super::ec_utils::{chained_ec_op_random_ec_point_hint, random_ec_point_hint, recover_y_hint}; use super::uint384::{ - add_no_uint384_check, uint384_split_128, uint384_sqrt, uint384_unsigned_div_rem, - uint384_unsigned_div_rem_expanded, + add_no_uint384_check, uint384_signed_nn, uint384_split_128, uint384_sqrt, + uint384_unsigned_div_rem, uint384_unsigned_div_rem_expanded, }; pub struct HintProcessorData { @@ -472,6 +472,9 @@ impl HintProcessor for BuiltinHintProcessor { hint_code::UINT384_SQRT => { uint384_sqrt(vm, &hint_data.ids_data, &hint_data.ap_tracking) } + hint_code::UINT384_SIGNED_NN => { + uint384_signed_nn(vm, &hint_data.ids_data, &hint_data.ap_tracking) + } hint_code::UINT256_MUL_DIV_MOD => { uint256_mul_div_mod(vm, &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 37151f829f..9d882207a0 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -727,6 +727,8 @@ root_split = split(root, num_bits_shift=128, length=3) ids.root.d0 = root_split[0] ids.root.d1 = root_split[1] ids.root.d2 = root_split[2]"; +pub(crate) const UINT384_SIGNED_NN: &str = + "memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0"; #[cfg(feature = "skip_next_instruction_hint")] pub(crate) const SKIP_NEXT_INSTRUCTION: &str = "skip_next_instruction()"; diff --git a/src/hint_processor/builtin_hint_processor/uint384.rs b/src/hint_processor/builtin_hint_processor/uint384.rs index 055d907dd7..3781c0bb85 100644 --- a/src/hint_processor/builtin_hint_processor/uint384.rs +++ b/src/hint_processor/builtin_hint_processor/uint384.rs @@ -15,6 +15,7 @@ use crate::{ use super::hint_utils::{ get_integer_from_var_name, get_relocatable_from_var_name, insert_value_from_var_name, + insert_value_into_ap, }; use super::secp::bigint_utils::BigInt3; // Notes: Hints in this lib use the type Uint384, which is equal to common lib's BigInt3 @@ -302,6 +303,23 @@ pub fn uint384_sqrt( } Ok(()) } + +/* Implements Hint: + memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0 +*/ +pub fn uint384_signed_nn( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + let a_addr = get_relocatable_from_var_name("a", vm, ids_data, ap_tracking)?; + let a_d2 = vm + .get_integer((a_addr + 2)?) + .map_err(|_| HintError::IdentifierHasNoMember("a".to_string(), "d2".to_string()))?; + let res = Felt252::from((a_d2.bits() <= 127) as u32); + insert_value_into_ap(vm, res) +} + #[cfg(test)] mod tests { use super::*; @@ -705,4 +723,71 @@ mod tests { Err(HintError::AssertionFailed(s)) if s == "assert 0 <= root < 2 ** 192" ); } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_signed_nn_ok_positive() { + let mut vm = vm_with_range_check!(); + //Initialize fp + vm.run_context.fp = 3; + //Create hint_data + let ids_data = non_continuous_ids_data![("a", -2)]; + //Insert ids into memory + vm.segments = segments![ + //a.d2 + ((1, 3), 1) + ]; + //Execute the hint + assert!(run_hint!(vm, ids_data, hint_code::UINT384_SIGNED_NN).is_ok()); + //Check hint memory inserts + check_memory![ + vm.segments.memory, + // ap + ((1, 0), 1) + ]; + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_signed_nn_missing_identifier() { + let mut vm = vm_with_range_check!(); + //Initialize fp + vm.run_context.fp = 3; + //Create hint_data + let ids_data = non_continuous_ids_data![("a", -2)]; + //Insert ids into memory + vm.segments = segments![ + //a.d0 + ((1, 1), 1), + //a.d1 + ((1, 2), 1) //a.d2 + ]; + //Execute the hint + assert_matches!(run_hint!(vm, ids_data, hint_code::UINT384_SIGNED_NN), + Err(HintError::IdentifierHasNoMember(s1, s2)) if s1 == "a" && s2 == "d2" + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_signed_nn_ok_negative() { + let mut vm = vm_with_range_check!(); + //Initialize fp + vm.run_context.fp = 3; + //Create hint_data + let ids_data = non_continuous_ids_data![("a", -2)]; + //Insert ids into memory + vm.segments = segments![ + //a.d0 + ((1, 3), 170141183460469231731687303715884105729_u128) + ]; + //Execute the hint + assert!(run_hint!(vm, ids_data, hint_code::UINT384_SIGNED_NN).is_ok()); + //Check hint memory inserts + check_memory![ + vm.segments.memory, + // ap + ((1, 0), 0) + ]; + } }