SHA-256 in Bash and Python – A speed comparison

When experimenting with generating Bitcoin private key and public address pairs, also widely known as brainwallet cracking (which is a subject that we will revisit many times), what you do is computing SHA-256 hashes of words, passwords or passphrases. You then take the hashes, which are conveniently 64 character hexadecimal strings (32 bytes or 256 bits, if you will), and convert them to Bitcoin private keys and their corresponding public addresses. Then you look up the public addresses on the blockchain, and if you are lucky you will get a few hits.

An infamous example is (not discovered by us, we will report our private findings in due time):

SHA256(“The quick brown fox jumps over the lazy dog”):
d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592

Bitcoin Private Key Uncompressed:
5KTGL3GhKP1bw4mePbdbgHJsRBtMJLb8yj9gw9FDV6cA5bAfhis

Bitcoin Public Legacy Address:
13w4Hn1BJQM4bjZZgYtXpyp4cioiw29tKj

As you can see on the blockchain, this public address has received more than 10 BTC. Should it be funded again, you now have its private key!

No but seriously… In order to engage in these endeavors, you will need to test hashes of large wordlists (and for any realistic chance, lists that no one else has access to). Let’s begin with downloading a list of nearly 470 thousand English words (about 4.6 MB). In your root folder, type:

wget https://github.com/dwyl/english-words/raw/master/words.txt

Good, you now have a wordlist called “words.txt” to work with. It should be exactly 466,551 lines (you can count the lines of a text file with the “wc -l filename” command), and contain:

2
1080
&c
10-point
10th



Zwolle
Zworykin
ZZ
zZt
ZZZ

Let’s move on and create two separate scripts, one in Bash and one in Python, that produce the exact same outputs.

Here is the Bash script – copy and save it as “sha256-bash”

#!/usr/bin/env bash
#Reads a file line by line and outputs the corresponding SHA-256 hashes

if [ -z "$1" ]; then
  echo "Error: No input file specified"
else
  while IFS= read -r line; do
    line=$(echo -n "$line" | tr -d '\r\n' | sha256sum | cut -c1-64)
    echo "$line"
  done < "$1"
fi

And here is the Python script – copy and save it as “sha256-python”

#!/usr/bin/env python3
#Reads a file line by line and outputs the corresponding SHA-256 hashes

import sys, hashlib

try:
  filename=sys.argv[1]
except IndexError:
  print('Error: No input file specified')
  sys.exit()

f = open(filename, 'r')

for line in f:
  line = line.replace('\n', '').replace('\r', '')
  sha256 = hashlib.sha256(line.encode('utf-8')).hexdigest()
  print(sha256)

They should be straightforward and quite self-explicatory. As usual, make these executable by running

chmod +x sha256-bash
chmod +x sha256-python

Great, now we have all in place to get to work. Let’s begin with the Python script. Also, bring in the “time” command, so we know how long the operation takes. We will pipe the output to “hashes.txt”. In other words, run:

time ./sha256-python words.txt > hashes-python.txt

How long did it take you to calculate are print out almost 470,000 lines of hashes? On my several-year-old notebook (4 cores, 8 GB RAM) it took 1.4 seconds. Not too shabby! How do you think Bash will do? Try:

time ./sha256-bash words.txt > hashes-bash.txt

I suggest you go make yourself a cup of coffee or something and then take out the trash while waiting for it to finish. My computer needed 21 minutes and 22 seconds to finish.

The content of the output files should be

d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35
32eb1a8dafeb0873c8d00b0e9058c8c77ff6c6d9235b3236989c50ef63d8f9ba
ef9d5f1f8123b6c9e371d37a328ba389b8d8955b37b7cf39a5446e1e3bdd6fe1
08626fa4ca073e17c263e237fe04ed7e1ca311c966b8d61a18c802cf976058ff
3d303171e2763bc5e53e750aa5598d4a2dd621c34f9d6a6db9158b13a46cc7d4



0b342d4000b457f7a0d63ae650dd8caa1564da1190d61d2d3769f25d8641e788
a3579ea3ad3d6943f02f50cdddafafb58914b3a84cf3ba0d5edd756e21fd3c02
099987a5188a32ab07b68b4219a824bb83bfcc10aca0fd4f58e41c99b37f09f9
b0071add61042e80272f694173dcf17390014cf5eb3f52f9a20ab21193f59fa0
71f3e86c42376ed1c9583f0117fad889f5139926594992b3f573e17939cb038f

For perfection, let’s verify that the two output files are bit-by-bit identical, run (hint: save this command somewhere, it is fast and useful)

cmp -s hashes-python.txt hashes-bash.txt && echo 'SUCCESS: Files are identical' || echo 'WARNING: Files not identical'

which will result in “SUCCESS: Files are identical”. Good.

Let’s do some numbers. 21 minutes is 21*60 = 1260 + 22 = 1288 seconds. And 1288 / 1.4 = 920

What have we learned here? Well, in conclusion, we have shown that file processing and hash calculations are almost 1,000 times faster in Python than in Bash. I’d say we have a very clear winner. The moral of the story is that for batch processing, you have to master Python. Or you will die of a coffee overdose while waiting for your Bash scripts to complete.

Python it is!

Comments or questions?

One more thing!

Consider the donation address at the bottom of the page. We re-invest all contributions into new projects for btcleak.com. Help us create new content and remain ad-free forever. Thank you.

Leave a Reply

Your email address will not be published.