diff --git a/CHANGELOG.md b/CHANGELOG.md index 450dddfca7..9b6ec3562c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ #### Upcoming Changes +* Update `starknet-crypto` to version `0.4.3` [#1011](https://github.com/lambdaclass/cairo-rs/pull/1011) + * The new version carries an 85% reduction in execution time for ECDSA signature verification + * BREAKING CHANGE: refactor `Program` to optimize `Program::clone` [#999](https://github.com/lambdaclass/cairo-rs/pull/999) * Breaking change: many fields that were (unnecessarily) public become hidden by the refactor. @@ -89,6 +92,16 @@ ) ``` +* 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/Cargo.lock b/Cargo.lock index 0900d49658..5512e91856 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1430,9 +1430,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "starknet-crypto" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d49eb65d58fa98a164ad2cd4d04775885386b83bdad6060f168a38ede77c9aed" +checksum = "8802a516a2556b2ddb9630898d2c8387d928a3e603799b8b2a7dc4018b852c8f" dependencies = [ "crypto-bigint", "hex", diff --git a/Cargo.toml b/Cargo.toml index 007a7ecfd1..e00bd25125 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ hex = { version = "0.4.3", default-features = false } bincode = { version = "2.0.0-rc.2", tag = "v2.0.0-rc.2", git = "https://github.com/bincode-org/bincode.git", default-features = false, features = [ "serde", ] } -starknet-crypto = { version = "0.4.2", default-features = false, features = [ +starknet-crypto = { version = "0.4.3", default-features = false, features = [ "signature-display", "alloc", ] } 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 7f2fef8b38..127198796b 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 5902583c33..4c16e46f59 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 1823d44b07..ff7f312f35 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::{ @@ -61,7 +60,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)?; @@ -90,7 +89,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)?; @@ -122,7 +121,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 @@ -156,7 +155,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 @@ -215,7 +214,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 f3d1aa5b8d..36974cf363 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -1344,6 +1344,13 @@ fn cairo_run_is_zero() { 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()); +} + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn cairo_run_quad_bit() {