diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c605e7234..b3550ca37c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -428,6 +428,20 @@ ids.flag = 1 if k > 0 else 0 ``` +* Add missing hint on cairo_secp lib [#1057](https://github.com/lambdaclass/cairo-rs/pull/1057): + + `BuiltinHintProcessor` now supports the following hint: + + ```python + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.python.math_utils import ec_double_slope + + # Compute the slope. + x = pack(ids.point.x, PRIME) + y = pack(ids.point.y, PRIME) + value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P) + ``` + * Add missing hint on uint256_improvements lib [#1025](https://github.com/lambdaclass/cairo-rs/pull/1025): `BuiltinHintProcessor` now supports the following hint: diff --git a/cairo_programs/ec_double_slope.cairo b/cairo_programs/ec_double_slope.cairo new file mode 100644 index 0000000000..1017748233 --- /dev/null +++ b/cairo_programs/ec_double_slope.cairo @@ -0,0 +1,212 @@ +%builtins range_check + +// Source: https://github.com/rdubois-crypto/efficient-secp256r1/blob/4b74807c5e91f1ed4cb00a1c973be05c63986e61/src/secp256r1/ec.cairo +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.ec import EcPoint + +// src.secp256r1.constants +// SECP_REM is defined by the equation: +// secp256r1_prime = 2 ** 256 - SECP_REM. +const SECP_REM = 2 ** 224 - 2 ** 192 - 2 ** 96 + 1; + +const BASE = 2 ** 86; + +// A = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc +const A0 = 0x3ffffffffffffffffffffc; +const A1 = 0x3ff; +const A2 = 0xffffffff0000000100000; + +// Constants for unreduced_mul/sqr +const s2 = (-(2 ** 76)) - 2 ** 12; +const s1 = (-(2 ** 66)) + 4; +const s0 = 2 ** 56; + +const r2 = 2 ** 54 - 2 ** 22; +const r1 = -(2 ** 12); +const r0 = 4; + +// src.secp256r1.field +// Adapt from starkware.cairo.common.math's assert_250_bit +func assert_165_bit{range_check_ptr}(value) { + const UPPER_BOUND = 2 ** 165; + const SHIFT = 2 ** 128; + const HIGH_BOUND = UPPER_BOUND / SHIFT; + + let low = [range_check_ptr]; + let high = [range_check_ptr + 1]; + + %{ + from starkware.cairo.common.math_utils import as_int + + # Correctness check. + value = as_int(ids.value, PRIME) % PRIME + assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).' + + # Calculation for the assertion. + ids.high, ids.low = divmod(ids.value, ids.SHIFT) + %} + + assert [range_check_ptr + 2] = HIGH_BOUND - 1 - high; + + assert value = high * SHIFT + low; + + let range_check_ptr = range_check_ptr + 3; + return (); +} + +// src.secp256r1.field +// Computes the multiplication of two big integers, given in BigInt3 representation, modulo the +// secp256r1 prime. +// +// Arguments: +// x, y - the two BigInt3 to operate on. +// +// Returns: +// x * y in an UnreducedBigInt3 representation (the returned limbs may be above 3 * BASE). +// +// This means that if unreduced_mul is called on the result of nondet_bigint3, or the difference +// between two such results, we have: +// Soundness guarantee: the limbs are in the range (). +// Completeness guarantee: the limbs are in the range (). +func unreduced_mul(a: BigInt3, b: BigInt3) -> (res_low: UnreducedBigInt3) { + tempvar twice_d2 = a.d2 * b.d2; + tempvar d1d2 = a.d2 * b.d1 + a.d1 * b.d2; + return ( + UnreducedBigInt3( + d0=a.d0 * b.d0 + s0 * twice_d2 + r0 * d1d2, + d1=a.d1 * b.d0 + a.d0 * b.d1 + s1 * twice_d2 + r1 * d1d2, + d2=a.d2 * b.d0 + a.d1 * b.d1 + a.d0 * b.d2 + s2 * twice_d2 + r2 * d1d2, + ), + ); +} + +// src.secp256r1.field +// Computes the square of a big integer, given in BigInt3 representation, modulo the +// secp256r1 prime. +// +// Has the same guarantees as in unreduced_mul(a, a). +func unreduced_sqr(a: BigInt3) -> (res_low: UnreducedBigInt3) { + tempvar twice_d2 = a.d2 * a.d2; + tempvar twice_d1d2 = a.d2 * a.d1 + a.d1 * a.d2; + tempvar d1d0 = a.d1 * a.d0; + return ( + UnreducedBigInt3( + d0=a.d0 * a.d0 + s0 * twice_d2 + r0 * twice_d1d2, + d1=d1d0 + d1d0 + s1 * twice_d2 + r1 * twice_d1d2, + d2=a.d2 * a.d0 + a.d1 * a.d1 + a.d0 * a.d2 + s2 * twice_d2 + r2 * twice_d1d2, + ), + ); +} + +// src.secp256r1.field +// Verifies that the given unreduced value is equal to zero modulo the secp256r1 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) { + alloc_locals; + local q; + // local q_sign; + let q_sign = 1; + // original: + // %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_P as SECP_P %} + // %{ + // from starkware.cairo.common.cairo_secp.secp_utils import 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}." + // if q >= 0: + // ids.q = q % PRIME + // ids.q_sign = 1 + // else: + // ids.q = (0-q) % PRIME + // ids.q_sign = -1 % PRIME + // %} + %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %} + %{ + from starkware.cairo.common.cairo_secp.secp_utils import 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 + %} + // assert_250_bit(q); // 256K steps + // assert_le_felt(q, 2**165); // 275K steps + assert_165_bit(q); + assert q_sign * (val.d2 + val.d1 / BASE + val.d0 / BASE ** 2) = q * ( + (BASE / 4) - SECP_REM / BASE ** 2 + ); + // Multiply by BASE**2 both sides: + // (q_sign) * val = q * (BASE**3 / 4 - SECP_REM) + // = q * (2**256 - SECP_REM) = q * secp256r1_prime = 0 mod secp256r1_prime + return (); +} + +// Computes the slope of the elliptic curve at a given point. +// The slope is used to compute point + point. +// +// Arguments: +// point - the point to operate on. +// +// Returns: +// slope - the slope of the curve at point, in BigInt3 representation. +// +// Assumption: point != 0. +func compute_doubling_slope{range_check_ptr}(point: EcPoint) -> (slope: BigInt3) { + // Note that y cannot be zero: assume that it is, then point = -point, so 2 * point = 0, which + // contradicts the fact that the size of the curve is odd. + // originals: + // %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_P as SECP_P %} + // %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_ALPHA as ALPHA %} + %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %} + %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA %} + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.python.math_utils import ec_double_slope + + # Compute the slope. + x = pack(ids.point.x, PRIME) + y = pack(ids.point.y, PRIME) + value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P) + %} + let (slope: BigInt3) = nondet_bigint3(); + + let (x_sqr: UnreducedBigInt3) = unreduced_sqr(point.x); + let (slope_y: UnreducedBigInt3) = unreduced_mul(slope, point.y); + verify_zero( + UnreducedBigInt3( + d0=3 * x_sqr.d0 + A0 - 2 * slope_y.d0, + d1=3 * x_sqr.d1 + A1 - 2 * slope_y.d1, + d2=3 * x_sqr.d2 + A2 - 2 * slope_y.d2, + ), + ); + + return (slope=slope); +} + +func test_doubling_slope{range_check_ptr}() { + let point = EcPoint(BigInt3(614323, 5456867, 101208), BigInt3(773712524, 77371252, 5298795)); + + let (slope) = compute_doubling_slope(point); + + assert slope = BigInt3( + 64081873649130491683833713, 34843994309543177837008178, 16548672716077616016846383 + ); + + let point = EcPoint( + BigInt3(51215, 36848548548458, 634734734), BigInt3(26362, 263724839599, 901297012) + ); + + let (slope) = compute_doubling_slope(point); + + assert slope = BigInt3( + 71848883893335852660776740, 75644451964360469099209675, 547087410329256463669633 + ); + + return (); +} + +func main{range_check_ptr}() { + test_doubling_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 ba666d33c2..f2a3fe4c48 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 @@ -6,8 +6,9 @@ use super::{ field_arithmetic::{u256_get_square_root, u384_get_square_root, uint384_div}, secp::{ ec_utils::{ - compute_slope_and_assing_secp_p, ec_double_assign_new_y, ec_mul_inner, - ec_negate_embedded_secp_p, ec_negate_import_secp_p, + compute_doubling_slope_external_consts, compute_slope_and_assing_secp_p, + ec_double_assign_new_y, ec_mul_inner, ec_negate_embedded_secp_p, + ec_negate_import_secp_p, }, secp_utils::{ALPHA, ALPHA_V2, SECP_P, SECP_P_V2}, }, @@ -455,7 +456,7 @@ impl HintProcessor for BuiltinHintProcessor { &hint_data.ids_data, &hint_data.ap_tracking, ), - hint_code::EC_DOUBLE_SCOPE_V1 => compute_doubling_slope( + hint_code::EC_DOUBLE_SLOPE_V1 => compute_doubling_slope( vm, exec_scopes, &hint_data.ids_data, @@ -464,7 +465,7 @@ impl HintProcessor for BuiltinHintProcessor { &SECP_P, &ALPHA, ), - hint_code::EC_DOUBLE_SCOPE_V2 => compute_doubling_slope( + hint_code::EC_DOUBLE_SLOPE_V2 => compute_doubling_slope( vm, exec_scopes, &hint_data.ids_data, @@ -473,7 +474,7 @@ impl HintProcessor for BuiltinHintProcessor { &SECP_P_V2, &ALPHA_V2, ), - hint_code::EC_DOUBLE_SCOPE_WHITELIST => compute_doubling_slope( + hint_code::EC_DOUBLE_SLOPE_V3 => compute_doubling_slope( vm, exec_scopes, &hint_data.ids_data, @@ -482,6 +483,12 @@ impl HintProcessor for BuiltinHintProcessor { &SECP_P, &ALPHA, ), + hint_code::EC_DOUBLE_SLOPE_EXTERNAL_CONSTS => compute_doubling_slope_external_consts( + vm, + exec_scopes, + &hint_data.ids_data, + &hint_data.ap_tracking, + ), hint_code::COMPUTE_SLOPE_V1 => compute_slope_and_assing_secp_p( 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 cdb44bc186..80cde7b140 100644 --- a/src/hint_processor/builtin_hint_processor/hint_code.rs +++ b/src/hint_processor/builtin_hint_processor/hint_code.rs @@ -615,7 +615,7 @@ y = pack(ids.point.y, PRIME) % SECP_P # The modulo operation in python always returns a nonnegative number. value = (-y) % SECP_P"#; -pub const EC_DOUBLE_SCOPE_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack +pub const EC_DOUBLE_SLOPE_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack from starkware.python.math_utils import ec_double_slope # Compute the slope. @@ -623,7 +623,7 @@ 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 const EC_DOUBLE_SCOPE_V2: &str = r#"from starkware.python.math_utils import ec_double_slope +pub const EC_DOUBLE_SLOPE_V2: &str = r#"from starkware.python.math_utils import ec_double_slope from starkware.cairo.common.cairo_secp.secp_utils import pack SECP_P = 2**255-19 @@ -632,7 +632,7 @@ x = pack(ids.point.x, PRIME) y = pack(ids.point.y, PRIME) value = slope = ec_double_slope(point=(x, y), alpha=42204101795669822316448953119945047945709099015225996174933988943478124189485, p=SECP_P)"#; -pub const EC_DOUBLE_SCOPE_WHITELIST: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack +pub const EC_DOUBLE_SLOPE_V3: &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. @@ -640,6 +640,14 @@ x = pack(ids.pt.x, PRIME) y = pack(ids.pt.y, PRIME) value = slope = div_mod(3 * x ** 2, 2 * y, SECP_P)"#; +pub const EC_DOUBLE_SLOPE_EXTERNAL_CONSTS: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack +from starkware.python.math_utils import ec_double_slope + +# Compute the slope. +x = pack(ids.point.x, PRIME) +y = pack(ids.point.y, PRIME) +value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)"#; + pub const COMPUTE_SLOPE_V1: &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 f80fe6caf1..1888aa8750 100644 --- a/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/ec_utils.rs @@ -138,6 +138,35 @@ pub fn compute_doubling_slope( Ok(()) } +/* +Implements hint: +%{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.python.math_utils import ec_double_slope + + # Compute the slope. + x = pack(ids.point.x, PRIME) + y = pack(ids.point.y, PRIME) + value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P) +%} +*/ +pub fn compute_doubling_slope_external_consts( + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + //ids.point + let point = EcPoint::from_var_name("point", vm, ids_data, ap_tracking)?; + let secp_p: BigInt = exec_scopes.get("SECP_P")?; + let alpha: BigInt = exec_scopes.get("ALPHA")?; + + let value = ec_double_slope(&(point.x.pack86(), point.y.pack86()), &alpha, &secp_p); + exec_scopes.insert_value("value", value.clone()); + exec_scopes.insert_value("slope", value); + Ok(()) +} + /* Implements hint: %{ @@ -457,7 +486,6 @@ mod tests { }; use assert_matches::assert_matches; - use num_bigint::BigUint; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -538,14 +566,14 @@ mod tests { ( "value", bigint_str!( - "40442433062102151071094722250325492738932110061897694430475034100717288403728" - ) + "40442433062102151071094722250325492738932110061897694430475034100717288403728" + ) ), ( "slope", bigint_str!( - "40442433062102151071094722250325492738932110061897694430475034100717288403728" - ) + "40442433062102151071094722250325492738932110061897694430475034100717288403728" + ) ) ] ); @@ -554,7 +582,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_ec_double_scope_v2_hint_ok() { - let hint_code = hint_code::EC_DOUBLE_SCOPE_V2; + let hint_code = hint_code::EC_DOUBLE_SLOPE_V2; let mut vm = vm_with_range_check!(); vm.segments = segments![ ((1, 0), 512), @@ -579,14 +607,14 @@ mod tests { ( "value", bigint_str!( - "48268701472940295594394094960749868325610234644833445333946260403470540790234" - ) + "48268701472940295594394094960749868325610234644833445333946260403470540790234" + ) ), ( "slope", bigint_str!( - "48268701472940295594394094960749868325610234644833445333946260403470540790234" - ) + "48268701472940295594394094960749868325610234644833445333946260403470540790234" + ) ), ("SECP_P", SECP_P_V2.clone()) ] @@ -621,19 +649,63 @@ mod tests { ( "value", bigint_str!( - "40442433062102151071094722250325492738932110061897694430475034100717288403728" - ) + "40442433062102151071094722250325492738932110061897694430475034100717288403728" + ) ), ( "slope", bigint_str!( - "40442433062102151071094722250325492738932110061897694430475034100717288403728" - ) + "40442433062102151071094722250325492738932110061897694430475034100717288403728" + ) ) ] ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn run_compute_doubling_slope_with_custom_consts_ok() { + let hint_code = hint_code::EC_DOUBLE_SLOPE_EXTERNAL_CONSTS; + 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!["point"]; + let mut exec_scopes = ExecutionScopes::new(); + + exec_scopes.insert_value("SECP_P", SECP256R1_P.clone()); + exec_scopes.insert_value("ALPHA", SECP256R1_ALPHA.clone()); + + //Execute the hint + assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(())); + check_scope!( + &exec_scopes, + [ + ( + "value", + bigint_str!( + "99065496658741969395000079476826955370154683653966841736214499259699304892273" + ) + ), + ( + "slope", + bigint_str!( + "99065496658741969395000079476826955370154683653966841736214499259699304892273" + ) + ), + ], + ); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn run_compute_slope_ok() { @@ -672,14 +744,14 @@ mod tests { ( "value", bigint_str!( - "41419765295989780131385135514529906223027172305400087935755859001910844026631" - ) + "41419765295989780131385135514529906223027172305400087935755859001910844026631" + ) ), ( "slope", bigint_str!( - "41419765295989780131385135514529906223027172305400087935755859001910844026631" - ) + "41419765295989780131385135514529906223027172305400087935755859001910844026631" + ) ) ] ); @@ -727,14 +799,14 @@ mod tests { ( "value", bigint_str!( - "39376930140709393693483102164172662915882483986415749881375763965703119677959" - ) + "39376930140709393693483102164172662915882483986415749881375763965703119677959" + ) ), ( "slope", bigint_str!( - "39376930140709393693483102164172662915882483986415749881375763965703119677959" - ) + "39376930140709393693483102164172662915882483986415749881375763965703119677959" + ) ) ] ); @@ -778,14 +850,14 @@ mod tests { ( "value", bigint_str!( - "41419765295989780131385135514529906223027172305400087935755859001910844026631" - ) + "41419765295989780131385135514529906223027172305400087935755859001910844026631" + ) ), ( "slope", bigint_str!( - "41419765295989780131385135514529906223027172305400087935755859001910844026631" - ) + "41419765295989780131385135514529906223027172305400087935755859001910844026631" + ) ) ] ); @@ -897,14 +969,14 @@ mod tests { ( "value", bigint_str!( - "7948634220683381957329555864604318996476649323793038777651086572350147290350" - ) + "7948634220683381957329555864604318996476649323793038777651086572350147290350" + ) ), ( "new_y", bigint_str!( - "7948634220683381957329555864604318996476649323793038777651086572350147290350" - ) + "7948634220683381957329555864604318996476649323793038777651086572350147290350" + ) ) ] ); @@ -954,14 +1026,14 @@ mod tests { ( "value", bigint_str!( - "8891838197222656627233627110766426698842623939023296165598688719819499152657" - ) + "8891838197222656627233627110766426698842623939023296165598688719819499152657" + ) ), ( "new_x", bigint_str!( - "8891838197222656627233627110766426698842623939023296165598688719819499152657" - ) + "8891838197222656627233627110766426698842623939023296165598688719819499152657" + ) ) ] ); @@ -1009,14 +1081,14 @@ mod tests { ( "value", bigint_str!( - "7948634220683381957329555864604318996476649323793038777651086572350147290350" - ) + "7948634220683381957329555864604318996476649323793038777651086572350147290350" + ) ), ( "new_y", bigint_str!( - "7948634220683381957329555864604318996476649323793038777651086572350147290350" - ) + "7948634220683381957329555864604318996476649323793038777651086572350147290350" + ) ) ] ); @@ -1181,8 +1253,8 @@ mod tests { assert_matches!(run_hint!(vm, ids_data, hint_code, &mut exec_scopes), Ok(())); //Check 'ALPHA' is defined in the vm scope assert_matches!( - exec_scopes.get::("ALPHA"), - Ok(x) if x == biguint_str!( + exec_scopes.get::("ALPHA"), + Ok(x) if x == bigint_str!( "115792089210356248762697446949407573530086143415290314195533631308867097853948" ) ); diff --git a/src/hint_processor/builtin_hint_processor/secp/secp_utils.rs b/src/hint_processor/builtin_hint_processor/secp/secp_utils.rs index 967e6da3e8..03607b8fd5 100644 --- a/src/hint_processor/builtin_hint_processor/secp/secp_utils.rs +++ b/src/hint_processor/builtin_hint_processor/secp/secp_utils.rs @@ -65,7 +65,7 @@ lazy_static! { "115792089210356248762697446949407573529996955224135760342422259061068512044369" ).unwrap(); //SECP256R1_ALPHA = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC - pub(crate) static ref SECP256R1_ALPHA: BigUint = BigUint::from_str( + pub(crate) static ref SECP256R1_ALPHA: BigInt = BigInt::from_str( "115792089210356248762697446949407573530086143415290314195533631308867097853948" ).unwrap(); } diff --git a/src/tests/cairo_run_test.rs b/src/tests/cairo_run_test.rs index ef3903621b..1885053a54 100644 --- a/src/tests/cairo_run_test.rs +++ b/src/tests/cairo_run_test.rs @@ -911,3 +911,10 @@ fn nondet_bigint3_v2() { let program_data = include_bytes!("../../cairo_programs/nondet_bigint3_v2.json"); run_program_simple(program_data.as_slice()); } + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn cairo_run_ec_double_slope() { + let program_data = include_bytes!("../../cairo_programs/ec_double_slope.json"); + run_program_simple_with_memory_holes(program_data.as_slice(), 0); +} diff --git a/src/utils.rs b/src/utils.rs index 0501c463bf..28a06d431b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -424,7 +424,7 @@ pub mod test_utils { pub(crate) use add_segments; macro_rules! check_scope { - ( $exec_scope: expr, [ $( ($name: expr, $val: expr)),* ] ) => { + ( $exec_scope: expr, [ $( ($name: expr, $val: expr)),*$(,)? ] $(,)? ) => { $( check_scope_value($exec_scope, $name, $val); )*