Programming - Implementing a Blockchain using Python and Flask [Dev Blog 4]

[Image 1]


Hey it's a me again drifter1!

I was quite busy during these days, but here is the fourth dev blog. The new additions have to do with the elliptic cryptography, which is used for addresses and transactions.

First of all, wallets can now be created, with their corresponding private and public ECDSA keys, as well as a shorter form of the public key in the form of a Ethereum-like address. This means that the (now renamed) "wallet.json" contains this information, and a new script manages the creation and JSON format. Of course, the private key is generated using a mnemonic seed phrase.

For the sake of transactions, the script also includes a function for verifying the signature from the original hash and the address. And, for now, the script also tests this behavior by signing test data, which is hashed using SHA-256.

So, without further ado, let's get more in-depth!

GitHub Repository

Elliptic Curve Cryptography

[Image 2]

Let's first get into what ECDSA is. An elliptic curve digital signature algorithm uses elliptic curve cryptography, which creates private and public keys (asymmetric cryptography) with very high security. From a randomly chosen point in the curve, the private key, one computes a public key. And so, in order to prove that some kind of message has been sent by the correct person, the sender signs the message using the private key, and the receiver then verifies the signature using the public key. The actual math behind these calculations is quite complicated and not necessary to known and understand completely, as many open-source libraries, such as Python's ecdsa package are available.

Various curves can be used, and Bitcoin, Ethereum and other widely known crypto-currencies and blockchains, tend to use 256-bit keys. In my implementation I chose the SECP256k1 curve, which is also used by Bitcoin.

So, in the notion of transactions, such signatures are used in order to verify that the sender is truly the sender. This is easy to implement, even when the address is a hash of the public key. In my implementation the steps of the transaction poster are:

  1. Include sender address in transaction info
  2. Calculate the transaction hash
  3. Sign that hash using the private key
whilst the validator simply has to:
  1. Extract the public keys from the signature and transaction hash
  2. Verify the signature using each public key
  3. Check if the hash of the public key(s) is equal to the sender address

Yes, it's truly possible to calculate the public key from the signature and information that was hashed. The address is simply used for "humanizing" the whole transaction procedure. Its easier to write down 40 hexadecimal characters then 100 or even more. The "safety" part is that the private key can't be derived from the public key, which is also why elliptic curves are used, instead of more simplistic DSA algorithms.

Wallet and Keys

The wallet is again defined as class, with corresponding JSON format, which includes:

  1. private key : random number generated using mnemonic seed phrase
  2. public key : derived from private key
  3. address : hash and trim of the public key
By default, each client stores this information in the "wallet.json" file.

For the seed phrase, the mnemonic package is used, which uses the BIP0039 word list. The mnemonic seed is then used as a seed for a secure random number generator (ecdsa's PRNG), and using the SigningKey class from the ecdsa package, and that secure random number as an entropy, the private key is generated. From the private key its then possible to extract the VerifyingKey, which is the public key. And that public key is then hashed using SHA-256 from the common hashlib package, trimmed to 20 bytes, leading to the address.

For the JSON format, the binascii package is used, for hexifying and unhexifying. That way, using the to_string() method of each of the Key classes, its possible to turn the key into "writable" and "readable" format, for later on.

For example, from the seed phrase:

mother general avocado south void beyond cart trumpet aunt
below milk drive cousin awesome pink toss gaze square
the following "wallet.json" file is created:
    "private_key": "f39d4408452b1acc7b92a950d9fbb17ccefe727a8a84dfd327437c62d9a39229",
    "public_key": "fa0942a6311a183a30e2dc9c0de59d14593237f435c297ed35ccfc70428d21132ed4cb77e4db1d48164ea3fa6b474786de2f27e6d4ae35f4ec2918a0983bb479",
    "address": "0x983c17900b103b6c4b8e548b72442c3c35a8942e"

Signature and Verification

The signature calculation part is easy-peasy. We simply use the sign() method of the corresponding private key on the data to-be-hashed, as follows:

signature = json_retrieve_private_key(wallet_json).sign(hash)
Afterwards, the verification of the signature, can be done by simply calling the verify_signature() function:
if verify_signature(signature, hash, address):
which in turn recovers/extracts the public keys from the signature and hash, verifies the signature, and afterwards checks if the address matches. Returning True or False correspondingly.





The rest is screenshots or made using

Previous dev blogs of the series

Final words | Next up

And this is actually it for today's post!

Next up, on my to-do list, is calling the signature verification function within the transaction endpoint callbacks. That way, the transaction sender will be verified, before adding the transaction to the unconfirmed transaction list! And then, we will have to get into some form of UTXO structure (unspent transaction output), so that it's easy to keep track of the balance that each address has available. The block reward, might also be a little challenging, as the sender will have to be the block id, or something. But, at that point we might already have replaced the sender and receiver fields with actual input and output locking scripts (as they are called). Either way, expect the next Dev Blog to be interesting as well!

I will keep you posted on my journey! Expect such articles to come out weekly, or even twice a week, until I'm finished!

Keep on drifting!

3 columns
2 columns
1 column
1 Comment