diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d9c96fce..1eb6131fd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -245,6 +245,42 @@ value = slope = div_mod(y0 - y1, x0 - x1, SECP_P) ``` +* Add missing hint on cairo_secp lib [#989]: + + `BuiltinHintProcessor` now supports the following hint: + ```python + from starkware.cairo.common.cairo_secp.secp_utils import SECP_P + 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 + ``` + +* Add missing hint on cairo_secp lib [#986]: + `BuiltinHintProcessor` now supports the following hint: + ```python + from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + from starkware.python.math_utils import div_mod + + # Compute the slope. + x = pack(ids.pt.x, PRIME) + y = pack(ids.pt.y, PRIME) + value = slope = div_mod(3 * x ** 2, 2 * y, SECP_P) + ``` + +* Add missing hint on cairo_secp lib [#984]: + `BuiltinHintProcessor` now supports the following hint: + ```python + from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + from starkware.python.math_utils import div_mod + + # Compute the slope. + x0 = pack(ids.pt0.x, PRIME) + y0 = pack(ids.pt0.y, PRIME) + x1 = pack(ids.pt1.x, PRIME) + y1 = pack(ids.pt1.y, PRIME) + value = slope = div_mod(y0 - y1, x0 - x1, SECP_P) + ``` + * Move `Memory` into `MemorySegmentManager` [#830](https://github.com/lambdaclass/cairo-rs/pull/830) * Structural changes: * Remove `memory: Memory` field from `VirtualMachine` diff --git a/cairo_programs/ed25519_field.cairo b/cairo_programs/ed25519_field.cairo new file mode 100644 index 0000000000..955de5f811 --- /dev/null +++ b/cairo_programs/ed25519_field.cairo @@ -0,0 +1,66 @@ +%builtins range_check + +// Source: https://github.com/NilFoundation/cairo-ed25519/blob/fee64a1a60b2e07b3b5c20df57f31d7ffcb29ac9/ed25519_field.cairo + +from starkware.cairo.common.cairo_secp.bigint import BASE, BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.constants import SECP_REM + +// Verifies that the given unreduced value is equal to zero modulo the secp256k1 prime. +// Completeness assumption: val's limbs are in the range (-2**210.99, 2**210.99). +// Soundness assumption: val's limbs are in the range (-2**250, 2**250). +func verify_zero{range_check_ptr}(val: UnreducedBigInt3) { + let x = val; + // Used just to import pack in scope + %{ + from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + + value = pack(ids.x, PRIME) % SECP_P + %} + nondet_bigint3(); + + let q = [ap]; + %{ + from starkware.cairo.common.cairo_secp.secp_utils import SECP_P + 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 + %} + let q_biased = [ap + 1]; + q_biased = q + 2 ** 127, ap++; + [range_check_ptr] = q_biased, ap++; + + tempvar r1 = (val.d0 + q * SECP_REM) / BASE; + assert [range_check_ptr + 1] = r1 + 2 ** 127; + // This implies r1 * BASE = val.d0 + q * SECP_REM (as integers). + + tempvar r2 = (val.d1 + r1) / BASE; + assert [range_check_ptr + 2] = r2 + 2 ** 127; + // This implies r2 * BASE = val.d1 + r1 (as integers). + // Therefore, r2 * BASE**2 = val.d1 * BASE + r1 * BASE. + + assert val.d2 = q * (BASE / 4) - r2; + // This implies q * BASE / 4 = val.d2 + r2 (as integers). + // Therefore, + // q * BASE**3 / 4 = val.d2 * BASE**2 + r2 * BASE ** 2 = + // val.d2 * BASE**2 + val.d1 * BASE + r1 * BASE = + // val.d2 * BASE**2 + val.d1 * BASE + val.d0 + q * SECP_REM = + // val + q * SECP_REM. + // Hence, val = q * (BASE**3 / 4 - SECP_REM) = q * (2**256 - SECP_REM). + + let range_check_ptr = range_check_ptr + 3; + return (); +} + +func test_verify_zero{range_check_ptr: felt}() { + let val = UnreducedBigInt3(0, 0, 0); + + verify_zero(val); + + return (); +} + +func main{range_check_ptr: felt}() { + test_verify_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 93fce74902..31aa8e2aa8 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 @@ -249,7 +249,9 @@ impl HintProcessor for BuiltinHintProcessor { hint_code::BLAKE2S_COMPUTE => { compute_blake2s(vm, &hint_data.ids_data, &hint_data.ap_tracking) } - hint_code::VERIFY_ZERO => verify_zero(vm, &hint_data.ids_data, &hint_data.ap_tracking), + hint_code::VERIFY_ZERO_V1 | hint_code::VERIFY_ZERO_V2 => { + verify_zero(vm, &hint_data.ids_data, &hint_data.ap_tracking) + } hint_code::NONDET_BIGINT3 => { nondet_bigint3(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index 9743b99f91..8bf667122e 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -384,12 +384,17 @@ pub(crate) const NONDET_BIGINT3: &str = r#"from starkware.cairo.common.cairo_sec segments.write_arg(ids.res.address_, split(value))"#; -pub(crate) const VERIFY_ZERO: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack +pub(crate) const VERIFY_ZERO_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack 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(crate) const VERIFY_ZERO_V2: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P +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(crate) const REDUCE: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack value = pack(ids.x, PRIME) % SECP_P"#; 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 da4080c388..9ee1a3598b 100644 --- a/src/hint_processor/builtin_hint_processor/secp/field_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/field_utils.rs @@ -171,6 +171,23 @@ mod tests { check_memory![vm.segments.memory, ((1, 9), 0)]; } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_verify_zero_without_pack_ok() { + let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME"; + let mut vm = vm_with_range_check!(); + //Initialize run_context + run_context!(vm, 0, 9, 9); + //Create hint data + let ids_data = non_continuous_ids_data![("val", -5), ("q", 0)]; + vm.segments = segments![((1, 4), 0), ((1, 5), 0), ((1, 6), 0)]; + //Execute the hint + assert!(run_hint!(vm, ids_data, hint_code, exec_scopes_ref!()).is_ok()); + //Check hint memory inserts + //ids.q + check_memory![vm.segments.memory, ((1, 9), 0)]; + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_verify_zero_error() { diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index 2e48ad7b71..54ddd004b7 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -1295,6 +1295,13 @@ fn cairo_run_uint384() { run_program_simple(program_data.as_slice()); } +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn cairo_run_ed25519_field() { + let program_data = include_bytes!("../../cairo_programs/ed25519_field.json"); + run_program_simple(program_data.as_slice()); +} + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn cairo_run_ed25519_ec() {