From 02cb8a26cb967c1693f46f50c9fd70db5c316862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= <47506558+MegaRedHand@users.noreply.github.com> Date: Tue, 18 Apr 2023 12:12:40 -0300 Subject: [PATCH] feat(hints): add NewHint#23 (#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 --- CHANGELOG.md | 9 ++ cairo_programs/is_zero.cairo | 59 +++++++++++++ .../builtin_hint_processor_definition.rs | 8 +- .../builtin_hint_processor/hint_code.rs | 5 ++ .../secp/field_utils.rs | 84 ++++++++++++------- src/tests/cairo_run_test.rs | 7 ++ 6 files changed, 140 insertions(+), 32 deletions(-) create mode 100644 cairo_programs/is_zero.cairo diff --git a/CHANGELOG.md b/CHANGELOG.md index e6e11d7e2d..b1af70896b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,15 @@ * 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 [#996](https://github.com/lambdaclass/cairo-rs/pull/996): + + `BuiltinHintProcessor` now supports the following hint: + + ```python + from starkware.python.math_utils import div_mod + 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):: `BuiltinHintProcessor` now supports the following hints: diff --git a/cairo_programs/is_zero.cairo b/cairo_programs/is_zero.cairo new file mode 100644 index 0000000000..edebe50b97 --- /dev/null +++ b/cairo_programs/is_zero.cairo @@ -0,0 +1,59 @@ +%builtins range_check + +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.field import unreduced_mul, verify_zero + +// Returns 1 if x == 0 (mod secp256k1_prime), and 0 otherwise. +// +// Completeness assumption: x's limbs are in the range (-BASE, 2*BASE). +// Soundness assumption: x's limbs are in the range (-2**107.49, 2**107.49). +func is_zero{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 + %} + if (nondet %{ x == 0 %} != 0) { + verify_zero(UnreducedBigInt3(d0=x.d0, d1=x.d1, d2=x.d2)); + return (res=1); + } + + %{ + 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); + + let (res: felt) = is_zero(zero); + assert res = 1; + + let one = BigInt3(1, 0, 0); + + let (res: felt) = is_zero(one); + assert res = 0; + + let secp256k1_prime = BigInt3( + 77371252455336262886226991, 77371252455336267181195263, 19342813113834066795298815 + ); + + let (res: felt) = is_zero(secp256k1_prime); + assert res = 1; + + return (); +} + +func main{range_check_ptr}() -> () { + test_is_zero(); + + return (); +} diff --git a/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs b/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs index 5dc58ab18c..93534f35f1 100644 --- a/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs +++ b/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs @@ -34,8 +34,9 @@ use crate::{ fast_ec_add_assign_new_y, }, field_utils::{ - is_zero_assign_scope_variables, is_zero_nondet, is_zero_pack, reduce, - verify_zero, verify_zero_with_external_const, + is_zero_assign_scope_variables, is_zero_assign_scope_variables_external_const, + is_zero_nondet, is_zero_pack, reduce, verify_zero, + verify_zero_with_external_const, }, signature::{ div_mod_n_packed_divmod, div_mod_n_packed_external_n, div_mod_n_safe_div, @@ -350,6 +351,9 @@ impl HintProcessor for BuiltinHintProcessor { } 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) + } hint_code::DIV_MOD_N_PACKED_DIVMOD_V1 => div_mod_n_packed_divmod( vm, exec_scopes, diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index 872a6ec5cf..dc9f36b4ab 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -435,11 +435,16 @@ pub const IS_ZERO_NONDET: &str = "memory[ap] = to_felt_or_relocatable(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"#; + pub const IS_ZERO_ASSIGN_SCOPE_VARS: &str = r#"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)"#; +pub const IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP: &str = r#"from starkware.python.math_utils import div_mod + +value = x_inv = div_mod(1, x, SECP_P)"#; + pub const DIV_MOD_N_PACKED_DIVMOD_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import N, pack from starkware.python.math_utils import div_mod, safe_div diff --git a/src/hint_processor/builtin_hint_processor/secp/field_utils.rs b/src/hint_processor/builtin_hint_processor/secp/field_utils.rs index cf9afb1d68..7bbb604700 100644 --- a/src/hint_processor/builtin_hint_processor/secp/field_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/field_utils.rs @@ -106,7 +106,6 @@ pub fn is_zero_pack( ap_tracking: &ApTracking, ) -> Result<(), HintError> { exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); - let x_packed = pack(BigInt3::from_var_name("x", vm, ids_data, ap_tracking)?); let x = x_packed.mod_floor(&SECP_P); exec_scopes.insert_value("x", x); @@ -156,9 +155,31 @@ pub fn is_zero_assign_scope_variables(exec_scopes: &mut ExecutionScopes) -> Resu Ok(()) } +/* +Implements hint: +%{ + from starkware.python.math_utils import div_mod + + value = x_inv = div_mod(1, x, SECP_P) +%} +*/ +pub fn is_zero_assign_scope_variables_external_const( + exec_scopes: &mut ExecutionScopes, +) -> Result<(), HintError> { + //Get variables from vm scope + let secp_p = exec_scopes.get_ref::("SECP_P")?; + let x = exec_scopes.get_ref::("x")?; + + let value = div_mod(&BigInt::one(), x, secp_p); + exec_scopes.insert_value("value", value.clone()); + exec_scopes.insert_value("x_inv", value); + Ok(()) +} + #[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::{ @@ -517,38 +538,41 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn is_zero_assign_scope_variables_ok() { - 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 mut vm = vm_with_range_check!(); - - //Initialize vm scope with variable `x` let mut exec_scopes = ExecutionScopes::new(); - exec_scopes.assign_or_update_variable( - "x", - any_box!(bigint_str!( - "52621538839140286024584685587354966255185961783273479086367" - )), - ); - //Execute the hint - assert_matches!( - run_hint!(vm, HashMap::new(), hint_code, &mut exec_scopes), - Ok(()) - ); + let hint_codes = vec![ + hint_code::IS_ZERO_ASSIGN_SCOPE_VARS, + hint_code::IS_ZERO_ASSIGN_SCOPE_VARS_EXTERNAL_SECP, + ]; - //Check 'value' is defined in the vm scope - assert_matches!( - exec_scopes.get::("value"), - Ok(x) if x == bigint_str!( - "19429627790501903254364315669614485084365347064625983303617500144471999752609" - ) - ); + for hint_code in hint_codes { + let mut vm = vm_with_range_check!(); - //Check 'x_inv' is defined in the vm scope - assert_matches!( - exec_scopes.get::("x_inv"), - Ok(x) if x == bigint_str!( - "19429627790501903254364315669614485084365347064625983303617500144471999752609" - ) - ); + //Initialize vm scope with variable `x` + exec_scopes.assign_or_update_variable( + "x", + any_box!(bigint_str!( + "52621538839140286024584685587354966255185961783273479086367" + )), + ); + //Execute the hint + assert!(run_hint!(vm, HashMap::new(), hint_code, &mut exec_scopes).is_ok()); + + //Check 'value' is defined in the vm scope + assert_matches!( + exec_scopes.get::("value"), + Ok(x) if x == bigint_str!( + "19429627790501903254364315669614485084365347064625983303617500144471999752609" + ) + ); + + //Check 'x_inv' is defined in the vm scope + assert_matches!( + exec_scopes.get::("x_inv"), + Ok(x) if x == bigint_str!( + "19429627790501903254364315669614485084365347064625983303617500144471999752609" + ) + ); + } } #[test] diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index 465d51e8f0..5650c38998 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -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_is_zero() { + let program_data = include_bytes!("../../cairo_programs/is_zero.json"); + run_program_simple(program_data.as_slice()); +}