From 61324829fce901d5d4753ccd80b6d85d33315d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Thu, 13 Apr 2023 17:08:41 -0300 Subject: [PATCH 01/11] Add `COMPUTE_SLOPE_WHITELIST` hint --- cairo_programs/ed25519_ec.cairo | 75 +++++++++++++++++++ .../builtin_hint_processor_definition.rs | 19 ++++- .../builtin_hint_processor/hint_code.rs | 10 +++ .../builtin_hint_processor/secp/ec_utils.rs | 57 +++++++++++++- src/tests/cairo_run_test.rs | 7 ++ 5 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 cairo_programs/ed25519_ec.cairo diff --git a/cairo_programs/ed25519_ec.cairo b/cairo_programs/ed25519_ec.cairo new file mode 100644 index 0000000000..4f6e6b5527 --- /dev/null +++ b/cairo_programs/ed25519_ec.cairo @@ -0,0 +1,75 @@ +%builtins range_check + +// Source: https://github.com/NilFoundation/cairo-ed25519/blob/fee64a1a60b2e07b3b5c20df57f31d7ffcb29ac9/ed25519_ec.cairo + +from starkware.cairo.common.serialize import serialize_word +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.field import ( + is_zero, + unreduced_mul, + unreduced_sqr, + verify_zero, +) + +// Represents a point on the elliptic curve. +// The zero point is represented using pt.x=0, as there is no point on the curve with this x value. +struct EcPoint { + x: BigInt3, + y: BigInt3, +} + +// Returns the slope of the line connecting the two given points. +// The slope is used to compute pt0 + pt1. +// Assumption: pt0.x != pt1.x (mod secp256k1_prime). +func compute_slope{range_check_ptr: felt}(pt0: EcPoint, pt1: EcPoint) -> (slope: BigInt3) { + %{ + 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) + %} + let (slope) = nondet_bigint3(); + + let x_diff = BigInt3(d0=pt0.x.d0 - pt1.x.d0, d1=pt0.x.d1 - pt1.x.d1, d2=pt0.x.d2 - pt1.x.d2); + let (x_diff_slope: UnreducedBigInt3) = unreduced_mul(x_diff, slope); + + verify_zero( + UnreducedBigInt3( + d0=x_diff_slope.d0 - pt0.y.d0 + pt1.y.d0, + d1=x_diff_slope.d1 - pt0.y.d1 + pt1.y.d1, + d2=x_diff_slope.d2 - pt0.y.d2 + pt1.y.d2, + ), + ); + + return (slope=slope); +} + +func test_compute_slope{range_check_ptr: felt}() { + let x0 = BigInt3(d0=1, d1=5, d2=10); + let y0 = BigInt3(d0=2, d1=4, d2=20); + + let pt0 = EcPoint(x=x0, y=y0); + + let x1 = BigInt3(d0=3, d1=3, d2=3); + let y1 = BigInt3(d0=3, d1=5, d2=22); + + let pt1 = EcPoint(x=x1, y=y1); + + // Compute slope + let (slope) = compute_slope(pt0, pt1); + + assert slope = BigInt3( + d0=39919528597790922692721903, d1=31451568879578276714332055, d2=6756007504256943629292535 + ); +} + +func main{range_check_ptr: felt}() { + test_compute_slope(); + + 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 535db3b7ec..89770142c3 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 @@ -356,9 +356,22 @@ impl HintProcessor for BuiltinHintProcessor { hint_code::EC_DOUBLE_SCOPE => { compute_doubling_slope(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } - hint_code::COMPUTE_SLOPE => { - compute_slope(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) - } + hint_code::COMPUTE_SLOPE => compute_slope( + vm, + exec_scopes, + &hint_data.ids_data, + &hint_data.ap_tracking, + "point0", + "point1", + ), + hint_code::COMPUTE_SLOPE_WHITELIST => compute_slope( + vm, + exec_scopes, + &hint_data.ids_data, + &hint_data.ap_tracking, + "pt0", + "pt1", + ), hint_code::EC_DOUBLE_ASSIGN_NEW_X => { ec_double_assign_new_x(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 aa0472104f..88fb0f7125 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -465,6 +465,16 @@ x1 = pack(ids.point1.x, PRIME) y1 = pack(ids.point1.y, PRIME) value = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"#; +pub(crate) const COMPUTE_SLOPE_WHITELIST: &str = r#"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)"#; + pub(crate) const EC_DOUBLE_ASSIGN_NEW_X: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack slope = pack(ids.slope, PRIME) 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 cd41607005..d59da2c96d 100644 --- a/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs @@ -113,11 +113,13 @@ pub fn compute_slope( exec_scopes: &mut ExecutionScopes, ids_data: &HashMap, ap_tracking: &ApTracking, + point0_alias: &str, + point1_alias: &str, ) -> Result<(), HintError> { //ids.point0 - let point0 = EcPoint::from_var_name("point0", vm, ids_data, ap_tracking)?; + let point0 = EcPoint::from_var_name(point0_alias, vm, ids_data, ap_tracking)?; //ids.point1 - let point1 = EcPoint::from_var_name("point1", vm, ids_data, ap_tracking)?; + let point1 = EcPoint::from_var_name(point1_alias, vm, ids_data, ap_tracking)?; let value = line_slope( &(pack(point0.x), pack(point0.y)), @@ -406,6 +408,57 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_compute_slope_wdivmod_ok() { + let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import div_mod\n\n# Compute the slope.\nx0 = pack(ids.pt0.x, PRIME)\ny0 = pack(ids.pt0.y, PRIME)\nx1 = pack(ids.pt1.x, PRIME)\ny1 = pack(ids.pt1.y, PRIME)\nvalue = slope = div_mod(y0 - y1, x0 - x1, SECP_P)"; + let mut vm = vm_with_range_check!(); + + // Insert ids.pt0 and ids.pt1 into memory + vm.segments = segments![ + ((1, 0), 134), + ((1, 1), 5123), + ((1, 2), 140), + ((1, 3), 1232), + ((1, 4), 4652), + ((1, 5), 720), + ((1, 6), 156), + ((1, 7), 6545), + ((1, 8), 100010), + ((1, 9), 1123), + ((1, 10), 1325), + ((1, 11), 910) + ]; + + // Initialize fp + vm.run_context.fp = 14; + let ids_data = HashMap::from([ + ("pt0".to_string(), HintReference::new_simple(-14)), + ("pt1".to_string(), HintReference::new_simple(-8)), + ]); + let mut exec_scopes = ExecutionScopes::new(); + + // Execute the hint + assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(())); + check_scope!( + &exec_scopes, + [ + ( + "value", + bigint_str!( + "41419765295989780131385135514529906223027172305400087935755859001910844026631" + ) + ), + ( + "slope", + bigint_str!( + "41419765295989780131385135514529906223027172305400087935755859001910844026631" + ) + ) + ] + ); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_ec_double_assign_new_x_ok() { diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index 9c12f8b0e3..22eb20e22c 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -1280,3 +1280,10 @@ fn cairo_run_is_quad_residue_test() { let program_data = include_bytes!("../../cairo_programs/is_quad_residue_test.json"); run_program_simple(program_data.as_slice()); } + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn cairo_run_ed25519_ec() { + let program_data = include_bytes!("../../cairo_programs/ed25519_ec.json"); + run_program_simple(program_data.as_slice()); +} From aaa202b0713d62cd36484479b058e41a46cf234a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Thu, 13 Apr 2023 17:54:33 -0300 Subject: [PATCH 02/11] Update changelog --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1c8956cac..e7d339ccc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ #### Upcoming Changes +* 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` From 6e54f1da8362aed6b9c119880ef1d33222dcdedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Thu, 13 Apr 2023 18:09:30 -0300 Subject: [PATCH 03/11] Fix: add missing return to cairo program --- cairo_programs/ed25519_ec.cairo | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cairo_programs/ed25519_ec.cairo b/cairo_programs/ed25519_ec.cairo index 4f6e6b5527..61425dbb22 100644 --- a/cairo_programs/ed25519_ec.cairo +++ b/cairo_programs/ed25519_ec.cairo @@ -66,6 +66,8 @@ func test_compute_slope{range_check_ptr: felt}() { assert slope = BigInt3( d0=39919528597790922692721903, d1=31451568879578276714332055, d2=6756007504256943629292535 ); + + return (); } func main{range_check_ptr: felt}() { From f35c393ee6107ea795f4a9883a84a7716a366bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Thu, 13 Apr 2023 18:41:31 -0300 Subject: [PATCH 04/11] Add `EC_DOUBLE_SCOPE_WHITELIST` hint --- cairo_programs/ed25519_ec.cairo | 48 +++++++++++++++++++ .../builtin_hint_processor_definition.rs | 17 +++++-- .../builtin_hint_processor/hint_code.rs | 8 ++++ .../builtin_hint_processor/secp/ec_utils.rs | 44 ++++++++++++++++- 4 files changed, 113 insertions(+), 4 deletions(-) diff --git a/cairo_programs/ed25519_ec.cairo b/cairo_programs/ed25519_ec.cairo index 61425dbb22..71c841cbd4 100644 --- a/cairo_programs/ed25519_ec.cairo +++ b/cairo_programs/ed25519_ec.cairo @@ -18,6 +18,37 @@ struct EcPoint { y: BigInt3, } +// Returns the slope of the elliptic curve at the given point. +// The slope is used to compute pt + pt. +// Assumption: pt != 0. +func compute_doubling_slope{range_check_ptr}(pt: EcPoint) -> (slope: BigInt3) { + // Note that y cannot be zero: assume that it is, then pt = -pt, so 2 * pt = 0, which + // contradicts the fact that the size of the curve is odd. + %{ + 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) + %} + let (slope: BigInt3) = nondet_bigint3(); + + let (x_sqr: UnreducedBigInt3) = unreduced_sqr(pt.x); + let (slope_y: UnreducedBigInt3) = unreduced_mul(slope, pt.y); + + verify_zero( + UnreducedBigInt3( + d0=3 * x_sqr.d0 - 2 * slope_y.d0, + d1=3 * x_sqr.d1 - 2 * slope_y.d1, + d2=3 * x_sqr.d2 - 2 * slope_y.d2, + ), + ); + + return (slope=slope); +} + // Returns the slope of the line connecting the two given points. // The slope is used to compute pt0 + pt1. // Assumption: pt0.x != pt1.x (mod secp256k1_prime). @@ -49,6 +80,22 @@ func compute_slope{range_check_ptr: felt}(pt0: EcPoint, pt1: EcPoint) -> (slope: return (slope=slope); } +func test_compute_double_slope{range_check_ptr: felt}() { + let x = BigInt3(d0=33, d1=24, d2=12412); + let y = BigInt3(d0=3232, d1=122, d2=31415); + + let pt = EcPoint(x=x, y=y); + + // Compute slope + let (slope) = compute_doubling_slope(pt); + + assert slope = BigInt3( + d0=56007611085086895200895667, d1=15076814030975805918069142, d2=6556143173243739984479201 + ); + + return (); +} + func test_compute_slope{range_check_ptr: felt}() { let x0 = BigInt3(d0=1, d1=5, d2=10); let y0 = BigInt3(d0=2, d1=4, d2=20); @@ -71,6 +118,7 @@ func test_compute_slope{range_check_ptr: felt}() { } func main{range_check_ptr: felt}() { + test_compute_double_slope(); test_compute_slope(); 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 89770142c3..bad11ca60e 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 @@ -353,9 +353,20 @@ impl HintProcessor for BuiltinHintProcessor { hint_code::EC_NEGATE => { ec_negate(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) } - hint_code::EC_DOUBLE_SCOPE => { - compute_doubling_slope(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking) - } + hint_code::EC_DOUBLE_SCOPE => compute_doubling_slope( + vm, + exec_scopes, + &hint_data.ids_data, + &hint_data.ap_tracking, + "point", + ), + hint_code::EC_DOUBLE_SCOPE_WHITELIST => compute_doubling_slope( + vm, + exec_scopes, + &hint_data.ids_data, + &hint_data.ap_tracking, + "pt", + ), hint_code::COMPUTE_SLOPE => compute_slope( 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 88fb0f7125..b2b13c6093 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -455,6 +455,14 @@ x = pack(ids.point.x, PRIME) y = pack(ids.point.y, PRIME) value = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)"#; +pub(crate) const EC_DOUBLE_SCOPE_WHITELIST: &str = r#"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)"#; + pub(crate) const COMPUTE_SLOPE: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack from starkware.python.math_utils import line_slope 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 d59da2c96d..9c7dfe74f8 100644 --- a/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs @@ -84,9 +84,10 @@ pub fn compute_doubling_slope( exec_scopes: &mut ExecutionScopes, ids_data: &HashMap, ap_tracking: &ApTracking, + point_alias: &str, ) -> Result<(), HintError> { //ids.point - let point = EcPoint::from_var_name("point", vm, ids_data, ap_tracking)?; + let point = EcPoint::from_var_name(point_alias, vm, ids_data, ap_tracking)?; let value = ec_double_slope(&(pack(point.x), pack(point.y)), &BigInt::zero(), &SECP_P); exec_scopes.insert_value("value", value.clone()); @@ -357,6 +358,47 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_compute_doubling_slope_wdivmod_ok() { + let hint_code = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import div_mod\n\n# Compute the slope.\nx = pack(ids.pt.x, PRIME)\ny = pack(ids.pt.y, PRIME)\nvalue = slope = div_mod(3 * x ** 2, 2 * y, SECP_P)"; + let mut vm = vm_with_range_check!(); + vm.segments = segments![ + ((1, 0), 614323u64), + ((1, 1), 5456867u64), + ((1, 2), 101208u64), + ((1, 3), 773712524u64), + ((1, 4), 77371252u64), + ((1, 5), 5298795u64) + ]; + + //Initialize fp + vm.run_context.fp = 1; + + let ids_data = ids_data!["pt"]; + let mut exec_scopes = ExecutionScopes::new(); + + //Execute the hint + assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(())); + check_scope!( + &exec_scopes, + [ + ( + "value", + bigint_str!( + "40442433062102151071094722250325492738932110061897694430475034100717288403728" + ) + ), + ( + "slope", + bigint_str!( + "40442433062102151071094722250325492738932110061897694430475034100717288403728" + ) + ) + ] + ); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_compute_slope_ok() { From 9f68e732649da2e1478d033010c36e74c49a0105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Thu, 13 Apr 2023 18:50:58 -0300 Subject: [PATCH 05/11] Update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7d339ccc9..274e925923 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ #### Upcoming Changes +* 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 181b41bf8cc22ec91f9dd58d792cd8f88d3ea265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Fri, 14 Apr 2023 11:41:42 -0300 Subject: [PATCH 06/11] Add NewHint#28 --- cairo_programs/ed25519_field.cairo | 64 +++++++++++++++++++ .../builtin_hint_processor_definition.rs | 4 +- .../builtin_hint_processor/hint_code.rs | 5 ++ .../secp/field_utils.rs | 20 ++++++ src/tests/cairo_run_test.rs | 7 ++ 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 cairo_programs/ed25519_field.cairo diff --git a/cairo_programs/ed25519_field.cairo b/cairo_programs/ed25519_field.cairo new file mode 100644 index 0000000000..0e1e8c6e41 --- /dev/null +++ b/cairo_programs/ed25519_field.cairo @@ -0,0 +1,64 @@ +%builtins range_check + +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 bad11ca60e..c645673806 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 @@ -244,7 +244,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 | hint_code::VERIFY_ZERO_WHITELIST => { + 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 b2b13c6093..f56f09aeaa 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -378,6 +378,11 @@ 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_WHITELIST: &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..db2cd670fe 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,26 @@ 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_matches!( + run_hint!(vm, ids_data, hint_code, exec_scopes_ref!()), + 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 22eb20e22c..4bad8a95b8 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -1287,3 +1287,10 @@ fn cairo_run_ed25519_ec() { let program_data = include_bytes!("../../cairo_programs/ed25519_ec.json"); 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()); +} From a3f4cd2d97c64ad94d0be4995508cf6919466038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Fri, 14 Apr 2023 11:50:49 -0300 Subject: [PATCH 07/11] Update changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 274e925923..3deca6bf46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ #### Upcoming Changes +* 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 f98b18ce4990fec127a4b67e1008f1f277ef566a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Fri, 14 Apr 2023 12:11:21 -0300 Subject: [PATCH 08/11] Use name without WHITELIST --- .../builtin_hint_processor_definition.rs | 2 +- src/hint_processor/builtin_hint_processor/hint_code.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 c645673806..4ef2bbc863 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 @@ -244,7 +244,7 @@ impl HintProcessor for BuiltinHintProcessor { hint_code::BLAKE2S_COMPUTE => { compute_blake2s(vm, &hint_data.ids_data, &hint_data.ap_tracking) } - hint_code::VERIFY_ZERO | hint_code::VERIFY_ZERO_WHITELIST => { + 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 => { diff --git a/src/hint_processor/builtin_hint_processor/hint_code.rs b/src/hint_processor/builtin_hint_processor/hint_code.rs index f56f09aeaa..8cf906fbe6 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -372,13 +372,13 @@ 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_WHITELIST: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P +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"#; From df42e7d4c9f6e69f76e5dcbc183b80beb13f4143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Fri, 14 Apr 2023 12:12:07 -0300 Subject: [PATCH 09/11] Remove comments and add source --- cairo_programs/ed25519_field.cairo | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/cairo_programs/ed25519_field.cairo b/cairo_programs/ed25519_field.cairo index 0e1e8c6e41..8eacaacc4c 100644 --- a/cairo_programs/ed25519_field.cairo +++ b/cairo_programs/ed25519_field.cairo @@ -1,11 +1,10 @@ %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 @@ -29,21 +28,11 @@ func verify_zero{range_check_ptr}(val: UnreducedBigInt3) { 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 (); From de8e14798476467165b88f7a39b0c7f253c53b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Fri, 14 Apr 2023 12:18:00 -0300 Subject: [PATCH 10/11] Readd deleted comments --- cairo_programs/ed25519_field.cairo | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cairo_programs/ed25519_field.cairo b/cairo_programs/ed25519_field.cairo index 8eacaacc4c..955de5f811 100644 --- a/cairo_programs/ed25519_field.cairo +++ b/cairo_programs/ed25519_field.cairo @@ -5,6 +5,9 @@ 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 @@ -28,11 +31,21 @@ func verify_zero{range_check_ptr}(val: UnreducedBigInt3) { 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 (); From 86ed3770e320fdcd0ee9b1b667a79982b349b8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= Date: Fri, 14 Apr 2023 12:56:43 -0300 Subject: [PATCH 11/11] Change assert_matches for assert + is_ok --- .../builtin_hint_processor/secp/field_utils.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 db2cd670fe..9ee1a3598b 100644 --- a/src/hint_processor/builtin_hint_processor/secp/field_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/field_utils.rs @@ -182,10 +182,7 @@ mod tests { 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_matches!( - run_hint!(vm, ids_data, hint_code, exec_scopes_ref!()), - Ok(()) - ); + 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)];