Skip to content

Commit 02cb8a2

Browse files
MegaRedHandOppen
authored andcommitted
feat(hints): add NewHint#23 (lambdaclass#996)
* Add NewHint#23 * Update changelog * Make hint codes public * Get and insert SECP_P from/into exec_scope in hint * Fix test * Change assert_matches for assert This should make the codecov patch check pass. --------- Co-authored-by: Mario Rugiero <[email protected]>
1 parent 38bae49 commit 02cb8a2

File tree

6 files changed

+140
-32
lines changed

6 files changed

+140
-32
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@
3131
* Added dynamic layout [#879](https://github.com/lambdaclass/cairo-rs/pull/879)
3232
* `get_segment_size` was exposed [#934](https://github.com/lambdaclass/cairo-rs/pull/934)
3333

34+
* Add missing hint on cairo_secp lib [#996](https://github.com/lambdaclass/cairo-rs/pull/996):
35+
36+
`BuiltinHintProcessor` now supports the following hint:
37+
38+
```python
39+
from starkware.python.math_utils import div_mod
40+
value = x_inv = div_mod(1, x, SECP_P)
41+
```
42+
3443
* Add missing hints on cairo_secp lib [#994](https://github.com/lambdaclass/cairo-rs/pull/994)::
3544

3645
`BuiltinHintProcessor` now supports the following hints:

cairo_programs/is_zero.cairo

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
%builtins range_check
2+
3+
from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3
4+
from starkware.cairo.common.cairo_secp.field import unreduced_mul, verify_zero
5+
6+
// Returns 1 if x == 0 (mod secp256k1_prime), and 0 otherwise.
7+
//
8+
// Completeness assumption: x's limbs are in the range (-BASE, 2*BASE).
9+
// Soundness assumption: x's limbs are in the range (-2**107.49, 2**107.49).
10+
func is_zero{range_check_ptr}(x: BigInt3) -> (res: felt) {
11+
%{
12+
from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
13+
14+
x = pack(ids.x, PRIME) % SECP_P
15+
%}
16+
if (nondet %{ x == 0 %} != 0) {
17+
verify_zero(UnreducedBigInt3(d0=x.d0, d1=x.d1, d2=x.d2));
18+
return (res=1);
19+
}
20+
21+
%{
22+
from starkware.python.math_utils import div_mod
23+
24+
value = x_inv = div_mod(1, x, SECP_P)
25+
%}
26+
let (x_inv) = nondet_bigint3();
27+
let (x_x_inv) = unreduced_mul(x, x_inv);
28+
29+
// Check that x * x_inv = 1 to verify that x != 0.
30+
verify_zero(UnreducedBigInt3(d0=x_x_inv.d0 - 1, d1=x_x_inv.d1, d2=x_x_inv.d2));
31+
return (res=0);
32+
}
33+
34+
func test_is_zero{range_check_ptr}() -> () {
35+
let zero = BigInt3(0, 0, 0);
36+
37+
let (res: felt) = is_zero(zero);
38+
assert res = 1;
39+
40+
let one = BigInt3(1, 0, 0);
41+
42+
let (res: felt) = is_zero(one);
43+
assert res = 0;
44+
45+
let secp256k1_prime = BigInt3(
46+
77371252455336262886226991, 77371252455336267181195263, 19342813113834066795298815
47+
);
48+
49+
let (res: felt) = is_zero(secp256k1_prime);
50+
assert res = 1;
51+
52+
return ();
53+
}
54+
55+
func main{range_check_ptr}() -> () {
56+
test_is_zero();
57+
58+
return ();
59+
}

src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ use crate::{
3434
fast_ec_add_assign_new_y,
3535
},
3636
field_utils::{
37-
is_zero_assign_scope_variables, is_zero_nondet, is_zero_pack, reduce,
38-
verify_zero, verify_zero_with_external_const,
37+
is_zero_assign_scope_variables, is_zero_assign_scope_variables_external_const,
38+
is_zero_nondet, is_zero_pack, reduce, verify_zero,
39+
verify_zero_with_external_const,
3940
},
4041
signature::{
4142
div_mod_n_packed_divmod, div_mod_n_packed_external_n, div_mod_n_safe_div,
@@ -350,6 +351,9 @@ impl HintProcessor for BuiltinHintProcessor {
350351
}
351352
hint_code::IS_ZERO_NONDET => is_zero_nondet(vm, exec_scopes),
352353
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS => is_zero_assign_scope_variables(exec_scopes),
354+
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP => {
355+
is_zero_assign_scope_variables_external_const(exec_scopes)
356+
}
353357
hint_code::DIV_MOD_N_PACKED_DIVMOD_V1 => div_mod_n_packed_divmod(
354358
vm,
355359
exec_scopes,

src/hint_processor/builtin_hint_processor/hint_code.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,11 +435,16 @@ pub const IS_ZERO_NONDET: &str = "memory[ap] = to_felt_or_relocatable(x == 0)";
435435
pub const IS_ZERO_PACK: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
436436
437437
x = pack(ids.x, PRIME) % SECP_P"#;
438+
438439
pub const IS_ZERO_ASSIGN_SCOPE_VARS: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P
439440
from starkware.python.math_utils import div_mod
440441
441442
value = x_inv = div_mod(1, x, SECP_P)"#;
442443

444+
pub const IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP: &str = r#"from starkware.python.math_utils import div_mod
445+
446+
value = x_inv = div_mod(1, x, SECP_P)"#;
447+
443448
pub const DIV_MOD_N_PACKED_DIVMOD_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import N, pack
444449
from starkware.python.math_utils import div_mod, safe_div
445450

src/hint_processor/builtin_hint_processor/secp/field_utils.rs

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ pub fn is_zero_pack(
106106
ap_tracking: &ApTracking,
107107
) -> Result<(), HintError> {
108108
exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone()));
109-
110109
let x_packed = pack(BigInt3::from_var_name("x", vm, ids_data, ap_tracking)?);
111110
let x = x_packed.mod_floor(&SECP_P);
112111
exec_scopes.insert_value("x", x);
@@ -156,9 +155,31 @@ pub fn is_zero_assign_scope_variables(exec_scopes: &mut ExecutionScopes) -> Resu
156155
Ok(())
157156
}
158157

158+
/*
159+
Implements hint:
160+
%{
161+
from starkware.python.math_utils import div_mod
162+
163+
value = x_inv = div_mod(1, x, SECP_P)
164+
%}
165+
*/
166+
pub fn is_zero_assign_scope_variables_external_const(
167+
exec_scopes: &mut ExecutionScopes,
168+
) -> Result<(), HintError> {
169+
//Get variables from vm scope
170+
let secp_p = exec_scopes.get_ref::<BigInt>("SECP_P")?;
171+
let x = exec_scopes.get_ref::<BigInt>("x")?;
172+
173+
let value = div_mod(&BigInt::one(), x, secp_p);
174+
exec_scopes.insert_value("value", value.clone());
175+
exec_scopes.insert_value("x_inv", value);
176+
Ok(())
177+
}
178+
159179
#[cfg(test)]
160180
mod tests {
161181
use super::*;
182+
use crate::hint_processor::builtin_hint_processor::hint_code;
162183
use crate::stdlib::string::ToString;
163184
use crate::vm::vm_memory::memory_segments::MemorySegmentManager;
164185
use crate::{
@@ -517,38 +538,41 @@ mod tests {
517538
#[test]
518539
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
519540
fn is_zero_assign_scope_variables_ok() {
520-
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)";
521-
let mut vm = vm_with_range_check!();
522-
523-
//Initialize vm scope with variable `x`
524541
let mut exec_scopes = ExecutionScopes::new();
525-
exec_scopes.assign_or_update_variable(
526-
"x",
527-
any_box!(bigint_str!(
528-
"52621538839140286024584685587354966255185961783273479086367"
529-
)),
530-
);
531-
//Execute the hint
532-
assert_matches!(
533-
run_hint!(vm, HashMap::new(), hint_code, &mut exec_scopes),
534-
Ok(())
535-
);
542+
let hint_codes = vec![
543+
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS,
544+
hint_code::IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP,
545+
];
536546

537-
//Check 'value' is defined in the vm scope
538-
assert_matches!(
539-
exec_scopes.get::<BigInt>("value"),
540-
Ok(x) if x == bigint_str!(
541-
"19429627790501903254364315669614485084365347064625983303617500144471999752609"
542-
)
543-
);
547+
for hint_code in hint_codes {
548+
let mut vm = vm_with_range_check!();
544549

545-
//Check 'x_inv' is defined in the vm scope
546-
assert_matches!(
547-
exec_scopes.get::<BigInt>("x_inv"),
548-
Ok(x) if x == bigint_str!(
549-
"19429627790501903254364315669614485084365347064625983303617500144471999752609"
550-
)
551-
);
550+
//Initialize vm scope with variable `x`
551+
exec_scopes.assign_or_update_variable(
552+
"x",
553+
any_box!(bigint_str!(
554+
"52621538839140286024584685587354966255185961783273479086367"
555+
)),
556+
);
557+
//Execute the hint
558+
assert!(run_hint!(vm, HashMap::new(), hint_code, &mut exec_scopes).is_ok());
559+
560+
//Check 'value' is defined in the vm scope
561+
assert_matches!(
562+
exec_scopes.get::<BigInt>("value"),
563+
Ok(x) if x == bigint_str!(
564+
"19429627790501903254364315669614485084365347064625983303617500144471999752609"
565+
)
566+
);
567+
568+
//Check 'x_inv' is defined in the vm scope
569+
assert_matches!(
570+
exec_scopes.get::<BigInt>("x_inv"),
571+
Ok(x) if x == bigint_str!(
572+
"19429627790501903254364315669614485084365347064625983303617500144471999752609"
573+
)
574+
);
575+
}
552576
}
553577

554578
#[test]

src/tests/cairo_run_test.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,3 +1329,10 @@ fn cairo_run_div_mod_n() {
13291329
let program_data = include_bytes!("../../cairo_programs/div_mod_n.json");
13301330
run_program_simple(program_data.as_slice());
13311331
}
1332+
1333+
#[test]
1334+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1335+
fn cairo_run_is_zero() {
1336+
let program_data = include_bytes!("../../cairo_programs/is_zero.json");
1337+
run_program_simple(program_data.as_slice());
1338+
}

0 commit comments

Comments
 (0)