使用 Python ECDSA(或 OpenSSL)簽署原始交易
我正在從 Redeeming a raw Tx Step By Step中尋找 Step15-17 的細節,這實際上是連接的原始 Tx 結構是雙 sha256 散列的步驟,然後用 ECDSA 庫簽名。我還參考了其他原始交易指南;我正在尋找如何在沒有 GUI/網站/等的情況下簽署原始十六進制 Tx 結構
我使用 Bitcoincore v0.10(一個完整節點)建構了一個測試網Tx,並嘗試使用 Python 進行相同操作,但無法使用Python ecdsa正確簽署原始 Tx 結構。
- TxID: 72b764383b99fb3d112ac8b474a5d7c4242b75dbfee2d4e9cf9a6703d90f805a
- 投票: 1
- 收件人: n1hjyVvYQPQtejJcAND5ZJM5rmxHCCgWL7
- 數量: 0.990 比特幣
我將首先展示Bitcoincore 命令:
importprivkey 93FxXUeMJp93YQAtGeW5cE23gFN4sJbBr1RBmerLFVUDuqQqKL5 mu858WTEPiWWpAJRTMxC4ka6DJqiaCZiSB createrawtransaction '[{"txid" : "72b764383b99fb3d112ac8b474a5d7c4242b75dbfee2d4e9cf9a6703d90f805a", "vout" : 1}]' '{"n1hjyVvYQPQtejJcANd5ZJM5rmxHCCgWL7" : 0.990}' signrawtransaction 01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b7720000000000ffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac00000000
最終的 bitcoincore hex Tx(使用
signrawtransaction
):01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b772010000008a47304402204d78d2e6c0f801573e4960fb8e51ad939380d119d25f97d15efdedf815b05f02022066bd2ab0b401e32e7ce67ea45f8224097eeafbef2335d563776e5efe6632732d01410479b22a5127d176a49d506c86f791031f94a389227ef46a8ddb725a88c944c37e3f753de6ee0b441a0237801f140810e111a1fd8276a2a5d0ee07224a1b551cc1ffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac00000000
現在Python 2.7.9程式碼如下(僅供參考,使用iPython 2.0,因此以下程式碼中缺少樣板):
# please excuse the hexlify/unhexlify, I work better in strings than bytes import __future__ from pybitcointools import sha256 import hashlib, ecdsa from ecdsa import SigningKey, SECP256k1 addr, pubkey = 'mu858WTEPiWWpAJRTMxC4ka6DJqiaCZiSB', '0479b22a5127d176a49d506c86f791031f94a389227ef46a8ddb725a88c944c37e3f753de6ee0b441a0237801f140810e111a1fd8276a2a5d0ee07224a1b551cc1' rawtx = '01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b7720100000000ffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac00000000' # TX structure with 00 as scriptSig, from bitcoincore createrawtransaction # replacing the '00' scriptSig value unsigned.append(rawtx[:82]) unsigned.append('19'+'76a914953de657be4b305f606d9a9fbd35b070a682475788ac') # scriptSig = scriptPubKey input unsigned.append(rawtx[84:]) unsigned.append('01000000') # appending sighash_all unsigned = ''.join(unsigned) unsigned = '01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b772010000001976a914953de657be4b305f606d9a9fbd35b070a682475788acffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac0000000001000000' # See https://github.com/warner/python-ecdsa/blob/master/README.md sig1 = sk.sign(sha256(sha256(unsigned)), hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_der) # note this references 2 different sha256 functions sig2 = [hex(len(sig1 + '\x01'))[2:], hexlify(sig1), hexlify('\x01'), hex(len(unhexlify(pubkey)))[2:], pubkey] sig2 >>> ['48', '304502200e98d54ad642488121fa1fd4d055ff8f5b40773a21ecb42b5ef44ed9fd3b103c022100a2a56ffc3f27021a4be5d1d7a3016eff08fe7f550a4a894cca845ceab54dc53b', '01', '41', '0479b22a5127d176a49d506c86f791031f94a389227ef46a8ddb725a88c944c37e3f753de6ee0b441a0237801f140810e111a1fd8276a2a5d0ee07224a1b551cc1'] sig2 = len(''.join(map(unhexlify, sig2))) hex(len(''.join(map(unhexlify, sig2))))[2:] >>> '8b' # push 139 bytes sig3 >>> 8b48304502200e98d54ad642488121fa1fd4d055ff8f5b40773a21ecb42b5ef44ed9fd3b103c022100a2a56ffc3f27021a4be5d1d7a3016eff08fe7f550a4a894cca845ceab54dc53b01410479b22a5127d176a49d506c86f791031f94a389227ef46a8ddb725a88c944c37e3f753de6ee0b441a0237801f140810e111a1fd8276a2a5d0ee07224a1b551cc1 signed = unsigned[:82] + sig3 + unsigned[84:] # inserting the signature into the 00 the core software uses in place of ScriptSig
最終(無效)Python Tx:
01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b772010000008b48304502200e98d54ad642488121fa1fd4d055ff8f5b40773a21ecb42b5ef44ed9fd3b103c022100a2a56ffc3f27021a4be5d1d7a3016eff08fe7f550a4a894cca845ceab54dc53b01410479b22a5127d176a49d506c86f791031f94a389227ef46a8ddb725a88c944c37e3f753de6ee0b441a0237801f140810e111a1fd8276a2a5d0ee07224a1b551cc1ffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac00000000
發送 Python 生成的 Tx 不起作用。如果我
sendrawtransaction <PYTHON HEX>
在 Bitcoincore 它返回一個無效的簽名錯誤(具體來說,16:強制腳本驗證標誌失敗(腳本評估沒有錯誤但以假/空頂部堆棧元素結束)(程式碼 -26))。(TL;DR) 問題:我在手動簽署原始交易結構時哪裡出錯了?
注意:我知道 pybitcointools 和相關庫可以簽署 Txs,但我正在尋找細節,因為即使是這兩個非常全面的比特幣 SE 資源(LINK1、LINK2)也忽略了細節。我更喜歡Python ECDSA或PyCrypto的答案,但我認為 OpenSSL 是下一個最佳答案。
好的,我想出瞭如何使用 Python ecdsa 對原始 Tx 進行簽名。我將逐步介紹:
記起:
createrawtransaction '[{"txid" : "72b764383b99fb3d112ac8b474a5d7c4242b75dbfee2d4e9cf9a6703d90f805a", "vout" : 1}]' '{"n2kx7k6JuA5Wy27fawaeiPX7dq8mbRDPAv" : 0.99}'
=01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b7720100000000ffffffff01c09ee605000000001976a914e900510876cb689f1db6fa982376c301362b740c88ac00000000
然後為 scriptSig 添加 scriptPubKey
00
:
unsigned = '01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b772010000001976a914953de657be4b305f606d9a9fbd35b070a682475788acffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac0000000001000000'
注意
unsigned
已01000000
附加,因為 SIGNHASH 是01
(也將在一分鐘內附加到 DER 簽名)因此,我們將 SHA256字節加倍並
txhash
以字節形式返回:txhash = hashlib.sha256(hashlib.sha256(unsigned.decode('hex')).digest()).digest()
我們還需要私鑰
mu858WTEPiWWpAJRTMxC4ka6DJqiaCZiSB
(以秘密指數形式,即十六進制): privkeyprivkey = 'dc57c6d067376c36bbed632c9d00f03767867f337d5a86b5b0308a60004f08ee'.zfill(64)
= ‘dc57c6d067376c36bbed632c9d00f03767867f337d5a86b5b0308a60004f08ee’現在,我們使用這個更正的程式碼進行簽名:
signingkey = ecdsa.SigningKey.from_string(privkey.decode('hex'), curve=ecdsa.SECP256k1) SIG = signingkey.sign_digest(txhash, sigencode=ecdsa.util.sigencode_der) +'01'.decode('hex')
這是工作程式碼。從這裡開始,我們只是在做簽名:
ScriptSig
=<varint of total sig length>
<SIG from code, including appended 01 SIGNHASH>
<length of pubkey (0x21 or 0x41)>
<pubkey>
在哪裡
pubkey = '0479b22a5127d176a49d506c86f791031f94a389227ef46a8ddb725a88c944c37e3f753de6ee0b441a0237801f140810e111a1fd8276a2a5d0ee07224a1b551cc1
在不使用 bitcoincore的情況下給我們一個有效的簽名 Tx :
01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b772010000008a47304402204d78d2e6c0f801573e4960fb8e51ad939380d119d25f97d15efdedf815b05f02022066bd2ab0b401e32e7ce67ea45f8224097eeafbef2335d563776e5efe6632732d01410479b22a5127d176a49d506c86f791031f94a389227ef46a8ddb725a88c944c37e3f753de6ee0b441a0237801f140810e111a1fd8276a2a5d0ee07224a1b551cc1ffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac00000000