Skip to content

Commit

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

* Update changelog

* Add rstest dependency and use it

* Trigger benchmarks at @Oppen's request

* Disable default features in rstest

This disables async-timeout, that's only used for async tests.

---------

Co-authored-by: Mario Rugiero <mario.rugiero@lambdaclass.com>
  • Loading branch information
MegaRedHand and Oppen authored Apr 20, 2023
1 parent 4bc5541 commit 14cee59
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 26 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

#### Upcoming Changes

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

`BuiltinHintProcessor` now supports the following hint:

```python
memory[ap] = int(x == 0)
```

* Implement hint on `get_felt_bitlength` [#993](https://github.com/lambdaclass/cairo-rs/pull/993)

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,13 @@ bitvec = { version = "1", default-features = false, features = ["alloc"] }
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.34"
assert_matches = "1.5.0"
rstest = { version = "0.17.0", default-features = false }

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
iai = "0.1"
rusty-hook = "0.11"
assert_matches = "1.5.0"
rstest = { version = "0.17.0", default-features = false }

This comment has been minimized.

Copy link
@Oppen

Oppen Apr 20, 2023

Author Contributor

It makes more sense to include it only once under [dev-dependencies], right?

criterion = { version = "0.3", features = ["html_reports"] }
proptest = "1.0.0"

Expand Down
50 changes: 50 additions & 0 deletions cairo_programs/is_zero.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ func is_zero{range_check_ptr}(x: BigInt3) -> (res: felt) {
return (res=0);
}

func is_zero_alt{range_check_ptr}(x: BigInt3) -> (res: felt) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
x = pack(ids.x, PRIME) % SECP_P
%}
%{ memory[ap] = int(x == 0) %}
tempvar x_is_zero;

if (x_is_zero != 0) {
verify_zero(UnreducedBigInt3(d0=x.d0, d1=x.d1, d2=x.d2));
return (res=1);
}

%{
from starkware.cairo.common.cairo_secp.secp_utils import SECP_P
from starkware.python.math_utils import div_mod
value = x_inv = div_mod(1, x, SECP_P)
%}
let (x_inv) = nondet_bigint3();
let (x_x_inv) = unreduced_mul(x, x_inv);

// Check that x * x_inv = 1 to verify that x != 0.
verify_zero(UnreducedBigInt3(d0=x_x_inv.d0 - 1, d1=x_x_inv.d1, d2=x_x_inv.d2));
return (res=0);
}

