Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,23 @@
* 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 hints on cairo_secp lib [#994](https://github.com/lambdaclass/cairo-rs/pull/994)::
* 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 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_nondet, is_zero_pack, reduce,
Expand Down Expand Up @@ -522,6 +522,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 @@ -776,5 +776,12 @@ ids.root.d1 = root_split[1]
ids.root.d2 = root_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()";
103 changes: 98 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,50 @@ 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 Some(m) = m_cow.as_ref().to_u32() else {
return insert_value_from_var_name("quad_bit", 0, vm, ids_data, ap_tracking);
};

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 +855,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;
// 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 @@ -1329,3 +1329,10 @@ fn cairo_run_div_mod_n() {
let program_data = include_bytes!("../../cairo_programs/div_mod_n.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());
}