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 2


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.


Check out these two Python methods taken from here

class PublicKey

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
            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')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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