0

I am trying to create a simple P2PKH raw bitcoin testnet transaction from the scratch. Here is the information about the transaction:

hash of the UTXO consumed - 03e3f89f38ea81a5f1ed277e6ac424cebde4426f4bcc291006f7ecf67350e986
index of the UTXO - 1
private key of the input - 4b5963fc219d1848cc67d52e0a929340f88ff9d316b1990b24d0ae1d37edeef1 
UTXO amount - 0.01 tBTC
receiving address - mtCrEgpKyRhLguqGySE4qUFXzn8sMG7hrm
receiving amount - 0.001 tBTC
change Address - mjHQ5W5B14psNsYBEmh1BykXyY4sY9r9DF
fees used - 378 sats
change amount - 0.00899622 tBTC

Here is the unsigned raw transaction I created:

010000000186e95073f6ecf7061029cc4b6f42e4bdce24c46a7e27edf1a581ea389ff8e303010000001976a914d4dc68f4d94196536c0726f51a91d500c7afa60888acffffffff0226ba0d00000000001976a914295033e5bfe3e8734334addc62c82d9c6eab981388aca0860100000000001976a9148b2d174384a41deeb78e012f4582e29b6e0d161588ac0000000001000000

Double SHA-256 digest of the above to be signed:

4b5963fc219d1848cc67d52e0a929340f88ff9d316b1990b24d0ae1d37edeef1

Next I am using self-written ECDSA library to sign the transaction. I have signed the above transaction using my library three times.

Signed Transaction 1:

010000000186e95073f6ecf7061029cc4b6f42e4bdce24c46a7e27edf1a581ea389ff8e303010000006b483045022100a482537e4225c1ba3470c68d2304d807a6e245491b486e1c6d0778a8436d25dd0220cf4cc90f2e41cafca39555caeb47be235b9c10c2b497528532cb419a7736a8d1012103ab127bf811fd8a6753fbc8cd68731a120d05ac64f1e03df5ec223d7a734e6199ffffffff0226ba0d00000000001976a914295033e5bfe3e8734334addc62c82d9c6eab981388aca0860100000000001976a9148b2d174384a41deeb78e012f4582e29b6e0d161588ac00000000

Signature: 3045022100a482537e4225c1ba3470c68d2304d807a6e245491b486e1c6d0778a8436d25dd0220cf4cc90f2e41cafca39555caeb47be235b9c10c2b497528532cb419a7736a8d1012103ab127bf811fd8a6753fbc8cd68731a120d05ac64f1e03df5ec223d7a734e6199

R: a482537e4225c1ba3470c68d2304d807a6e245491b486e1c6d0778a8436d25dd
S: cf4cc90f2e41cafca39555caeb47be235b9c10c2b497528532cb419a7736a8d1

Signed Transaction 2:

010000000186e95073f6ecf7061029cc4b6f42e4bdce24c46a7e27edf1a581ea389ff8e303010000006b48304502210076a3092727f537453e938a07c9558c605bb79824972b50386e909d8b0394f9700220745b9869b1a4e7b4671a538b7f015a19567250a66f7e965af09060450fdf4288012103ab127bf811fd8a6753fbc8cd68731a120d05ac64f1e03df5ec223d7a734e6199ffffffff0226ba0d00000000001976a914295033e5bfe3e8734334addc62c82d9c6eab981388aca0860100000000001976a9148b2d174384a41deeb78e012f4582e29b6e0d161588ac00000000

Signature: 304502210076a3092727f537453e938a07c9558c605bb79824972b50386e909d8b0394f9700220745b9869b1a4e7b4671a538b7f015a19567250a66f7e965af09060450fdf4288012103ab127bf811fd8a6753fbc8cd68731a120d05ac64f1e03df5ec223d7a734e6199

R: 76a3092727f537453e938a07c9558c605bb79824972b50386e909d8b0394f970
S: 745b9869b1a4e7b4671a538b7f015a19567250a66f7e965af09060450fdf4288

Signed Transaction 3:

