Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 18 additions & 23 deletions ngu/bip39.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@


def get_word_index(word):
"input string word; return int index in wordlist, or ValueError"
# input string word; return int index in wordlist, or ValueError
# - also accepts just first four distinctive characters of the word

try:
Expand All @@ -316,7 +316,7 @@ def get_word_index(word):


def b2a_words(msg):
"map binary to words, including a few bits of checksum, per BIP39 spec"
# map binary to words, including a few bits of checksum, per BIP39 spec
l = len(msg)
assert 16 <= l <= 32
assert l % 4 == 0
Expand Down Expand Up @@ -345,7 +345,7 @@ def b2a_words(msg):


def _split_lookup(phrase):
"decode & lookup only"
# decode & lookup only

if isinstance(phrase, str):
phrase = phrase.split()
Expand All @@ -360,7 +360,7 @@ def _split_lookup(phrase):
return num, rv

def a2b_words(phrase):
"decode, raise on bad checksum"
# decode, raise on bad checksum

num, rv = _split_lookup(phrase)

Expand All @@ -382,7 +382,7 @@ def a2b_words(phrase):
return bits

def a2b_words_guess(phrase):
"generate a list of possible final words"
# generate a list of possible final words
num, rv = _split_lookup(phrase)

if num not in { 11, 14, 17, 20, 23 }:
Expand All @@ -409,30 +409,25 @@ def next_char(prefix):
assert pl >= 1

try:
wn = wordlist_en.index(prefix)
if pl >= 4:
return (True, '', wordlist_en[wn])
exact = True
except ValueError:
exact = False
# skip down until first 1-2 char(s) match
try:
wn = _lookup[prefix[0:2]]
except KeyError:
# 2-prefix not in list
return (False, '', None)
wn = _lookup[prefix[0:2]]
except KeyError:
# prefix not in the _lookup list
return False, '', None

first = None
count = 0

exact = False
chars = []
for wn in range(wn, 0x800):
word = wordlist_en[wn]
if word[0:pl] > prefix: break
if word[0:pl] == prefix:
wc = word[0:pl]
if wc > prefix: break # lexicographical ordering
if wc == prefix:
if word == prefix:
exact = True
if pl >= 4:
# they gave 4+ letter prefix of correct word; they're done
return (True, '', word)
return True, '', word

if not count:
first = word
Expand All @@ -452,6 +447,6 @@ def master_secret(words, pw=b''):
import ngu
return ngu.hash.pbkdf2_sha512(words, salt, 2048)
except ImportError:
import wallycore
return wallycore.pbkdf2_hmac_sha512(words, salt, 0, 2048)
import hashlib
return hashlib.pbkdf2_hmac("sha512", words, salt, 2048, dklen=64)

3 changes: 3 additions & 0 deletions ngu/ngu_tests/test_bip39.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,13 @@ def test_prefix():
assert bip39.next_char('dkfjh') == (False, '', None)
assert bip39.next_char('a') == (False, 'bcdefghilmnprstuvwx', None)
assert bip39.next_char('q') == (False, 'u', None)
assert bip39.next_char('x') == (False, '', None) # only char not in the _lookup
assert bip39.next_char('qu') == (False, 'aeio', None)
assert bip39.next_char('present') == (True, '', 'present')
assert bip39.next_char('zoo') == (True, '', 'zoo')
assert bip39.next_char('zo') == (False, 'no', None)
assert bip39.next_char('fat') == (True, 'ahi', None)
assert bip39.next_char('win') == (True, 'degknt', None)

wl = bip39.wordlist_en
for w in wl:
Expand Down