Seems like a waste of time to use random BIP words, as the seed word generation process involves checks, and many randomly generated combinations will be invalid.
Plus, even with a list of valid word combinations, it's a fools game in terms of odds.
That may be the case but what about weak seeds I also think the use of the script below might be helpful?
Hmm... what's the point of throwing randomly selected word sets at your address checker? The chances of matching a 12 word passphrase are essentially zero.
I think your size calcs may be off a bit, too. I pre-calculated the RMD160 values for all ASCII 1 to 5 character words, and the output is about 0.9TB in size. To increase to 6 characters would result in a file size about 95 times that (about 80TB) and to go up to 7 characters would result in an output of over 7000TB. And consider the amount of time needed to check 135 trillion entries.
That's one of the interesting things about SHA256 brainwallets (so long as you're doing this for fun) : it can be easy to find them, but it's also very, very hard.

As for the tables sizes I think they are about right to be honest they are not hash160's they are raw hex combinations
see below I have tested on the smaller value ones at the come out pretty close to the figures quoted. So the DB for this type of data is vast.
I am currently at around block 259090 of importing all the transactions into mysql database ( Currently 3 days reading from blk files)
Combination data from 10Hex ./10hex | brainflayer -v -b example.blf
https://github.com/wpatoolkit/10-Hex-Generator
010316ead1
010316ead2
010316ead3
010316ead4
010316ead5
010316ead6
010316ead7
010316ead8
010316ead9
010316eada
010316eadb
010316eadc
010316eadd
010316eade
010316eadf
010316eae0
010316eae1
010316eae2
010316eae3
010316eae4
010316eae5
010316eae6
010316eae7
010316eae8
010316eae9
010316eaea
010316eaeb
010316eaec
010316eaed
010316eaee
010316eaef
010316eaf0
010316eaf1
010316eaf2
010316eaf3
010316eaf4
010316eaf5
010316eaf6
010316eaf7
010316eaf8
010316eaf9
010316eafa
010316eafb
010316eafc
010316eafd
010316eafe
010316eaff
010316eb01
010316eb02
010316eb03
010316eb04
010316eb05
010316eb06
010316eb07
010316eb08
010316eb09
010316eb0a
010316eb0b
010316eb0c
010316eb0d
010316eb0e
010316eb0f
010316eb10
after setting up ABE it is far quicker at checking against the database for balance than my previous method of API calls to Blockchain.com
def mn_encode( message ):
out = []
for i in range(len(message)/8):
word = message[8*i:8*i+8]
x = int(word, 16)
w1 = (x%n)
w2 = ((x/n) + w1)%n
w3 = ((x/n/n) + w2)%n
out += [ words[w1], words[w2], words[w3] ]
return out
def mn_decode( wlist ):
out = ''
for i in range(len(wlist)/3):
word1, word2, word3 = wlist[3*i:3*i+3]
w1 = words.index(word1)
w2 = (words.index(word2))%n
w3 = (words.index(word3))%n
x = w1 +n*((w2-w1)%n) +n*n*((w3-w2)%n)
out += '%08x'%x
return out
def stretch_key(seed):
oldseed = seed
for i in range(100000):
seed = hashlib.sha256(seed + oldseed).digest()
return string_to_number( seed )
def mpk_from_seed(seed):
curve = SECP256k1
secexp = stretch_key(seed)
master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
master_public_key = master_private_key.get_verifying_key().to_string().encode('hex')
return master_public_key
class Account(object):
def __init__(self, v):
self.addresses = v.get('0', [])
self.change = v.get('1', [])
def dump(self):
return {'0':self.addresses, '1':self.change}
def get_addresses(self, for_change):
return self.change[:] if for_change else self.addresses[:]
def create_new_address(self, for_change):
addresses = self.change if for_change else self.addresses
n = len(addresses)
address = self.get_address( for_change, n)
addresses.append(address)
return address
def get_address(self, for_change, n):
pass
def get_pubkeys(self, sequence):
return [ self.get_pubkey( *sequence )]
class OldAccount(Account):
""" Privatekey(type,n) = Master_private_key + H(n|S|type) """
def __init__(self, v):
self.addresses = v.get(0, [])
self.change = v.get(1, [])
self.mpk = v['mpk'].decode('hex')
def dump(self):
return {0:self.addresses, 1:self.change}
@classmethod
def mpk_from_seed(klass, seed):
curve = SECP256k1
secexp = klass.stretch_key(seed)
master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
master_public_key = master_private_key.get_verifying_key().to_string().encode('hex')
return master_public_key
@classmethod
def stretch_key(self,seed):
oldseed = seed
for i in range(100000):
seed = hashlib.sha256(seed + oldseed).digest()
return string_to_number( seed )
def get_sequence(self, for_change, n):
return string_to_number( Hash( "%d:%d:"%(n,for_change) + self.mpk ) )
def get_address(self, for_change, n):
pubkey = self.get_pubkey(for_change, n)
address = public_key_to_bc_address( pubkey.decode('hex') )
return address
def get_pubkey(self, for_change, n):
curve = SECP256k1
mpk = self.mpk
z = self.get_sequence(for_change, n)
master_public_key = ecdsa.VerifyingKey.from_string( mpk, curve = SECP256k1 )
pubkey_point = master_public_key.pubkey.point + z*curve.generator
public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 )
return '04' + public_key2.to_string().encode('hex')
def get_private_key_from_stretched_exponent(self, for_change, n, secexp):
order = generator_secp256k1.order()
secexp = ( secexp + self.get_sequence(for_change, n) ) % order
pk = number_to_string( secexp, generator_secp256k1.order() )
compressed = False
return SecretToASecret( pk, compressed )
def get_private_key(self, seed, sequence):
for_change, n = sequence
secexp = self.stretch_key(seed)
return self.get_private_key_from_stretched_exponent(for_change, n, secexp)
def check_seed(self, seed):
curve = SECP256k1
secexp = self.stretch_key(seed)
master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
master_public_key = master_private_key.get_verifying_key().to_string().encode('hex')
if master_public_key != self.mpk:
print_error('invalid password (mpk)')
raise BaseException('Invalid password')
return True
def redeem_script(self, sequence):
return None
def b58encode(v):
""" encode v, which is a string of bytes, to base58."""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += (256**i) * ord(c)
result = ''
while long_value >= __b58base:
div, mod = divmod(long_value, __b58base)
result = __b58chars[mod] + result
long_value = div
result = __b58chars[long_value] + result
# Bitcoin does a little leading-zero-compression:
# leading 0-bytes in the input become leading-1s
nPad = 0
for c in v:
if c == '\0': nPad += 1
else: break
return (__b58chars[0]*nPad) + result
def b58decode(v, length):
""" decode v into a string of len bytes."""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += __b58chars.find(c) * (__b58base**i)
result = ''
while long_value >= 256:
div, mod = divmod(long_value, 256)
result = chr(mod) + result
long_value = div
result = chr(long_value) + result
nPad = 0
for c in v:
if c == __b58chars[0]: nPad += 1
else: break
result = chr(0)*nPad + result
if length is not None and len(result) != length:
return None
return result
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)
def EncodeBase58Check(vchIn):
hash = Hash(vchIn)
return b58encode(vchIn + hash[0:4])
def DecodeBase58Check(psz):
vchRet = b58decode(psz, None)
key = vchRet[0:-4]
csum = vchRet[-4:]
hash = Hash(key)
cs32 = hash[0:4]
if cs32 != csum:
return None
else:
return key
def public_key_to_bc_address(public_key):
h160 = hash_160(public_key)
return hash_160_to_bc_address(h160)
def hash_160(public_key):
try:
md = hashlib.new('ripemd160')
md.update(hashlib.sha256(public_key).digest())
return md.digest()
except:
import ripemd
md = ripemd.new(hashlib.sha256(public_key).digest())
return md.digest()
def hash_160_to_bc_address(h160, addrtype = 0):
vh160 = chr(addrtype) + h160
h = Hash(vh160)
addr = vh160 + h[0:4]
return b58encode(addr)
mnemonic_hash = lambda x: hmac_sha_512("Bitcoin mnemonic", x).encode('hex')
hmac_sha_512 = lambda x,y: hmac.new(x, y, hashlib.sha512).digest()
Hash = lambda x: hashlib.sha256(hashlib.sha256(x).digest()).digest()
def hack(t, d):
while True:
guess = random.sample(words,12)
#guess = "shirt always flat become bird company everytime poet least soar crack story".split()
#print guess
seed = mn_decode(guess)
mpk = OldAccount.mpk_from_seed(seed)
acc = OldAccount({'mpk':mpk, 0:[], 1:[]})
#pk = number_to_string( secexp, generator_secp256k1.order() )
#compressed = False
# SecretToASecret( pk, compressed )
addy = acc.create_new_address(False)
myurl = "http://localhost:2750/chain/Bitcoin/q/getreceivedbyaddress/" + addy
f = urllib.urlopen(myurl)
balance = f.read()
print balance + ": " + addy
if balance != "0":
with open("addresses.txt", "a+") as myfile:
myfile.write(balance + ": " + addy + "\t" + seed + "\n")