Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@

#### 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 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`
Expand Down
125 changes: 125 additions & 0 deletions cairo_programs/ed25519_ec.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
%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 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).
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_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);

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_double_slope();
test_compute_slope();

return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -353,12 +353,36 @@ 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::COMPUTE_SLOPE => {
compute_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,
&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)
}
Expand Down
18 changes: 18 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -465,6 +473,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)
Expand Down
101 changes: 98 additions & 3 deletions src/hint_processor/builtin_hint_processor/secp/ec_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ pub fn compute_doubling_slope(
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
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());
Expand All @@ -113,11 +114,13 @@ pub fn compute_slope(
exec_scopes: &mut ExecutionScopes,
ids_data: &HashMap<String, HintReference>,
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)),
Expand Down Expand Up @@ -355,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() {
Expand Down Expand Up @@ -406,6 +450,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() {
Expand Down
7 changes: 7 additions & 0 deletions src/tests/cairo_run_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}