diff --git a/CHANGELOG.md b/CHANGELOG.md index c05303be3c..0130567606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ #### Upcoming Changes +* Add missing hint on cairo_secp lib [#1009](https://github.com/lambdaclass/cairo-rs/pull/1009): + + `BuiltinHintProcessor` now supports the following hint: + + ```python + ids.dibit = ((ids.scalar_u >> ids.m) & 1) + 2 * ((ids.scalar_v >> ids.m) & 1) + ``` + * Add getters to read properties of a `Program` [#1017](https://github.com/lambdaclass/cairo-rs/pull/1017): * `prime(&self) -> &str`: get the prime associated to data in hex representation * `iter_data(&self) -> Iterator`: get an iterator over all elements in the program data diff --git a/cairo_programs/quad_bit.cairo b/cairo_programs/n_bit.cairo similarity index 70% rename from cairo_programs/quad_bit.cairo rename to cairo_programs/n_bit.cairo index 0dab02ae00..4d1cce8e46 100644 --- a/cairo_programs/quad_bit.cairo +++ b/cairo_programs/n_bit.cairo @@ -14,12 +14,21 @@ func get_quad_bit{range_check_ptr}(scalar_u: felt, scalar_v: felt, m: felt) -> f return quad_bit; } +func get_dibit{range_check_ptr}(scalar_u: felt, scalar_v: felt, m: felt) -> felt { + alloc_locals; + local dibit: felt; + %{ ids.dibit = ((ids.scalar_u >> ids.m) & 1) + 2 * ((ids.scalar_v >> ids.m) & 1) %} + return dibit; +} + func test_quad_bit{range_check_ptr}() { let u = 4194304; // 1 << 22 let v = 8388608; // 1 << 23 // 8 * 1 + 4 * 0 + 2 * 0 + 1 * 1 assert get_quad_bit(u, v, 23) = 9; + // 2 * 1 + 1 * 0 + assert get_dibit(u, v, 23) = 2; 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 6c279e81ab..1626f02c1e 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 @@ -29,7 +29,7 @@ use crate::{ secp::{ bigint_utils::{bigint_to_uint256, hi_max_bitlen, nondet_bigint3}, ec_utils::{ - compute_doubling_slope, compute_slope, ec_double_assign_new_x, + compute_doubling_slope, compute_slope, di_bit, ec_double_assign_new_x, ec_double_assign_new_y, ec_mul_inner, ec_negate, fast_ec_add_assign_new_x, fast_ec_add_assign_new_y, quad_bit, }, @@ -540,6 +540,7 @@ impl HintProcessor for BuiltinHintProcessor { hi_max_bitlen(vm, &hint_data.ids_data, &hint_data.ap_tracking) } hint_code::QUAD_BIT => quad_bit(vm, &hint_data.ids_data, &hint_data.ap_tracking), + hint_code::DI_BIT => di_bit(vm, &hint_data.ids_data, &hint_data.ap_tracking), #[cfg(feature = "skip_next_instruction_hint")] hint_code::SKIP_NEXT_INSTRUCTION => skip_next_instruction(vm), code => Err(HintError::UnknownHint(code.to_string())), diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index 4b23fe2ae8..4d98e5840b 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -829,5 +829,8 @@ pub const QUAD_BIT: &str = r#"ids.quad_bit = ( + ((ids.scalar_u >> (ids.m - 1)) & 1) )"#; +pub const DI_BIT: &str = + r#"ids.dibit = ((ids.scalar_u >> ids.m) & 1) + 2 * ((ids.scalar_v >> ids.m) & 1)"#; + #[cfg(feature = "skip_next_instruction_hint")] pub const SKIP_NEXT_INSTRUCTION: &str = "skip_next_instruction()"; diff --git a/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs b/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs index ff7f312f35..4e26682cb3 100644 --- a/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs @@ -288,6 +288,28 @@ pub fn quad_bit( vm: &mut VirtualMachine, ids_data: &HashMap, ap_tracking: &ApTracking, +) -> Result<(), HintError> { + n_pair_bits(vm, ids_data, ap_tracking, "quad_bit", 2) +} + +/* +Implements hint: +%{ ids.dibit = ((ids.scalar_u >> ids.m) & 1) + 2 * ((ids.scalar_v >> ids.m) & 1) %} +*/ +pub fn di_bit( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + n_pair_bits(vm, ids_data, ap_tracking, "dibit", 1) +} + +pub fn n_pair_bits( + vm: &mut VirtualMachine, + ids_data: &HashMap, + ap_tracking: &ApTracking, + result_name: &str, + number_of_pairs: u32, ) -> Result<(), HintError> { let scalar_v_cow = get_integer_from_var_name("scalar_v", vm, ids_data, ap_tracking)?; let scalar_u_cow = get_integer_from_var_name("scalar_u", vm, ids_data, ap_tracking)?; @@ -303,24 +325,29 @@ pub fn quad_bit( } let one = &Felt252::one(); + let two = &Felt252::from(2); + + // Each step, fetches the bits in mth position for v and u, + // and appends them to the accumulator. i.e: + // 10 + // ↓↓ + // 1010101__ -> 101010110 + let res: Felt252 = (0..number_of_pairs) + .map(|i| { + let bit_1 = (scalar_v >> (m - i - 1)) & two; + // 1 * ((ids.scalar_u >> ids.m) & 1) + let bit_0 = (scalar_u >> (m - i)) & one; + bit_0 + bit_1 + }) + .fold(Felt252::zero(), |acc, x| (acc << 2_u32) + x); - // 8 * ((ids.scalar_v >> ids.m) & 1) - let quad_bit_3 = ((scalar_v >> m) & one) << 3u32; - // 4 * ((ids.scalar_u >> ids.m) & 1) - let quad_bit_2 = ((scalar_u >> m) & one) << 2u32; - // 2 * ((ids.scalar_v >> (ids.m - 1)) & 1) - let quad_bit_1 = ((scalar_v >> (m - 1)) & one) << 1u32; - // 1 * ((ids.scalar_u >> (ids.m - 1)) & 1) - let quad_bit_0 = (scalar_u >> (m - 1)) & one; - - let res = quad_bit_0 + quad_bit_1 + quad_bit_2 + quad_bit_3; - - insert_value_from_var_name("quad_bit", res, vm, ids_data, ap_tracking) + insert_value_from_var_name(result_name, res, vm, ids_data, ap_tracking) } #[cfg(test)] mod tests { use super::*; + use crate::hint_processor::builtin_hint_processor::hint_code; use crate::stdlib::string::ToString; use crate::vm::vm_memory::memory_segments::MemorySegmentManager; use crate::{ @@ -858,7 +885,7 @@ mod tests { #[test] fn run_quad_bit_ok() { - let hint_code = "ids.quad_bit = (\n 8 * ((ids.scalar_v >> ids.m) & 1)\n + 4 * ((ids.scalar_u >> ids.m) & 1)\n + 2 * ((ids.scalar_v >> (ids.m - 1)) & 1)\n + ((ids.scalar_u >> (ids.m - 1)) & 1)\n)"; + let hint_code = hint_code::QUAD_BIT; let mut vm = vm_with_range_check!(); let scalar_u = 89712; @@ -881,7 +908,7 @@ mod tests { #[test] fn run_quad_bit_with_max_m_ok() { - let hint_code = "ids.quad_bit = (\n 8 * ((ids.scalar_v >> ids.m) & 1)\n + 4 * ((ids.scalar_u >> ids.m) & 1)\n + 2 * ((ids.scalar_v >> (ids.m - 1)) & 1)\n + ((ids.scalar_u >> (ids.m - 1)) & 1)\n)"; + let hint_code = hint_code::QUAD_BIT; let mut vm = vm_with_range_check!(); let scalar_u = 89712; @@ -902,4 +929,27 @@ mod tests { // Check hint memory inserts check_memory![vm.segments.memory, ((1, 3), 0)]; } + + #[test] + fn run_di_bit_ok() { + let hint_code = hint_code::DI_BIT; + let mut vm = vm_with_range_check!(); + + let scalar_u = 0b10101111001110000; + let scalar_v = 0b101101000111011111100; + let m = 3; + // Insert ids.scalar into memory + vm.segments = segments![((1, 0), scalar_u), ((1, 1), scalar_v), ((1, 2), m)]; + + // Initialize RunContext + run_context!(vm, 0, 4, 4); + + let ids_data = ids_data!["scalar_u", "scalar_v", "m", "dibit"]; + + // Execute the hint + assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(())); + + // Check hint memory inserts + check_memory![vm.segments.memory, ((1, 3), 2)]; + } } diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index de2d2951f5..ba2c26390e 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -1353,8 +1353,8 @@ fn cairo_run_is_zero_pack() { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] -fn cairo_run_quad_bit() { - let program_data = include_bytes!("../../cairo_programs/quad_bit.json"); +fn cairo_run_n_bit() { + let program_data = include_bytes!("../../cairo_programs/n_bit.json"); run_program_simple(program_data.as_slice()); }