0

I am trying to understand and verify P2SH script by writing a python code to parse real transaction in blockchain. I have chosen below Transaction randomly. TxID: 7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45

I am getting BadSignatureError.

Raw transaction:

bitcoin-cli getrawtransaction 7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45
0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee40000000009000483045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51aefeffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca7270400

Decode above Raw transaction and get Transaction ID of locking script:

bitcoin-cli decoderawtransaction $(bitcoin-cli getrawtransaction 7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45)
{
  "txid": "7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45",
  "hash": "7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45",
  "version": 1,
  "size": 229,
  "vsize": 229,
  "weight": 916,
  "locktime": 272295,
  "vin": [
    {
      "txid": "40eee3ae1760e3a8532263678cdf64569e6ad06abc133af64f735e52562bccc8",
      "vout": 0,
      "scriptSig": {
        "asm": "0 3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b790[ALL] 5141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae",
        "hex": "00483045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae"
      },
      "sequence": 4294967294
    }
  ],
  "vout": [
    {
      "value": 0.00980000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 1d30342095961d951d306845ef98ac08474b36a0 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9141d30342095961d951d306845ef98ac08474b36a088ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "13fLLox43yXYvfoZadXpGbkTUXkW8bhqut"
        ]
      }
    }
  ]
}

Get Decoded Transaction of locking script:

bitcoin-cli decoderawtransaction $(bitcoin-cli getrawtransaction 40eee3ae1760e3a8532263678cdf64569e6ad06abc133af64f735e52562bccc8)
{
  "txid": "40eee3ae1760e3a8532263678cdf64569e6ad06abc133af64f735e52562bccc8",
  "hash": "40eee3ae1760e3a8532263678cdf64569e6ad06abc133af64f735e52562bccc8",
  "version": 1,
  "size": 189,
  "vsize": 189,
  "weight": 756,
  "locktime": 0,
  "vin": [
    {
      "txid": "42a3fdd7d7baea12221f259f38549930b47cec288b55e4a8facc3c899f4775da",
      "vout": 0,
      "scriptSig": {
        "asm": "3044022048d1468895910edafe53d4ec4209192cc3a8f0f21e7b9811f83b5e419bfb57e002203fef249b56682dbbb1528d4338969abb14583858488a3a766f609185efe68bca[ALL] 031a455dab5e1f614e574a2f4f12f22990717e93899695fb0d81e4ac2dcfd25d00",
        "hex": "473044022048d1468895910edafe53d4ec4209192cc3a8f0f21e7b9811f83b5e419bfb57e002203fef249b56682dbbb1528d4338969abb14583858488a3a766f609185efe68bca0121031a455dab5e1f614e574a2f4f12f22990717e93899695fb0d81e4ac2dcfd25d00"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.00990000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_HASH160 e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a OP_EQUAL",
        "hex": "a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a87",
        "reqSigs": 1,
        "type": "scripthash",
        "addresses": [
          "3P14159f73E4gFr7JterCCQh9QjiTjiZrG"
        ]
      }
    }
  ]
}

We need to evaluate unlocking script + locking script.

unlocking script:

00483045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae

Evaluate unlocking script:

step 1: stack -> 0x00 (OP_0)
step 2: stack -> 0x00, 0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001
step 3: stack -> 0x00, 
0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001, 
0x5141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae

Copy this stack as stack_copy

locking script:

a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a87

Evaluate locking script now with the stack:

step 4: 0xa9 (OP_HASH160)
stack -> 0x00,
0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001,
0xe9c3dd0c07aac76179ebc76a6c78d4d67c6c160a

step 5: 0x14 (pushdata 20 bytes) 0xe9c3dd0c07aac76179ebc76a6c78d4d67c6c160a
stack -> 0x00,
0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001,
0xe9c3dd0c07aac76179ebc76a6c78d4d67c6c160a,
0xe9c3dd0c07aac76179ebc76a6c78d4d67c6c160a

step 6: 87 OP_EQUAL
stack -> 0x00,
0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001,
0x01

Since OP_EQUAL returned True and it is P2SH we evaluate redeem script against copied stack

stack = stack_copy

redeem script = stack.pop():

0x5141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae

Evaluate redeem script:

step 7: 0x51 (OP_1)
stack -> 0x00,
0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001,
0x01

step 8: 0x41 (Pushdata 65 bytes) 042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf
stack -> 0x00,
0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001,
0x01,
0x042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf

