Skip to content

Commit b92fe86

Browse files
1 parent 2238463 commit b92fe86

File tree

4 files changed

+76
-31
lines changed

4 files changed

+76
-31
lines changed

C/secp256k1/int128.h

+14-3
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@
1212
# error "Please select int128 implementation"
1313
# endif
1414

15+
/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */
16+
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo);
17+
1518
/* Multiply two unsigned 64-bit values a and b and write the result to r. */
1619
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
1720

1821
/* Multiply two unsigned 64-bit values a and b and add the result to r.
19-
* The final result is taken moduluo 2^128.
22+
* The final result is taken modulo 2^128.
2023
*/
2124
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
2225

2326
/* Add an unsigned 64-bit value a to r.
24-
* The final result is taken moduluo 2^128.
27+
* The final result is taken modulo 2^128.
2528
*/
2629
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a);
2730

@@ -44,6 +47,9 @@ static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint6
4447
*/
4548
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n);
4649

50+
/* Construct an signed 128-bit value from a high and a low 64-bit value. */
51+
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo);
52+
4753
/* Multiply two signed 64-bit values a and b and write the result to r. */
4854
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b);
4955

@@ -60,7 +66,12 @@ static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a,
6066
*/
6167
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b);
6268

63-
/* Return the low 64-bits of a 128-bit value interpreted as an signed 64-bit value. */
69+
/* Return the input value modulo 2^64. */
70+
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a);
71+
72+
/* Return the value as a signed 64-bit value.
73+
* Requires the input to be between INT64_MIN and INT64_MAX.
74+
*/
6475
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a);
6576

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

C/secp256k1/int128_native_impl.h

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
#include "int128.h"
55

6+
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
7+
*r = (((uint128_t)hi) << 64) + lo;
8+
}
9+
610
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
711
*r = (uint128_t)a * b;
812
}
@@ -37,6 +41,10 @@ static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r
3741
return (*r >> n == 0);
3842
}
3943

44+
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
45+
*r = (((uint128_t)(uint64_t)hi) << 64) + lo;
46+
}
47+
4048
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
4149
*r = (int128_t)a * b;
4250
}
@@ -59,7 +67,12 @@ static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned
5967
*r >>= n;
6068
}
6169

70+
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
71+
return (uint64_t)*a;
72+
}
73+
6274
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
75+
VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX);
6376
return *a;
6477
}
6578

C/secp256k1/int128_struct_impl.h

+29-8
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,26 @@
55

66
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
77
# include <intrin.h>
8-
# if defined(_M_X64)
9-
/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */
10-
# define secp256k1_umul128 _umul128
11-
# define secp256k1_mul128 _mul128
12-
# else
13-
/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications. */
8+
# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
9+
/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications.
10+
(Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64,
11+
which supports both __(u)mulh and _umul128.) */
12+
# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
13+
# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.")
14+
# endif
1415
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
1516
*hi = __umulh(a, b);
1617
return a * b;
1718
}
1819

1920
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
2021
*hi = __mulh(a, b);
21-
return a * b;
22+
return (uint64_t)a * (uint64_t)b;
2223
}
24+
# else
25+
/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */
26+
# define secp256k1_umul128 _umul128
27+
# define secp256k1_mul128 _mul128
2328
# endif
2429
#else
2530
/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */
@@ -44,6 +49,11 @@ static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t*
4449
}
4550
#endif
4651

52+
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
53+
r->hi = hi;
54+
r->lo = lo;
55+
}
56+
4757
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
4858
r->lo = secp256k1_umul128(a, b, &r->hi);
4959
}
@@ -93,6 +103,11 @@ static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r
93103
: r->hi == 0 && r->lo >> n == 0;
94104
}
95105

106+
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
107+
r->hi = hi;
108+
r->lo = lo;
109+
}
110+
96111
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
97112
int64_t hi;
98113
r->lo = (uint64_t)secp256k1_mul128(a, b, &hi);
@@ -155,8 +170,14 @@ static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned
155170
}
156171
}
157172

