Bitcoin public keys from uncompressed to compressed version with code sample

The Overload Genius 06/12/2018. 2 answers, 105 views
wallet public-key

Hi there I was looking for some code sample on compressing a bitcoin public keys from the curve secp256k1. Just for me to get a good grasp, I have seen code going from compressed to uncompressed, I'd like to see also code from uncompressed to compressed.Any language is fine, preferably Java/Js.

2 Answers


Mike D 06/12/2018.

Check out these two Python methods taken from here

class PublicKey

@classmethod
def decode(cls, key: bytes) -> 'PublicKey':
    if key.startswith(b'\x04'):        # uncompressed key
        assert len(key) == 65, 'An uncompressed public key must be 65 bytes long'
        x, y = bytes_to_int(key[1:33]), bytes_to_int(key[33:])
    else:                              # compressed key
        assert len(key) == 33, 'A compressed public key must be 33 bytes long'
        x = bytes_to_int(key[1:])
        root = modsqrt(CURVE.f(x), P)
        if key.startswith(b'\x03'):    # odd root
            y = root if root % 2 == 1 else -root % P
        elif key.startswith(b'\x02'):  # even root
            y = root if root % 2 == 0 else -root % P
        else:
            assert False, 'Wrong key format'

    return cls(Point(x, y))

def encode(self, compressed=False) -> bytes:
    if compressed:
        if self.y & 1:  # odd root
            return b'\x03' + int_to_bytes(self.x).rjust(32, b'\x00')
        else:           # even root
            return b'\x02' + int_to_bytes(self.x).rjust(32, b'\x00')
    return b'\x04' + int_to_bytes(self.x).rjust(32, b'\x00') + int_to_bytes(self.y).rjust(32, b'\x00')

Andrew Chow 06/12/2018.

Here is how Bitcoin Core's libsecp256k1 performs public key serialization, which includes the compression. Here is the relevant parts:

static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) {
    ...
    secp256k1_fe_get_b32(&pub[1], &elem->x);
    if (compressed) {
        *size = 33;
        pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
    } else {
        ...
    }
    return 1;
}

Compression is very simply, if the Y value of the pubkey is odd, place an 0x03 byte. If it is even, place a 0x02 byte. Then write out the 32 bytes for the X value. That's it.

Related questions

Hot questions

Language

Popular Tags