9

Given a private key, I can get the uncompressed or compressed version of the public key like so.

EC_KEY* pKey = EC_KEY_new_by_curve_name(NID_secp256k1);

std::vector<unsigned char> getPubKey(EC_KEY* pKey, bool compressed) const {
    if (compressed)
        EC_KEY_set_conv_form(pKey, POINT_CONVERSION_COMPRESSED);
    else
        EC_KEY_set_conv_form(pKey, POINT_CONVERSION_UNCOMPRESSED);

    int nSize = i2o_ECPublicKey(pKey, NULL);
    std::vector<unsigned char> pubKey(nSize, 0)
    unsigned char* pBegin = &pubKey[0];
    i2o_ECPublicKey(pKey, &pBegin)
    return pubKey;
}

But how can I get the uncompressed public key from the compressed public key without knowing the private key?

user299648
  • 471
  • 1
  • 4
  • 12
  • 1
    I answered the same question here, but with an answer in Python: https://bitcointalk.org/index.php?topic=644919.msg7205689#msg7205689 If a language-agnostic answer is suitable, I can post this as an answer. – Tim S. Jul 09 '14 at 17:59
  • Thanks for the solution, but I'm looking fora a canonical solution using openssl. – user299648 Jul 09 '14 at 19:39

3 Answers3

2

If you have a compressed octet pubkey, use octet to point, then point to octet.

EC_POINT_oct2point(group, point, data, size, ctx);
EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, data, len, ctx);
Erik Aronesty
  • 447
  • 5
  • 9
2

You could also use the following to get an EC_POINT from a compressed key:

int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
                                             EC_POINT *p,
                                             const BIGNUM *x, int y_bit,
                                             BN_CTX *ctx);

and the following to convert the EC_POINT to an EC_KEY:

 int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);

From EC_POINT_new documentation:

Points can also be described in terms of their compressed co-ordinates. For a point (x, y), for any given value for x such that the point is on the curve there will only ever be two possible values for y. Therefore a point can be set using the EC_POINT_set_compressed_coordinates_GFp() and EC_POINT_set_compressed_coordinates_GF2m() functions where x is the x co-ordinate and y_bit is a value 0 or 1 to identify which of the two possible values for y should be used.

and EC_KEY_new documentation:

The functions EC_KEY_get0_group(), EC_KEY_set_group(), EC_KEY_get0_private_key(), EC_KEY_set_private_key(), EC_KEY_get0_public_key(), and EC_KEY_set_public_key() get and set the EC_GROUP object, the private key, and the EC_POINT public key for the key respectively.

JBaczuk
  • 7,388
  • 1
  • 13
  • 34
0

Sample code using boringssl in c.

EC_KEY  eckey = EC_KEY_new();
EC_GROUP = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_KEY_set_group(eckey, ecgrp);

EVP_PKEY pubkey = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(pubkey, eckey);

unsigned char ptr = raw_data->data; o2i_ECPublicKey(&eckey, (const uint8_t *)&ptr, raw_data->len);

//pubkey is the required public key

nick
  • 1