Skip to content

Commit a9db9f2

Browse files
Merge #1480: Get rid of untested sizeof(secp256k1_ge_storage) == 64 code path
ba5d72d assumptions: Use new STATIC_ASSERT macro (Tim Ruffing) e53c2d9 Require that sizeof(secp256k1_ge_storage) == 64 (Tim Ruffing) d0ba2ab util: Add STATIC_ASSERT macro (Tim Ruffing) Pull request description: This gets rid of an untested code path. Resolves #1352. This is a bit opinionated in the sense that it adds a static assertion where it's needed in `secp256k1_pubkey_save` and `secp256k1_pubkey_load`. I think this is justified in this case. It helps the reviewer verify that these functions are correct. See individual commit messages. ACKs for top commit: sipa: utACK ba5d72d jonasnick: ACK ba5d72d Tree-SHA512: 2553c0610b62bcda6d4ef26eb26b5b2e07acf723bcd299691a2d02da57af22b8763f63c2d4adb17d30de8825b6157be6e4f0398147854fbabdf8b865fb0b5c88
2 parents 74b7c3b + ba5d72d commit a9db9f2

File tree

3 files changed

+81
-74
lines changed

3 files changed

+81
-74
lines changed

src/assumptions.h

+52-48
Original file line numberDiff line numberDiff line change
@@ -19,65 +19,69 @@
1919
reduce the odds of experiencing an unwelcome surprise.
2020
*/
2121

