Because I recently made a CRC-16 brute forcer, I’d like to know how fast Python really is when it comes to hashing. So I created a little benchmarking script which tries to create as many hashes as possible in a set amount of time – for all available algorithms.
Libraries used: tabulate (to print the results in a nice readable way)
import time import hashlib import sys from tabulate import tabulate deltaTime = 0.1 # Seconds hashPerSecond = dict() algorithms = hashlib.algorithms_available filteredAlgorithms = list() seen = set() seen.add("SHA") # Weird undocumented SHA algorithm for algorithm in algorithms: algorithmNormalized = algorithm.upper() if algorithmNormalized not in seen: filteredAlgorithms.append(algorithm) seen.add(algorithmNormalized) print ("HASHING BENCHMARK\n{0} available hashing algorithms will be tested for {1} seconds each".format(str(len(filteredAlgorithms)), str(deltaTime))) input("Press enter to start >") for algorithm in filteredAlgorithms: counter = 0 startTime = time.time() endTime = startTime + deltaTime print ("Testing {0}".format(algorithm.upper())) while (time.time() < endTime): h = hashlib.new(algorithm) h.update(b"Hello World!") h.digest() counter += 1 hashPerSecond[algorithm] = round(counter/deltaTime) algorithmsSorted = sorted(hashPerSecond, key=lambda key: hashPerSecond[key], reverse=True) output = list() for algorithm in algorithmsSorted: line = [algorithm.upper(), str(hashPerSecond[algorithm])] output.append(line) headers = ["Algorithm", "Hashes per second"] print (tabulate(output, headers, tablefmt="psql"))
As you can see, first I get all of the available algorithms. Because there are duplicates in the list, I filter the list. I have also removed an obscure ‘SHA’ algorithm which I couldn’t find documentation about and doesn’t give the same results as SHA1.
Then I iterate through all the rest and let them generate as many hashes as they can in ‘deltaTime’ seconds. I set it to a low value as setting is to higher values didn’t make much of a difference – the hashes per second stayed the ~same.
When done, I sort the results and generate some outputlines to feed tabulate with.
Example results:
HASHING BENCHMARK 14 available hashing algorithms will be tested for 0.1 seconds each Press enter to start > Testing RIPEMD160 Testing SHA1 Testing SHA224 Testing DSA Testing MD5 Testing MD4 Testing SHA256 Testing DSA-SHA Testing SHA512 Testing ECDSA-WITH-SHA1 Testing SHA384 Testing DSAENCRYPTION Testing WHIRLPOOL Testing DSAWITHSHA +-----------------+---------------------+ | Algorithm | Hashes per second | |-----------------+---------------------| | MD5 | 453440 | | MD4 | 449250 | | DSA | 433300 | | SHA1 | 429570 | | DSA-SHA | 425580 | | DSAWITHSHA | 424790 | | DSAENCRYPTION | 422710 | | ECDSA-WITH-SHA1 | 421060 | | SHA256 | 404070 | | SHA224 | 401780 | | RIPEMD160 | 396920 | | WHIRLPOOL | 360560 | | SHA384 | 349780 | | SHA512 | 349200 | +-----------------+---------------------+
So. Not that fast, really.
Let’s try again using PyPy – because it should be way quicker, right?
C:\Users\PiPro\pypy3-2.4.0-win32>pypy.exe "HashMark.py" Traceback (most recent call last): File "HashMark.py", line 4, in <module> from tabulate import tabulate ImportError: No module named tabulate
But …
HASHING BENCHMARK 14 available hashing algorithms will be tested for 0.1 seconds each Press enter to start > Testing SHA1 Testing SHA224 Testing SHA384 Testing ECDSA-WITH-SHA1 Testing SHA256 Testing SHA512 Testing MD4 Testing MD5 Testing DSAWITHSHA Testing DSA-SHA Testing DSAENCRYPTION Testing DSA Testing RIPEMD160 Testing WHIRLPOOL +-----------------+---------------------+ | Algorithm | Hashes per second | |-----------------+---------------------| | DSA-SHA | 144060 | | MD4 | 142910 | | SHA256 | 142660 | | ECDSA-WITH-SHA1 | 142200 | | DSAENCRYPTION | 141560 | | DSAWITHSHA | 140800 | | RIPEMD160 | 140050 | | SHA1 | 137250 | | MD5 | 133770 | | DSA | 129750 | | WHIRLPOOL | 126450 | | SHA512 | 123780 | | SHA384 | 119360 | | SHA224 | 116380 | +-----------------+---------------------+
Apparently that’s not the case. MD5 (the fastest when using regular Python) is ~3 times slower – and the fastest when using PyPy, DSA-SHA, is still ~3 times slower than the regular Python version.