Bitcoin Stack Exchange is a question and answer site for Bitcoin crypto-currency enthusiasts. It only takes a minute to sign up.
Sign up to join this communityAnybody can ask a question
Anybody can answer
The best answers are voted up and rise to the top
A friend of mine and I are trying to learn how to read the bitcoin blockchain. We've gotten pretty much everything except the ECDSA verification that the coins spent actually belong to the person who is spending them.
We're working off this answer from @amaclin from here: https://bitcoin.stackexchange.com/a/32308/235711
Here's our gist: https://gist.github.com/bnsh/922b5331a77f6b85d14e0bd682f6304d
And, here's the code directly.
#! /usr/bin/env python3 # vim: expandtab shift4 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()
We're using the ecdsa python library (but we're OK with any other more appropriate library). How can we verify the signature using python?
Thanks.
OK, answering my own question..
There were three problems:
VerifyingKey.verify
's default value forhashfunc
ishashlib.sha1
, but we needhashlib.sha256
. So, we need to add ahashfunc=hashlib.sha256
to theverify
call. ECDSA docsWhat needs to get passed to the digest should be a single call to
hashlib.sha256
, not the double call that's usually done.The
signature
is actually a DER signature, which needs to be extracted. There is a library to do this, but we wanted to understand what was happening.a. The first byte in the signature is a 0x30 which signifies a "sequence" Intro to ASN.1.
b. Next comes a 0x45, which indicates that the total following length of the sequence in bytes: 4 * 16 + 5 = 69.
c. Next comes a 0x02, which indicates an integer.
d. Next comes a 0x21. This is supposed to be the length of the first integer in the signature. But, we have to only extract the last 32 bytes of the integer.
e. After the 33 bytes at byte 37 is another 0x02 (for another integer)
f. Then comes a 0x20 (32 bytes) for the next integer
So, the "real" signature is
signature[5:(5+32)] + signature[39:(39+32)]
If we then do verkey.verify(signature, digest, hashfunc=hashlib.sha256)
it runs without any exception.
The fixed code is here: https://gist.github.com/bnsh/808f2652818907e5153ee0dfde57a40f
You can get bonuses upto $100 FREE BONUS when you:
π° Install these recommended apps:
π² SocialGood - 100% Crypto Back on Everyday Shopping
π² xPortal - The DeFi For The Next Billion
π² CryptoTab Browser - Lightweight, fast, and ready to mine!
π° Register on these recommended exchanges:
π‘ Binanceπ‘ Bitfinexπ‘ Bitmartπ‘ Bittrexπ‘ Bitget
π‘ CoinExπ‘ Crypto.comπ‘ Gate.ioπ‘ Huobiπ‘ Kucoin.
Comments