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?
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
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP