<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>

CC BY-SA 4.0
2022-06-08T04:53:59.130Z
2022-06-08T04:53:59.130Z
bnsh
<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>

<python><ecdsa><verification>
Verifying the Pizza transaction in Python
bnsh
# Verifying the Pizza transaction in Python

(Asked by: username_0 on 2022-06-02)

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/username_0/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.

**Tags:** python, ecdsa, verification


---

## 1 answers

### Answer by username_0 on 2022-06-08. Score: 3 | Accepted answer

OK, answering my own question..

There were three problems:

1. `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](https://pypi.org/project/ecdsa/)
2. What needs to get passed to the digest should be a *single* call to `hashlib.sha256`, not the double call that's usually done.
3. 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](https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/#sequence-encoding).

   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/username_0/808f2652818907e5153ee0dfde57a40f>


---