func test_is_zero{range_check_ptr}() -> () {
let zero = BigInt3(0, 0, 0);

Expand All @@ -52,8 +80,30 @@ func test_is_zero{range_check_ptr}() -> () {
return ();
}

func test_is_zero_alt{range_check_ptr}() -> () {
let zero = BigInt3(0, 0, 0);

let (res: felt) = is_zero_alt(zero);
assert res = 1;

let one = BigInt3(1, 0, 0);

let (res: felt) = is_zero_alt(one);
assert res = 0;

let secp256k1_prime = BigInt3(
77371252455336262886226991, 77371252455336267181195263, 19342813113834066795298815
);

let (res: felt) = is_zero_alt(secp256k1_prime);
assert res = 1;

return ();
}

func main{range_check_ptr}() -> () {
test_is_zero();
test_is_zero_alt();

return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -352,13 +352,13 @@ impl HintProcessor for BuiltinHintProcessor {
hint_code::IS_ZERO_PACK => {
is_zero_pack(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::IS_ZERO_NONDET | hint_code::IS_ZERO_INT => is_zero_nondet(vm, exec_scopes),
hint_code::IS_ZERO_PACK_EXTERNAL_SECP => is_zero_pack_external_secp(
vm,
exec_scopes,
&hint_data.ids_data,
&hint_data.ap_tracking,
),
hint_code::IS_ZERO_NONDET => is_zero_nondet(vm, exec_scopes),
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS => is_zero_assign_scope_variables(exec_scopes),
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP => {
is_zero_assign_scope_variables_external_const(exec_scopes)
Expand Down
1 change: 1 addition & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ ids.high = int.from_bytes(hashed[:16], 'big')
ids.low = int.from_bytes(hashed[16:32], 'big')"#;

pub const IS_ZERO_NONDET: &str = "memory[ap] = to_felt_or_relocatable(x == 0)";
pub const IS_ZERO_INT: &str = "memory[ap] = int(x == 0)";
pub const IS_ZERO_PACK: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
x = pack(ids.x, PRIME) % SECP_P"#;
Expand Down
55 changes: 30 additions & 25 deletions src/hint_processor/builtin_hint_processor/secp/field_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ mod tests {
};
use assert_matches::assert_matches;

use rstest::rstest;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;

Expand Down Expand Up @@ -448,10 +449,11 @@ mod tests {
);
}

#[test]
#[rstest]
#[case(hint_code::IS_ZERO_NONDET)]
#[case(hint_code::IS_ZERO_INT)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_is_zero_nondet_ok_true() {
let hint_code = "memory[ap] = to_felt_or_relocatable(x == 0)";
fn run_is_zero_nondet_ok_true(#[case] hint_code: &str) {
let mut vm = vm_with_range_check!();

//Initialize memory
Expand All @@ -475,10 +477,11 @@ mod tests {
check_memory!(vm.segments.memory, ((1, 15), 1));
}

#[test]
#[rstest]
#[case(hint_code::IS_ZERO_NONDET)]
#[case(hint_code::IS_ZERO_INT)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_is_zero_nondet_ok_false() {
let hint_code = "memory[ap] = to_felt_or_relocatable(x == 0)";
fn run_is_zero_nondet_ok_false(#[case] hint_code: &str) {
let mut vm = vm_with_range_check!();

//Initialize memory
Expand All @@ -502,10 +505,11 @@ mod tests {
check_memory!(vm.segments.memory, ((1, 15), 0));
}

#[test]
#[rstest]
#[case(hint_code::IS_ZERO_NONDET)]
#[case(hint_code::IS_ZERO_INT)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_is_zero_nondet_scope_error() {
let hint_code = "memory[ap] = to_felt_or_relocatable(x == 0)";
fn run_is_zero_nondet_scope_error(#[case] hint_code: &str) {
let mut vm = vm_with_range_check!();

//Initialize memory
Expand All @@ -523,10 +527,11 @@ mod tests {
);
}

#[test]
#[rstest]
#[case(hint_code::IS_ZERO_NONDET)]
#[case(hint_code::IS_ZERO_INT)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn run_is_zero_nondet_invalid_memory_insert() {
let hint_code = "memory[ap] = to_felt_or_relocatable(x == 0)";
fn run_is_zero_nondet_invalid_memory_insert(#[case] hint_code: &str) {
let mut vm = vm_with_range_check!();

//Insert a value in ap before the hint execution, so the hint memory insert fails
Expand All @@ -540,18 +545,17 @@ mod tests {
exec_scopes.assign_or_update_variable("x", any_box!(BigInt::zero()));
//Execute the hint
assert_matches!(
run_hint!(vm, HashMap::new(), hint_code, &mut exec_scopes),
Err(HintError::Memory(
MemoryError::InconsistentMemory(
x,
y,
z
)
)) if x ==
vm.run_context.get_ap() &&
y == MaybeRelocatable::from(Felt252::new(55i32)) &&
z == MaybeRelocatable::from(Felt252::new(1i32))
);
run_hint!(vm, HashMap::new(), hint_code, &mut exec_scopes),
Err(HintError::Memory(
MemoryError::InconsistentMemory(
x,
y,
z
)
)) if x == vm.run_context.get_ap()
&& y == MaybeRelocatable::from(Felt252::new(55i32))
&& z == MaybeRelocatable::from(Felt252::new(1i32))
);
}

#[test]
Expand All @@ -560,6 +564,7 @@ mod tests {
let mut exec_scopes = ExecutionScopes::new();
let hint_codes = vec![
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS,
// NOTE: this one requires IS_ZERO_ASSIGN_SCOPE_VARS to execute first.
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP,
];

Expand Down Expand Up @@ -597,7 +602,7 @@ mod tests {
#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn is_zero_assign_scope_variables_scope_error() {
let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P\nfrom starkware.python.math_utils import div_mod\n\nvalue = x_inv = div_mod(1, x, SECP_P)";
let hint_code = hint_code::IS_ZERO_ASSIGN_SCOPE_VARS;
let mut vm = vm_with_range_check!();
//Skip `x` assignment
//Execute the hint
Expand Down

0 comments on commit 14cee59

Please sign in to comment.