173+
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
174+
return a->lo;
175+
}
176+
158177
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
159-
return (int64_t)a->lo;
178+
/* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */
179+
VERIFY_CHECK(a->hi == -(a->lo >> 63));
180+
return (int64_t)secp256k1_i128_to_u64(a);
160181
}
161182

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

C/secp256k1/modinv64_impl.h

+20-20
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));
@@ -244,7 +244,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
244244
* This implements the update_de function from the explanation.
245245
*/
246246
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) {
247-
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
247+
const uint64_t M62 = UINT64_MAX >> 2;
248248
const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4];
249249
const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4];
250250
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
@@ -257,8 +257,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
257257
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
258258
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */
259259
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */
260-
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= M62 + 1); /* |u|+|v| <= 2^62 */
261-
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= M62 + 1); /* |q|+|r| <= 2^62 */
260+
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= (int64_t)1 << 62); /* |u|+|v| <= 2^62 */
261+
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= (int64_t)1 << 62); /* |q|+|r| <= 2^62 */
262262
#endif
263263
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
264264
sd = d4 >> 63;
@@ -271,14 +271,14 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
271271
secp256k1_i128_mul(&ce, q, d0);
272272
secp256k1_i128_accum_mul(&ce, r, e0);
273273
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
274-
md -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&cd) + md) & M62;
275-
me -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&ce) + me) & M62;
274+
md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62;
275+
me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62;
276276
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
277277
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md);
278278
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me);
279279
/* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
280-
VERIFY_CHECK((secp256k1_i128_to_i64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
281-
VERIFY_CHECK((secp256k1_i128_to_i64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
280+
VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
281+
VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
282282
/* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
283283
secp256k1_i128_accum_mul(&cd, u, d1);
284284
secp256k1_i128_accum_mul(&cd, v, e1);
@@ -288,8 +288,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
288288
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md);
289289
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me);
290290
}
291-
d->v[0] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
292-
e->v[0] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
291+
d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
292+
e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
293293
/* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
294294
secp256k1_i128_accum_mul(&cd, u, d2);
295295
secp256k1_i128_accum_mul(&cd, v, e2);
@@ -299,8 +299,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
299299
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md);
300300
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me);
301301
}
302-
d->v[1] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
303-
e->v[1] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
302+
d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
303+
e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
304304
/* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
305305
secp256k1_i128_accum_mul(&cd, u, d3);
306306
secp256k1_i128_accum_mul(&cd, v, e3);
@@ -310,17 +310,17 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
310310
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md);
311311
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me);
312312
}
313-
d->v[2] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
314-
e->v[2] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
313+
d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
314+
e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
315315
/* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
316316
secp256k1_i128_accum_mul(&cd, u, d4);
317317
secp256k1_i128_accum_mul(&cd, v, e4);
318318
secp256k1_i128_accum_mul(&ce, q, d4);
319319
secp256k1_i128_accum_mul(&ce, r, e4);
320320
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md);
321321
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me);
322-
d->v[3] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
323-
e->v[3] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
322+
d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
323+
e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
324324
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
325325
d->v[4] = secp256k1_i128_to_i64(&cd);
326326
e->v[4] = secp256k1_i128_to_i64(&ce);
@@ -339,7 +339,7 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
339339
* This implements the update_fg function from the explanation.
340340
*/
341341
static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
342-
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
342+
const uint64_t M62 = UINT64_MAX >> 2;
343343
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
344344
int64_t fi, gi;
345345
secp256k1_int128 cf, cg;
@@ -353,8 +353,8 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign
353353
secp256k1_i128_mul(&cg, q, fi);
354354
secp256k1_i128_accum_mul(&cg, r, gi);
355355
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
356-
VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
357-
VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
356+
VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
357+
VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
358358
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
359359
* down by 62 bits). */
360360
for (i = 1; i < len; ++i) {

0 commit comments

Comments
 (0)