diff --git a/CHANGELOG.md b/CHANGELOG.md index 0130567606..15e5034f35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ #### Upcoming Changes + +* Implement hint on `get_felt_bitlength` [#993](https://github.com/lambdaclass/cairo-rs/pull/993) + + `BuiltinHintProcessor` now supports the following hint: + ```python + x = ids.x + ids.bit_length = x.bit_length() + ``` + Used by the [`Garaga` library function `get_felt_bitlength`](https://github.com/keep-starknet-strange/garaga/blob/249f8a372126b3a839f9c1e1080ea8c6f9374c0c/src/utils.cairo#L54) + * Add missing hint on cairo_secp lib [#1009](https://github.com/lambdaclass/cairo-rs/pull/1009): `BuiltinHintProcessor` now supports the following hint: diff --git a/cairo_programs/garaga.cairo b/cairo_programs/garaga.cairo new file mode 100644 index 0000000000..e301e934bc --- /dev/null +++ b/cairo_programs/garaga.cairo @@ -0,0 +1,344 @@ +%builtins range_check bitwise + +from starkware.cairo.common.uint256 import ( + Uint256, + uint256_reverse_endian, + uint256_unsigned_div_rem, + uint256_mul, + uint256_add, + uint256_pow2, +) + +from starkware.cairo.common.cairo_builtins import BitwiseBuiltin +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.math import unsigned_div_rem as felt_divmod, split_felt +from starkware.cairo.common.math_cmp import is_le +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.pow import pow + +// y MUST be a power of 2 +func bitwise_divmod{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x: felt, y: felt) -> ( + q: felt, r: felt +) { + assert bitwise_ptr.x = x; + assert bitwise_ptr.y = y - 1; + let x_and_y = bitwise_ptr.x_and_y; + + let bitwise_ptr = bitwise_ptr + BitwiseBuiltin.SIZE; + return (q=(x - x_and_y) / y, r=x_and_y); +} +func felt_divmod_no_input_check{range_check_ptr}(value, div) -> (q: felt, r: felt) { + // let r = [range_check_ptr]; + // let q = [range_check_ptr + 1]; + // let range_check_ptr = range_check_ptr + 2; + alloc_locals; + local r; + local q; + %{ + from starkware.cairo.common.math_utils import assert_integer + assert_integer(ids.div) + assert 0 < ids.div <= PRIME // range_check_builtin.bound, \ + f'div={hex(ids.div)} is out of the valid range.' + ids.q, ids.r = divmod(ids.value, ids.div) + %} + + assert [range_check_ptr] = div - 1 - r; + let range_check_ptr = range_check_ptr + 1; + // assert_le(r, div - 1); + + assert value = q * div + r; + return (q, r); +} + +func get_felt_bitlength{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(x: felt) -> felt { + alloc_locals; + local bit_length; + %{ + x = ids.x + ids.bit_length = x.bit_length() + %} + + // Next two lines Not necessary : will fail if pow2(bit_length) is too big, unknown cell. + // let le = is_le(bit_length, 252); + // assert le = 1; + assert bitwise_ptr[0].x = x; + let n = pow2(bit_length); + assert bitwise_ptr[0].y = n - 1; + tempvar word = bitwise_ptr[0].x_and_y; + assert word = x; + + assert bitwise_ptr[1].x = x; + + let n = pow2(bit_length - 1); + + assert bitwise_ptr[1].y = n - 1; + tempvar word = bitwise_ptr[1].x_and_y; + assert word = x - n; + + let bitwise_ptr = bitwise_ptr + 2 * BitwiseBuiltin.SIZE; + return bit_length; +} + +func pow2(i) -> felt { + let (data_address) = get_label_location(data); + return [data_address + i]; + + data: + dw 0x1; + dw 0x2; + dw 0x4; + dw 0x8; + dw 0x10; + dw 0x20; + dw 0x40; + dw 0x80; + dw 0x100; + dw 0x200; + dw 0x400; + dw 0x800; + dw 0x1000; + dw 0x2000; + dw 0x4000; + dw 0x8000; + dw 0x10000; + dw 0x20000; + dw 0x40000; + dw 0x80000; + dw 0x100000; + dw 0x200000; + dw 0x400000; + dw 0x800000; + dw 0x1000000; + dw 0x2000000; + dw 0x4000000; + dw 0x8000000; + dw 0x10000000; + dw 0x20000000; + dw 0x40000000; + dw 0x80000000; + dw 0x100000000; + dw 0x200000000; + dw 0x400000000; + dw 0x800000000; + dw 0x1000000000; + dw 0x2000000000; + dw 0x4000000000; + dw 0x8000000000; + dw 0x10000000000; + dw 0x20000000000; + dw 0x40000000000; + dw 0x80000000000; + dw 0x100000000000; + dw 0x200000000000; + dw 0x400000000000; + dw 0x800000000000; + dw 0x1000000000000; + dw 0x2000000000000; + dw 0x4000000000000; + dw 0x8000000000000; + dw 0x10000000000000; + dw 0x20000000000000; + dw 0x40000000000000; + dw 0x80000000000000; + dw 0x100000000000000; + dw 0x200000000000000; + dw 0x400000000000000; + dw 0x800000000000000; + dw 0x1000000000000000; + dw 0x2000000000000000; + dw 0x4000000000000000; + dw 0x8000000000000000; + dw 0x10000000000000000; + dw 0x20000000000000000; + dw 0x40000000000000000; + dw 0x80000000000000000; + dw 0x100000000000000000; + dw 0x200000000000000000; + dw 0x400000000000000000; + dw 0x800000000000000000; + dw 0x1000000000000000000; + dw 0x2000000000000000000; + dw 0x4000000000000000000; + dw 0x8000000000000000000; + dw 0x10000000000000000000; + dw 0x20000000000000000000; + dw 0x40000000000000000000; + dw 0x80000000000000000000; + dw 0x100000000000000000000; + dw 0x200000000000000000000; + dw 0x400000000000000000000; + dw 0x800000000000000000000; + dw 0x1000000000000000000000; + dw 0x2000000000000000000000; + dw 0x4000000000000000000000; + dw 0x8000000000000000000000; + dw 0x10000000000000000000000; + dw 0x20000000000000000000000; + dw 0x40000000000000000000000; + dw 0x80000000000000000000000; + dw 0x100000000000000000000000; + dw 0x200000000000000000000000; + dw 0x400000000000000000000000; + dw 0x800000000000000000000000; + dw 0x1000000000000000000000000; + dw 0x2000000000000000000000000; + dw 0x4000000000000000000000000; + dw 0x8000000000000000000000000; + dw 0x10000000000000000000000000; + dw 0x20000000000000000000000000; + dw 0x40000000000000000000000000; + dw 0x80000000000000000000000000; + dw 0x100000000000000000000000000; + dw 0x200000000000000000000000000; + dw 0x400000000000000000000000000; + dw 0x800000000000000000000000000; + dw 0x1000000000000000000000000000; + dw 0x2000000000000000000000000000; + dw 0x4000000000000000000000000000; + dw 0x8000000000000000000000000000; + dw 0x10000000000000000000000000000; + dw 0x20000000000000000000000000000; + dw 0x40000000000000000000000000000; + dw 0x80000000000000000000000000000; + dw 0x100000000000000000000000000000; + dw 0x200000000000000000000000000000; + dw 0x400000000000000000000000000000; + dw 0x800000000000000000000000000000; + dw 0x1000000000000000000000000000000; + dw 0x2000000000000000000000000000000; + dw 0x4000000000000000000000000000000; + dw 0x8000000000000000000000000000000; + dw 0x10000000000000000000000000000000; + dw 0x20000000000000000000000000000000; + dw 0x40000000000000000000000000000000; + dw 0x80000000000000000000000000000000; + dw 0x100000000000000000000000000000000; + dw 0x200000000000000000000000000000000; + dw 0x400000000000000000000000000000000; + dw 0x800000000000000000000000000000000; + dw 0x1000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000000000000000000000000; + dw 0x800000000000000000000000000000000000000000000000000000000000; + dw 0x1000000000000000000000000000000000000000000000000000000000000; + dw 0x2000000000000000000000000000000000000000000000000000000000000; + dw 0x4000000000000000000000000000000000000000000000000000000000000; + dw 0x8000000000000000000000000000000000000000000000000000000000000; + dw 0x10000000000000000000000000000000000000000000000000000000000000; + dw 0x20000000000000000000000000000000000000000000000000000000000000; + dw 0x40000000000000000000000000000000000000000000000000000000000000; + dw 0x80000000000000000000000000000000000000000000000000000000000000; + dw 0x100000000000000000000000000000000000000000000000000000000000000; + dw 0x200000000000000000000000000000000000000000000000000000000000000; + dw 0x400000000000000000000000000000000000000000000000000000000000000; +} + +func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { + let x = get_felt_bitlength(42); + assert x = 6; + 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 1626f02c1e..50bba6935a 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 @@ -80,6 +80,8 @@ use felt::Felt252; #[cfg(feature = "skip_next_instruction_hint")] use crate::hint_processor::builtin_hint_processor::skip_next_instruction::skip_next_instruction; +use super::garaga::get_felt_bitlenght; + pub struct HintProcessorData { pub code: String, pub ap_tracking: ApTracking, @@ -367,6 +369,9 @@ impl HintProcessor for BuiltinHintProcessor { &hint_data.ids_data, &hint_data.ap_tracking, ), + hint_code::GET_FELT_BIT_LENGTH => { + get_felt_bitlenght(vm, &hint_data.ids_data, &hint_data.ap_tracking) + } hint_code::DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N => div_mod_n_packed_external_n( vm, exec_scopes, diff --git a/src/hint_processor/builtin_hint_processor/garaga.rs b/src/hint_processor/builtin_hint_processor/garaga.rs new file mode 100644 index 0000000000..5bb4aada88 --- /dev/null +++ b/src/hint_processor/builtin_hint_processor/garaga.rs @@ -0,0 +1,86 @@ +use crate::stdlib::collections::HashMap; +use crate::stdlib::prelude::String; + +use crate::{ + hint_processor::hint_processor_definition::HintReference, + serde::deserialize_program::ApTracking, + vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}, +}; + +use super::hint_utils::{get_integer_from_var_name, insert_value_from_var_name}; + +/// Implements hint: +/// ```python +/// x = ids.x, +/// ids.bit_length = x.bit_length() +/// ``` +pub fn get_felt_bitlenght( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + let x = get_integer_from_var_name("x", vm, ids_data, ap_tracking)?; + let bit_length = x.bits() as usize; + insert_value_from_var_name("bit_length", bit_length, vm, ids_data, ap_tracking) +} + +#[cfg(test)] +mod tests { + use crate::any_box; + use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; + use crate::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData; + use crate::hint_processor::hint_processor_definition::HintProcessor; + use crate::types::exec_scope::ExecutionScopes; + use crate::{hint_processor::builtin_hint_processor::hint_code, utils::test_utils::*}; + use felt::Felt252; + use num_traits::{Bounded, One, Zero}; + + #[cfg(target_arch = "wasm32")] + use wasm_bindgen_test::*; + + use super::*; + + fn run_hint(x: Felt252) -> Result { + let ids_data = non_continuous_ids_data![ + ("x", 0), // located at `fp + 0`. + ("bit_length", 1) // located at `fp + 1`. + ]; + + let mut vm = vm!(); + vm.run_context.fp = 0; + add_segments!(vm, 2); // Alloc space for `ids.x` and `ids.bit_length` + vm.insert_value((1, 0).into(), x).unwrap(); + + run_hint!(vm, ids_data, hint_code::GET_FELT_BIT_LENGTH).unwrap(); + Ok(vm.get_integer((1, 1).into()).unwrap().into_owned()) + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_simple() { + let bit_length_result = run_hint(Felt252::new(7)); + assert!(bit_length_result.is_ok()); + assert_eq!(bit_length_result.unwrap(), Felt252::from(3)); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_in_range() { + for i in 0..252_usize { + let x: Felt252 = Felt252::one() << i; + + let bit_length_result = run_hint(x); + assert!(bit_length_result.is_ok()); + assert_eq!(bit_length_result.unwrap(), Felt252::from(i + 1)); + } + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_wraparound() { + let x = Felt252::max_value() + Felt252::one(); + let bit_length_result = run_hint(x); + assert!(bit_length_result.is_ok()); + assert_eq!(bit_length_result.unwrap(), Felt252::zero()); + } +} diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index 4d98e5840b..a603ded506 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -465,6 +465,9 @@ value = res = div_mod(a, b, N)"#; pub const DIV_MOD_N_SAFE_DIV: &str = r#"value = k = safe_div(res * b - a, N)"#; +pub const GET_FELT_BIT_LENGTH: &str = r#"x = ids.x +ids.bit_length = x.bit_length()"#; + pub const DIV_MOD_N_SAFE_DIV_PLUS_ONE: &str = r#"value = k_plus_one = safe_div(res * b - a, N) + 1"#; diff --git a/src/hint_processor/builtin_hint_processor/mod.rs b/src/hint_processor/builtin_hint_processor/mod.rs index 28a6e2e27e..53dfe1a726 100644 --- a/src/hint_processor/builtin_hint_processor/mod.rs +++ b/src/hint_processor/builtin_hint_processor/mod.rs @@ -6,6 +6,7 @@ pub mod dict_hint_utils; pub mod dict_manager; pub mod ec_utils; pub mod find_element_hint; +pub mod garaga; pub mod hint_code; pub mod hint_utils; pub mod keccak_utils; diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index ba2c26390e..c6bfa5522a 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -1330,6 +1330,13 @@ fn cairo_run_efficient_secp256r1_ec() { run_program_simple(program_data.as_slice()); } +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn cairo_run_garaga() { + let program_data = include_bytes!("../../cairo_programs/garaga.json"); + run_program_simple(program_data.as_slice()); +} + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn cairo_run_div_mod_n() {