-
Notifications
You must be signed in to change notification settings - Fork 156
/
ec_double_slope.cairo
212 lines (181 loc) · 7.22 KB
/
ec_double_slope.cairo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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 ();
}