In the eckey_impl.h header file, the implementation of secp256k1_eckey_pubkey_parse checks if the first byte of a 65-byte public key is 0x04, 0x06 or 0x07. Where can I find documentation regarding the 0x06 and 0x07 prefixes?

static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
    if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
        secp256k1_fe x;
        return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);
    } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
        secp256k1_fe x, y;
        if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
            return 0;
        secp256k1_ge_set_xy(elem, &x, &y);
        if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) {
            return 0;
        return secp256k1_ge_is_valid_var(elem);
    } else {
        return 0;

These are used in the "hybrid" public key format, which is an uncompressed format (it has both X and Y coordinates, like 0x04) that still stores the odd/evenness of the Y coordinate (like 0x02/0x03).

It is defined in ANSI X9.62-1998 Sections 4.3.6 and 4.3.7, and seems totally useless to me. However, OpenSSL supported it, thus when switching to libsecp256k1 for validation, it had to support it too, or we'd risk consensus failures in the network if such a pubkey would ever be used. Now we're pretty much stuck with it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.