Skip to content

Commit e7f7083

Browse files
Merge #1774: refactor: split up internal pubkey serialization function into compressed/uncompressed variants
f5e815f remove secp256k1_eckey_pubkey_serialize function (Sebastian Falbesoner) 0d3659c use new `_eckey_pubkey_serialize{33,65}` functions in modules (ellswift,musig) (Sebastian Falbesoner) adb76f8 use new `_eckey_pubkey_serialize{33,65}` functions in public API (Sebastian Falbesoner) fc7458c introduce `secp256k1_eckey_pubkey_serialize{33,65}` functions (Sebastian Falbesoner) Pull request description: This PR splits up the pubkey serialization function `secp256k1_eckey_pubkey_serialize` into two variants for the compressed (33 bytes) and uncompressed (65 bytes) public key output format each, where only non-infinity group elements as input are allowed. The motivation is to simplify call-sites significantly, as they currently need to introduce two variables and a VERIFY_CHECKs on the return value and the in/out size parameter within a pre-processor block, typically leading to 8 lines of code. By using the new functions, the code is reduced to a single line of code that just calls the function (see #1773). This is helpful for already existing modules on master (ellswift, musig) and upcoming ones (silentpayments, see #1765). One drawback is that the public API function `secp256k1_ec_pubkey_serialize` is now slightly more complex (we now call one of two functions instead of a single one, depending on whether the compressed flag is set or not), but that should hopefully not be a problem. The commits are intentionally kept small to ease review, happy to squash them if that is preferred. (Kudos to w0xlt for the initial idea (#1765 (review)) and to real-or-random for the suggestion to split the already existing function (#1773 (comment)).) ACKs for top commit: real-or-random: utACK f5e815f w0xlt: ACK f5e815f Tree-SHA512: da576bbeae477f31ba76c0001f8df08b51fe5e31d67b422a238348ead3341bf37f0c1509ad9d0a93b63e6d61c152707c85beabd02f4eac3b3bdcff129e0ea750
2 parents b6c2a3c + f5e815f commit e7f7083

File tree

7 files changed

+39
-75
lines changed

7 files changed

+39
-75
lines changed

src/eckey.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
#include "ecmult_gen.h"
1616

1717
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size);
18-
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed);
18+
/** Serialize a group element (that is not allowed to be infinity) to a compressed public key (33 bytes). */
19+
static void secp256k1_eckey_pubkey_serialize33(secp256k1_ge *elem, unsigned char *pub33);
20+
/** Serialize a group element (that is not allowed to be infinity) to an uncompressed public key (65 bytes). */
21+
static void secp256k1_eckey_pubkey_serialize65(secp256k1_ge *elem, unsigned char *pub65);
1922

2023
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak);
2124
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak);

src/eckey_impl.h

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,23 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char
3535
}
3636
}
3737

