Skip to content

Commit b0b2410

Browse files
Add a secp256k1_i128_to_u64 function.
1 parent 6138d73 commit b0b2410

5 files changed

+56
-40
lines changed

src/int128.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,12 @@ static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a,
6060
*/
6161
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b);
6262

63-
/* Return the low 64-bits of a 128-bit value interpreted as an signed 64-bit value. */
63+
/* Return the input value modulo 2^64. */
64+
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a);
65+
66+
/* Return the value as a signed 64-bit value.
67+
* Requires the input to be between INT64_MIN and INT64_MAX.
68+
*/
6469
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a);
6570

6671
/* Write a signed 64-bit value to r. */

src/int128_native_impl.h

+5
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned
5959
*r >>= n;
6060
}
6161

62+
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
63+
return *a;
64+
}
65+
6266
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
67+
VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX);
6368
return *a;
6469
}
6570

src/int128_struct_impl.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,14 @@ static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned
155155
}
156156
}
157157

158+
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
159+
return a->lo;
160+
}
161+
158162
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
159-
return (int64_t)a->lo;
163+
/* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */
164+
VERIFY_CHECK((uint64_t)((int64_t)a->lo >> 63) == a->hi);
165+
return (int64_t)secp256k1_i128_to_u64(a);
160166
}
161167

162168
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {

src/modinv64_impl.h

+33-33
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}};
3939

