Sign / Verify Messages using ECDSA - Examples in Python

After we explained in details how the ECDSA signature algorithm works, now let's demonstrate it in practice with code examples.

In this example, we shall use the pycoinPython package, which implements the ECDSA signature algorithm with the curve secp256k1 (used in the Bitcoin cryptography), as well as many other functionalities related to the Bitcoin blockchain:

The hashing function sha3_256Hash(msg) computes and returns a SHA3-256 hash, represented as 256-bit integer number. It will be used in the sign / verify processes later.

The signECDSAsecp256k1(msg, privKey) function takes a text message and 256-bit secp256k1 private key and calculates the ECDSA signature {r, s} and returns it as pair of 256-bit integers. The ECDSA signature, generated by the pycoin library by default is deterministic, as described in RFC 6979.

The verifyECDSAsecp256k1(msg, signature, pubKey) function takes a text message, a ECDSA signature {r, s} and a 2*256-bit ECDSA public key (uncompressed) and returns whether the signature is valid or not.

Now let's demonstrate the above defined functions to sign a message and verify its signature:

As it is visible from the above output, the random generated secp256k1 private key is 64 hex digits (256 bits). After signing, the obtained signature {r, s} consists of 2 * 256-bit integers. The public key, obtained by multiplying the private key by the curve generator point, consists of 2 * 256 bits (uncompressed). The produced ECDSA digital signature verifies correctly after signing. If the message is tampered, the signature fails to verify.

Public Key Recovery from the ECDSA Signature

As we already know, in ECDSA it is possible to recover the public key from signature. Let's demonstrate this by adding the following code at the end of the previous example:

The above code recovers the all possible EC public keys from the ECDSA signature + the signed message, using the algorithm, described in http://www.secg.org/sec1-v2.pdf. Note that multiple EC public keys (0, 1 or 2) may match the message + signature. The expected output from the above code (together with the previous code) looks like this:

It is obvious that the recovered possible public keys are 2: one is equal to the public key, matching the signer's private key, and the other is not (it matches the math behind the public key recovery, but is not the correct one). To avoid this ambiguity, the signature can be extended to hold {r, s, v}, where v holds the parity of the y coordinate of the random point R from the ECDSA signing algorithm. This coordinate is lost, because the ECDSA signature takes just the x coordinate or R.

Public Key Recovery from Extended ECDSA Signature

To recover with confidence the public key from ECDSA signature + message, we need a library that generates extended ECDSA signatures {r, s, v} and supports internally the public key recovery. Let's play with the eth_keys Python library:

pip install eth_keys

The eth_keys is part of the Ethereum project and implements secp256k1-based ECC cryptography, private and public keys, ECDSA extended signatures {r, s, v} and Ethereum blockchain addresses. The following example demonstrates private key generation, message signing, public key recovery from signature + message and signature verification:

The public key recovery will always be successful, because there is no ambiguity with the extended ECDSA signature. The signature verification will be successful, unless the message, the public key or the signature is tampered. You are free to play with the above code, to change it, to tamper the signed message and to see what happens. Enjoy!