1
0

Provide warnings about invalid BIP39 checksum in seed dialog

This commit is contained in:
Kacper Żuk
2017-01-22 15:58:37 +01:00
committed by ThomasV
parent 8b194cd409
commit c6e09a6038
4 changed files with 60 additions and 16 deletions

View File

@@ -24,6 +24,7 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import struct
from unicodedata import normalize
@@ -35,7 +36,7 @@ from bitcoin import *
from bitcoin import is_old_seed, is_new_seed, is_seed
from util import PrintError, InvalidPassword
from mnemonic import Mnemonic
from mnemonic import Mnemonic, load_wordlist
class KeyStore(PrintError):
@@ -555,7 +556,34 @@ def bip39_to_seed(mnemonic, passphrase):
iterations = PBKDF2_ROUNDS, macmodule = hmac,
digestmodule = hashlib.sha512).read(64)
# returns tuple (is_checksum_valid, is_wordlist_valid)
def bip39_is_checksum_valid(mnemonic):
words = [ normalize('NFKD', word) for word in mnemonic.split() ]
words_len = len(words)
wordlist = load_wordlist("english.txt")
n = len(wordlist)
checksum_length = 11*words_len//33
entropy_length = 32*checksum_length
i = 0
words.reverse()
while words:
w = words.pop()
try:
k = wordlist.index(w)
except ValueError:
return False, False
i = i*n + k
if words_len not in [12, 15, 18, 21, 24]:
return False, True
entropy = i >> checksum_length
checksum = i % 2**checksum_length
h = '{:x}'.format(entropy)
while len(h) < entropy_length/4:
h = '0'+h
b = bytearray.fromhex(h)
hashed = int(hashlib.sha256(b).digest().encode('hex'), 16)
calculated_checksum = hashed >> (256 - checksum_length)
return checksum == calculated_checksum, True
# extended pubkeys

View File

@@ -91,6 +91,20 @@ def normalize_text(seed):
seed = u''.join([seed[i] for i in range(len(seed)) if not (seed[i] in string.whitespace and is_CJK(seed[i-1]) and is_CJK(seed[i+1]))])
return seed
def load_wordlist(filename):
path = os.path.join(os.path.dirname(__file__), 'wordlist', filename)
s = open(path,'r').read().strip()
s = unicodedata.normalize('NFKD', s.decode('utf8'))
lines = s.split('\n')
wordlist = []
for line in lines:
line = line.split('#')[0]
line = line.strip(' \r')
assert ' ' not in line
if line:
wordlist.append(line)
return wordlist
filenames = {
'en':'english.txt',
@@ -110,17 +124,7 @@ class Mnemonic(object):
lang = lang or 'en'
print_error('language', lang)
filename = filenames.get(lang[0:2], 'english.txt')
path = os.path.join(os.path.dirname(__file__), 'wordlist', filename)
s = open(path,'r').read().strip()
s = unicodedata.normalize('NFKD', s.decode('utf8'))
lines = s.split('\n')
self.wordlist = []
for line in lines:
line = line.split('#')[0]
line = line.strip(' \r')
assert ' ' not in line
if line:
self.wordlist.append(line)
self.wordlist = load_wordlist(filename)
print_error("wordlist has %d words"%len(self.wordlist))
@classmethod

View File

@@ -1,4 +1,5 @@
import unittest
from lib import keystore
from lib import mnemonic
from lib import old_mnemonic
@@ -27,3 +28,11 @@ class Test_OldMnemonic(unittest.TestCase):
words = 'hardly point goal hallway patience key stone difference ready caught listen fact'
self.assertEquals(result, words.split())
self.assertEquals(old_mnemonic.mn_decode(result), seed)
class Test_BIP39Checksum(unittest.TestCase):
def test(self):
mnemonic = u'gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog'
is_checksum_valid, is_wordlist_valid = keystore.bip39_is_checksum_valid(mnemonic)
self.assertTrue(is_wordlist_valid)
self.assertTrue(is_checksum_valid)