Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hints): add NewHint#13 #1006

Merged
merged 10 commits into from
Apr 19, 2023
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@
* Added dynamic layout [#879](https://github.com/lambdaclass/cairo-rs/pull/879)
* `get_segment_size` was exposed [#934](https://github.com/lambdaclass/cairo-rs/pull/934)

* Add missing hint on cairo_secp lib [#1006](https://github.com/lambdaclass/cairo-rs/pull/1006):

`BuiltinHintProcessor` now supports the following hint:

```python
ids.quad_bit = (
8 * ((ids.scalar_v >> ids.m) & 1)
+ 4 * ((ids.scalar_u >> ids.m) & 1)
+ 2 * ((ids.scalar_v >> (ids.m - 1)) & 1)
+ ((ids.scalar_u >> (ids.m - 1)) & 1)
)
```

* Add missing hint on cairo_secp lib [#996](https://github.com/lambdaclass/cairo-rs/pull/996):

`BuiltinHintProcessor` now supports the following hint:
Expand All @@ -80,9 +93,10 @@
value = x_inv = div_mod(1, x, SECP_P)
```

* Add missing hints on cairo_secp lib [#994](https://github.com/lambdaclass/cairo-rs/pull/994)::
* Add missing hints on cairo_secp lib [#994](https://github.com/lambdaclass/cairo-rs/pull/994):

`BuiltinHintProcessor` now supports the following hints:

```python
from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import div_mod, safe_div
Expand Down
31 changes: 31 additions & 0 deletions cairo_programs/quad_bit.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
%builtins range_check

func get_quad_bit{range_check_ptr}(scalar_u: felt, scalar_v: felt, m: felt) -> felt {
alloc_locals;
local quad_bit: felt;
%{
ids.quad_bit = (
8 * ((ids.scalar_v >> ids.m) & 1)
+ 4 * ((ids.scalar_u >> ids.m) & 1)
+ 2 * ((ids.scalar_v >> (ids.m - 1)) & 1)
+ ((ids.scalar_u >> (ids.m - 1)) & 1)
)
%}
return quad_bit;
}

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;

return ();
}

func main{range_check_ptr}() {
test_quad_bit();

return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{
ec_utils::{
compute_doubling_slope, compute_slope, 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,
fast_ec_add_assign_new_y, quad_bit,
},
field_utils::{
is_zero_assign_scope_variables, is_zero_assign_scope_variables_external_const,
Expand Down Expand Up @@ -531,6 +531,7 @@ impl HintProcessor for BuiltinHintProcessor {
hint_code::UINT256_MUL_DIV_MOD => {
uint256_mul_div_mod(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::QUAD_BIT => quad_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
7 changes: 7 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,5 +815,12 @@ ids.remainder.d1 = remainder_split[1]
ids.remainder.d2 = remainder_split[2]";
pub const UINT384_SIGNED_NN: &str = "memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0";

pub const QUAD_BIT: &str = r#"ids.quad_bit = (
8 * ((ids.scalar_v >> ids.m) & 1)
+ 4 * ((ids.scalar_u >> ids.m) & 1)
+ 2 * ((ids.scalar_v >> (ids.m - 1)) & 1)
+ ((ids.scalar_u >> (ids.m - 1)) & 1)
)"#;

#[cfg(feature = "skip_next_instruction_hint")]
pub const SKIP_NEXT_INSTRUCTION: &str = "skip_next_instruction()";
106 changes: 101 additions & 5 deletions src/hint_processor/builtin_hint_processor/secp/ec_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ use crate::{
hint_processor::{
builtin_hint_processor::{
hint_utils::{
get_integer_from_var_name, get_relocatable_from_var_name, insert_value_into_ap,
get_integer_from_var_name, get_relocatable_from_var_name,
insert_value_from_var_name, insert_value_into_ap,
},
secp::{
bigint_utils::BigInt3,
secp_utils::{pack, SECP_P},
},
secp::secp_utils::pack,
},
hint_processor_definition::HintReference,
},
Expand All @@ -18,9 +22,7 @@ use crate::{
use felt::Felt252;
use num_bigint::BigInt;
use num_integer::Integer;
use num_traits::{One, Zero};

use super::{bigint_utils::BigInt3, secp_utils::SECP_P};
use num_traits::{One, ToPrimitive, Zero};

#[derive(Debug, PartialEq)]
struct EcPoint<'a> {
Expand Down Expand Up @@ -272,6 +274,53 @@ pub fn ec_mul_inner(
insert_value_into_ap(vm, scalar)
}

/*
Implements hint:
%{
ids.quad_bit = (
8 * ((ids.scalar_v >> ids.m) & 1)
+ 4 * ((ids.scalar_u >> ids.m) & 1)
+ 2 * ((ids.scalar_v >> (ids.m - 1)) & 1)
+ ((ids.scalar_u >> (ids.m - 1)) & 1)
)
%}
*/
pub fn quad_bit(
vm: &mut VirtualMachine,
ids_data: &HashMap<String, HintReference>,
ap_tracking: &ApTracking,
) -> 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)?;
let m_cow = get_integer_from_var_name("m", vm, ids_data, ap_tracking)?;

let scalar_v = scalar_v_cow.as_ref();
let scalar_u = scalar_u_cow.as_ref();

// If m is too high the shift result will always be zero
let m = match m_cow.as_ref().to_u32() {
Some(m) if m <= 252 => m,
None | Some(_) => {
return insert_value_from_var_name("quad_bit", 0, vm, ids_data, ap_tracking)
}
MegaRedHand marked this conversation as resolved.
Show resolved Hide resolved
};

let one = &Felt252::one();

// 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)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -809,4 +858,51 @@ mod tests {
let r = EcPoint::from_var_name("e", &vm, &ids_data, &ap_tracking);
assert_matches!(r, Err(HintError::UnknownIdentifier(x)) if x == "e")
}

#[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 mut vm = vm_with_range_check!();

let scalar_u = 89712;
let scalar_v = 1478396;
let m = 4;
// 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", "quad_bit"];

// Execute the hint
assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));

// Check hint memory inserts
check_memory![vm.segments.memory, ((1, 3), 14)];
}

#[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 mut vm = vm_with_range_check!();

let scalar_u = 89712;
let scalar_v = 1478396;
// Value is so high the result will always be zero
let m = i128::MAX;
MegaRedHand marked this conversation as resolved.
Show resolved Hide resolved
// 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", "quad_bit"];

// Execute the hint
assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));

// Check hint memory inserts
check_memory![vm.segments.memory, ((1, 3), 0)];
}
}
7 changes: 7 additions & 0 deletions src/tests/cairo_run_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1343,3 +1343,10 @@ fn cairo_run_is_zero() {
let program_data = include_bytes!("../../cairo_programs/is_zero.json");
run_program_simple(program_data.as_slice());
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn cairo_run_quad_bit() {
let program_data = include_bytes!("../../cairo_programs/quad_bit.json");
run_program_simple(program_data.as_slice());
}