user132129: 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 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()

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.

user132129: OK, answering my own question..
There were three problems:

VerifyingKey.verify's default value for hashfunc is hashlib.sha1, but we need hashlib.sha256. So, we need to add a hashfunc=hashlib.sha256 to the verify call. ECDSA docs

What 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

132129: <p>A friend of mine and I are trying to learn how to read the bitcoin blockchain. We've gotten pretty much everything <em>except</em> the ECDSA verification that the coins spent actually belong to the person who is spending them.</p>
<p>We're working off this answer from @amaclin from here: <a href="https://bitcoin.stackexchange.com/a/32308/235711">https://bitcoin.stackexchange.com/a/32308/235711</a></p>
<p>Here's our gist: <a href="https://gist.github.com/bnsh/922b5331a77f6b85d14e0bd682f6304d" rel="nofollow noreferrer">https://gist.github.com/bnsh/922b5331a77f6b85d14e0bd682f6304d</a></p>
<p>And, here's the code directly.</p>
<pre><code>#! /usr/bin/env python3
# vim: expandtab shiftwidth=4 tabstop=4

&quot;&quot;&quot;
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 ( &quot;01000000018dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d41&quot;
                                            &quot;5db55d07a1000000001976a91446af3fb481837fadbb421727f9959c2d32a368&quot;
                                            &quot;2988acffffffff0200719a81860000001976a914df1bd49a6c9e34dfa8631f2c&quot;
                                            &quot;54cf39986027501b88ac009f0a5362000000434104cd5e9726e6afeae357b180&quot;
                                            &quot;6be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce33&quot;
                                            &quot;88fa1abd0fa88b06c44ce81e2234aa70fe578d455dac0000000001000000&quot; ) );
const MyKey32 digest ( xx.constData ( ), xx.size ( ) ); // construct object of sha256 (sha256 ( xx ) )
_trace ( digest.toString ( ) );                         // print result
const QByteArray pubkey ( QByteArray::fromHex ( &quot;042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb&quot; ) );
const QByteArray signature ( QByteArray::fromHex ( &quot;30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e&quot; ) );
_trace ( QString ( &quot;verify=%1&quot; ).arg ( digest.verify ( pubkey, signature ) ) );
&quot;&quot;&quot;

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 &quot;&quot;.join(reversed([f&quot;{int(val):02x}&quot; 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(
        &quot;01000000018dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d41&quot;
        &quot;5db55d07a1000000001976a91446af3fb481837fadbb421727f9959c2d32a368&quot;
        &quot;2988acffffffff0200719a81860000001976a914df1bd49a6c9e34dfa8631f2c&quot;
        &quot;54cf39986027501b88ac009f0a5362000000434104cd5e9726e6afeae357b180&quot;
        &quot;6be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce33&quot;
        &quot;88fa1abd0fa88b06c44ce81e2234aa70fe578d455dac0000000001000000&quot;
    )
    digest = mykey32(xx)
    print(to_hex(digest)) # This clearly works as described in the post.

    pubkey = from_hex(&quot;042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb&quot;)
    signature = from_hex(&quot;30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e&quot;)
    
    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__ == &quot;__main__&quot;:
    main()
</code></pre>
<p>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?</p>
<p>Thanks.</p>
 132129: <p>OK, answering my own question..</p>
<p>There were three problems:</p>
<ol>
<li><p><code>VerifyingKey.verify</code>'s default value for <code>hashfunc</code> is <code>hashlib.sha1</code>, but we need <code>hashlib.sha256</code>. So, we need to add a <code>hashfunc=hashlib.sha256</code> to the <code>verify</code> call. <a href="https://pypi.org/project/ecdsa/" rel="nofollow noreferrer">ECDSA docs</a></p>
</li>
<li><p>What needs to get passed to the digest should be a <em>single</em> call to <code>hashlib.sha256</code>, not the double call that's usually done.</p>
</li>
<li><p>The <code>signature</code> is actually a DER signature, which needs to be extracted. There <em>is</em> a library to do this, but we wanted to understand what was happening.</p>
<p>a. The first byte in the signature is a 0x30 which signifies a &quot;sequence&quot; <a href="https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/#sequence-encoding" rel="nofollow noreferrer">Intro to ASN.1</a>.</p>
<p>b. Next comes a 0x45, which indicates that the total following length of the sequence in bytes: 4 * 16 + 5 = 69.</p>
<p>c. Next comes a 0x02, which indicates an integer.</p>
<p>d. Next comes a 0x21. This is supposed to be the <em>length</em> of the first integer in the signature. But, we have to only extract the <em>last</em> 32 bytes of the integer.</p>
<p>e. After the 33 bytes at byte 37 is another 0x02 (for another integer)</p>
<p>f. Then comes a 0x20 (32 bytes) for the next integer</p>
<p>So, the &quot;real&quot; signature is <code>signature[5:(5+32)] + signature[39:(39+32)]</code></p>
</li>
</ol>
<p>If we then do <code>verkey.verify(signature, digest, hashfunc=hashlib.sha256)</code> it runs without any exception.</p>
<p>The fixed code is here: <a href="https://gist.github.com/bnsh/808f2652818907e5153ee0dfde57a40f" rel="nofollow noreferrer">https://gist.github.com/bnsh/808f2652818907e5153ee0dfde57a40f</a></p>