010000000186e95073f6ecf7061029cc4b6f42e4bdce24c46a7e27edf1a581ea389ff8e303010000006b4830450221009b6cf3115f5738998b249cafecd69bc489b770cb104a885f93f000df662ca9860220459c6548f4a5b8032529069d704857b92ff3693684be401430a7ca6b2c28e66d012103ab127bf811fd8a6753fbc8cd68731a120d05ac64f1e03df5ec223d7a734e6199ffffffff0226ba0d00000000001976a914295033e5bfe3e8734334addc62c82d9c6eab981388aca0860100000000001976a9148b2d174384a41deeb78e012f4582e29b6e0d161588ac00000000

Signature: 30450221009b6cf3115f5738998b249cafecd69bc489b770cb104a885f93f000df662ca9860220459c6548f4a5b8032529069d704857b92ff3693684be401430a7ca6b2c28e66d012103ab127bf811fd8a6753fbc8cd68731a120d05ac64f1e03df5ec223d7a734e6199

R: 9b6cf3115f5738998b249cafecd69bc489b770cb104a885f93f000df662ca986
S: 459c6548f4a5b8032529069d704857b92ff3693684be401430a7ca6b2c28e66d

I used Blockstream Broadcasting tool to push my transaction. However, signed transaction 1 and 2 failed with the following error:

sendrawtransaction RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Non-canonical DER signature)"}

Finally, signed transaction 3 went successfully and confirmed on the blockchain. I have verified all three signatures and there is nothing wrong in ECDSA params R and S. So, in my view the problem locates in the DER-encoding of the signature. Help me locate the problem about why do the sig-script verification failed for the first two transactions.

1 Answer 1

0

There are a few rules regarding the DER signature that you are not following. In the first transaction, you fail to follow the Low-S value rule. In the second transaction, you fail to follow the strict DER encoding rule.

In the first transaction, the s value is too high. Current standardness rules require that the s be between 0x1 and 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 inclusive. Your s is out of this range. To convert a high s to a low s, you do s' = n - s where n is the order of the secp256k1 curve, i.e. n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141.

In the second transaction, your signature does not follow the strict DER encoding rules. These rules are defined in BIP 66. Specifically, the r is encoded using 33 bytes when only 32 bytes is sufficient. The 0x00 that you have prepended is unnecessary in this case because r as a 32 byte signed integer is positive. That prepended 0x00 is only necessary when r as a 32 byte signed integer would be a negative number, i.e. the top bit is set.

In your third transaction, you got lucky. Because you are using a random nonce, half of the time s will be low, and half of the time r as a 32 byte integer will be negative and require the prepended 0x00 to become positive. So 1 in 4 signatures should be accepted, and that's basically what we see here.

Related to the error in the second transaction, on thing you need to watch out for is when r or s is smaller than 32 bytes. This rare, but it can happen. Essentially the rule for encoding these numbers is to encode them as a big endian signed integer but do it as small as possible.

3
  • Thank you for the answer Andrew. I wasn't aware of DER encoding rules as defined in BIP-66. I have tried to inculcate the rules in my code. Now I am converting high S into low S which solves problem for half of the transaction. However, R encoding is still not working when R as signed integer is positive. Let me show you the example: 304402203faf4f96f781a8819531c4a78a35e9c4ea3f1f4ef56493d18eff52881cdf43a702206b0f0072964a7819a9c223f38d7fd73c7063423cb49aa480eedc3b284b41c23b01210329d4fec73ecf28f4bcbe7e235c63764e1c7c3ba7f1d90feeea9be1a8a0696498 What could possibly be wrong?
    – CryptoSar
    Commented Jan 26, 2021 at 7:01
  • @CryptoSar How do you put this in a transaction? The signature seems fine to me but maybe you are encoding it incorrectly in the transaction.
    – Ava Chow
    Commented Jan 26, 2021 at 17:15
  • Yes, you are right Andrew. Actually the problem was in the byte just before signatures representing the sig length. I have rectified it and it is working 100% now. Thanks once again.
    – CryptoSar
    Commented Jan 26, 2021 at 18:31

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.