Skip to content

Commit 59963c0

Browse files
committed
Add NewHint#19
1 parent 45a43aa commit 59963c0

File tree

6 files changed

+353
-46
lines changed

6 files changed

+353
-46
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
%builtins range_check
2+
3+
// Source: https://github.com/rdubois-crypto/efficient-secp256r1/blob/4b74807c5e91f1ed4cb00a1c973be05c63986e61/src/secp256r1/ec.cairo
4+
from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3
5+
from starkware.cairo.common.cairo_secp.ec import EcPoint
6+
7+
// src.secp256r1.constants
8+
// SECP_REM is defined by the equation:
9+
// secp256r1_prime = 2 ** 256 - SECP_REM.
10+
const SECP_REM = 2 ** 224 - 2 ** 192 - 2 ** 96 + 1;
11+
12+
const BASE = 2 ** 86;
13+
14+
// A = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
15+
const A0 = 0x3ffffffffffffffffffffc;
16+
const A1 = 0x3ff;
17+
const A2 = 0xffffffff0000000100000;
18+
19+
// Constants for unreduced_mul/sqr
20+
const s2 = (-(2 ** 76)) - 2 ** 12;
21+
const s1 = (-(2 ** 66)) + 4;
22+
const s0 = 2 ** 56;
23+
24+
const r2 = 2 ** 54 - 2 ** 22;
25+
const r1 = -(2 ** 12);
26+
const r0 = 4;
27+
28+
// src.secp256r1.field
29+
// Adapt from starkware.cairo.common.math's assert_250_bit
30+
func assert_165_bit{range_check_ptr}(value) {
31+
const UPPER_BOUND = 2 ** 165;
32+
const SHIFT = 2 ** 128;
33+
const HIGH_BOUND = UPPER_BOUND / SHIFT;
34+
35+
let low = [range_check_ptr];
36+
let high = [range_check_ptr + 1];
37+
38+
%{
39+
from starkware.cairo.common.math_utils import as_int
40+
41+
# Correctness check.
42+
value = as_int(ids.value, PRIME) % PRIME
43+
assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).'
44+
45+
# Calculation for the assertion.
46+
ids.high, ids.low = divmod(ids.value, ids.SHIFT)
47+
%}
48+
49+
assert [range_check_ptr + 2] = HIGH_BOUND - 1 - high;
50+
51+
assert value = high * SHIFT + low;
52+
53+
let range_check_ptr = range_check_ptr + 3;
54+
return ();
55+
}
56+
57+
// src.secp256r1.field
58+
// Computes the multiplication of two big integers, given in BigInt3 representation, modulo the
59+
// secp256r1 prime.
60+
//
61+
// Arguments:
62+
// x, y - the two BigInt3 to operate on.
63+
//
64+
// Returns:
65+
// x * y in an UnreducedBigInt3 representation (the returned limbs may be above 3 * BASE).
66+
//
67+
// This means that if unreduced_mul is called on the result of nondet_bigint3, or the difference
68+
// between two such results, we have:
69+
// Soundness guarantee: the limbs are in the range ().
70+
// Completeness guarantee: the limbs are in the range ().
71+
func unreduced_mul(a: BigInt3, b: BigInt3) -> (res_low: UnreducedBigInt3) {
72+
tempvar twice_d2 = a.d2 * b.d2;
73+
tempvar d1d2 = a.d2 * b.d1 + a.d1 * b.d2;
74+
return (
75+
UnreducedBigInt3(
76+
d0=a.d0 * b.d0 + s0 * twice_d2 + r0 * d1d2,
77+
d1=a.d1 * b.d0 + a.d0 * b.d1 + s1 * twice_d2 + r1 * d1d2,
78+
d2=a.d2 * b.d0 + a.d1 * b.d1 + a.d0 * b.d2 + s2 * twice_d2 + r2 * d1d2,
79+
),
80+
);
81+
}
82+
83+
// src.secp256r1.field
84+
// Computes the square of a big integer, given in BigInt3 representation, modulo the
85+
// secp256r1 prime.
86+
//
87+
// Has the same guarantees as in unreduced_mul(a, a).
88+
func unreduced_sqr(a: BigInt3) -> (res_low: UnreducedBigInt3) {
89+
tempvar twice_d2 = a.d2 * a.d2;
90+
tempvar twice_d1d2 = a.d2 * a.d1 + a.d1 * a.d2;
91+
tempvar d1d0 = a.d1 * a.d0;
92+
return (
93+
UnreducedBigInt3(
94+
d0=a.d0 * a.d0 + s0 * twice_d2 + r0 * twice_d1d2,
95+
d1=d1d0 + d1d0 + s1 * twice_d2 + r1 * twice_d1d2,
96+
d2=a.d2 * a.d0 + a.d1 * a.d1 + a.d0 * a.d2 + s2 * twice_d2 + r2 * twice_d1d2,
97+
),
98+
);
99+
}
100+
101+
// src.secp256r1.field
102+
// Verifies that the given unreduced value is equal to zero modulo the secp256r1 prime.
103+
//
104+
// Completeness assumption: val's limbs are in the range (-2**210.99, 2**210.99).
105+
// Soundness assumption: val's limbs are in the range (-2**250, 2**250).
106+
func verify_zero{range_check_ptr}(val: UnreducedBigInt3) {
107+
alloc_locals;
108+
local q;
109+
// local q_sign;
110+
let q_sign = 1;
111+
// original:
112+
// %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_P as SECP_P %}
113+
// %{
114+
// from starkware.cairo.common.cairo_secp.secp_utils import pack
115+
116+
// q, r = divmod(pack(ids.val, PRIME), SECP_P)
117+
// assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
118+
// if q >= 0:
119+
// ids.q = q % PRIME
120+
// ids.q_sign = 1
121+
// else:
122+
// ids.q = (0-q) % PRIME
123+
// ids.q_sign = -1 % PRIME
124+
// %}
125+
%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %}
126+
%{
127+
from starkware.cairo.common.cairo_secp.secp_utils import pack
128+
129+
q, r = divmod(pack(ids.val, PRIME), SECP_P)
130+
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
131+
ids.q = q % PRIME
132+
%}
133+
// assert_250_bit(q); // 256K steps
134+
// assert_le_felt(q, 2**165); // 275K steps
135+
assert_165_bit(q);
136+
assert q_sign * (val.d2 + val.d1 / BASE + val.d0 / BASE ** 2) = q * (
137+
(BASE / 4) - SECP_REM / BASE ** 2
138+
);
139+
// Multiply by BASE**2 both sides:
140+
// (q_sign) * val = q * (BASE**3 / 4 - SECP_REM)
141+
// = q * (2**256 - SECP_REM) = q * secp256r1_prime = 0 mod secp256r1_prime
142+
return ();
143+
}
144+
145+
// Computes the slope of the elliptic curve at a given point.
146+
// The slope is used to compute point + point.
147+
//
148+
// Arguments:
149+
// point - the point to operate on.
150+
//
151+
// Returns:
152+
// slope - the slope of the curve at point, in BigInt3 representation.
153+
//
154+
// Assumption: point != 0.
155+
func compute_doubling_slope{range_check_ptr}(point: EcPoint) -> (slope: BigInt3) {
156+
// Note that y cannot be zero: assume that it is, then point = -point, so 2 * point = 0, which
157+
// contradicts the fact that the size of the curve is odd.
158+
// originals:
159+
// %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_P as SECP_P %}
160+
// %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_ALPHA as ALPHA %}
161+
%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %}
162+
%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA %}
163+
%{
164+
from starkware.cairo.common.cairo_secp.secp_utils import pack
165+
from starkware.python.math_utils import ec_double_slope
166+
167+
# Compute the slope.
168+
x = pack(ids.point.x, PRIME)
169+
y = pack(ids.point.y, PRIME)
170+
value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)
171+
%}
172+
let (slope: BigInt3) = nondet_bigint3();
173+
174+
let (x_sqr: UnreducedBigInt3) = unreduced_sqr(point.x);
175+
let (slope_y: UnreducedBigInt3) = unreduced_mul(slope, point.y);
176+
verify_zero(
177+
UnreducedBigInt3(
178+
d0=3 * x_sqr.d0 + A0 - 2 * slope_y.d0,
179+
d1=3 * x_sqr.d1 + A1 - 2 * slope_y.d1,
180+
d2=3 * x_sqr.d2 + A2 - 2 * slope_y.d2,
181+
),
182+
);
183+
184+
return (slope=slope);
185+
}
186+
187+
func test_doubling_slope{range_check_ptr}() {
188+
let point = EcPoint(BigInt3(614323, 5456867, 101208), BigInt3(773712524, 77371252, 5298795));
189+
190+
let (slope) = compute_doubling_slope(point);
191+
192+
assert slope = BigInt3(
193+
64081873649130491683833713, 34843994309543177837008178, 16548672716077616016846383
194+
);
195+
196+
let point = EcPoint(
197+
BigInt3(51215, 36848548548458, 634734734), BigInt3(26362, 263724839599, 901297012)
198+
);
199+
200+
let (slope) = compute_doubling_slope(point);
201+
202+
assert slope = BigInt3(
203+
71848883893335852660776740, 75644451964360469099209675, 547087410329256463669633
204+
);
205+
206+
return ();
207+
}
208+
209+
func main{range_check_ptr}() {
210+
test_doubling_slope();
211+
return ();
212+
}