38-
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) {
39-
VERIFY_CHECK(compressed == 0 || compressed == 1);
38+
static void secp256k1_eckey_pubkey_serialize33(secp256k1_ge *elem, unsigned char *pub33) {
39+
VERIFY_CHECK(!secp256k1_ge_is_infinity(elem));
4040

41-
if (secp256k1_ge_is_infinity(elem)) {
42-
return 0;
43-
}
4441
secp256k1_fe_normalize_var(&elem->x);
4542
secp256k1_fe_normalize_var(&elem->y);
46-
secp256k1_fe_get_b32(&pub[1], &elem->x);
47-
if (compressed) {
48-
*size = 33;
49-
pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
50-
} else {
51-
*size = 65;
52-
pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
53-
secp256k1_fe_get_b32(&pub[33], &elem->y);
54-
}
55-
return 1;
43+
pub33[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
44+
secp256k1_fe_get_b32(&pub33[1], &elem->x);
45+
}
46+
47+
static void secp256k1_eckey_pubkey_serialize65(secp256k1_ge *elem, unsigned char *pub65) {
48+
VERIFY_CHECK(!secp256k1_ge_is_infinity(elem));
49+
50+
secp256k1_fe_normalize_var(&elem->x);
51+
secp256k1_fe_normalize_var(&elem->y);
52+
pub65[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
53+
secp256k1_fe_get_b32(&pub65[1], &elem->x);
54+
secp256k1_fe_get_b32(&pub65[33], &elem->y);
5655
}
5756

5857
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {

src/modules/ellswift/main_impl.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -406,19 +406,12 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64
406406
if (secp256k1_pubkey_load(ctx, &p, pubkey)) {
407407
secp256k1_fe t;
408408
unsigned char p64[64] = {0};
409-
size_t ser_size;
410-
int ser_ret;
411409
secp256k1_sha256 hash;
412410

413411
/* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using
414412
* BIP340 tagged hash with tag "secp256k1_ellswift_encode". */
415413
secp256k1_ellswift_sha256_init_encode(&hash);
416-
ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1);
417-
#ifdef VERIFY
418-
VERIFY_CHECK(ser_ret && ser_size == 33);
419-
#else
420-
(void)ser_ret;
421-
#endif
414+
secp256k1_eckey_pubkey_serialize33(&p, p64);
422415
secp256k1_sha256_write(&hash, p64, sizeof(p64));
423416
secp256k1_sha256_write(&hash, rnd32, 32);
424417

src/modules/musig/keyagg_impl.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,11 @@ static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsig
124124
} else {
125125
secp256k1_sha256 sha;
126126
unsigned char buf[33];
127-
size_t buflen = sizeof(buf);
128-
int ret;
129127
secp256k1_musig_keyaggcoef_sha256(&sha);
130128
secp256k1_sha256_write(&sha, pks_hash, 32);
131-
ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1);
132-
#ifdef VERIFY
133129
/* Serialization does not fail since the pk is not the point at infinity
134130
* (according to this function's precondition). */
135-
VERIFY_CHECK(ret && buflen == sizeof(buf));
136-
#else
137-
(void) ret;
138-
#endif
131+
secp256k1_eckey_pubkey_serialize33(pk, buf);
139132
secp256k1_sha256_write(&sha, buf, sizeof(buf));
140133
secp256k1_sha256_finalize(&sha, buf);
141134
secp256k1_scalar_set_b32(r, buf, NULL);

src/modules/musig/session_impl.h

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,8 @@ static void secp256k1_musig_ge_serialize_ext(unsigned char *out33, secp256k1_ge*
2525
if (secp256k1_ge_is_infinity(ge)) {
2626
memset(out33, 0, 33);
2727
} else {
28-
int ret;
29-
size_t size = 33;
30-
ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1);
31-
#ifdef VERIFY
3228
/* Serialize must succeed because the point is not at infinity */
33-
VERIFY_CHECK(ret && size == 33);
34-
#else
35-
(void) ret;
36-
#endif
29+
secp256k1_eckey_pubkey_serialize33(ge, out33);
3730
}
3831
}
3932

@@ -224,15 +217,8 @@ int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned ch
224217
return 0;
225218
}
226219
for (i = 0; i < 2; i++) {
227-
int ret;
228-
size_t size = 33;
229-
ret = secp256k1_eckey_pubkey_serialize(&ges[i], &out66[33*i], &size, 1);
230-
#ifdef VERIFY
231220
/* serialize must succeed because the point was just loaded */
232-
VERIFY_CHECK(ret && size == 33);
233-
#else
234-
(void) ret;
235-
#endif
221+
secp256k1_eckey_pubkey_serialize33(&ges[i], &out66[33*i]);
236222
}
237223
return 1;
238224
}
@@ -398,11 +384,9 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp
398384
secp256k1_gej nonce_ptj[2];
399385
int i;
400386
unsigned char pk_ser[33];
401-
size_t pk_ser_len = sizeof(pk_ser);
402387
unsigned char aggpk_ser[32];
403388
unsigned char *aggpk_ser_ptr = NULL;
404389
secp256k1_ge pk;
405-
int pk_serialize_success;
406390
int ret = 1;
407391

408392
ARG_CHECK(pubnonce != NULL);
@@ -429,15 +413,8 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp
429413
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
430414
return 0;
431415
}
432-
pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, 1);
433-
434-
#ifdef VERIFY
435416
/* A pubkey cannot be the point at infinity */
436-
VERIFY_CHECK(pk_serialize_success);
437-
VERIFY_CHECK(pk_ser_len == sizeof(pk_ser));
438-
#else
439-
(void) pk_serialize_success;
440-
#endif
417+
secp256k1_eckey_pubkey_serialize33(&pk, pk_ser);
441418

