1import hashlib 2import os.path 3import binascii 4import random 5from bisect import bisect_left 6 7wordlist_english=list(open(os.path.join(os.path.dirname(os.path.realpath(__file__)),'english.txt'),'r')) 8 9def eint_to_bytes(entint,entbits): 10 a=hex(entint)[2:].rstrip('L').zfill(32) 11 print(a) 12 return binascii.unhexlify(a) 13 14def mnemonic_int_to_words(mint,mint_num_words,wordlist=wordlist_english): 15 backwords=[wordlist[(mint >> (11*x)) & 0x7FF].strip() for x in range(mint_num_words)] 16 return backwords[::-1] 17 18def entropy_cs(entbytes): 19 entropy_size=8*len(entbytes) 20 checksum_size=entropy_size//32 21 hd=hashlib.sha256(entbytes).hexdigest() 22 csint=int(hd,16) >> (256-checksum_size) 23 return csint,checksum_size 24 25def entropy_to_words(entbytes,wordlist=wordlist_english): 26 if(len(entbytes) < 4 or len(entbytes) % 4 != 0): 27 raise ValueError("The size of the entropy must be a multiple of 4 bytes (multiple of 32 bits)") 28 entropy_size=8*len(entbytes) 29 csint,checksum_size = entropy_cs(entbytes) 30 entint=int(binascii.hexlify(entbytes),16) 31 mint=(entint << checksum_size) | csint 32 mint_num_words=(entropy_size+checksum_size)//11 33 34 return mnemonic_int_to_words(mint,mint_num_words,wordlist) 35 36def words_bisect(word,wordlist=wordlist_english): 37 lo=bisect_left(wordlist,word) 38 hi=len(wordlist)-bisect_left(wordlist[:lo:-1],word) 39 40 return lo,hi 41 42def words_split(wordstr,wordlist=wordlist_english): 43 def popword(wordstr,wordlist): 44 for fwl in range(1,9): 45 w=wordstr[:fwl].strip() 46 lo,hi=words_bisect(w,wordlist) 47 if(hi-lo == 1): 48 return w,wordstr[fwl:].lstrip() 49 wordlist=wordlist[lo:hi] 50 raise Exception("Wordstr %s not found in list" %(w)) 51 52 words=[] 53 tail=wordstr 54 while(len(tail)): 55 head,tail=popword(tail,wordlist) 56 words.append(head) 57 return words 58 59def words_to_mnemonic_int(words,wordlist=wordlist_english): 60 if(instance(words,str)): 61 words=words_split(words,wordlist) 62 return sum([wordlist.index(w) << (11*x) for x,w in enumerate(words[::-1])]) 63 64def words_verify(words,wordlist=wordlist_english): 65 if(isinstance(words,str)): 66 words=words_split(words,wordlist) 67 68 mint = words_to_mnemonic_int(words,wordlist) 69 mint_bits=len(words)*11 70 cs_bits=mint_bits//32 71 entropy_bits=mint_bits-cs_bits 72 eint=mint >> cs_bits 73 csint=mint & ((1 << cs_bits)-1) 74 ebytes=_eint_to_bytes(eint,entropy_bits) 75 return csint == entropy_cs(ebytes) 76 77def mnemonic_to_seed(mnemonic_phrase,passphrase=u''): 78 try: 79 from hashlib import pbkdf2_hmac 80 def pbkdf2_hmac_sha256(password,salt,iters=2048): 81 return pbkdf2_hmac(hash_name='sha512',password=password,salt=salt,iterations=iters) 82 except: 83 try: 84 from Crypto.Protocol.KDF import PBKDF2 85 from Crypto.Hash import SHA512,HMAC 86 87 def pbkdf2_hmac_sha256(password,salt,iters=2048): 88 return PBKDF2(password=password,salt=salt,dkLen=64,count=iters,prf=lambda p,s: HMAC.new(p,s,SHA512).digest()) 89 except: 90 try: 91 92 from pbkdf2 import PBKDF2 93 import hmac 94 def pbkdf2_hmac_sha256(password,salt,iters=2048): 95 return PBKDF2(password,salt, iterations=iters, macmodule=hmac, digestmodule=hashlib.sha512).read(64) 96 except: 97 raise RuntimeError("No implementation of pbkdf2 was found!") 98 99 return pbkdf2_hmac_sha256(password=mnemonic_phrase,salt='mnemonic'+passphrase) 100 101def words_mine(prefix,entbits,satisfunction,wordlist=wordlist_english,randombits=random.getrandbits): 102 prefix_bits=len(prefix)*11 103 mine_bits=entbits-prefix_bits 104 pint=words_to_mnemonic_int(prefix,wordlist) 105 pint<<=mine_bits 106 dint=randombits(mine_bits) 107 count=0 108 while(not satisfunction(entropy_to_words(eint_to_bytes(pint+dint,entbits)))): 109 dint=randombits(mine_bits) 110 if((count & 0xFFFF) == 0): 111 print("Searched %f percent of the space" % (float(count)/float(1 << mine_bits))) 112 113 return entropy_to_words(eint_to_bytes(pint+dint,entbits)) 114 115if __name__=="__main__": 116 import json 117 testvectors=json.load(open('vectors.json','r')) 118 passed=True 119 for v in testvectors['english']: 120 ebytes=binascii.unhexlify(v[0]) 121 w=' '.join(entropy_to_words(ebytes)) 122 seed=mnemonic_to_seed(w,passphrase='TREZOR') 123 passed = passed and w==v[1] 124 passed = passed and binascii.hexlify(seed)==v[2] 125 print("Tests %s." % ("Passed" if passed else "Failed")) 126 127 128