src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use super::{
66
field_arithmetic::{u256_get_square_root, u384_get_square_root, uint384_div},
77
secp::{
88
ec_utils::{
9-
compute_slope_and_assing_secp_p, ec_double_assign_new_y, ec_mul_inner,
10-
ec_negate_embedded_secp_p, ec_negate_import_secp_p,
9+
compute_doubling_slope_external_consts, compute_slope_and_assing_secp_p,
10+
ec_double_assign_new_y, ec_mul_inner, ec_negate_embedded_secp_p,
11+
ec_negate_import_secp_p,
1112
},
1213
secp_utils::{ALPHA, ALPHA_V2, SECP_P, SECP_P_V2},
1314
},
@@ -455,7 +456,7 @@ impl HintProcessor for BuiltinHintProcessor {
455456
&hint_data.ids_data,
456457
&hint_data.ap_tracking,
457458
),
458-
hint_code::EC_DOUBLE_SCOPE_V1 => compute_doubling_slope(
459+
hint_code::EC_DOUBLE_SLOPE_V1 => compute_doubling_slope(
459460
vm,
460461
exec_scopes,
461462
&hint_data.ids_data,
@@ -464,7 +465,7 @@ impl HintProcessor for BuiltinHintProcessor {
464465
&SECP_P,
465466
&ALPHA,
466467
),
467-
hint_code::EC_DOUBLE_SCOPE_V2 => compute_doubling_slope(
468+
hint_code::EC_DOUBLE_SLOPE_V2 => compute_doubling_slope(
468469
vm,
469470
exec_scopes,
470471
&hint_data.ids_data,
@@ -473,7 +474,7 @@ impl HintProcessor for BuiltinHintProcessor {
473474
&SECP_P_V2,
474475
&ALPHA_V2,
475476
),
476-
hint_code::EC_DOUBLE_SCOPE_WHITELIST => compute_doubling_slope(
477+
hint_code::EC_DOUBLE_SLOPE_V3 => compute_doubling_slope(
477478
vm,
478479
exec_scopes,
479480
&hint_data.ids_data,
@@ -482,6 +483,12 @@ impl HintProcessor for BuiltinHintProcessor {
482483
&SECP_P,
483484
&ALPHA,
484485
),
486+
hint_code::EC_DOUBLE_SLOPE_EXTERNAL_CONSTS => compute_doubling_slope_external_consts(
487+
vm,
488+
exec_scopes,
489+
&hint_data.ids_data,
490+
&hint_data.ap_tracking,
491+
),
485492
hint_code::COMPUTE_SLOPE_V1 => compute_slope_and_assing_secp_p(
486493
vm,
487494
exec_scopes,

src/hint_processor/builtin_hint_processor/hint_code.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -615,15 +615,15 @@ y = pack(ids.point.y, PRIME) % SECP_P
615615
# The modulo operation in python always returns a nonnegative number.
616616
value = (-y) % SECP_P"#;
617617

618-
pub const EC_DOUBLE_SCOPE_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
618+
pub const EC_DOUBLE_SLOPE_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
619619
from starkware.python.math_utils import ec_double_slope
620620
621621
# Compute the slope.
622622
x = pack(ids.point.x, PRIME)
623623
y = pack(ids.point.y, PRIME)
624624
value = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)"#;
625625

626-
pub const EC_DOUBLE_SCOPE_V2: &str = r#"from starkware.python.math_utils import ec_double_slope
626+
pub const EC_DOUBLE_SLOPE_V2: &str = r#"from starkware.python.math_utils import ec_double_slope
627627
from starkware.cairo.common.cairo_secp.secp_utils import pack
628628
SECP_P = 2**255-19
629629
@@ -632,14 +632,22 @@ x = pack(ids.point.x, PRIME)
632632
y = pack(ids.point.y, PRIME)
633633
value = slope = ec_double_slope(point=(x, y), alpha=42204101795669822316448953119945047945709099015225996174933988943478124189485, p=SECP_P)"#;
634634

635-
pub const EC_DOUBLE_SCOPE_WHITELIST: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
635+
pub const EC_DOUBLE_SLOPE_V3: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
636636
from starkware.python.math_utils import div_mod
637637
638638
# Compute the slope.
639639
x = pack(ids.pt.x, PRIME)
640640
y = pack(ids.pt.y, PRIME)
641641
value = slope = div_mod(3 * x ** 2, 2 * y, SECP_P)"#;
642642

643+
pub const EC_DOUBLE_SLOPE_EXTERNAL_CONSTS: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import pack
644+
from starkware.python.math_utils import ec_double_slope
645+
646+
# Compute the slope.
647+
x = pack(ids.point.x, PRIME)
648+
y = pack(ids.point.y, PRIME)
649+
value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)"#;
650+
643651
pub const COMPUTE_SLOPE_V1: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
644652
from starkware.python.math_utils import line_slope
645653

0 commit comments

Comments
 (0)