442419
secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32);
443420
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0]));

src/secp256k1.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,14 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o
280280
ARG_CHECK(pubkey != NULL);
281281
ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION);
282282
if (secp256k1_pubkey_load(ctx, &Q, pubkey)) {
283-
ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, !!(flags & SECP256K1_FLAGS_BIT_COMPRESSION));
284-
if (ret) {
285-
*outputlen = len;
283+
if (flags & SECP256K1_FLAGS_BIT_COMPRESSION) {
284+
secp256k1_eckey_pubkey_serialize33(&Q, output);
285+
*outputlen = 33;
286+
} else {
287+
secp256k1_eckey_pubkey_serialize65(&Q, output);
288+
*outputlen = 65;
286289
}
290+
ret = 1;
287291
}
288292
return ret;
289293
}

src/tests.c

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4315,8 +4315,6 @@ static void test_point_times_order(const secp256k1_gej *point) {
43154315
secp256k1_scalar nx;
43164316
secp256k1_gej res1, res2;
43174317
secp256k1_ge res3;
4318-
unsigned char pub[65];
4319-
size_t psize = 65;
43204318
testutil_random_scalar_order_test(&x);
43214319
secp256k1_scalar_negate(&nx, &x);
43224320
secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */
@@ -4326,9 +4324,6 @@ static void test_point_times_order(const secp256k1_gej *point) {
43264324
secp256k1_ge_set_gej(&res3, &res1);
43274325
CHECK(secp256k1_ge_is_infinity(&res3));
43284326
CHECK(secp256k1_ge_is_valid_var(&res3) == 0);
4329-
CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0);
4330-
psize = 65;
4331-
CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0);
43324327
/* check zero/one edge cases */
43334328
secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_zero);
43344329
secp256k1_ge_set_gej(&res3, &res1);
@@ -5435,7 +5430,6 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar
54355430
secp256k1_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj;
54365431
secp256k1_ge r;
54375432
unsigned char bytes[65];
5438-
size_t size = 65;
54395433
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
54405434
secp256k1_gej_set_infinity(&infj);
54415435
secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj1, x);
@@ -5456,9 +5450,8 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar
54565450
secp256k1_sha256_write(acc, zerobyte, 1);
54575451
} else {
54585452
/* Store other points using their uncompressed serialization. */
5459-
secp256k1_eckey_pubkey_serialize(&r, bytes, &size, 0);
5460-
CHECK(size == 65);
5461-
secp256k1_sha256_write(acc, bytes, size);
5453+
secp256k1_eckey_pubkey_serialize65(&r, bytes);
5454+
secp256k1_sha256_write(acc, bytes, sizeof(bytes));
54625455
}
54635456
}
54645457

@@ -6543,16 +6536,18 @@ static void test_random_pubkeys(void) {
65436536
size_t size = len;
65446537
firstb = in[0];
65456538
/* If the pubkey can be parsed, it should round-trip... */
6546-
CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33));
6547-
CHECK(size == len);
6539+
if (len == 33) {
6540+
secp256k1_eckey_pubkey_serialize33(&elem, out);
6541+
} else {
6542+
secp256k1_eckey_pubkey_serialize65(&elem, out);
6543+
}
65486544
CHECK(secp256k1_memcmp_var(&in[1], &out[1], len-1) == 0);
65496545
/* ... except for the type of hybrid inputs. */
65506546
if ((in[0] != 6) && (in[0] != 7)) {
65516547
CHECK(in[0] == out[0]);
65526548
}
65536549
size = 65;
6554-
CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0));
6555-
CHECK(size == 65);
6550+
secp256k1_eckey_pubkey_serialize65(&elem, in);
65566551
CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size));
65576552
CHECK(secp256k1_ge_eq_var(&elem2, &elem));
65586553
/* Check that the X9.62 hybrid type is checked. */
@@ -6567,7 +6562,7 @@ static void test_random_pubkeys(void) {
65676562
}
65686563
if (res) {
65696564
CHECK(secp256k1_ge_eq_var(&elem, &elem2));
6570-
CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0));
6565+
secp256k1_eckey_pubkey_serialize65(&elem, out);
65716566
CHECK(secp256k1_memcmp_var(&in[1], &out[1], 64) == 0);
65726567
}
65736568
}

0 commit comments

Comments
 (0)