In my situation my private key is in an HSM. I cannot access it for use with the various bitcoin golang libraries. Most of the functions require the private key "in-use". Although in my case, I can generate the signature later used for signing with an HSM API, I can't use the remainder of the library because of this issue.


Hence the question, How do I turn an 88 byte ECDSA public key into a 65 byte uncompressed or 33 byte compressed key for use with bitcoin?


When you say, 88 byte ECDSA public key, I think what you are actually referring to is a 65-byte uncompressed public key, which has been base64-encoded. Base64 encoding requires 4 characters for every 3 bytes encoded, then the string's length is padded up to a multiple of 4. S0, base64-encoding 65 bytes would result in a base64-encoded string 88 characters long.

Assuming your are given a base64-encoded string 88 characters in length, like so:


You can convert it to hexadecimal using the following command:

echo -n 'BFCGOtZKh66KL+g8GvGoQDy1P1PkhthRHa2KBIh+WyNSLNRwJDRTopn6nncjdxYQOrwRod84hV7W8u4YfpxYK6Y=' | base64 -d | xxd -p

which produces:


As you can see, this is 65 bytes (each pair of hexadecimal characters represents one byte). The first hexadecimal character is 04 (to signify a 65-byte uncompressed public key), followed by the 32-byte X value, followed by the 32-byte Y value.


Thank you for your comment. This is helpful.

The hex string that you provided is:


The first 23 bytes are just ASN.1 stuff. The remaining 65 bytes contain the uncompressed public key.


The first hexadecimal character is 04 (to signify a 65-byte uncompressed public key), followed by the 32-byte X value, followed by the 32-byte Y value. So, the X and Y values are:

X:  9bb8e80670371f45508b5f8f59946a7c4dea4b3a23a036cf24c1f40993f4a1da
Y:  ad1716de8bd664ecb4596648d722a4685293de208c1d2da9361b9cba74c3d1ec

To check if this is correct, we can verify that the point (X, Y) is on the secp256k1 curve, using the short python script below, based on the definition of the secp256k1 curve. The script prints True if the point is on the curve, and False if not:


ispoint=(y * y - x * x * x - a * x - b) % p == 0 

Running the script prouduces:


*As always, when playing with Bitcoin addresses, be sure that you have the correct private key corresponding with your Bitcoin address before sending a large amount of Bitcoin to this address. You might want to send a small amount of Bitcoin to the address first, and check that you can then spend these coins (using the private key to sign the transaction), before sending a large amount of Bitcoin to this address.

  • I did a bit more research and learned that the API that returns the public key returns it asa ASN.1 DER encoding of a BIP-32 derived public key based on the chainPath. When I print it out the bytes as a hex string the value is: 3056301006072a8648ce3d020106052b8104000a034200049bb8e80670371f45508b5f8f59946a7c4dea4b3a23a036cf24c1f40993f4a1daad1716de8bd664ecb4596648d722a4685293de208c1d2da9361b9cba74c3d1ec Does your response still apply to ANS.1 DER format? I would then need to some how decode ANS.1 DER format back to ECDSA decoded base64? Thanks
    – Pete
    Sep 29 '21 at 0:43
  • @Pete Thanks for your comment. This is helpful. Please see the edit I made to my answer.
    – mti2935
    Sep 29 '21 at 10:59

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.