22-
struct secp256k1_assumption_checker {
23-
/* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not
24-
allowed. */
25-
int dummy_array[(
26-
/* Bytes are 8 bits. */
27-
(CHAR_BIT == 8) &&
22+
#if defined(__has_attribute)
23+
# if __has_attribute(__unavailable__)
24+
__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function.")))
25+
# endif
26+
#endif
27+
static void secp256k1_assumption_checker(void) {
28+
/* Bytes are 8 bits. */
29+
STATIC_ASSERT(CHAR_BIT == 8);
2830

29-
/* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
30-
without signed overflow, which would be undefined behaviour. */
31-
(UINT_MAX <= UINT32_MAX) &&
31+
/* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
32+
without signed overflow, which would be undefined behaviour. */
33+
STATIC_ASSERT(UINT_MAX <= UINT32_MAX);
3234

33-
/* Conversions from unsigned to signed outside of the bounds of the signed type are
34-
implementation-defined. Verify that they function as reinterpreting the lower
35-
bits of the input in two's complement notation. Do this for conversions:
36-
- from uint(N)_t to int(N)_t with negative result
37-
- from uint(2N)_t to int(N)_t with negative result
38-
- from int(2N)_t to int(N)_t with negative result
39-
- from int(2N)_t to int(N)_t with positive result */
35+
/* Conversions from unsigned to signed outside of the bounds of the signed type are
36+
implementation-defined. Verify that they function as reinterpreting the lower
37+
bits of the input in two's complement notation. Do this for conversions:
38+
- from uint(N)_t to int(N)_t with negative result
39+
- from uint(2N)_t to int(N)_t with negative result
40+
- from int(2N)_t to int(N)_t with negative result
41+
- from int(2N)_t to int(N)_t with positive result */
4042

41-
/* To int8_t. */
42-
((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) &&
43-
((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) &&
44-
((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) &&
45-
((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) &&
43+
/* To int8_t. */
44+
STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55));
45+
STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33);
46+
STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF);
47+
STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34);
4648

47-
/* To int16_t. */
48-
((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) &&
49-
((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) &&
50-
((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) &&
51-
((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) &&
49+
/* To int16_t. */
50+
STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322);
51+
STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C);
52+
STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4);
53+
STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678);
5254

53-
/* To int32_t. */
54-
((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) &&
55-
((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) &&
56-
((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) &&
57-
((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) &&
55+
/* To int32_t. */
56+
STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B);
57+
STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE);
58+
STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8);
59+
STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789);
5860

59-
/* To int64_t. */
60-
((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
61+
/* To int64_t. */
62+
STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL);
6163
#if defined(SECP256K1_INT128_NATIVE)
62-
((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
63-
(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
64-
(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
64+
STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL);
65+
STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL);
66+
STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL);
6567

66-
/* To int128_t. */
67-
((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) &&
68+
/* To int128_t. */
69+
STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL));
6870
#endif
6971

70-
/* Right shift on negative signed values is implementation defined. Verify that it
71-
acts as a right shift in two's complement with sign extension (i.e duplicating
72-
the top bit into newly added bits). */
73-
((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) &&
74-
((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
75-
((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
76-
((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
72+
/* Right shift on negative signed values is implementation defined. Verify that it
73+
acts as a right shift in two's complement with sign extension (i.e duplicating
74+
the top bit into newly added bits). */
75+
STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA);
76+
STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A);
77+
STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48);
78+
STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL);
7779
#if defined(SECP256K1_INT128_NATIVE)
78-
((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
80+
STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL));
7981
#endif
80-
1) * 2 - 1];
81-
};
82+
83+
/* This function is not supposed to be called. */
84+
VERIFY_CHECK(0);
85+
}
8286

8387
#endif /* SECP256K1_ASSUMPTIONS_H */

src/secp256k1.c

+14-25
Original file line numberDiff line numberDiff line change
@@ -237,36 +237,25 @@ static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx,
237237
}
238238

239239
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
240-
if (sizeof(secp256k1_ge_storage) == 64) {
241-
/* When the secp256k1_ge_storage type is exactly 64 byte, use its
242-
* representation inside secp256k1_pubkey, as conversion is very fast.
243-
* Note that secp256k1_pubkey_save must use the same representation. */
244-
secp256k1_ge_storage s;
245-
memcpy(&s, &pubkey->data[0], sizeof(s));
246-
secp256k1_ge_from_storage(ge, &s);
247-
} else {
248-
/* Otherwise, fall back to 32-byte big endian for X and Y. */
249-
secp256k1_fe x, y;
250-
ARG_CHECK(secp256k1_fe_set_b32_limit(&x, pubkey->data));
251-
ARG_CHECK(secp256k1_fe_set_b32_limit(&y, pubkey->data + 32));
252-
secp256k1_ge_set_xy(ge, &x, &y);
253-
}
240+
secp256k1_ge_storage s;
241+
242+
/* We require that the secp256k1_ge_storage type is exactly 64 bytes.
243+
* This is formally not guaranteed by the C standard, but should hold on any
244+
* sane compiler in the real world. */
245+
STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
246+
memcpy(&s, &pubkey->data[0], 64);
247+
secp256k1_ge_from_storage(ge, &s);
254248
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
255249
return 1;
256250
}
257251

258252
static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
259-
if (sizeof(secp256k1_ge_storage) == 64) {
260-
secp256k1_ge_storage s;
261-
secp256k1_ge_to_storage(&s, ge);
262-
memcpy(&pubkey->data[0], &s, sizeof(s));
263-
} else {
264-
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
265-
secp256k1_fe_normalize_var(&ge->x);
266-
secp256k1_fe_normalize_var(&ge->y);
267-
secp256k1_fe_get_b32(pubkey->data, &ge->x);
268-
secp256k1_fe_get_b32(pubkey->data + 32, &ge->y);
269-
}
253+
secp256k1_ge_storage s;
254+
255+
STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
256+
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
257+
secp256k1_ge_to_storage(&s, ge);
258+
memcpy(&pubkey->data[0], &s, 64);
270259
}
271260

272261
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {

src/util.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,27 @@ static void print_buf_plain(const unsigned char *buf, size_t len) {
5151
# define SECP256K1_INLINE inline
5252
# endif
5353

54+
/** Assert statically that expr is true.
55+
*
56+
* This is a statement-like macro and can only be used inside functions.
57+
*/
58+
#define STATIC_ASSERT(expr) do { \
59+
switch(0) { \
60+
case 0: \
61+
/* If expr evaluates to 0, we have two case labels "0", which is illegal. */ \
62+
case /* ERROR: static assertion failed */ (expr): \
63+
; \
64+
} \
65+
} while(0)
66+
5467
/** Assert statically that expr is an integer constant expression, and run stmt.
5568
*
5669
* Useful for example to enforce that magnitude arguments are constant.
5770
*/
5871
#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \
5972
switch(42) { \
60-
case /* ERROR: integer argument is not constant */ expr: \
73+
/* C allows only integer constant expressions as case labels. */ \
74+
case /* ERROR: integer argument is not constant */ (expr): \
6175
break; \
6276
default: ; \
6377
} \

0 commit comments

Comments
 (0)