python中的P2SH簽名驗證
我試圖通過編寫 python 程式碼來解析區塊鏈中的真實交易來理解和驗證 P2SH 腳本。我隨機選擇了下面的交易。TxID:7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45
我收到 BadSignatureError。
原始交易:
bitcoin-cli getrawtransaction 7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45 0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee40000000009000483045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51aefeffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca7270400
解碼以上 Raw transaction 並獲取鎖定腳本的 Transaction ID:
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" ] } } ] }
獲取鎖定腳本的解碼事務:
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" ] } } ] }
我們需要評估解鎖腳本+鎖定腳本。
解鎖腳本:
00483045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae
評估解鎖腳本:
step 1: stack -> 0x00 (OP_0) step 2: stack -> 0x00, 0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001 step 3: stack -> 0x00, 0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001, 0x5141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae
將此堆棧複製為 stack_copy
鎖定腳本:
a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a87
現在使用堆棧評估鎖定腳本:
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
由於 OP_EQUAL 返回 True 並且它是 P2SH,我們根據複製的堆棧評估兌換腳本
堆棧 = stack_copy
兌換腳本 = stack.pop():
0x5141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae
評估兌換腳本:
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.
來自堆棧的簽名:
0x3045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001
解析簽名:
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 是 SIGHASH_ALL 所以我們只用鎖定腳本替換解鎖腳本。
r||s: ——————————————— —————-(1) ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf8830b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b790
解析解鎖腳本的原始交易:
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
用解鎖腳本替換鎖定腳本後:
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
現在執行 OP_CHECKMULTISIG:所以我們有已簽名的交易: ——————————(2)
0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee400000000017a914e9c3dd0c07aac76179ebc76a6c78d4d67c6c160a87feffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca727040001000000
在堆棧上我們有: 0x00 -> 簽名 -> 0x01 -> Pubkey -> 0x01
公鑰:0x042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf
0x04 表示未壓縮。刪除我們擁有的: Pubkey : ——————————————- ——-(3)
0x2f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf
我使用 r||s 作為 (1) 的字節,將 raw_txn 作為 (2) 的字節,使用 pub_key 作為 (3) 的字節,作為以下 Python 程式碼的參數來執行 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
該程序非常適合在 P2PKH 場景中進行檢查,但在這裡失敗了,我不知道。執行這個程序我得到了 BadSignatureError。
我已經非常詳細地說明了我在做什麼。請幫助我理解並解決這個問題。
我正在使用先前交易的鎖定腳本(scriptPubKey)來替換目前交易的解鎖腳本(scriptSig)。相反,我需要使用redeemScript。解鎖腳本是 OP_0 。
所以為了得到(2)我們首先從解鎖腳本中得到redeemScript。
解鎖腳本:
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 <-------------------------
我們得到了已簽名的原始交易:
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
已簽名的原始交易:————————————(2)
0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee4000000000455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51aefeffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca727040001000000
現在 (1)、(2) 和 (3) 給出簽名是有效的。
來自堆棧的腳本:
那是一個簽名,而不是 scriptSig。scriptSig 就是您所說的解鎖腳本。
用解鎖腳本替換鎖定腳本後:
因為您正在嘗試驗證 P2SH 交易,所以您實際上將 scriptSig 替換為redeemScript,而不是鎖定腳本(通常稱為 scriptPubKey)。