Skip to content

Commit 99143cf

Browse files
committed
Added bip039 functionality. Not tested yet
1 parent e7b2b74 commit 99143cf

File tree

1 file changed

+45
-19
lines changed

1 file changed

+45
-19
lines changed

bitcoin/bip39.py

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
11
import hashlib
22
import os.path
3-
from bisect import bisect_right,bisect_left
4-
5-
wordlist_english=list(open(os.path.join(os.path.dirpath(__file__),'english.txt'),'r'))
3+
from bisect import bisect_left
64

5+
wordlist_english=list(open(os.path.join(os.path.dirpath(os.path.realpath(__file__)),'english.txt'),'r'))
6+
def _eint_to_bytes(entint,entbits):
7+
return binascii.unhexlify(hex(entint)[2:].zfill(entbits//4).rstrip("L"))
8+
79
def entropy_cs(entbytes):
810
entropy_size=8*len(entbytes)
911
checksum_size=entropy_size//32
1012
hd=hashlib.sha256(entbytes).hexdigest()
1113
csint=int(hd,16) >> (256-checksum_size)
1214
return csint,checksum_size
1315

16+
def mnemonic_int_to_words(mint,mint_num_words,wordlist=wordlist_english):
17+
backwords=[wordlist[(mint >> (11*x)) & 0x7FF].strip() for x in range(mint_num_words)]
18+
return backwords[::-1]
19+
1420
def entropy_to_words(entbytes,wordlist=wordlist_english):
21+
if(len(entbytes) < 4 || len(entbytes) % 4 != 0):
22+
raise ValueError("The size of the entropy must be a multiple of 4 bytes (multiple of 32 bits)")
1523
entropy_size=8*len(entbytes)
1624
csint,checksum_size = entropy_cs(entbytes)
1725

1826
mint=(entint << checksum_size) | csint
19-
mnemonic_size=(entropy_size+checksum_size)/11
20-
21-
backwords=[wordlist[(seedint >> (11*x)) & 0x7FF].strip() for x in range(seedsize)]
22-
return reversed(backwords)
23-
24-
25-
#def words_to_seed(words,wordlist=wordlist_english):
27+
mint_num_words=(entropy_size+checksum_size)//11
2628

29+
return mnemonic_int_to_words(mint,mint_num_words,wordlist)
2730

2831
def words_bisect(word,wordlist=wordlist_english):
2932
lo=bisect_left(wordlist,word)
30-
hi=lo
31-
lw=len(word)
32-
while(wordlist[hi][:lw]==word):
33-
hi+=1
33+
hi=len(wordlist)-bisect_left(wordlist[:lo:-1],word)
3434

3535
return lo,hi
3636

3737
def words_split(wordstr,wordlist=wordlist_english):
3838
def popword(wordstr,wordlist):
3939
for fwl in range(1,9):
40-
w=wordstr[:fwl]
40+
w=wordstr[:fwl].strip()
4141
lo,hi=words_bisect(w,wordlist)
4242
if(hi-lo == 1):
43-
return w,wordstr[fwl:]
43+
return w,wordstr[fwl:].lstrip()
4444
wordlist=wordlist[lo:hi]
4545
raise Exception("Wordstr %s not found in list" %(w))
4646

@@ -51,7 +51,33 @@ def popword(wordstr,wordlist):
5151
words.append(head)
5252
return words
5353

54-
def words_verify(words):
55-
pass
56-
#if words in string, split them first.
54+
def words_to_mnemonic_int(words,wordlist=wordlist_english):
55+
if(instance(words,str)):
56+
words=words_split(words,wordlist)
57+
return sum([wordlist.index(w) << (11*x) for x,w in enumerate(words[::-1])])
58+
59+
def words_verify(words,wordlist=wordlist_english):
60+
if(isinstance(words,str)):
61+
words=words_split(words,wordlist)
5762

63+
mint = words_to_mnemonic_int(words,wordlist)
64+
mint_bits=len(words)*11
65+
cs_bits=mint_bits//32
66+
entropy_bits=mint_bits-cs_bits
67+
eint=mint >> cs_bits
68+
csint=mint & ((1 << cs_bits)-1)
69+
ebytes=_eint_to_bytes(eint,entropy_bits)
70+
return csint == entropy_cs(ebytes)
71+
72+
def mnemonic_to_seed(mnemonic_phrase,passphrase=""):
73+
try:
74+
from hashlib import pbkdf2_hmac
75+
def pbkdf2_hmac_sha256(password,salt,iters=2048):
76+
return pbkdf2_hmac(name='sha512',password=password,salt=salt,iters)
77+
except:
78+
from Crypto.Protocol.KDF import PBKDF2
79+
from Crypto.Hash import SHA512,HMAC
80+
81+
def pbkdf2_hmac_sha256(password,salt,iters=2048):
82+
return PBKDF2(password=password,salt=salt,dkLen=64,count=iters,prf:lambda p,s: HMAC.new(p,s,SHA512).digest())
83+
return pbkdf2_hmac_sha256(password=mnemonic_phrase,salt="mnemonic"+passphrase)

0 commit comments

Comments
 (0)