4040
/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */
4141
static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) {
42-
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
42+
const uint64_t M62 = UINT64_MAX >> 2;
4343
secp256k1_int128 c, d;
4444
int i;
4545
secp256k1_i128_from_i64(&c, 0);
4646
for (i = 0; i < 4; ++i) {
4747
if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor);
48-
r->v[i] = secp256k1_i128_to_i64(&c) & M62; secp256k1_i128_rshift(&c, 62);
48+
r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62);
4949
}
5050
if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor);
5151
secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c));
@@ -314,7 +314,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
314314
* This implements the update_de function from the explanation.
315315
*/
316316
static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) {
317-
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
317+
const uint64_t M62 = UINT64_MAX >> 2;
318318
const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4];
319319
const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4];
320320
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
@@ -327,8 +327,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
327327
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
328328
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */
329329
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */
330-
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= M62 + 1); /* |u|+|v| <= 2^62 */
331-
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= M62 + 1); /* |q|+|r| <= 2^62 */
330+
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= (int64_t)1 << 62); /* |u|+|v| <= 2^62 */
331+
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= (int64_t)1 << 62); /* |q|+|r| <= 2^62 */
332332
#endif
333333
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
334334
sd = d4 >> 63;
@@ -341,14 +341,14 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
341341
secp256k1_i128_mul(&ce, q, d0);
342342
secp256k1_i128_accum_mul(&ce, r, e0);
343343
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
344-
md -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&cd) + md) & M62;
345-
me -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&ce) + me) & M62;
344+
md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62;
345+
me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62;
346346
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
347347
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md);
348348
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me);
349349
/* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
350-
VERIFY_CHECK((secp256k1_i128_to_i64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
351-
VERIFY_CHECK((secp256k1_i128_to_i64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
350+
VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
351+
VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
352352
/* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
353353
secp256k1_i128_accum_mul(&cd, u, d1);
354354
secp256k1_i128_accum_mul(&cd, v, e1);
@@ -358,8 +358,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
358358
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md);
359359
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me);
360360
}
361-
d->v[0] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
362-
e->v[0] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
361+
d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
362+
e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
363363
/* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
364364
secp256k1_i128_accum_mul(&cd, u, d2);
365365
secp256k1_i128_accum_mul(&cd, v, e2);
@@ -369,8 +369,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
369369
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md);
370370
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me);
371371
}
372-
d->v[1] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
373-
e->v[1] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
372+
d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
373+
e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
374374
/* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
375375
secp256k1_i128_accum_mul(&cd, u, d3);
376376
secp256k1_i128_accum_mul(&cd, v, e3);
@@ -380,17 +380,17 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
380380
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md);
381381
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me);
382382
}
383-
d->v[2] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
384-
e->v[2] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
383+
d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
384+
e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
385385
/* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
386386
secp256k1_i128_accum_mul(&cd, u, d4);
387387
secp256k1_i128_accum_mul(&cd, v, e4);
388388
secp256k1_i128_accum_mul(&ce, q, d4);
389389
secp256k1_i128_accum_mul(&ce, r, e4);
390390
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md);
391391
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me);
392-
d->v[3] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
393-
e->v[3] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
392+
d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
393+
e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
394394
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
395395
d->v[4] = secp256k1_i128_to_i64(&cd);
396396
e->v[4] = secp256k1_i128_to_i64(&ce);
@@ -407,7 +407,7 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
407407
* This implements the update_fg function from the explanation.
408408
*/
409409
static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
410-
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
410+
const uint64_t M62 = UINT64_MAX >> 2;
411411
const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4];
412412
const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4];
413413
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
@@ -418,36 +418,36 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
418418
secp256k1_i128_mul(&cg, q, f0);
419419
secp256k1_i128_accum_mul(&cg, r, g0);
420420
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
421-
VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
422-
VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
421+
VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
422+
VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
423423
/* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */
424424
secp256k1_i128_accum_mul(&cf, u, f1);
425425
secp256k1_i128_accum_mul(&cf, v, g1);
426426
secp256k1_i128_accum_mul(&cg, q, f1);
427427
secp256k1_i128_accum_mul(&cg, r, g1);
428-
f->v[0] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
429-
g->v[0] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
428+
f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
429+
g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
430430
/* Compute limb 2 of t*[f,g], and store it as output limb 1. */
431431
secp256k1_i128_accum_mul(&cf, u, f2);
432432
secp256k1_i128_accum_mul(&cf, v, g2);
433433
secp256k1_i128_accum_mul(&cg, q, f2);
434434
secp256k1_i128_accum_mul(&cg, r, g2);
435-
f->v[1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
436-
g->v[1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
435+
f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
436+
g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
437437
/* Compute limb 3 of t*[f,g], and store it as output limb 2. */
438438
secp256k1_i128_accum_mul(&cf, u, f3);
439439
secp256k1_i128_accum_mul(&cf, v, g3);
440440
secp256k1_i128_accum_mul(&cg, q, f3);
441441
secp256k1_i128_accum_mul(&cg, r, g3);
442-
f->v[2] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
443-
g->v[2] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
442+
f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
443+
g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
444444
/* Compute limb 4 of t*[f,g], and store it as output limb 3. */
445445
secp256k1_i128_accum_mul(&cf, u, f4);
446446
secp256k1_i128_accum_mul(&cf, v, g4);
447447
secp256k1_i128_accum_mul(&cg, q, f4);
448448
secp256k1_i128_accum_mul(&cg, r, g4);
449-
f->v[3] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
450-
g->v[3] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
449+
f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
450+
g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
451451
/* What remains is limb 5 of t*[f,g]; store it as output limb 4. */
452452
f->v[4] = secp256k1_i128_to_i64(&cf);
453453
g->v[4] = secp256k1_i128_to_i64(&cg);
@@ -460,7 +460,7 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
460460
* This implements the update_fg function from the explanation.
461461
*/
462462
static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
463-
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
463+
const uint64_t M62 = UINT64_MAX >> 2;
464464
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
465465
int64_t fi, gi;
466466
secp256k1_int128 cf, cg;
@@ -474,8 +474,8 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign
474474
secp256k1_i128_mul(&cg, q, fi);
475475
secp256k1_i128_accum_mul(&cg, r, gi);
476476
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
477-
VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
478-
VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
477+
VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
478+
VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
479479
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
480480
* down by 62 bits). */
481481
for (i = 1; i < len; ++i) {
@@ -485,8 +485,8 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign
485485
secp256k1_i128_accum_mul(&cf, v, gi);
486486
secp256k1_i128_accum_mul(&cg, q, fi);
487487
secp256k1_i128_accum_mul(&cg, r, gi);
488-
f->v[i - 1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
489-
g->v[i - 1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
488+
f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
489+
g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
490490
}
491491
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
492492
f->v[len - 1] = secp256k1_i128_to_i64(&cf);

src/tests.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -451,21 +451,21 @@ void run_int128_tests(void) {
451451
secp256k1_i128_from_i64(&res, 0);
452452
secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX);
453453
secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX);
454-
CHECK(secp256k1_i128_to_i64(&res) == 2);
454+
CHECK(secp256k1_i128_to_u64(&res) == 2);
455455
secp256k1_i128_accum_mul(&res, 4, 9223372036854775807);
456456
secp256k1_i128_accum_mul(&res, 1, 1);
457-
CHECK((uint64_t)secp256k1_i128_to_i64(&res) == UINT64_MAX);
457+
CHECK(secp256k1_i128_to_u64(&res) == UINT64_MAX);
458458
secp256k1_i128_rshift(&res, 64);
459459
CHECK(secp256k1_i128_to_i64(&res) == INT64_MAX);
460460

461461
/* Compute INT128_MIN = - 2^127 with secp256k1_i128_accum_mul */
462462
secp256k1_i128_from_i64(&res, 0);
463463
secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN);
464-
CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN);
464+
CHECK(secp256k1_i128_to_u64(&res) == INT64_MIN);
465465
secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN);
466-
CHECK(secp256k1_i128_to_i64(&res) == 0);
466+
CHECK(secp256k1_i128_to_u64(&res) == 0);
467467
secp256k1_i128_accum_mul(&res, 2, INT64_MIN);
468-
CHECK(secp256k1_i128_to_i64(&res) == 0);
468+
CHECK(secp256k1_i128_to_u64(&res) == 0);
469469
secp256k1_i128_rshift(&res, 64);
470470
CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN);
471471
}

0 commit comments

Comments
 (0)