Skip to content

Commit

Permalink
feat(hints): add NewHint#15 (#1009)
Browse files Browse the repository at this point in the history
* Add NewHint#15

* Update changelog

* Remove allow

* Rename `n_pair_bits`'s `n` parameter
  • Loading branch information
MegaRedHand authored Apr 19, 2023
1 parent 5254822 commit 11b6c37
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 17 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<Item = &MaybeRelocatable>`: get an iterator over all elements in the program data
Expand Down
9 changes: 9 additions & 0 deletions cairo_programs/quad_bit.cairo → cairo_programs/n_bit.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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 ();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down Expand Up @@ -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())),
Expand Down
3 changes: 3 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()";
78 changes: 64 additions & 14 deletions src/hint_processor/builtin_hint_processor/secp/ec_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,28 @@ pub fn quad_bit(
vm: &mut VirtualMachine,
ids_data: &HashMap<String, HintReference>,
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<String, HintReference>,
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<String, HintReference>,
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)?;
Expand All @@ -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::{
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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)];
}
}
4 changes: 2 additions & 2 deletions src/tests/cairo_run_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down

0 comments on commit 11b6c37

Please sign in to comment.