diff --git a/include/secp256k1.h b/include/secp256k1.h index 06afd4c..beda1e7 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -262,18 +262,20 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( /** Decompress a public key. * In: ctx: pointer to a context object (cannot be NULL) - * In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key. - * It must contain a 33-byte or 65-byte public key already (cannot be NULL) - * pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL) - * It will be updated to reflect the new size. - * Returns: 0: pubkey was invalid - * 1: pubkey was valid, and was replaced with its decompressed version + * In: pubkeyin: pointer to a 33-byte or 65-byte public key (cannot be NULL) + * In/Out: pubkeyout: pointer to a 65-byte array to put the decompressed public key (cannot be NULL) + * May alias pubkeyin. + * pubkeylen: pointer to the size of the public key pointed to by pubkeyin (cannot be NULL) + * It will be updated to reflect the size of the public key in pubkeyout. + * Returns: 0: pubkeyin was invalid + * 1: pubkeyin was valid, and pubkeyout is its decompressed version */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress( const secp256k1_context_t* ctx, - unsigned char *pubkey, + const unsigned char *pubkeyin, + unsigned char *pubkeyout, int *pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Export a private key in DER format. * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) diff --git a/src/secp256k1.c b/src/secp256k1.c index d6192dc..552c196 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -271,15 +271,16 @@ int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pu return ret; } -int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen) { +int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, const unsigned char *pubkeyin, unsigned char *pubkeyout, int *pubkeylen) { secp256k1_ge_t p; int ret = 0; - DEBUG_CHECK(pubkey != NULL); + DEBUG_CHECK(pubkeyin != NULL); + DEBUG_CHECK(pubkeyout != NULL); DEBUG_CHECK(pubkeylen != NULL); (void)ctx; - if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) { - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0); + if (secp256k1_eckey_pubkey_parse(&p, pubkeyin, *pubkeylen)) { + ret = secp256k1_eckey_pubkey_serialize(&p, pubkeyout, pubkeylen, 0); } return ret; } diff --git a/src/tests.c b/src/tests.c index fb8ce76..7ac02ef 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1511,7 +1511,19 @@ void test_ecdsa_end_to_end(void) { CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); if (secp256k1_rand32() & 1) { - CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubkeylen)); + unsigned char pubkey2[65] = {0}; + int pubkey2len = pubkeylen; + /* Decompress into a new array */ + CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, pubkey2, &pubkey2len)); + /* Check that the key was changed iff it was originally compressed */ + if (pubkeylen == 65) { + CHECK(memcmp(pubkey, pubkey2, 65) == 0); + } else { + CHECK(memcmp(pubkey, pubkey2, 65) != 0); + } + /* Decompress in place */ + CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, pubkey, &pubkeylen)); + CHECK(memcmp(pubkey, pubkey2, 65) == 0); } CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen));