Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hints): add NewHint#19 #1057

Merged
merged 4 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
212 changes: 212 additions & 0 deletions cairo_programs/ec_double_slope.cairo
Original file line number Diff line number Diff line change
@@ -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 ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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},
},
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
14 changes: 11 additions & 3 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,15 +615,15 @@ 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.
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

Expand All @@ -632,14 +632,22 @@ 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.
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

Expand Down
Loading