Bitcoin Core  25.99.0
P2P Digital Currency
int128_struct_impl.h
Go to the documentation of this file.
1 #ifndef SECP256K1_INT128_STRUCT_IMPL_H
2 #define SECP256K1_INT128_STRUCT_IMPL_H
3 
4 #include "int128.h"
5 
6 #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
7 # include <intrin.h>
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
15 static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
16  *hi = __umulh(a, b);
17  return a * b;
18 }
19 
20 static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
21  *hi = __mulh(a, b);
22  return (uint64_t)a * (uint64_t)b;
23 }
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
28 # endif
29 #else
30 /* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */
31 static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
32  uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
33  uint64_t lh = (uint32_t)a * (b >> 32);
34  uint64_t hl = (a >> 32) * (uint32_t)b;
35  uint64_t hh = (a >> 32) * (b >> 32);
36  uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
37  *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
38  return (mid34 << 32) + (uint32_t)ll;
39 }
40 
41 static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
42  uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
43  int64_t lh = (uint32_t)a * (b >> 32);
44  int64_t hl = (a >> 32) * (uint32_t)b;
45  int64_t hh = (a >> 32) * (b >> 32);
46  uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
47  *hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
48  return (mid34 << 32) + (uint32_t)ll;
49 }
50 #endif
51 
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 
57 static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
58  r->lo = secp256k1_umul128(a, b, &r->hi);
59 }
60 
61 static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
62  uint64_t lo, hi;
63  lo = secp256k1_umul128(a, b, &hi);
64  r->lo += lo;
65  r->hi += hi + (r->lo < lo);
66 }
67 
69  r->lo += a;
70  r->hi += r->lo < a;
71 }
72 
73 /* Unsigned (logical) right shift.
74  * Non-constant time in n.
75  */
76 static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
77  VERIFY_CHECK(n < 128);
78  if (n >= 64) {
79  r->lo = r->hi >> (n-64);
80  r->hi = 0;
81  } else if (n > 0) {
82  r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
83  r->hi >>= n;
84  }
85 }
86 
88  return a->lo;
89 }
90 
92  return a->hi;
93 }
94 
96  r->hi = 0;
97  r->lo = a;
98 }
99 
100 static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
101  VERIFY_CHECK(n < 128);
102  return n >= 64 ? r->hi >> (n - 64) == 0
103  : r->hi == 0 && r->lo >> n == 0;
104 }
105 
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 
111 static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
112  int64_t hi;
113  r->lo = (uint64_t)secp256k1_mul128(a, b, &hi);
114  r->hi = (uint64_t)hi;
115 }
116 
117 static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
118  int64_t hi;
119  uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
120  r->lo += lo;
121  hi += r->lo < lo;
122  /* Verify no overflow.
123  * If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set),
124  * then we require that the resulting value also be positive (the sign bit is not set).
125  * Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1).
126  */
127  VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu));
128  /* Verify no underflow.
129  * If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set),
130  * then we require that the resulting value also be negative (the sign bit is set).
131  */
132  VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu));
133  r->hi += hi;
134 }
135 
136 static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
137  int64_t hi;
138  uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
139  hi += r->lo < lo;
140  /* Verify no overflow.
141  * If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set),
142  * then we require that the resulting value also be positive (the sign bit is not set).
143  */
144  VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu));
145  /* Verify no underflow.
146  * If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set),
147  * then we require that the resulting value also be negative (the sign bit is set).
148  */
149  VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu));
150  r->hi -= hi;
151  r->lo -= lo;
152 }
153 
154 static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
155  secp256k1_i128_mul(r, a, d);
156  secp256k1_i128_dissip_mul(r, b, c);
157 }
158 
159 /* Signed (arithmetic) right shift.
160  * Non-constant time in n.
161  */
162 static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
163  VERIFY_CHECK(n < 128);
164  if (n >= 64) {
165  r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64));
166  r->hi = (uint64_t)((int64_t)(r->hi) >> 63);
167  } else if (n > 0) {
168  r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
169  r->hi = (uint64_t)((int64_t)(r->hi) >> n);
170  }
171 }
172 
174  return a->lo;
175 }
176 
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);
181 }
182 
184  r->hi = (uint64_t)(a >> 63);
185  r->lo = (uint64_t)a;
186 }
187 
189  return a->hi == b->hi && a->lo == b->lo;
190 }
191 
192 static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
193  VERIFY_CHECK(n < 127);
194  VERIFY_CHECK(sign == 1 || sign == -1);
195  return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0
196  : r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n;
197 }
198 
199 #endif
int128_t secp256k1_int128
Definition: int128_native.h:17
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo)
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d)
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n)
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n)
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a)
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a)
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a)
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a)
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b)
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a)
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b)
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t *hi)
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t *hi)
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n)
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign)
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a)
static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b)
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b)
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b)
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo)
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b)
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a)
#define VERIFY_CHECK(cond)
Definition: util.h:96
#define SECP256K1_INLINE
Definition: secp256k1.h:131