diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bfee36afc..ef5f086406 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ #### Upcoming Changes +* Add REDUCE_V2 hint [#1420](https://github.com/lambdaclass/cairo-vm/pull/1420): + * Implement REDUCE_V2 hint + * Rename hint REDUCE -> REDUCE_V1 + * BREAKING: Add `disable_trace_padding` to `CairoRunConfig`[#1233](https://github.com/lambdaclass/cairo-rs/pull/1233) * feat: Implement `CairoRunner.get_cairo_pie`[#1375](https://github.com/lambdaclass/cairo-vm/pull/1375/files) diff --git a/cairo_programs/reduce.cairo b/cairo_programs/reduce.cairo index b78e91c9d4..486e8b22de 100644 --- a/cairo_programs/reduce.cairo +++ b/cairo_programs/reduce.cairo @@ -83,7 +83,45 @@ func test_reduce_ed25519{range_check_ptr}() { return (); } +func reduce_v2{range_check_ptr}(x: UnreducedBigInt3) -> (reduced_x: BigInt3) { + let orig_x = x; + %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %} + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + value = pack(ids.x, PRIME) % SECP_P + %} + let (reduced_x: BigInt3) = nondet_bigint3(); + + verify_zero( + UnreducedBigInt3( + d0=orig_x.d0 - reduced_x.d0, + d1=orig_x.d1 - reduced_x.d1, + d2=orig_x.d2 - reduced_x.d2 + ) + ); + return (reduced_x=reduced_x); +} + func main{range_check_ptr}() { test_reduce_ed25519(); + + // reduce_v2 tests + let x = UnreducedBigInt3(0, 0, 0); + let (reduce_v2_a) = reduce_v2(x); + assert reduce_v2_a = BigInt3( + 0, 0, 0 + ); + + let y = UnreducedBigInt3(12354, 745634534, 81298789312879123); + let (reduce_v2_b) = reduce_v2(y); + assert reduce_v2_b = BigInt3( + 12354, 745634534, 81298789312879123 + ); + + let z = UnreducedBigInt3(12354812987893128791212331231233, 7453123123123123312634534, 8129224990312325879); + let (reduce_v2_c) = reduce_v2(z); + assert reduce_v2_c = BigInt3( + 16653320122975184709085185, 7453123123123123312794216, 8129224990312325879 + ); return (); } diff --git a/fuzzer/src/fuzz_json.rs b/fuzzer/src/fuzz_json.rs index ea80ea5017..57361a0bbc 100644 --- a/fuzzer/src/fuzz_json.rs +++ b/fuzzer/src/fuzz_json.rs @@ -112,7 +112,7 @@ const HINTS_CODE: [&str; 184] = [ VERIFY_ZERO_V2, VERIFY_ZERO_V3, VERIFY_ZERO_EXTERNAL_SECP, - REDUCE, + REDUCE_V1, REDUCE_ED25519, UNSAFE_KECCAK, UNSAFE_KECCAK_FINALIZE, diff --git a/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs b/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs index 845b0eda2e..1c3c5f4b40 100644 --- a/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs +++ b/vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs @@ -67,8 +67,8 @@ use crate::{ }, field_utils::{ is_zero_assign_scope_variables, is_zero_assign_scope_variables_external_const, - is_zero_nondet, is_zero_pack, is_zero_pack_external_secp, reduce, verify_zero, - verify_zero_with_external_const, + is_zero_nondet, is_zero_pack, is_zero_pack_external_secp, reduce_v1, reduce_v2, + verify_zero, verify_zero_with_external_const, }, signature::{ div_mod_n_packed_divmod, div_mod_n_packed_external_n, div_mod_n_safe_div, @@ -329,8 +329,11 @@ impl HintProcessorLogic for BuiltinHintProcessor { hint_code::NONDET_BIGINT3_V1 | hint_code::NONDET_BIGINT3_V2 => { nondet_bigint3(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } - hint_code::REDUCE => { - reduce(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) + hint_code::REDUCE_V1 => { + reduce_v1(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) + } + hint_code::REDUCE_V2 => { + reduce_v2(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } hint_code::REDUCE_ED25519 => { ed25519_reduce(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) diff --git a/vm/src/hint_processor/builtin_hint_processor/hint_code.rs b/vm/src/hint_processor/builtin_hint_processor/hint_code.rs index e1e88af924..8f07ba94cf 100644 --- a/vm/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/vm/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -532,10 +532,13 @@ q, r = divmod(pack(ids.val, PRIME), SECP_P) assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." ids.q = q % PRIME"#; -pub const REDUCE: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack +pub const REDUCE_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack value = pack(ids.x, PRIME) % SECP_P"#; +pub const REDUCE_V2: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack +value = pack(ids.x, PRIME) % SECP_P"#; + pub const REDUCE_ED25519: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack SECP_P=2**255-19 diff --git a/vm/src/hint_processor/builtin_hint_processor/secp/field_utils.rs b/vm/src/hint_processor/builtin_hint_processor/secp/field_utils.rs index 1290d1a904..ea4448c5ad 100644 --- a/vm/src/hint_processor/builtin_hint_processor/secp/field_utils.rs +++ b/vm/src/hint_processor/builtin_hint_processor/secp/field_utils.rs @@ -78,7 +78,7 @@ Implements hint: value = pack(ids.x, PRIME) % SECP_P %} */ -pub fn reduce( +pub fn reduce_v1( vm: &mut VirtualMachine, exec_scopes: &mut ExecutionScopes, ids_data: &HashMap, @@ -90,6 +90,25 @@ pub fn reduce( Ok(()) } +/* +Implements hint: +%{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + value = pack(ids.x, PRIME) % SECP_P +%} +*/ +pub fn reduce_v2( + 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 value = Uint384::from_var_name("x", vm, ids_data, ap_tracking)?.pack86(); + exec_scopes.insert_value("value", value.mod_floor(secp_p)); + Ok(()) +} + /* Implements hint: %{ @@ -191,7 +210,7 @@ pub fn is_zero_assign_scope_variables_external_const( #[cfg(test)] mod tests { use super::*; - use crate::hint_processor::builtin_hint_processor::hint_code; + use crate::hint_processor::builtin_hint_processor::hint_code::{self, REDUCE_V2}; use crate::stdlib::string::ToString; use crate::{ @@ -395,6 +414,61 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_reduce_v2_ok() { + let hint_code = REDUCE_V2; + let mut vm = vm_with_range_check!(); + add_segments!(vm, 3); + + //Initialize fp + vm.run_context.fp = 25; + + //Create hint data + let ids_data = non_continuous_ids_data![("x", -5)]; + + vm.segments = segments![ + ((1, 20), ("132181232131231239112312312313213083892150", 10)), + ((1, 21), ("12354812987893128791212331231233", 10)), + ((1, 22), ("654867675805132187", 10)) + ]; + + let mut exec_scopes = ExecutionScopes::new(); + exec_scopes.insert_value("SECP_P", SECP_P.clone()); + //Execute the hint + assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(())); + + //Check 'value' is defined in the vm scope + assert_matches!( + exec_scopes.get::("value"), + Ok(x) if x == bigint_str!( + "3920241379018821570896271640300310233395357371896837069219347149797814" + ) + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_reduce_v2_with_no_secp() { + let hint_code = REDUCE_V2; + let mut vm = vm_with_range_check!(); + add_segments!(vm, 3); + + //Initialize fp + vm.run_context.fp = 25; + + //Create hint data + let ids_data = non_continuous_ids_data![("x", -5)]; + + vm.segments = segments![((1, 20), 1), ((1, 21), 1), ((1, 22), 1)]; + + let mut exec_scopes = ExecutionScopes::new(); + // Skip the SECP definition, so the hint fails + // exec_scopes.insert_value("SECP_P", SECP_P.clone()); + //Execute the hint + assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Err(_)); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_is_zero_pack_ok() {