Проверка подписи P2SH в python

Я пытаюсь понять и проверить сценарий P2SH, написав код Python для анализа реальной транзакции в блокчейне. Я выбрал ниже транзакцию случайным образом. TxID: 7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45

Я получаю BadSignatureError.

Необработанная транзакция:

bitcoin-cli getrawtransaction 7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45
0100000001c8cc2b56525e734ff63a13bc6ad06a9e5664df8c67632253a8e36017aee3ee40000000009000483045022100ad0851c69dd756b45190b5a8e97cb4ac3c2b0fa2f2aae23aed6ca97ab33bf88302200b248593abc1259512793e7dea61036c601775ebb23640a0120b0dba2c34b79001455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51aefeffffff0120f40e00000000001976a9141d30342095961d951d306845ef98ac08474b36a088aca7270400

Расшифруйте приведенную выше необработанную транзакцию и получите идентификатор транзакции блокирующего скрипта:

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.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

Тип подписи — SIGHASH_ALL, поэтому мы заменяем только сценарий разблокировки сценарием блокировки.

р||с: ------------------------------------------------------------- ----------------(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 -> Signature -> 0x01 -> Pubkey -> 0x01

pubkey: 0x042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896

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.

Я очень подробно описал, чем я занимаюсь. Пожалуйста, помогите мне понять и решить это.

Ответы (2)

scriptsig из стека:

Это подпись, а не scriptSig. scriptSig — это то, что вы называете сценарием разблокировки.

После замены сценария блокировки на сценарий разблокировки:

Поскольку вы пытаетесь проверить транзакцию P2SH, вы фактически заменяете scriptSig на redeemScript, а не на блокирующий скрипт (обычно называемый scriptPubKey).

Я изменил scriptsig на подпись. Я не получил ваш второй комментарий, так как scriptPubKey предыдущей транзакции имеет OP_HASH160 <хэш погашения сценария> OP_EQUAL, который я упомянул как сценарий блокировки. Сценарий разблокировки - это сценарий выкупа, который выглядит так: OP_0 <Signature> OP_1 <Pubkey> OP_1 OP_CHECKMULTISIG Итак, как еще я должен заменить. Не могли бы вы объяснить, как мне решить эту проблему?
Нет, "скрипт разблокировки" - это не redeemScript. Это на самом деле OP_0 <sig> <redeemScript>. RedeemScript — это OP_<pubkey> OP_1 OP_CHECKMULTISIG`. Вы хотите заменить scriptSig на redeemScript. В настоящее время вы заменяете его на scriptPubKey предыдущей транзакции.
Я уберу OP_0 и <sig> из скрипта разблокировки и попробую.

Я использовал сценарий блокировки (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) дает Подпись действительна.