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.


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 last byte for the recovery id.

  • 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. – Parean Dec 25 '18 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. – Andrew Chow Dec 25 '18 at 16:22

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.