Faster and cleaner SHA-1 leading zero histogram with Python I've written a python code for finding the distribution of the leading zeros of SHA-1. Using random inputs and hashing-then-counting. Normally it is expected to fit the n/2^i curve where n is the number of trials. After this, a plot is drawn.
import hashlib
import random
import matplotlib.pyplot as plt

leading = [0] * 160

trials = 10000000000

for i in range(trials):
    
    randomInput= random.getrandbits(128)
    
    hasvalue = hashlib.sha1(str(randomInput).encode('ASCII')).hexdigest()

    b = bin(int(hasvalue, 16))
    c= b[2:].zfill(160)
    zeroes = str(c).index('1')
    leading[zeroes] = leading[zeroes] + 1

The most time-consuming part of this code is of course the SHA-1 calculation and we cannot do something for that except parallelization with pymp or some other library. What I'm not mostly unhappy here is the whole conversions between str, bin and back.
Any improvements for a cleaner code and little speed up?
Instead of str(random.getrandbits(128)).encode('ASCII') I'd use os.urandom(16). Much simpler, ought to be more random, shorter result, and a bit faster (at least for me). Or convert your random number to bytes directly, even faster (at least for me):
&gt;&gt;&gt; timeit(lambda: str(random.getrandbits(128)).encode('ASCII'))
1.320366100000001
&gt;&gt;&gt; timeit(lambda: os.urandom(16))
0.7796178000000111
&gt;&gt;&gt; timeit(lambda: random.getrandbits(128).to_bytes(16, 'big'))
0.6476696999999945

From the doc:

os.urandom(size)
Return a string of size random bytes suitable for cryptographic use.

And to count zeros, perhaps use digest(), make an int from it and ask for its bit length:
    hashvalue = hashlib.sha1(os.urandom(16)).digest()
    i = int.from_bytes(hashvalue, 'big')
    zeroes = 160 - i.bit_length()

Benchmark results (numbers are times, so lower=faster):
0.56 zeroes_you
0.31 zeroes_me
0.29 zeroes_me2
0.26 zeroes_me3

0.60 zeroes_you
0.31 zeroes_me
0.28 zeroes_me2
0.24 zeroes_me3

0.57 zeroes_you
0.31 zeroes_me
0.28 zeroes_me2
0.24 zeroes_me3

Benchmark code:
import hashlib
import random
import os
from timeit import repeat

def zeroes_you():
    randomInput= random.getrandbits(128)
    hashvalue = hashlib.sha1(str(randomInput).encode('ASCII')).hexdigest()
    b = bin(int(hashvalue, 16))
    c= b[2:].zfill(160)
    zeroes = str(c).index('1')

def zeroes_me():
    hashvalue = hashlib.sha1(os.urandom(16)).digest()
    i = int.from_bytes(hashvalue, 'big')
    zeroes = 160 - i.bit_length()

def zeroes_me2():
    randomInput = random.getrandbits(128)
    hashvalue = hashlib.sha1(randomInput.to_bytes(16, 'big')).digest()
    i = int.from_bytes(hashvalue, 'big')
    zeroes = 160 - i.bit_length()
    
def zeroes_me3(randbits=random.getrandbits, sha1=hashlib.sha1, int_from_bytes=int.from_bytes):
    hashvalue = sha1(randbits(128).to_bytes(16, 'big')).digest()
    zeroes = 160 - int_from_bytes(hashvalue, 'big').bit_length()

for _ in range(3):
    for zeroes in zeroes_you, zeroes_me, zeroes_me2, zeroes_me3:
        t = min(repeat(zeroes, number=100000))
        print('%.2f' % t, zeroes.__name__)
    print()