step 9: 0x51 (OP_1)
stack -> 0x00,
0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001,
0x01,
0x042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf,
0x01

step 10: 0xae (OP_CHECKMULTISIG)
We have 1 sig and 1 pubkey. To check multisig we need to get transaction which was signed. We will come back to this step once we have transaction which was signed.

Signature from stack:

0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001

Parse Signature:

0x30 DER
0x45 Length
0x02 Type Integer
0x21 Length of r
00 (ignore) ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf883 (r)
02 Type Integer
20 Length of s
0b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b790 (s)
01 SIGHASH_ALL

Sig-type is SIGHASH_ALL so we replace only unlocking script with locking script.

r||s: -------------------------------------------------------------(1) ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf8830b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b790

Parsing raw transaction of unlocking script:

01 00 00 00 Version
01 input count
c8 cc 2b 56 52 5e 73 4f f6 3a 13 bc 6a d0 6a 9e 56 64 df 8c 67 63 22 53 a8 e3 60 17 ae e3 ee 40 Previous transaction
00 00 00 00 Previous transaction out index
--------- replace this [
90 
00 48 30 45 02 21 00 ad 08 51 c6 9d d7 56 b4 51 
90 b5 a8 e9 7c b4 ac 3c 2b 0f a2 f2 aa e2 3a ed 
6c a9 7a b3 3b f8 83 02 20 0b 24 85 93 ab c1 25
95 12 79 3e 7d ea 61 03 6c 60 17 75 eb b2 36 40 
a0 12 0b 0d ba 2c 34 b7 90 01 45 51 41 04 2f 90 
07 4d 7a 5b f3 0c 72 cf 3a 8d fd 13 81 bd bd 30 
40 70 10 e8 78 f3 a1 12 69 d5 f7 4a 58 78 85 05 
cd ca 22 ea 6e ab 7c fb 40 dc 0e 07 ab a2 00 42 
4a b0 d7 91 22 a6 53 ad 0c 7e c9 89 6b df 51 ae
------------- ]
fe ff ff ff sequence
01 out count
20 f4 0e 00 00 00 00 00 value 
19 script size
76 a9 14 1d 30 34 20 95 96 1d 95 1d 30 68 45 ef 98 ac 08 47 4b 36 a0 88 ac script pubkey
a7 27 04 00 lock time
---> Add SIGHASH_ALL here

After replacing locking script with unlocking script:

01 00 00 00 Version
01 input count
c8 cc 2b 56 52 5e 73 4f f6 3a 13 bc 6a d0 6a 9e 56 64 df 8c 67 63 22 53 a8 e3 60 17 ae e3 ee 40 Previous transaction
00 00 00 00 Previous transaction out index
------- locking script [
17
a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a87
------- ]
fe ff ff ff sequence
01 out count
20 f4 0e 00 00 00 00 00 value 
19 script size
76 a9 14 1d 30 34 20 95 96 1d 95 1d 30 68 45 ef 98 ac 08 47 4b 36 a0 88 ac 
a7 27 04 00 lock time
01 00 00 00 SIGHASH_ALL

Now performing OP_CHECKMULTISIG: So we have transaction which is signed: ------------------------------(2)

0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee400000000017a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a87feffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca727040001000000 

On stack we have: 0x00 -> Signature -> 0x01 -> Pubkey -> 0x01

pubkey : 0x042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf

0x04 denote uncompressed. Removing that we have: Pubkey : --------------------------------------------------------------(3)

0x2f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf

I used r||s as bytes of (1), raw_txn as bytes of (2) and pub_key as bytes as (3) for argument of below Python code to perform sigcheck:

def sigcheck(sig_b: bytes, pubkey_b: bytes, raw_txn_b: bytes):
        txn_sha256_b = hashlib.sha256(raw_txn_b).digest()

        prefix = pubkey_b[0:1]
        print('prefix = %s' % prefix)
        print('input pubkey = %s' % bytes.decode(binascii.hexlify(pubkey_b)))
        if prefix == b'\x02' or prefix == b'\x03':
                pubkey_b = getFullPubKeyFromCompressed(pubkey_b)[1:]
        elif prefix == b'\x04':
                pubkey_b = pubkey_b[1:]

        try:
                print("full public key = %s" % bytes.decode(binascii.hexlify(pubkey_b)))
                vk = ecdsa.VerifyingKey.from_string(pubkey_b, curve=ecdsa.SECP256k1)
                if vk.verify(sig_b, txn_sha256_b, hashlib.sha256) == True:
                        print('valid')
                        return 1
                else:
                        print('sigcheck: invalid')
                        return 0
        except ecdsa.BadSignatureError:
                print('sigcheck: Bad Signature')
                return 0

