Tag Archives: benchmark

Python HashMark

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.

Logic.