diff --git a/CHANGELOG.md b/CHANGELOG.md index c624546ac0..965ce58b10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,16 @@ * 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 [#1003](https://github.com/lambdaclass/cairo-rs/pull/1003): + + `BuiltinHintProcessor` now supports the following hint: + + ```python + from starkware.cairo.common.cairo_secp.secp_utils import pack + + x = pack(ids.x, PRIME) % SECP_P + ``` + * Add missing hint on cairo_secp lib [#996](https://github.com/lambdaclass/cairo-rs/pull/996): `BuiltinHintProcessor` now supports the following hint: diff --git a/cairo_programs/is_zero_pack.cairo b/cairo_programs/is_zero_pack.cairo new file mode 100644 index 0000000000..9b79126418 --- /dev/null +++ b/cairo_programs/is_zero_pack.cairo @@ -0,0 +1,49 @@ +%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 + +func is_zero_pack{range_check_ptr}(x: BigInt3) -> (res: felt) { + // just to import SECP_P + %{ + from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + + value = pack(ids.x, PRIME) % SECP_P + %} + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + + x = pack(ids.x, PRIME) % SECP_P + %} + if (nondet %{ x == 0 %} != 0) { + return (res=1); + } + return (res=0); +} + +func test_is_zero_pack{range_check_ptr}() -> () { + let zero = BigInt3(0, 0, 0); + + let (res: felt) = is_zero_pack(zero); + assert res = 1; + + let one = BigInt3(1, 0, 0); + + let (res: felt) = is_zero_pack(one); + assert res = 0; + + let secp256k1_prime = BigInt3( + 77371252455336262886226991, 77371252455336267181195263, 19342813113834066795298815 + ); + + let (res: felt) = is_zero_pack(secp256k1_prime); + assert res = 1; + + return (); +} + +func main{range_check_ptr}() -> () { + test_is_zero_pack(); + + 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 76db67251d..69e0618f84 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 @@ -35,7 +35,7 @@ use crate::{ }, field_utils::{ is_zero_assign_scope_variables, is_zero_assign_scope_variables_external_const, - is_zero_nondet, is_zero_pack, reduce, verify_zero, + is_zero_nondet, is_zero_pack, is_zero_pack_external_secp, reduce, verify_zero, verify_zero_with_external_const, }, signature::{ @@ -351,6 +351,12 @@ 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_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 => { diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index 2e14f1ca65..b1698eb051 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -436,6 +436,10 @@ pub const IS_ZERO_PACK: &str = r#"from starkware.cairo.common.cairo_secp.secp_ut x = pack(ids.x, PRIME) % SECP_P"#; +pub const IS_ZERO_PACK_EXTERNAL_SECP: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import 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 diff --git a/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs b/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs index dc5822d28f..cbcdc37bf0 100644 --- a/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs @@ -1,5 +1,4 @@ use crate::{ - any_box, hint_processor::{ builtin_hint_processor::{ hint_utils::{ @@ -59,7 +58,7 @@ pub fn ec_negate( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); //ids.point let point_y = (get_relocatable_from_var_name("point", vm, ids_data, ap_tracking)? + 3i32)?; let y_bigint3 = BigInt3::from_base_addr(point_y, "point.y", vm)?; @@ -88,7 +87,7 @@ pub fn compute_doubling_slope( ap_tracking: &ApTracking, point_alias: &str, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); //ids.point let point = EcPoint::from_var_name(point_alias, vm, ids_data, ap_tracking)?; @@ -120,7 +119,7 @@ pub fn compute_slope( point0_alias: &str, point1_alias: &str, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); //ids.point0 let point0 = EcPoint::from_var_name(point0_alias, vm, ids_data, ap_tracking)?; //ids.point1 @@ -154,7 +153,7 @@ pub fn ec_double_assign_new_x( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); //ids.slope let slope = BigInt3::from_var_name("slope", vm, ids_data, ap_tracking)?; //ids.point @@ -213,7 +212,7 @@ pub fn fast_ec_add_assign_new_x( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); //ids.slope let slope = BigInt3::from_var_name("slope", vm, ids_data, ap_tracking)?; //ids.point0 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 7bbb604700..e321801b9a 100644 --- a/src/hint_processor/builtin_hint_processor/secp/field_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/field_utils.rs @@ -1,13 +1,17 @@ -use crate::any_box; -use crate::stdlib::{collections::HashMap, prelude::*}; - use crate::{ hint_processor::{ - builtin_hint_processor::hint_utils::{insert_value_from_var_name, insert_value_into_ap}, + builtin_hint_processor::{ + hint_utils::{insert_value_from_var_name, insert_value_into_ap}, + secp::{ + bigint_utils::BigInt3, + secp_utils::{pack, SECP_P}, + }, + }, hint_processor_definition::HintReference, }, math_utils::div_mod, serde::deserialize_program::ApTracking, + stdlib::{collections::HashMap, prelude::*}, types::exec_scope::ExecutionScopes, vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}, }; @@ -16,9 +20,6 @@ use num_bigint::BigInt; use num_integer::Integer; use num_traits::{One, Zero}; -use super::secp_utils::SECP_P; -use super::{bigint_utils::BigInt3, secp_utils::pack}; - /* Implements hint: %{ @@ -35,7 +36,7 @@ pub fn verify_zero( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); let val = pack(BigInt3::from_var_name("val", vm, ids_data, ap_tracking)?); let (q, r) = val.div_rem(&SECP_P); if !r.is_zero() { @@ -85,7 +86,7 @@ pub fn reduce( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); let value = pack(BigInt3::from_var_name("x", vm, ids_data, ap_tracking)?); exec_scopes.insert_value("value", value.mod_floor(&SECP_P)); Ok(()) @@ -105,13 +106,26 @@ pub fn is_zero_pack( ids_data: &HashMap, ap_tracking: &ApTracking, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", 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); Ok(()) } +pub fn is_zero_pack_external_secp( + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + let secp_p = exec_scopes.get_ref("SECP_P")?; + 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); + Ok(()) +} + /* Implements hint: in .cairo program @@ -145,7 +159,7 @@ Implements hint: %} */ pub fn is_zero_assign_scope_variables(exec_scopes: &mut ExecutionScopes) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); //Get `x` variable from vm scope let x = exec_scopes.get::("x")?; @@ -370,36 +384,41 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_is_zero_pack_ok() { - let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\n\nx = pack(ids.x, PRIME) % SECP_P"; - let mut vm = vm_with_range_check!(); - - //Initialize fp - vm.run_context.fp = 15; - - //Create hint data - let ids_data = HashMap::from([("x".to_string(), HintReference::new_simple(-5))]); - //Insert ids.x.d0, ids.x.d1, ids.x.d2 into memory - vm.segments = segments![ - ((1, 10), 232113757366008801543585_i128), - ((1, 11), 232113757366008801543585_i128), - ((1, 12), 232113757366008801543585_i128) + let mut exec_scopes = ExecutionScopes::new(); + let hint_codes = vec![ + hint_code::IS_ZERO_PACK, + // NOTE: this one requires IS_ZERO_ASSIGN_SCOPE_VARS to execute first. + hint_code::IS_ZERO_PACK_EXTERNAL_SECP, ]; + for hint_code in hint_codes { + let mut vm = vm_with_range_check!(); - let mut exec_scopes = ExecutionScopes::new(); + //Initialize fp + vm.run_context.fp = 15; - //Execute the hint - assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(())); + //Create hint data + let ids_data = HashMap::from([("x".to_string(), HintReference::new_simple(-5))]); + //Insert ids.x.d0, ids.x.d1, ids.x.d2 into memory + vm.segments = segments![ + ((1, 10), 232113757366008801543585_i128), + ((1, 11), 232113757366008801543585_i128), + ((1, 12), 232113757366008801543585_i128) + ]; - //Check 'x' is defined in the vm scope - check_scope!( - &exec_scopes, - [( - "x", - bigint_str!( + //Execute the hint + assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(())); + + //Check 'x' is defined in the vm scope + check_scope!( + &exec_scopes, + [( + "x", + bigint_str!( "1389505070847794345082847096905107459917719328738389700703952672838091425185" ) - )] - ); + )] + ); + } } #[test] diff --git a/src/hint_processor/builtin_hint_processor/secp/signature.rs b/src/hint_processor/builtin_hint_processor/secp/signature.rs index 54b13b0bf4..c4086fc99e 100644 --- a/src/hint_processor/builtin_hint_processor/secp/signature.rs +++ b/src/hint_processor/builtin_hint_processor/secp/signature.rs @@ -109,7 +109,7 @@ pub fn get_point_from_x( ap_tracking: &ApTracking, constants: &HashMap, ) -> Result<(), HintError> { - exec_scopes.assign_or_update_variable("SECP_P", any_box!(SECP_P.clone())); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); #[allow(deprecated)] let beta = constants .get(BETA) diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index 4e42fe4b4b..216b2b8597 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -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_is_zero_pack() { + let program_data = include_bytes!("../../cairo_programs/is_zero_pack.json"); + run_program_simple(program_data.as_slice()); +}