secp256k1-native 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +14 -0
- data/LICENSE +21 -0
- data/README.md +139 -0
- data/ext/secp256k1_native/extconf.rb +24 -0
- data/ext/secp256k1_native/field.c +622 -0
- data/ext/secp256k1_native/jacobian.c +459 -0
- data/ext/secp256k1_native/scalar.c +421 -0
- data/ext/secp256k1_native/secp256k1_native.c +29 -0
- data/ext/secp256k1_native/secp256k1_native.h +123 -0
- data/lib/secp256k1/version.rb +5 -0
- data/lib/secp256k1.rb +626 -0
- data/lib/secp256k1_native.bundle +0 -0
- data/secp256k1-native.gemspec +29 -0
- metadata +58 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/* frozen_string_literal: true */
|
|
2
|
+
#include "secp256k1_native.h"
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* jacobian.c — Jacobian point operations on the secp256k1 curve.
|
|
6
|
+
*
|
|
7
|
+
* Points are represented as three uint256_t values [X, Y, Z] in Jacobian
|
|
8
|
+
* (homogeneous projective) coordinates. The affine point (x, y) corresponds
|
|
9
|
+
* to the Jacobian point (X, Y, Z) via:
|
|
10
|
+
*
|
|
11
|
+
* x = X / Z² and y = Y / Z³
|
|
12
|
+
*
|
|
13
|
+
* The point at infinity is represented as [0, 1, 0] (Z = 0).
|
|
14
|
+
*
|
|
15
|
+
* All three functions (jp_double, jp_add, jp_neg) call the internal field
|
|
16
|
+
* operations from field.c directly — no Ruby method dispatch occurs for
|
|
17
|
+
* intermediate field arithmetic. A single jp_double executes ~14 field
|
|
18
|
+
* operations entirely in C; a single jp_add executes ~18.
|
|
19
|
+
*
|
|
20
|
+
* Formulae from hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
|
|
21
|
+
* (parameter a = 0 for secp256k1).
|
|
22
|
+
*
|
|
23
|
+
* Constant-time discipline
|
|
24
|
+
* ------------------------
|
|
25
|
+
* jp_double: The Y=0 (point at infinity) check is handled branchlessly by
|
|
26
|
+
* computing the full result and masking to JP_INFINITY when Y is zero.
|
|
27
|
+
* jp_add: Branches on pz==0 / qz==0 / h==0 operate on public data in all
|
|
28
|
+
* call paths (the wNAF accumulator starts at infinity, which is public).
|
|
29
|
+
* The field arithmetic within the main computation path is branchless.
|
|
30
|
+
* jp_neg: Branchless — delegates the zero-checking to fneg_internal.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/* The point at infinity: [0, 1, 0] */
|
|
34
|
+
static const uint256_t JP_INF_X = {{ 0ULL, 0ULL, 0ULL, 0ULL }};
|
|
35
|
+
static const uint256_t JP_INF_Y = {{ 1ULL, 0ULL, 0ULL, 0ULL }};
|
|
36
|
+
static const uint256_t JP_INF_Z = {{ 0ULL, 0ULL, 0ULL, 0ULL }};
|
|
37
|
+
|
|
38
|
+
/* Small field element constants used in point formulae. */
|
|
39
|
+
static const uint256_t SMALL_2 = {{ 2ULL, 0ULL, 0ULL, 0ULL }};
|
|
40
|
+
static const uint256_t SMALL_3 = {{ 3ULL, 0ULL, 0ULL, 0ULL }};
|
|
41
|
+
static const uint256_t SMALL_4 = {{ 4ULL, 0ULL, 0ULL, 0ULL }};
|
|
42
|
+
static const uint256_t SMALL_8 = {{ 8ULL, 0ULL, 0ULL, 0ULL }};
|
|
43
|
+
|
|
44
|
+
/* Unpack a Ruby Array of 3 Integers into a uint256_t[3].
|
|
45
|
+
* Indices: 0 = X, 1 = Y, 2 = Z. */
|
|
46
|
+
static void unpack_point(uint256_t out[3], VALUE rb_point)
|
|
47
|
+
{
|
|
48
|
+
Check_Type(rb_point, T_ARRAY);
|
|
49
|
+
if (RARRAY_LEN(rb_point) != 3) {
|
|
50
|
+
rb_raise(rb_eArgError, "Jacobian point must be an Array of 3 integers [X, Y, Z]");
|
|
51
|
+
}
|
|
52
|
+
out[0] = rb_to_uint256(rb_ary_entry(rb_point, 0));
|
|
53
|
+
out[1] = rb_to_uint256(rb_ary_entry(rb_point, 1));
|
|
54
|
+
out[2] = rb_to_uint256(rb_ary_entry(rb_point, 2));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Pack a uint256_t[3] into a new Ruby Array of 3 Integers. */
|
|
58
|
+
static VALUE pack_point(const uint256_t r[3])
|
|
59
|
+
{
|
|
60
|
+
VALUE result = rb_ary_new_capa(3);
|
|
61
|
+
rb_ary_push(result, uint256_to_rb(&r[0]));
|
|
62
|
+
rb_ary_push(result, uint256_to_rb(&r[1]));
|
|
63
|
+
rb_ary_push(result, uint256_to_rb(&r[2]));
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* -----------------------------------------------------------------------
|
|
68
|
+
* Internal Jacobian point operations — called from Ruby-facing wrappers
|
|
69
|
+
* and from each other. No Ruby interaction occurs within these functions.
|
|
70
|
+
* ----------------------------------------------------------------------- */
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* jp_double_internal — double a Jacobian point.
|
|
74
|
+
*
|
|
75
|
+
* Formula (a=0 for secp256k1, from hyperelliptic.org):
|
|
76
|
+
*
|
|
77
|
+
* Y1sq = Y1²
|
|
78
|
+
* S = 4 · X1 · Y1sq
|
|
79
|
+
* M = 3 · X1²
|
|
80
|
+
* X3 = M² - 2·S
|
|
81
|
+
* Y3 = M·(S - X3) - 8·Y1sq²
|
|
82
|
+
* Z3 = 2·Y1·Z1
|
|
83
|
+
*
|
|
84
|
+
* Special case: if Y1 = 0 the point is at infinity. Handled branchlessly:
|
|
85
|
+
* the full result is computed and then replaced by JP_INFINITY when Y1 is
|
|
86
|
+
* zero (using a selection mask derived from uint256_is_zero).
|
|
87
|
+
*
|
|
88
|
+
* Matches the Ruby jp_double implementation exactly, including computation
|
|
89
|
+
* order, so that wNAF cache entries produced by C are identical to those
|
|
90
|
+
* produced by Ruby.
|
|
91
|
+
*/
|
|
92
|
+
void jp_double_internal(uint256_t r[3], const uint256_t p[3])
|
|
93
|
+
{
|
|
94
|
+
uint256_t y1sq, s, m, x3, y3, z3;
|
|
95
|
+
uint256_t tmp;
|
|
96
|
+
|
|
97
|
+
/* y1sq = Y1² */
|
|
98
|
+
fsqr_internal(&y1sq, &p[1]);
|
|
99
|
+
|
|
100
|
+
/* s = 4 * (X1 * y1sq) */
|
|
101
|
+
fmul_internal(&tmp, &p[0], &y1sq);
|
|
102
|
+
fmul_internal(&s, &SMALL_4, &tmp);
|
|
103
|
+
|
|
104
|
+
/* m = 3 * X1² */
|
|
105
|
+
fsqr_internal(&tmp, &p[0]);
|
|
106
|
+
fmul_internal(&m, &SMALL_3, &tmp);
|
|
107
|
+
|
|
108
|
+
/* x3 = m² - 2*s */
|
|
109
|
+
fsqr_internal(&tmp, &m);
|
|
110
|
+
uint256_t two_s;
|
|
111
|
+
fmul_internal(&two_s, &SMALL_2, &s);
|
|
112
|
+
fsub_internal(&x3, &tmp, &two_s);
|
|
113
|
+
|
|
114
|
+
/* y3 = m * (s - x3) - 8 * y1sq² */
|
|
115
|
+
uint256_t s_minus_x3, y1sq_sq, eight_y1sq_sq;
|
|
116
|
+
fsub_internal(&s_minus_x3, &s, &x3);
|
|
117
|
+
fmul_internal(&tmp, &m, &s_minus_x3);
|
|
118
|
+
fsqr_internal(&y1sq_sq, &y1sq);
|
|
119
|
+
fmul_internal(&eight_y1sq_sq, &SMALL_8, &y1sq_sq);
|
|
120
|
+
fsub_internal(&y3, &tmp, &eight_y1sq_sq);
|
|
121
|
+
|
|
122
|
+
/* z3 = 2 * Y1 * Z1 */
|
|
123
|
+
fmul_internal(&tmp, &p[1], &p[2]);
|
|
124
|
+
fmul_internal(&z3, &SMALL_2, &tmp);
|
|
125
|
+
|
|
126
|
+
/* Branchless infinity check: if Y1 == 0, result is [0, 1, 0].
|
|
127
|
+
*
|
|
128
|
+
* Compute mask = all 1s if Y1 is zero, all 0s otherwise.
|
|
129
|
+
* Use the mask to select between [x3, y3, z3] and JP_INFINITY. */
|
|
130
|
+
uint64_t is_zero = uint256_is_zero(&p[1]);
|
|
131
|
+
uint64_t mask = -(uint64_t)(is_zero != 0); /* all 1s if Y1 == 0 */
|
|
132
|
+
int i;
|
|
133
|
+
for (i = 0; i < 4; i++) {
|
|
134
|
+
r[0].d[i] = (x3.d[i] & ~mask) | (JP_INF_X.d[i] & mask);
|
|
135
|
+
r[1].d[i] = (y3.d[i] & ~mask) | (JP_INF_Y.d[i] & mask);
|
|
136
|
+
r[2].d[i] = (z3.d[i] & ~mask) | (JP_INF_Z.d[i] & mask);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/*
|
|
141
|
+
* jp_add_internal — add two Jacobian points.
|
|
142
|
+
*
|
|
143
|
+
* Formula (from hyperelliptic.org, "add-2007-bl"):
|
|
144
|
+
*
|
|
145
|
+
* Z1Z1 = Z1², Z2Z2 = Z2²
|
|
146
|
+
* U1 = X1·Z2Z2, U2 = X2·Z1Z1
|
|
147
|
+
* S1 = Y1·Z2·Z2Z2, S2 = Y2·Z1·Z1Z1
|
|
148
|
+
* H = U2 - U1
|
|
149
|
+
* R = S2 - S1
|
|
150
|
+
* H2 = H², H3 = H·H2
|
|
151
|
+
* V = U1·H2
|
|
152
|
+
* X3 = R² - H3 - 2·V
|
|
153
|
+
* Y3 = R·(V - X3) - S1·H3
|
|
154
|
+
* Z3 = H·Z1·Z2
|
|
155
|
+
*
|
|
156
|
+
* Special cases (handled with branches — all operate on public data):
|
|
157
|
+
* - pz == 0 (p is infinity) → return q
|
|
158
|
+
* - qz == 0 (q is infinity) → return p
|
|
159
|
+
* - h == 0, r == 0 → points are equal, call jp_double_internal(p)
|
|
160
|
+
* - h == 0, r != 0 → points are negatives of each other → infinity
|
|
161
|
+
*
|
|
162
|
+
* Matches the Ruby jp_add implementation exactly.
|
|
163
|
+
*/
|
|
164
|
+
void jp_add_internal(uint256_t r[3], const uint256_t p[3], const uint256_t q[3])
|
|
165
|
+
{
|
|
166
|
+
/* Handle point-at-infinity cases (pz == 0 or qz == 0).
|
|
167
|
+
* These branch on public data (Z coordinates are public in all call paths). */
|
|
168
|
+
if (uint256_is_zero(&p[2])) {
|
|
169
|
+
r[0] = q[0]; r[1] = q[1]; r[2] = q[2];
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (uint256_is_zero(&q[2])) {
|
|
173
|
+
r[0] = p[0]; r[1] = p[1]; r[2] = p[2];
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
uint256_t z1z1, z2z2;
|
|
178
|
+
uint256_t u1, u2;
|
|
179
|
+
uint256_t s1, s2;
|
|
180
|
+
uint256_t tmp;
|
|
181
|
+
|
|
182
|
+
/* z1z1 = Z1², z2z2 = Z2² */
|
|
183
|
+
fsqr_internal(&z1z1, &p[2]);
|
|
184
|
+
fsqr_internal(&z2z2, &q[2]);
|
|
185
|
+
|
|
186
|
+
/* u1 = X1 * z2z2, u2 = X2 * z1z1 */
|
|
187
|
+
fmul_internal(&u1, &p[0], &z2z2);
|
|
188
|
+
fmul_internal(&u2, &q[0], &z1z1);
|
|
189
|
+
|
|
190
|
+
/* s1 = Y1 * Z2 * z2z2, s2 = Y2 * Z1 * z1z1 */
|
|
191
|
+
fmul_internal(&tmp, &q[2], &z2z2);
|
|
192
|
+
fmul_internal(&s1, &p[1], &tmp);
|
|
193
|
+
|
|
194
|
+
fmul_internal(&tmp, &p[2], &z1z1);
|
|
195
|
+
fmul_internal(&s2, &q[1], &tmp);
|
|
196
|
+
|
|
197
|
+
/* h = u2 - u1, r_val = s2 - s1 */
|
|
198
|
+
uint256_t h, r_val;
|
|
199
|
+
fsub_internal(&h, &u2, &u1);
|
|
200
|
+
fsub_internal(&r_val, &s2, &s1);
|
|
201
|
+
|
|
202
|
+
/* Handle the h == 0 special cases.
|
|
203
|
+
* h == 0 means the points have the same X (in affine).
|
|
204
|
+
* r == 0 additionally means the same Y → equal points → double.
|
|
205
|
+
* r != 0 means opposite Y → additive inverse → infinity. */
|
|
206
|
+
if (uint256_is_zero(&h)) {
|
|
207
|
+
if (uint256_is_zero(&r_val)) {
|
|
208
|
+
jp_double_internal(r, p);
|
|
209
|
+
} else {
|
|
210
|
+
r[0] = JP_INF_X;
|
|
211
|
+
r[1] = JP_INF_Y;
|
|
212
|
+
r[2] = JP_INF_Z;
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
uint256_t h2, h3, v, x3, y3, z3;
|
|
218
|
+
|
|
219
|
+
/* h2 = h², h3 = h * h2 */
|
|
220
|
+
fsqr_internal(&h2, &h);
|
|
221
|
+
fmul_internal(&h3, &h, &h2);
|
|
222
|
+
|
|
223
|
+
/* v = u1 * h2 */
|
|
224
|
+
fmul_internal(&v, &u1, &h2);
|
|
225
|
+
|
|
226
|
+
/* x3 = r² - h3 - 2*v */
|
|
227
|
+
uint256_t r_sq, two_v;
|
|
228
|
+
fsqr_internal(&r_sq, &r_val);
|
|
229
|
+
fmul_internal(&two_v, &SMALL_2, &v);
|
|
230
|
+
fsub_internal(&tmp, &r_sq, &h3);
|
|
231
|
+
fsub_internal(&x3, &tmp, &two_v);
|
|
232
|
+
|
|
233
|
+
/* y3 = r * (v - x3) - s1 * h3 */
|
|
234
|
+
uint256_t v_minus_x3, s1h3;
|
|
235
|
+
fsub_internal(&v_minus_x3, &v, &x3);
|
|
236
|
+
fmul_internal(&tmp, &r_val, &v_minus_x3);
|
|
237
|
+
fmul_internal(&s1h3, &s1, &h3);
|
|
238
|
+
fsub_internal(&y3, &tmp, &s1h3);
|
|
239
|
+
|
|
240
|
+
/* z3 = h * Z1 * Z2 */
|
|
241
|
+
fmul_internal(&tmp, &p[2], &q[2]);
|
|
242
|
+
fmul_internal(&z3, &h, &tmp);
|
|
243
|
+
|
|
244
|
+
r[0] = x3;
|
|
245
|
+
r[1] = y3;
|
|
246
|
+
r[2] = z3;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/*
|
|
250
|
+
* jp_neg_internal — negate a Jacobian point.
|
|
251
|
+
*
|
|
252
|
+
* Negation simply flips the Y coordinate: (X, Y, Z) → (X, -Y, Z).
|
|
253
|
+
* The point at infinity (Z = 0) is its own negation.
|
|
254
|
+
*
|
|
255
|
+
* fneg_internal handles the zero case branchlessly (fneg(0) = 0),
|
|
256
|
+
* so this function requires no special-casing.
|
|
257
|
+
*
|
|
258
|
+
* Matches the Ruby jp_neg implementation exactly.
|
|
259
|
+
*/
|
|
260
|
+
void jp_neg_internal(uint256_t r[3], const uint256_t p[3])
|
|
261
|
+
{
|
|
262
|
+
r[0] = p[0];
|
|
263
|
+
fneg_internal(&r[1], &p[1]);
|
|
264
|
+
r[2] = p[2];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* -----------------------------------------------------------------------
|
|
268
|
+
* Ruby-facing wrapper functions
|
|
269
|
+
* ----------------------------------------------------------------------- */
|
|
270
|
+
|
|
271
|
+
/*
|
|
272
|
+
* call-seq:
|
|
273
|
+
* Secp256k1Native.jp_double(point) -> Array
|
|
274
|
+
*
|
|
275
|
+
* Double a Jacobian point.
|
|
276
|
+
*
|
|
277
|
+
* @param point [Array(Integer, Integer, Integer)] Jacobian point [X, Y, Z]
|
|
278
|
+
* @return [Array(Integer, Integer, Integer)] doubled point
|
|
279
|
+
*/
|
|
280
|
+
static VALUE rb_jp_double(VALUE self, VALUE rb_point)
|
|
281
|
+
{
|
|
282
|
+
(void)self;
|
|
283
|
+
uint256_t p[3], r[3];
|
|
284
|
+
unpack_point(p, rb_point);
|
|
285
|
+
jp_double_internal(r, p);
|
|
286
|
+
return pack_point(r);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/*
|
|
290
|
+
* call-seq:
|
|
291
|
+
* Secp256k1Native.jp_add(p, q) -> Array
|
|
292
|
+
*
|
|
293
|
+
* Add two Jacobian points.
|
|
294
|
+
*
|
|
295
|
+
* @param p [Array(Integer, Integer, Integer)] first Jacobian point [X, Y, Z]
|
|
296
|
+
* @param q [Array(Integer, Integer, Integer)] second Jacobian point [X, Y, Z]
|
|
297
|
+
* @return [Array(Integer, Integer, Integer)] sum
|
|
298
|
+
*/
|
|
299
|
+
static VALUE rb_jp_add(VALUE self, VALUE rb_p, VALUE rb_q)
|
|
300
|
+
{
|
|
301
|
+
(void)self;
|
|
302
|
+
uint256_t p[3], q[3], r[3];
|
|
303
|
+
unpack_point(p, rb_p);
|
|
304
|
+
unpack_point(q, rb_q);
|
|
305
|
+
jp_add_internal(r, p, q);
|
|
306
|
+
return pack_point(r);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/*
|
|
310
|
+
* call-seq:
|
|
311
|
+
* Secp256k1Native.jp_neg(point) -> Array
|
|
312
|
+
*
|
|
313
|
+
* Negate a Jacobian point (flip the Y coordinate).
|
|
314
|
+
*
|
|
315
|
+
* @param point [Array(Integer, Integer, Integer)] Jacobian point [X, Y, Z]
|
|
316
|
+
* @return [Array(Integer, Integer, Integer)] negated point
|
|
317
|
+
*/
|
|
318
|
+
static VALUE rb_jp_neg(VALUE self, VALUE rb_point)
|
|
319
|
+
{
|
|
320
|
+
(void)self;
|
|
321
|
+
uint256_t p[3], r[3];
|
|
322
|
+
unpack_point(p, rb_point);
|
|
323
|
+
jp_neg_internal(r, p);
|
|
324
|
+
return pack_point(r);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* -----------------------------------------------------------------------
|
|
328
|
+
* Constant-time scalar multiplication — Montgomery ladder
|
|
329
|
+
* ----------------------------------------------------------------------- */
|
|
330
|
+
|
|
331
|
+
/*
|
|
332
|
+
* cswap — branchless conditional swap of two Jacobian points.
|
|
333
|
+
*
|
|
334
|
+
* Each Jacobian point is three uint256_t values (X, Y, Z = 4 limbs each).
|
|
335
|
+
* If bit == 1, the contents of a and b are swapped.
|
|
336
|
+
* If bit == 0, nothing changes.
|
|
337
|
+
*
|
|
338
|
+
* The mask is derived from bit without any branch on it, so execution time
|
|
339
|
+
* does not depend on the value of the scalar bit being processed.
|
|
340
|
+
*/
|
|
341
|
+
static void cswap(uint64_t bit, uint256_t a[3], uint256_t b[3])
|
|
342
|
+
{
|
|
343
|
+
uint64_t mask = -(uint64_t)bit; /* all-ones if bit==1, all-zeros if bit==0 */
|
|
344
|
+
int j, k;
|
|
345
|
+
for (j = 0; j < 3; j++) {
|
|
346
|
+
for (k = 0; k < 4; k++) {
|
|
347
|
+
uint64_t tmp = mask & (a[j].d[k] ^ b[j].d[k]);
|
|
348
|
+
a[j].d[k] ^= tmp;
|
|
349
|
+
b[j].d[k] ^= tmp;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/*
|
|
355
|
+
* scalar_multiply_ct_internal — constant-time scalar multiplication via the
|
|
356
|
+
* Montgomery ladder.
|
|
357
|
+
*
|
|
358
|
+
* Computes r = k × base using a branchless double-and-add loop. The two
|
|
359
|
+
* accumulators r0 (result) and r1 (result + base) are swapped before and
|
|
360
|
+
* after each iteration according to the current scalar bit, ensuring that
|
|
361
|
+
* the sequence of point operations executed is independent of k.
|
|
362
|
+
*
|
|
363
|
+
* Invariant: r1 = r0 + base throughout the loop.
|
|
364
|
+
*
|
|
365
|
+
* In-place aliasing: jp_add_internal reads all inputs into stack locals
|
|
366
|
+
* (u1, u2, s1, s2, h, r_val, etc.) before writing the output, and
|
|
367
|
+
* jp_double_internal similarly reads into locals (y1sq, s, m, etc.)
|
|
368
|
+
* before writing. This makes jp_add_internal(r1, r0, r1) and
|
|
369
|
+
* jp_double_internal(r0, r0) safe when output overlaps an input.
|
|
370
|
+
*
|
|
371
|
+
* @param r output: k × base as a Jacobian point
|
|
372
|
+
* @param k secret scalar (256 bits, caller ensures 0 < k < N)
|
|
373
|
+
* @param base base point in Jacobian coordinates
|
|
374
|
+
*/
|
|
375
|
+
void scalar_multiply_ct_internal(uint256_t r[3], const uint256_t *k, const uint256_t base[3])
|
|
376
|
+
{
|
|
377
|
+
/* r0 = infinity [0, 1, 0]; r1 = base */
|
|
378
|
+
uint256_t r0[3], r1[3];
|
|
379
|
+
memset(r0, 0, sizeof(uint256_t) * 3);
|
|
380
|
+
r0[1].d[0] = 1; /* Y = 1 */
|
|
381
|
+
memcpy(r1, base, sizeof(uint256_t) * 3);
|
|
382
|
+
|
|
383
|
+
int i;
|
|
384
|
+
for (i = 255; i >= 0; i--) {
|
|
385
|
+
uint64_t bit = (uint64_t)uint256_bit(k, i);
|
|
386
|
+
cswap(bit, r0, r1);
|
|
387
|
+
jp_add_internal(r1, r0, r1);
|
|
388
|
+
jp_double_internal(r0, r0);
|
|
389
|
+
cswap(bit, r0, r1);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
memcpy(r, r0, sizeof(uint256_t) * 3);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/*
|
|
396
|
+
* call-seq:
|
|
397
|
+
* Secp256k1Native.scalar_multiply_ct(k, px, py) -> Array
|
|
398
|
+
*
|
|
399
|
+
* Constant-time scalar multiplication using the Montgomery ladder.
|
|
400
|
+
*
|
|
401
|
+
* Computes k × (px, py) entirely in C with no per-iteration Ruby dispatch.
|
|
402
|
+
* The ladder loop is branchless with respect to the scalar bits (via cswap).
|
|
403
|
+
* Note: jp_add_internal still branches on infinity/collision edge cases,
|
|
404
|
+
* so full constant-time depends on the point operations being hardened
|
|
405
|
+
* separately. The k==0 early return is on a non-secret value (k==0 is
|
|
406
|
+
* never a valid private key or nonce).
|
|
407
|
+
*
|
|
408
|
+
* @param k [Integer] scalar (must be in [0, N))
|
|
409
|
+
* @param px [Integer] affine x-coordinate of the base point
|
|
410
|
+
* @param py [Integer] affine y-coordinate of the base point
|
|
411
|
+
* @return [Array(Integer, Integer, Integer)] result as a Jacobian point
|
|
412
|
+
* @raise [ArgumentError] if k >= N (curve order)
|
|
413
|
+
*/
|
|
414
|
+
static VALUE rb_scalar_multiply_ct(VALUE self, VALUE rb_k, VALUE rb_px, VALUE rb_py)
|
|
415
|
+
{
|
|
416
|
+
(void)self;
|
|
417
|
+
uint256_t k = rb_to_uint256(rb_k);
|
|
418
|
+
|
|
419
|
+
/* Validate k < N — belt-and-braces guard for direct callers. */
|
|
420
|
+
uint256_t tmp;
|
|
421
|
+
uint64_t borrow = uint256_sub(&tmp, &k, &CURVE_N);
|
|
422
|
+
if (!borrow) {
|
|
423
|
+
/* k >= N: borrow would be 1 if k < N, so borrow == 0 means k >= N */
|
|
424
|
+
rb_raise(rb_eArgError, "scalar k must be in [0, N) (curve order)");
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* k = 0: return the point at infinity [0, 1, 0]. */
|
|
428
|
+
if (uint256_is_zero(&k)) {
|
|
429
|
+
VALUE result = rb_ary_new_capa(3);
|
|
430
|
+
rb_ary_push(result, INT2FIX(0));
|
|
431
|
+
rb_ary_push(result, INT2FIX(1));
|
|
432
|
+
rb_ary_push(result, INT2FIX(0));
|
|
433
|
+
return result;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/* Construct Jacobian base point [px, py, 1]. */
|
|
437
|
+
uint256_t base[3];
|
|
438
|
+
base[0] = rb_to_uint256(rb_px);
|
|
439
|
+
base[1] = rb_to_uint256(rb_py);
|
|
440
|
+
memset(&base[2], 0, sizeof(uint256_t));
|
|
441
|
+
base[2].d[0] = 1;
|
|
442
|
+
|
|
443
|
+
uint256_t r[3];
|
|
444
|
+
scalar_multiply_ct_internal(r, &k, base);
|
|
445
|
+
|
|
446
|
+
return pack_point(r);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* -----------------------------------------------------------------------
|
|
450
|
+
* Registration — called from Init_secp256k1_native in secp256k1_native.c
|
|
451
|
+
* ----------------------------------------------------------------------- */
|
|
452
|
+
|
|
453
|
+
void register_jacobian_methods(VALUE mod)
|
|
454
|
+
{
|
|
455
|
+
rb_define_module_function(mod, "jp_double", rb_jp_double, 1);
|
|
456
|
+
rb_define_module_function(mod, "jp_add", rb_jp_add, 2);
|
|
457
|
+
rb_define_module_function(mod, "jp_neg", rb_jp_neg, 1);
|
|
458
|
+
rb_define_module_function(mod, "scalar_multiply_ct", rb_scalar_multiply_ct, 3);
|
|
459
|
+
}
|