Raw-Transaction

使用 Python ECDSA(或 OpenSSL)簽署原始交易

  • March 16, 2015

我正在從 Redeeming a raw Tx Step By Step中尋找 Step15-17 的細節,這實際上是連接的原始 Tx 結構是雙 sha256 散列的步驟,然後用 ECDSA 庫簽名。我還參考了其他原始交易指南我正在尋找如何在沒有 GUI/網站/等的情況下簽署原始十六進制 Tx 結構

我使用 Bitcoincore v0.10(一個完整節點)建構了一個測試網Tx,並嘗試使用 Python 進行相同操作,但無法使用Python ecdsa正確簽署原始 Tx 結構。

我將首先展示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 資源(LINK1LINK2)也忽略了細節。我更喜歡Python ECDSAPyCrypto的答案,但我認為 OpenSSL 是下一個最佳答案。

好的,我想出瞭如何使用 Python ecdsa 對原始 Tx 進行簽名。我將逐步介紹:

記起:

createrawtransaction '[{"txid" : "72b764383b99fb3d112ac8b474a5d7c4242b75dbfee2d4e9cf9a6703d90f805a", "vout" : 1}]' '{"n2kx7k6JuA5Wy27fawaeiPX7dq8mbRDPAv" : 0.99}'= 01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b7720100000000ffffffff01c09ee605000000001976a914e900510876cb689f1db6fa982376c301362b740c88ac00000000

然後為 scriptSig 添加 scriptPubKey 00

unsigned = '01000000015a800fd903679acfe9d4e2fedb752b24c4d7a574b4c82a113dfb993b3864b772010000001976a914953de657be4b305f606d9a9fbd35b070a682475788acffffffff01c09ee605000000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88ac0000000001000000'

注意unsigned01000000附加,因為 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

引用自:https://bitcoin.stackexchange.com/questions/36440