Skip to content

Commit e53c2d9

Browse files
Require that sizeof(secp256k1_ge_storage) == 64
This gets rid of an untested code path. Resolves #1352. secp256k1_ge_storage is a struct with two secp256k1_fe_storage fields. The C standard allows the compiler to add padding between the fields and at the end of the struct, but no sane compiler in the end would do this: The only reason to add padding is to ensure alignment, but such padding is never necessary between two fields of the same type. Similarly, secp256k1_fe_storage is a struct with a single array of uintXX_t. No padding is allowed between array elements. Again, C allows the compiler to insert padding at the end of the struct, but there's no absolute reason to do so in this case. For the uintXX_t itself, this guaranteed to have no padding bits, i.e., it's guaranteed to have exactly XX bits. So I claim that for any existing compiler in the real world, sizeof(secp256k1_ge_storage) == 64.
1 parent d0ba2ab commit e53c2d9

File tree

1 file changed

+14
-25
lines changed

1 file changed

+14
-25
lines changed

src/secp256k1.c

Lines changed: 14 additions & 25 deletions
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) {

0 commit comments

Comments
 (0)