Skip to content

Instantly share code, notes, and snippets.

@ZenulAbidin
Last active December 31, 2021 08:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ZenulAbidin/ac00845048c36ceb81df6bc47cbcb4e5 to your computer and use it in GitHub Desktop.
Save ZenulAbidin/ac00845048c36ceb81df6bc47cbcb4e5 to your computer and use it in GitHub Desktop.
Birthday problem but applied to randomly generated OpenSSL keys.
# First, run this in shell:
# j=1000 # Sample size, feel free to change.
# for ((i=0; $i<$j; i++)); do openssl rand -hex 32 >> ~/Documents/randalysis.txt; echo -en "\n" >> ~/Documents/randalysis.txt; done
# sed -i '/^\s*$/d' ~/Documents/randalysis.txt
# pip install bitarray
import bitarray
import bitarray.util
from os.path import expanduser
sample=1000 # This is the number of example private keys you have generated above.
nkeys = 260 # This is the number of keys you want, change it accordingly.
home = expanduser("~")
with open(home+"/Documents/randalysis.txt", "r") as fp:
s = fp.read()
l = s.split("\n")
l = l[:-1] # Remove extraneous blank element
cl = [0]*256
delta = [0]*256
# Values closer to zero - more likely to be zero, values closer to one - more likely to be one
for i in l:
ba = bitarray.util.hex2ba(i)
ba.reverse()
for j in range(0, 256):
cl[j] += ba[j]
delta[j] = cl[j]/sample
# Values negative - more likely to be zero, values positive - more likely to be one
# Because values will be between -0.5 and 0.5, we must "explode" this
# (by two to get values from -1 to 1)
# to get percentages between 0% and 100% for likely zero and likely one.
deltat = [((delta[t] - 0.5)*2, t) for t in range(0,256)]
deltat = sorted(deltat, key=lambda x: abs(x[0]), reverse=True)
#deltat.sort(key=lambda x: x[0])
#deltatmin = [t for t in deltat if t[0] < 0.5]
#deltatmax = [t for t in deltat if t[0] > 0.5]
#deltatmax.sort(key=lambda x: x[0], reverse=True)
#deltateq = [t for t in deltat if t[0] == 0.5]
#delta = [d - 0.5 for d in delta]
import itertools
lz = []
# Adjust this value to return the combinations of probabilities for larger groups of bits.
# Warning: you should experiment with this setting, because setting this too high will
# make so many combinations, it will finish your RAM.
# Probability theory means that the probability of multiple bits having some specific values is
# __MUCH LESS__ than the probability of one bit having a aprticular value.
maxcomb = 2
for i in range(1,maxcomb+1):
cdt = itertools.combinations(deltat, i)
for c in cdt:
total_prob = 1
bit_configs = []
for it in c:
if it[0] < 0:
# Zero
bit_configs.append((it[1], 0))
elif it[0] < 1:
# One
bit_configs.append((it[1], 1))
else:
# perfectly even, no bias here so skip to next one
continue
total_prob *= abs(it[0])
lz.append((total_prob*100, bit_configs))
lz.sort(key = lambda x: x[0], reverse=True)
import pprint
print("========== TOP {} MOST LIKELY BIT CONFIGURATIONS (Highest probability first) ==========".format(nkeys))
print("Output format: <probability> [(<bit number between 0-255>, <0 or 1>), ...]")
pprint.pprint(lz[0:nkeys])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment