I would like to understand how to get Bitcoin ECDSA signature in a compact format, when it's exactly 65 bytes.

In the bitcoin-core repository, secp256k1_ecdsa_recoverable_signature_load is responsible for this. As far as I understand, in it r and s are separately reduced to a 32 byte representation using secp256k1_scalar_set_b32, but I don't understand how it function works. What is a EXHAUSTIVE_TEST_ORDER? Why does the resulting representation of 32b scalar remain valid after it? I would be very grateful if someone could explain it to me.

1 Answer 1


What you are looking at is just an implementation detail that you really don't need to worry about. It's just converting from an internal format (which may use different coordinate systems and bit lengths, especially for tests) to the standard output format. Within the library itself, the data in the signature may be easier and more efficient to handle when in other formats or coordinates systems. So the structures that represent that data store the data differently. However when outputting results, it must all be in a standard format, so that's what these conversions do: change from internal representation to a standard output format.

This is done for any of the signature serialization outputs that libsecp256k1 does. The compact format is just the two 256 bit values for R and s concatenated with each other. The first 32 bytes is R, the second is s. For standard compact signatures, that's it. For compact recoverable signatures (which is what you are looking at), there is an additional byte for the recovery id that is prepended to the compact signature.

  • In fact, I want to get a compact format of signature using the OpenSSL library. it has ECDSA_do_sign function which returns a structure consisting of two pointers to BIGNUM. Could you please tell me how to convert this internal representation from the OpenSSL into a standard one? I cannot find in the interface a function similar to the function from bitcoin-core.
    – Oroffe
    Dec 25, 2018 at 8:25
  • Of course you won't be able to find how to do that in Bitcoin Core because Bitcoin Core does not use OpenSSL for signature operations anymore. The ways that libsecp and openssl represent things internally are different from each other. You can use ECDSA_SIG_get0 to get the BIGNUMs for r and s, then use BN_bn2binpad to get the BIGNUMs serialized as 32 byte big-endian integers. Then just concatenate the two byte strings to get the compact signature.
    – Ava Chow
    Dec 25, 2018 at 16:22
  • How to verify the compact signature? as bitcoinjs-message nodejs library throw error Error: Invalid signature length. Aug 6, 2020 at 8:57
  • @AndrewChow, i believe the recovery ID byte is prepended to the signature (r,s). It is the first byte, not the last. Jun 16, 2022 at 21:45
  • 1
    @SachinMeier Oh, indeed it is the first byte. I have updated the answer.
    – Ava Chow
    Jun 17, 2022 at 15:10

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.