I am writing transactions manually and have stumbled across a rather bizarre situation.

Only one in a few of the transactions I broadcast to bitcoind is accepted, otherwise I get a REJECT_NONSTANDARD (Non-canonical DER signature).

So I got my hands dirty and tracked the rejection to be originating from this line: https://github.com/bitcoin/bitcoin/blob/9c5f0d542d1db507b3b9c87bd9de6d0d758d51c1/src/script/interpreter.cpp#L163

I read about DER encoding and checked how IsValidSignatureEncoding is enforcing it, but I do not know why OpenSSL generates not-DER-compliant (r, s) values?

How should I overcome this? I am thinking of something along the lines of (pseudocode):

Pair (r, s);
   (r, s) = sign(hash, pvtkey);
} while (r[0] >= 128 || s[0] >= 128); // where r[0], s[0] should be the very first byte of each value

But isn't that kind of redundant? Can I give OpenSSL any flag to produce a valid DER (R, S) pair in the first place?

  • 1
    Are you using OpenSSL to encode the DER or did you write your own DER encoding function? It's very easy to end up with a function that is only correct for some inputs.
    – G. Maxwell
    Nov 18 '18 at 17:56

A possible reason is that Bitcoin Core expects a low S value. Try changing s with N-s if s > N/2 (N is the curve order).

Source here

  • Actually that was not my initial issue, that's a completely different error code which I am getting now (SCRIPT_ERR_SIG_HIGH_S) after prepending my faulty S value with an 0x00 byte (I read in some other thread that should be done if the initial S's first byte is >= 128). So yeah most likely what I have to do now is what you suggested
    – Tedy S.
    Oct 18 '18 at 11:39

The following python code can create a valid DER encoded signature given r and s as byte objects:

def ser_sig_der(r, s):
    sig = b"\x30"

    # Make r and s as short as possible
    ri = 0
    for b in r:
        if b == "\x00":
            ri += 1
    r = r[ri:]
    si = 0
    for b in s:
        if b == "\x00":
            si += 1
    s = s[si:]

    # Make positive of neg
    first = r[0]
    if first & (1 << 7) != 0:
        r = b"\x00" + r
    first = s[0]
    if first & (1 << 7) != 0:
        s = b"\x00" + s

    # Write total length
    total_len = len(r) + len(s) + 4
    sig += struct.pack("B", total_len)

    # write r
    sig += b"\x02"
    sig += struct.pack("B", len(r))
    sig += r

    # write s
    sig += b"\x02"
    sig += struct.pack("B", len(s))
    sig += s
    return sig

It is important to note that signatures in Bitcoin also contain an extra byte appended to the DER encoded signature which represents the sighash type. You will need to add that byte yourself.


The third byte encodes information about the content length. If content length is less than 127 bytes third byte is equal to content length. If it is greater than 127 and less than 255, the third byte is 0x81. If it is greater than 255, the third byte is 0x82.

The next byte(s) indicates the content length.

Reference: https://github.com/openssl/openssl/blob/master/crypto/asn1_dsa.c encode_der_length https://www.itu.int/rec/T-REC-X.690-201508-I/en

  • 1
    Although bitcoin signatures use secp256k1, and low-S as MikeD noted, so all of the value parts never exceed 69 bytes and your second and third cases of length encoding never occur. (The third case actually is >=256 and <65536; for longer than that, there are more length encodings you don't mention, but they aren't supported or needed by the code you link.) Sep 4 '20 at 5:18

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.