Python
在 Python 中驗證 Pizza 交易
我和我的一個朋友正在嘗試學習如何閱讀比特幣區塊鏈。我們已經得到了幾乎所有東西,除了ECDSA 驗證所花費的硬幣實際上屬於花費它們的人。
我們正在從@amaclin 那裡得到這個答案:https ://bitcoin.stackexchange.com/a/32308/235711
這是我們的要點:https ://gist.github.com/bnsh/922b5331a77f6b85d14e0bd682f6304d
而且,這是直接的程式碼。
#! /usr/bin/env python3 # vim: expandtab shiftwidth=4 tabstop=4 """ Hi. We're trying to implement this code at https://bitcoin.stackexchange.com/a/32308/235711 in python with the ecdsa library. Unfortunately, we're not clear on what language this code below is written in.. C++? C#? We'd like to verify using python, but it doesn't seem to work. Can someone tell us what we're doing wrong? const QByteArray xx ( QByteArray::fromHex ( "01000000018dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d41" "5db55d07a1000000001976a91446af3fb481837fadbb421727f9959c2d32a368" "2988acffffffff0200719a81860000001976a914df1bd49a6c9e34dfa8631f2c" "54cf39986027501b88ac009f0a5362000000434104cd5e9726e6afeae357b180" "6be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce33" "88fa1abd0fa88b06c44ce81e2234aa70fe578d455dac0000000001000000" ) ); const MyKey32 digest ( xx.constData ( ), xx.size ( ) ); // construct object of sha256 (sha256 ( xx ) ) _trace ( digest.toString ( ) ); // print result const QByteArray pubkey ( QByteArray::fromHex ( "042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb" ) ); const QByteArray signature ( QByteArray::fromHex ( "30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e" ) ); _trace ( QString ( "verify=%1" ).arg ( digest.verify ( pubkey, signature ) ) ); """ import hashlib import ecdsa def from_hex(hexval): return bytes(int(hexval[idx:(idx+2)], 16) for idx in range(0, len(hexval), 2)) def to_hex(raw): return "".join(reversed([f"{int(val):02x}" for val in raw])) def mykey32(data): return hashlib.sha256(hashlib.sha256(data).digest()).digest() def main(): # We're preserving the same variable names as the sample code above # for clarity. xx = from_hex( "01000000018dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d41" "5db55d07a1000000001976a91446af3fb481837fadbb421727f9959c2d32a368" "2988acffffffff0200719a81860000001976a914df1bd49a6c9e34dfa8631f2c" "54cf39986027501b88ac009f0a5362000000434104cd5e9726e6afeae357b180" "6be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce33" "88fa1abd0fa88b06c44ce81e2234aa70fe578d455dac0000000001000000" ) digest = mykey32(xx) print(to_hex(digest)) # This clearly works as described in the post. pubkey = from_hex("042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb") signature = from_hex("30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e") verkey = ecdsa.VerifyingKey.from_string(pubkey, curve=ecdsa.SECP256k1) # This fails with ecdsa.keys.BadSignatureError: MalformedSignature('Invalid length of signature[...]') # It seems like it wants a 64 byte signature. verkey.verify(signature, digest) # How would we verify the pizza transaction as was done in the post # in python? # Thanks! if __name__ == "__main__": main()
我們正在使用 ecdsa python 庫(但我們可以使用任何其他更合適的庫)。我們如何使用python驗證簽名?
謝謝。
好的,回答我自己的問題..
出現了三個問題:
VerifyingKey.verify
的預設值為hashfunc
,hashlib.sha1
但我們需要hashlib.sha256
. 所以,我們需要hashfunc=hashlib.sha256
在verify
呼叫中添加一個。ECDSA 文件- 需要傳遞給摘要的應該是對 的一次呼叫
hashlib.sha256
,而不是通常完成的兩次呼叫。- 這
signature
實際上是一個DER簽名,需要提取。有一個圖書館可以做到這一點,但我們想了解發生了什麼。一個。簽名中的第一個字節是 0x30,它表示 ASN.1 的“序列”介紹。
灣。接下來是一個 0x45,它表示序列的以下總長度(以字節為單位):4 * 16 + 5 = 69。
C。接下來是一個 0x02,它表示一個整數。
d。接下來是 0x21。這應該是簽名中第一個整數的長度。但是,我們只需要提取整數的最後32 個字節。
e. 在字節 37 的 33 個字節之後是另一個 0x02(另一個整數)
F。然後是下一個整數的 0x20(32 字節)
所以,“真正的”簽名是
signature[5:(5+32)] + signature[39:(39+32)]
如果我們這樣做
verkey.verify(signature, digest, hashfunc=hashlib.sha256)
,它就會毫無例外地執行。固定程式碼在這裡:https ://gist.github.com/bnsh/808f2652818907e5153ee0dfde57a40f