From e01a9edfcc144b5e864fc55a85ce9eec8c2a4902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= <47506558+MegaRedHand@users.noreply.github.com> Date: Fri, 14 Apr 2023 18:54:16 -0300 Subject: [PATCH] feat(hints): add NewHint#30 (#984) * Add `COMPUTE_SLOPE_WHITELIST` hint * Update changelog * Fix: add missing return to cairo program * Separate changelog item and description Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> * Format --------- Co-authored-by: fmoletta <99273364+fmoletta@users.noreply.github.com> Co-authored-by: Mario Rugiero --- CHANGELOG.md | 15 ++++ cairo_programs/ed25519_ec.cairo | 77 +++++++++++++++++++ .../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 ++ 6 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 cairo_programs/ed25519_ec.cairo diff --git a/CHANGELOG.md b/CHANGELOG.md index 63e315f345..12d25961fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,21 @@ * ExecutionResource operations: add and substract [#774](https://github.com/lambdaclass/cairo-rs/pull/774), multiplication [#908](https://github.com/lambdaclass/cairo-rs/pull/908) , and `AddAssign` [#914](https://github.com/lambdaclass/cairo-rs/pull/914) +* 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) + ``` + * Implement hints on uint384 lib (Part 2) [#971](https://github.com/lambdaclass/cairo-rs/pull/971) `BuiltinHintProcessor` now supports the following hint: diff --git a/cairo_programs/ed25519_ec.cairo b/cairo_programs/ed25519_ec.cairo new file mode 100644 index 0000000000..61425dbb22 --- /dev/null +++ b/cairo_programs/ed25519_ec.cairo @@ -0,0 +1,77 @@ +%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 + ); + + return (); +} + +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 8ae2f7f60e..f6db107dac 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 @@ -361,9 +361,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 9d882207a0..067d4d4b9d 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -477,6 +477,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 38ed99621f..2e48ad7b71 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -1294,3 +1294,10 @@ fn cairo_run_uint384() { let program_data = include_bytes!("../../cairo_programs/uint384.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()); +}