AnswerBun.com

Bitcoind does not like ECDSA (r, s) pair produced by OpenSSL

Bitcoin Asked by Tedy S. on February 9, 2021

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);
do
{
   (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?

3 Answers

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

Answered by garima on February 9, 2021

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
        else:
            break
    r = r[ri:]
    si = 0
    for b in s:
        if b == "x00":
            si += 1
        else:
            break;
    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.

Answered by Andrew Chow on February 9, 2021

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

Answered by Mike D on February 9, 2021

Add your own answers!

Related Questions

Name of attack where you pay a high fee to block others

2  Asked on October 24, 2021 by m-johnson

 

Configure Bitcoin full node in my local LAN

1  Asked on October 24, 2021 by miltonc

 

missing transaction not received

2  Asked on October 24, 2021 by n-w

 

I received an email that says someone sent me bitcoin

2  Asked on October 24, 2021 by user107566

 

OP_LSHIFT & OP_RSHIFT purpose & functionality

1  Asked on October 24, 2021 by bhala-t-r

 

What is proof-of-work?

3  Asked on October 24, 2021 by dr-haribo

     

How do I get hash to verify transaction?

1  Asked on October 24, 2021 by kriley

     

Blockchain API whitelist all IP addresses

1  Asked on October 24, 2021 by samuel-ralak

     

Error on Centos Minergate Installation

0  Asked on October 24, 2021 by centosminer

   

bitcoin-cli “Could not connect to the server”

1  Asked on October 24, 2021 by user97315

 

Ask a Question

Get help from others!

© 2022 AnswerBun.com. All rights reserved. Sites we Love: PCI Database, MenuIva, UKBizDB, Menu Kuliner, Sharing RPP, SolveDir