This program works perfectly to checksig in P2PKH scenario but it is failing here and I have no clue. Running this program I am getting BadSignatureError.

I have given in great detail what I am doing. Please help me understand and solve this.

2 Answers 2

2

scriptsig from stack:

That is a signature, not the scriptSig. The scriptSig is what you are calling the unlocking script.

After replacing locking script with unlocking script:

Because you are trying to verify a P2SH transaction, you actually replace the scriptSig with the redeemScript, not the locking script (typically called the scriptPubKey).

3
  • I changed scriptsig to signature. I didn't get your second comment as scriptPubKey of previous Transaction has OP_HASH160 <Redeem Script Hash> OP_EQUAL which I mentioned as locking script. The unlocking script is the redeem script which is like: OP_0 <Signature> OP_1 <Pubkey> OP_1 OP_CHECKMULTISIG So how else I should replace. Could you please explain how should I fix this issue? May 25, 2018 at 14:49
  • No, the "unlocking script" is not the redeemScript. It is actually OP_0 <sig> <redeemScript>. The redeemScript is OP_ <pubkey> OP_1 OP_CHECKMULTISIG`. You want to replace the scriptSig with the redeemScript. What you are currently doing is replacing it with the scriptPubKey of the previous transaction.
    – Andrew Chow
    May 25, 2018 at 15:56
  • I'll remove OP_0 and <sig> from unlocking script and try. May 25, 2018 at 16:08
0

I was using locking script (scriptPubKey) of previous transaction to replace unlocking script (scriptSig) of current transaction. Instead I needed to use redeemScript. Unlocking script is OP_0 .

So to get (2) we first get redeemScript from unlocking script.

Unlocking script:

90 Length of scriptSig
00 OP_0
48 Length of Signature
30 
45 
02 
21 
00 ad 08 51 c6 9d d7 56 b4 51 90 b5 a8 e9 7c b4 ac 3c 2b 0f a2 f2 aa e2 3a ed 6c a9 7a b3 3b f8 83 
02 
20 
0b 24 85 93 ab c1 25 95 12 79 3e 7d ea 61 03 6c 60 17 75 eb b2 36 40 a0 12 0b 0d ba 2c 34 b7 90 
01 SIGHASH_ALL
------ Redeem script ---->
45 51 41 04 2f 90 
07 4d 7a 5b f3 0c 72 cf 3a 8d fd 13 81 bd bd 30 
40 70 10 e8 78 f3 a1 12 69 d5 f7 4a 58 78 85 05 
cd ca 22 ea 6e ab 7c fb 40 dc 0e 07 ab a2 00 42 
4a b0 d7 91 22 a6 53 ad 0c 7e c9 89 6b df 51 ae
<-------------------------

We got Raw Transaction which was signed:

01 00 00 00 Version
01 input count
c8 cc 2b 56 52 5e 73 4f f6 3a 13 bc 6a d0 6a 9e 56 64 df 8c 67 63 22 53 a8 e3 60 17 ae e3 ee 40 Previous transaction
00 00 00 00 Previous transaction out index
------ Redeem script ---->
45 51 41 04 2f 90 
07 4d 7a 5b f3 0c 72 cf 3a 8d fd 13 81 bd bd 30 
40 70 10 e8 78 f3 a1 12 69 d5 f7 4a 58 78 85 05 
cd ca 22 ea 6e ab 7c fb 40 dc 0e 07 ab a2 00 42 
4a b0 d7 91 22 a6 53 ad 0c 7e c9 89 6b df 51 ae
<-------------------------
fe ff ff ff sequence
01 out count
20 f4 0e 00 00 00 00 00 value 
19 script size
76 a9 14 1d 30 34 20 95 96 1d 95 1d 30 68 45 ef 98 ac 08 47 4b 36 a0 88 ac 
a7 27 04 00 lock time
01 00 00 00 SIGHASH_ALL

Raw transaction which is signed: ------------------------------------(2)

0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee4000000000455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51aefeffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca727040001000000

Now (1), (2) and (3) gives Signature is Valid.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.