Git Product home page Git Product logo

python-mnemonic's Introduction

python-mnemonic

image

Reference implementation of BIP-0039: Mnemonic code for generating deterministic keys

Abstract

This BIP describes the implementation of a mnemonic code or mnemonic sentence --a group of easy to remember words -- for the generation of deterministic wallets.

It consists of two parts: generating the mnenomic, and converting it into a binary seed. This seed can be later used to generate deterministic wallets using BIP-0032 or similar methods.

BIP Paper

See https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki for full specification

Installation

To install this library and its dependencies use:

pip install mnemonic

Usage examples

Import library into python project via:

from mnemonic import Mnemonic

Initialize class instance, picking from available dictionaries:

  • english
  • chinese_simplified
  • chinese_traditional
  • french
  • italian
  • japanese
  • korean
  • spanish
  • turkish
  • czech
  • portuguese
mnemo = Mnemonic(language)
mnemo = Mnemonic("english")

Generate word list given the strength (128 - 256):

words = mnemo.generate(strength=256)

Given the word list and custom passphrase (empty in example), generate seed:

seed = mnemo.to_seed(words, passphrase="")

Given the word list, calculate original entropy:

entropy = mnemo.to_entropy(words)

python-mnemonic's People

Contributors

admin-slush avatar bip39jp avatar fujicoin avatar funilrys avatar gavinshox avatar greenaddress avatar hegjon avatar hknylcnsy avatar hukkinj1 avatar junderw avatar kigawas avatar luciensong avatar lyndsysimon avatar matejcik avatar mikemacintire avatar mruddy avatar nglsena0722 avatar pabraksas avatar periodic1236 avatar pjkundert avatar posita avatar prusnak avatar salamzadeh avatar sasa-buklijas avatar strangework avatar tongokongo avatar willianpaixao avatar wmacevoy avatar yihuang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-mnemonic's Issues

Use scrypt for key stretching

Running HMAC 10000 times on the password material is a bit ad-hoc as key derivation function. Any algorithm that is constructed as M = F(M) is needlessly insecure should F conerge or have fixed-points. PBKDF2, for instance, keeps a running XOR to defend against undesired properties of F.

While PBKDF2 is quite nice, it does not defend well against ASICs. The scrypt key derivation artificially bloats working memory requirements so that an ASIC targeted toward that key derivation would have to include that working memory on its die. With that requirement, the die size grows significantly, making it less efficient -- and therefore more costly -- to produce ASICs.

See http://www.tarsnap.com/scrypt/scrypt.pdf and
http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00

cut new release?

The last version 0.20 has been released in July 2021

Since then lot of smaller improvements has landed to master.

Should we release them as 0.21? @matejcik do you seen any blockers? If not, I can cut a new release to PyPI. just let me know what you think ...

UnicodeWarning when calling check()

$ python
Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mnemonic
>>> mnemonic.Mnemonic('english').check('error fragile gadget')
/usr/local/lib/python2.7/dist-packages/mnemonic/mnemonic.py:78: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
  if first in mnemo.wordlist:
True
>>> 

mnemo.wordlist is a list of strings, first is unicode. Python 2.7 is trying to convert the Japanese text in the wordlist to unicode using the default ascii codec and failing.

Maybe it would be better to normalize_string() on each word in the wordlist in __init__() when we first read the wordlist from disk.

UnicodeDecodeError when calling detect_language()

In detect_language(), at line 81:

for lang in languages:
    mnemo = cls(lang)

This will call __init__():

def __init__(self, language):
    self.radix = 2048
    with open('%s/%s.txt' % (self._get_directory(), language), 'r') as f:
        self.wordlist = [w.strip().decode('utf8') if sys.version < '3' else w.strip() for w in f.readlines()]
    if len(self.wordlist) != self.radix:
        raise ConfigurationError('Wordlist should contain %d words, but it contains %d words.' % (self.radix, len(self.wordlist)))

And open "japanese.txt" with encoding "US-ASCII", and then decode error raised:

/Users/peter.zhao/.pyenv/versions/py36-blockchain/lib/python3.6/site-packages/mnemonic/mnemonic.py:146: in to_mnemonic
    if self.detect_language(' '.join(result)) == 'japanese':  # Japanese must be joined by ideographic space.
/Users/peter.zhao/.pyenv/versions/py36-blockchain/lib/python3.6/site-packages/mnemonic/mnemonic.py:81: in detect_language
    mnemo = cls(lang)
/Users/peter.zhao/.pyenv/versions/py36-blockchain/lib/python3.6/site-packages/mnemonic/mnemonic.py:51: in __init__
    self.wordlist = [w.strip() for w in f.readlines()]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <encodings.ascii.IncrementalDecoder object at 0x10d9dc6a0>
input = b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x93\xe3\x81\x8f\xe3\x81\x97\xe3\x82\x93\n\xe3\x81\x82\xe3\x81\x84\xe3\x81\x95\xe3\x...93\xe3\x81\x86\xe3\x81\xaa\xe3\x81\x84\n\xe3\x81\x93\xe3\x81\x86\xe3\x81\xaf\xe3\x81\x84\n\xe3\x81\x93\xe3\x82\x99\xe3'
final = False

    def decode(self, input, final=False):
>       return codecs.ascii_decode(input, self.errors)[0]
E       UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)

I edit the code to this:

def __init__(self, language):
    self.radix = 2048
    with open('%s/%s.txt' % (self._get_directory(), language), 'r', encoding='utf8') as f:
        self.wordlist = [w.strip().decode('utf8') if sys.version < '3' else w.strip() for w in f.readlines()]
    if len(self.wordlist) != self.radix:
        raise ConfigurationError('Wordlist should contain %d words, but it contains %d words.' % (self.radix, len(self.wordlist)))

and now everything is ok in my environment. But I'm not sure this will work fine in other versions of Python, like, 2.7.

Feature request: Create combination of mnemo.check and mnemo.to_seed for optimal performance

Great library.
I am using this library among others in a scripts to brute force the order of mnemonics (for treasure hunts).
Since I generate all orders of passwords, this means I have to use the mnemonic package twice:,
I) to check if mnemonic is valid (runtime 0.00097 seconds)
II) a second time to generate the seed (runtime 0.00195 seconds)

I was wondering if it would be possible and make sense to combine the two, and as save up to 30% on total runtime for generating a valid seeds?

E.g.
mnemo.to_seed(mnemonic, checksum=True)

Which would return the seed if checksum is True and would return False if the checksum fails. I am certain I am not the only one who uses this library and wants to get the maximum performance, in which case combination of the check for valid checksum and seed generation step would make sense.

Let me know your thoughts on this.

test_mnemonic.py doesn't handle UTF-8 wordlists well

Although UTF-8 wordlist is valid by BIP39, there're some issues in acceptance tests in test_mnemonic.py. For example, using french dict (as accepted in BIP39 spec) fail to pass "Test of word prefixes", because unit test cannot handle multi-byte characters well. Following words actually differ in fourth position:

Test of word prefixes:
Duplicate prefix aér for words ['aérer', 'aéronef']
Duplicate prefix cré for words ['créature', 'créditer', 'crémeux']

Python 3.11 includes all files in repo in sdist

Python 3.11 includes all files, but Python 3.7 is installing correct files when generating sdist tarball. Revision f5a975a.

Output from Python 3.11:

jonny in python-mnemonic on  master via 🐍 v3.11.4
❯ make clean
rm -fr build/
rm -fr dist/
rm -fr .eggs/
find . -name '*.egg-info' -exec rm -fr {} +
find . -name '*.egg' -exec rm -f {} +
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
find . -name '__pycache__' -exec rm -fr {} +
rm -fr .tox/
rm -f .coverage
rm -fr htmlcov/
rm -fr .pytest_cache

jonny in python-mnemonic on  master via 🐍 v3.11.4
❯ python --version
Python 3.11.4

jonny in python-mnemonic on  master via 🐍 v3.11.4
❯ python setup.py sdist
running sdist
running egg_info
creating src/mnemonic.egg-info
writing src/mnemonic.egg-info/PKG-INFO
writing dependency_links to src/mnemonic.egg-info/dependency_links.txt
writing top-level names to src/mnemonic.egg-info/top_level.txt
writing manifest file 'src/mnemonic.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
adding license file 'LICENSE'
adding license file 'AUTHORS'
writing manifest file 'src/mnemonic.egg-info/SOURCES.txt'
running check
creating mnemonic-0.20
creating mnemonic-0.20/.github
creating mnemonic-0.20/.github/workflows
creating mnemonic-0.20/src
creating mnemonic-0.20/src/mnemonic
creating mnemonic-0.20/src/mnemonic.egg-info
creating mnemonic-0.20/src/mnemonic/wordlist
creating mnemonic-0.20/tests
creating mnemonic-0.20/tools
copying files to mnemonic-0.20...
copying .editorconfig -> mnemonic-0.20
copying .gitignore -> mnemonic-0.20
copying AUTHORS -> mnemonic-0.20
copying CHANGELOG.rst -> mnemonic-0.20
copying LICENSE -> mnemonic-0.20
copying MANIFEST.in -> mnemonic-0.20
copying Makefile -> mnemonic-0.20
copying README.rst -> mnemonic-0.20
copying setup.cfg -> mnemonic-0.20
copying setup.py -> mnemonic-0.20
copying tox.ini -> mnemonic-0.20
copying vectors.json -> mnemonic-0.20
copying .github/workflows/python-package.yml -> mnemonic-0.20/.github/workflows
copying .github/workflows/style-check.yml -> mnemonic-0.20/.github/workflows
copying src/mnemonic/__init__.py -> mnemonic-0.20/src/mnemonic
copying src/mnemonic/mnemonic.py -> mnemonic-0.20/src/mnemonic
copying src/mnemonic/py.typed -> mnemonic-0.20/src/mnemonic
copying src/mnemonic.egg-info/PKG-INFO -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic.egg-info/SOURCES.txt -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic.egg-info/dependency_links.txt -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic.egg-info/not-zip-safe -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic.egg-info/top_level.txt -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic/wordlist/chinese_simplified.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/chinese_traditional.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/czech.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/english.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/french.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/italian.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/japanese.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/korean.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/portuguese.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/russian.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/spanish.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/turkish.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying tests/test_mnemonic.py -> mnemonic-0.20/tests
copying tools/generate_vectors.py -> mnemonic-0.20/tools
Writing mnemonic-0.20/setup.cfg
creating dist
Creating tar archive
removing 'mnemonic-0.20' (and everything under it)

jonny in python-mnemonic on  master via 🐍 v3.11.4
❯ tar tzf dist/mnemonic-0.20.tar.gz
mnemonic-0.20/
mnemonic-0.20/.editorconfig
mnemonic-0.20/.github/
mnemonic-0.20/.github/workflows/
mnemonic-0.20/.github/workflows/python-package.yml
mnemonic-0.20/.github/workflows/style-check.yml
mnemonic-0.20/.gitignore
mnemonic-0.20/AUTHORS
mnemonic-0.20/CHANGELOG.rst
mnemonic-0.20/LICENSE
mnemonic-0.20/MANIFEST.in
mnemonic-0.20/Makefile
mnemonic-0.20/PKG-INFO
mnemonic-0.20/README.rst
mnemonic-0.20/setup.cfg
mnemonic-0.20/setup.py
mnemonic-0.20/src/
mnemonic-0.20/src/mnemonic/
mnemonic-0.20/src/mnemonic/__init__.py
mnemonic-0.20/src/mnemonic/mnemonic.py
mnemonic-0.20/src/mnemonic/py.typed
mnemonic-0.20/src/mnemonic/wordlist/
mnemonic-0.20/src/mnemonic/wordlist/chinese_simplified.txt
mnemonic-0.20/src/mnemonic/wordlist/chinese_traditional.txt
mnemonic-0.20/src/mnemonic/wordlist/czech.txt
mnemonic-0.20/src/mnemonic/wordlist/english.txt
mnemonic-0.20/src/mnemonic/wordlist/french.txt
mnemonic-0.20/src/mnemonic/wordlist/italian.txt
mnemonic-0.20/src/mnemonic/wordlist/japanese.txt
mnemonic-0.20/src/mnemonic/wordlist/korean.txt
mnemonic-0.20/src/mnemonic/wordlist/portuguese.txt
mnemonic-0.20/src/mnemonic/wordlist/russian.txt
mnemonic-0.20/src/mnemonic/wordlist/spanish.txt
mnemonic-0.20/src/mnemonic/wordlist/turkish.txt
mnemonic-0.20/src/mnemonic.egg-info/
mnemonic-0.20/src/mnemonic.egg-info/PKG-INFO
mnemonic-0.20/src/mnemonic.egg-info/SOURCES.txt
mnemonic-0.20/src/mnemonic.egg-info/dependency_links.txt
mnemonic-0.20/src/mnemonic.egg-info/not-zip-safe
mnemonic-0.20/src/mnemonic.egg-info/top_level.txt
mnemonic-0.20/tests/
mnemonic-0.20/tests/test_mnemonic.py
mnemonic-0.20/tools/
mnemonic-0.20/tools/generate_vectors.py
mnemonic-0.20/tox.ini
mnemonic-0.20/vectors.json

Works fine with Python 3.7:

jonny in python-mnemonic on  master via 🐍 v3.7.16 (py37)
❯ make clean
rm -fr build/
rm -fr dist/
rm -fr .eggs/
find . -name '*.egg-info' -exec rm -fr {} +
find . -name '*.egg' -exec rm -f {} +
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
find . -name '__pycache__' -exec rm -fr {} +
rm -fr .tox/
rm -f .coverage
rm -fr htmlcov/
rm -fr .pytest_cache

jonny in python-mnemonic on  master via 🐍 v3.7.16 (py37)
❯ python --version
Python 3.7.16

jonny in python-mnemonic on  master via 🐍 v3.7.16 (py37)
❯ python setup.py sdist
running sdist
running egg_info
creating src/mnemonic.egg-info
writing src/mnemonic.egg-info/PKG-INFO
writing dependency_links to src/mnemonic.egg-info/dependency_links.txt
writing top-level names to src/mnemonic.egg-info/top_level.txt
writing manifest file 'src/mnemonic.egg-info/SOURCES.txt'
reading manifest file 'src/mnemonic.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
adding license file 'LICENSE'
adding license file 'AUTHORS'
writing manifest file 'src/mnemonic.egg-info/SOURCES.txt'
running check
creating mnemonic-0.20
creating mnemonic-0.20/src
creating mnemonic-0.20/src/mnemonic
creating mnemonic-0.20/src/mnemonic.egg-info
creating mnemonic-0.20/src/mnemonic/wordlist
creating mnemonic-0.20/tests
creating mnemonic-0.20/tools
copying files to mnemonic-0.20...
copying AUTHORS -> mnemonic-0.20
copying CHANGELOG.rst -> mnemonic-0.20
copying LICENSE -> mnemonic-0.20
copying MANIFEST.in -> mnemonic-0.20
copying README.rst -> mnemonic-0.20
copying setup.cfg -> mnemonic-0.20
copying setup.py -> mnemonic-0.20
copying tox.ini -> mnemonic-0.20
copying src/mnemonic/__init__.py -> mnemonic-0.20/src/mnemonic
copying src/mnemonic/mnemonic.py -> mnemonic-0.20/src/mnemonic
copying src/mnemonic/py.typed -> mnemonic-0.20/src/mnemonic
copying src/mnemonic.egg-info/PKG-INFO -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic.egg-info/SOURCES.txt -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic.egg-info/dependency_links.txt -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic.egg-info/not-zip-safe -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic.egg-info/top_level.txt -> mnemonic-0.20/src/mnemonic.egg-info
copying src/mnemonic/wordlist/chinese_simplified.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/chinese_traditional.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/czech.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/english.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/french.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/italian.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/japanese.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/korean.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/portuguese.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/russian.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/spanish.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying src/mnemonic/wordlist/turkish.txt -> mnemonic-0.20/src/mnemonic/wordlist
copying tests/test_mnemonic.py -> mnemonic-0.20/tests
copying tools/generate_vectors.py -> mnemonic-0.20/tools
Writing mnemonic-0.20/setup.cfg
creating dist
Creating tar archive
removing 'mnemonic-0.20' (and everything under it)

jonny in python-mnemonic on  master via 🐍 v3.7.16 (py37)
❯ tar tzf dist/mnemonic-0.20.tar.gz
mnemonic-0.20/
mnemonic-0.20/AUTHORS
mnemonic-0.20/CHANGELOG.rst
mnemonic-0.20/LICENSE
mnemonic-0.20/MANIFEST.in
mnemonic-0.20/PKG-INFO
mnemonic-0.20/README.rst
mnemonic-0.20/setup.cfg
mnemonic-0.20/setup.py
mnemonic-0.20/src/
mnemonic-0.20/src/mnemonic/
mnemonic-0.20/src/mnemonic/__init__.py
mnemonic-0.20/src/mnemonic/mnemonic.py
mnemonic-0.20/src/mnemonic/py.typed
mnemonic-0.20/src/mnemonic/wordlist/
mnemonic-0.20/src/mnemonic/wordlist/chinese_simplified.txt
mnemonic-0.20/src/mnemonic/wordlist/chinese_traditional.txt
mnemonic-0.20/src/mnemonic/wordlist/czech.txt
mnemonic-0.20/src/mnemonic/wordlist/english.txt
mnemonic-0.20/src/mnemonic/wordlist/french.txt
mnemonic-0.20/src/mnemonic/wordlist/italian.txt
mnemonic-0.20/src/mnemonic/wordlist/japanese.txt
mnemonic-0.20/src/mnemonic/wordlist/korean.txt
mnemonic-0.20/src/mnemonic/wordlist/portuguese.txt
mnemonic-0.20/src/mnemonic/wordlist/russian.txt
mnemonic-0.20/src/mnemonic/wordlist/spanish.txt
mnemonic-0.20/src/mnemonic/wordlist/turkish.txt
mnemonic-0.20/src/mnemonic.egg-info/
mnemonic-0.20/src/mnemonic.egg-info/PKG-INFO
mnemonic-0.20/src/mnemonic.egg-info/SOURCES.txt
mnemonic-0.20/src/mnemonic.egg-info/dependency_links.txt
mnemonic-0.20/src/mnemonic.egg-info/not-zip-safe
mnemonic-0.20/src/mnemonic.egg-info/top_level.txt
mnemonic-0.20/tests/
mnemonic-0.20/tests/test_mnemonic.py
mnemonic-0.20/tools/
mnemonic-0.20/tools/generate_vectors.py
mnemonic-0.20/tox.ini

Why are words repeated?

mnemonic:edit casual fatigue mechanic dash quantum yellow rival erosion erosion fluid immense

Tasks

No tasks being tracked yet.

italian wordlist

Hello,
I'm collecting a list of italian words to create the localized version of the wordlist. I'm using the rules of BIP 39 and I'm trying to select very different words (very different => at least 4 changes required to transform a word into another of the list).
Do you have some advises in order to agevolate the integration with your work?
Thanks!
Best regards
Martino

Feature: More reliable detection of mnemonic language

There is an overlap of 100 words in the English and French BIP39 wordlists, thus when using the current detect_language method in a code snippet like this ...

    language = Mnemonic.detect_language(mnemonic)
    mnemo = Mnemonic(language)
    wordlist = mnemo.wordlist

... it can happen that the French wordlist (abaisser, abandon, abdiquer, ...)
is used whereas the original mnemonic was actually an English one (abandon, knee, cruel ... )

Perhaps, it would be as easy as checking the first two or three seed words to determine the language instead of just the first one here:

if first in mnemo.wordlist:

@prusnak what do you think?

Missing history on master branch

#6 and #7 are currently missing from the commits on master even though they were merged. It seems like a forced update was done in the last month.

You should probably rebase c48303b and all subsequent commits onto 9941049, which was made as part of #7 (although I don't know if there are any commits with 9941049 as parent that were lost).

seed = mnemo.to_seed(words, passphrase="") get error bad key length

mnemo = Mnemonic("english")
words = mnemo.generate(strength=256)
seed = mnemo.to_seed(words, passphrase="")

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/edison/Library/Python/3.8/lib/python/site-packages/mnemonic/mnemonic.py", line 239, in to_seed
    stretched = hashlib.pbkdf2_hmac(
ValueError: [digital envelope routines: CRYPTO_internal] bad key length

Language is not define

I am beginner in python and try to run this script using the command shown but it it is not successful the command run show this.
mnemo = Mnemonic(language)
NameError: name 'language' is not defined

We changed random-source from /dev/urandom to /dev/random

Hello,

Thanks for making the library. I just wanted to let you know we modified the code to use /dev/random instead.

    def _getentropy(self, bytes):
        fd = os.open('/dev/random', os.O_RDONLY)
        try:
            data = ''
            while len(data) < bytes:
                print "Collected %d bytes of entropy, " \
                      "need an extra %d" % (len(data), bytes - len(data))
                data += os.read(fd, bytes - len(data))
            return data
        finally:
            os.close(fd)

Shouldn't seed conversion preserve data?

I would think that seed conversion would preserve data, but this doesn't seem to be the case:

In [36]: seed
Out[36]: '\xbc\x01%F\x0e\xff\xba\x12,K\x10\xf5\x94q1\xac\xd8"\x9a`$\xf3\xa9\xd2\xb2P\xabm\x0bb\xdd\xed\xdd\x14\x88\x8a\\\x15\xa2\xe5\xe2\x8e\xe4\xbf\xbdN*&\xdf\xf9X\xe1\xab\xee1\x89h\xcbG\x107q\xedP'

In [37]: seed == mnemonic.to_seed(mnemonic.to_mnemonic(seed))
Out[37]: False

Shouldn't the seed match itself after getting converted to words? What am I missing?

Version release

Hi,

I'd like to make a release of python-mnemonic for gentoo, are you planning to create a release ?
Thanks

english.txt wordlist is not installed as part of standard python installation

Following

sudo python setup.py install for "python_trezor" and "Cython-0.20.2", the /wordlist/english.txt file and folder are missing from /usr/local/lib/python2.7/site-packages/mnemonic-0.8-py2.7.egg/mnemonic/

this requires the user to manually download english.txt, in order to use /python-trezor/mnemonic_check.py

Use of native random function to generate seed phrase

Good morning!

I wanted to ask if the following would be a proper and safe approach to generating a seed phrase, as opposed to using the generate function in the mnemonic class:

  • use the native python random function to pick the first 23 words of the seed phrase
  • iterate over all 2048 words in the word list to find the 8 valid options for the 24th word
  • use the native python random function again to pick one of the valid 8 seed phrases

Thank you!

Arbitrary length data - Data length should be one of the following: [16, 20, 24, 28, 32]

I am trying to encode an SSH ECDSA key (162 bytes). When I pass a bytes object of my data to mnem.to_mnemonic(data), I get

ValueError: Data length should be one of the following: [16, 20, 24, 28, 32]

It's not clear from the documentation which function of the API I should be using. Nor, it's not clear why I am not able to encode arbitrary length data.

Thanks,

Can't use Shamir's secret sharing with 12/24 word seeds

len(seed) is bigger than primes.keys() in shamir.py so you get an "Unknown data length" exception. Works fine with the example sentence "Shamir's Secret Sharing Scheme!" because it's 31 in length, but can't be used with real BIP39 examples.

Tests are failing on `master`

Possibly related to #10, but running tests results in many failures:

% tox -e py27
GLOB sdist-make: /.../posita/python-mnemonic/setup.py
py27 inst-nodeps: /.../posita/python-mnemonic/.tox/dist/mnemonic-0.12.zip
py27 installed: mnemonic==0.12,pbkdf2==1.3,wheel==0.24.0
py27 runtests: PYTHONHASHSEED='2037693756'
py27 runtests: commands[0] | python test_mnemonic.py
...FLanguage 'english'
Language 'japanese'
------------------------------------
Test of word prefixes:
Duplicate prefix あ<E3> for words ['\xe3\x81\x82\xe3\x81\x84\xe3\x81\x93\xe3\x81\x8f\xe3\x81\x97\xe3\x82\x93', '\xe3\x81\x82\xe3\x81\x84\xe3\x81\x95\xe3\x81\xa4', '\xe3\x81\x82\xe3\x81\x84\xe3\x81\x9f\xe3\x82\x99', '\xe3\x81\x82\xe3\x81\x8a\xe3\x81\x9d\xe3\x82\x99\xe3\x82\x89', '\xe3\x81\x82\xe3\x81\x8b\xe3\x81\xa1\xe3\x82\x83\xe3\x82\x93', '\xe3\x81\x82\xe3\x81\x8d\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\x91\xe3\x81\x8b\xe3\x82\x99\xe3\x81\x9f', '\xe3\x81\x82\xe3\x81\x91\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\x93\xe3\x81\x8b\xe3\x82\x99\xe3\x82\x8c\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\x95\xe3\x81\x84', '\xe3\x81\x82\xe3\x81\x95\xe3\x81\xb2', '\xe3\x81\x82\xe3\x81\x97\xe3\x81\x82\xe3\x81\xa8', '\xe3\x81\x82\xe3\x81\x97\xe3\x82\x99\xe3\x82\x8f\xe3\x81\x86', '\xe3\x81\x82\xe3\x81\x99\xe3\x82\x99\xe3\x81\x8b\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\x99\xe3\x82\x99\xe3\x81\x8d', '\xe3\x81\x82\xe3\x81\x9d\xe3\x81\xb5\xe3\x82\x99', '\xe3\x81\x82\xe3\x81\x9f\xe3\x81\x88\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\x9f\xe3\x81\x9f\xe3\x82\x81\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\x9f\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x88', '\xe3\x81\x82\xe3\x81\x9f\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\xa4\xe3\x81\x84', '\xe3\x81\x82\xe3\x81\xa4\xe3\x81\x8b\xe3\x81\x86', '\xe3\x81\x82\xe3\x81\xa3\xe3\x81\x97\xe3\x82\x85\xe3\x81\x8f', '\xe3\x81\x82\xe3\x81\xa4\xe3\x81\xbe\xe3\x82\x8a', '\xe3\x81\x82\xe3\x81\xa4\xe3\x82\x81\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\xa6\xe3\x81\xaa', '\xe3\x81\x82\xe3\x81\xa6\xe3\x81\xaf\xe3\x81\xbe\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\xb2\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\xb5\xe3\x82\x99\xe3\x82\x89', '\xe3\x81\x82\xe3\x81\xb5\xe3\x82\x99\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\xb5\xe3\x82\x8c\xe3\x82\x8b', '\xe3\x81\x82\xe3\x81\xbe\xe3\x81\x84', '\xe3\x81\x82\xe3\x81\xbe\xe3\x81\xa8\xe3\x82\x99', '\xe3\x81\x82\xe3\x81\xbe\xe3\x82\x84\xe3\x81\x8b\xe3\x81\x99', '\xe3\x81\x82\xe3\x81\xbe\xe3\x82\x8a', '\xe3\x81\x82\xe3\x81\xbf\xe3\x82\x82\xe3\x81\xae', '\xe3\x81\x82\xe3\x82\x81\xe3\x82\x8a\xe3\x81\x8b', '\xe3\x81\x82\xe3\x82\x84\xe3\x81\xbe\xe3\x82\x8b', '\xe3\x81\x82\xe3\x82\x86\xe3\x82\x80', '\xe3\x81\x82\xe3\x82\x89\xe3\x81\x84\xe3\x81\x8f\xe3\x82\x99\xe3\x81\xbe', '\xe3\x81\x82\xe3\x82\x89\xe3\x81\x97', '\xe3\x81\x82\xe3\x82\x89\xe3\x81\x99\xe3\x81\x97\xe3\x82\x99', '\xe3\x81\x82\xe3\x82\x89\xe3\x81\x9f\xe3\x82\x81\xe3\x82\x8b', '\xe3\x81\x82\xe3\x82\x89\xe3\x82\x86\xe3\x82\x8b', '\xe3\x81\x82\xe3\x82\x89\xe3\x82\x8f\xe3\x81\x99', '\xe3\x81\x82\xe3\x82\x8a\xe3\x81\x8b\xe3\x82\x99\xe3\x81\xa8\xe3\x81\x86', '\xe3\x81\x82\xe3\x82\x8f\xe3\x81\x9b\xe3\x82\x8b', '\xe3\x81\x82\xe3\x82\x8f\xe3\x81\xa6\xe3\x82\x8b', '\xe3\x81\x82\xe3\x82\x93\xe3\x81\x84', '\xe3\x81\x82\xe3\x82\x93\xe3\x81\x8b\xe3\x82\x99\xe3\x81\x84', '\xe3\x81\x82\xe3\x82\x93\xe3\x81\x93', '\xe3\x81\x82\xe3\x82\x93\xe3\x81\x9b\xe3\x82\x99\xe3\x82\x93', '\xe3\x81\x82\xe3\x82\x93\xe3\x81\xa6\xe3\x81\x84', '\xe3\x81\x82\xe3\x82\x93\xe3\x81\xaa\xe3\x81\x84', '\xe3\x81\x82\xe3\x82\x93\xe3\x81\xbe\xe3\x82\x8a']
...
Duplicate prefix ろ<E3> for words ['\xe3\x82\x8d\xe3\x81\x86\xe3\x81\x8b', '\xe3\x82\x8d\xe3\x81\x86\xe3\x81\x93\xe3\x82\x99', '\xe3\x82\x8d\xe3\x81\x86\xe3\x81\x97\xe3\x82\x99\xe3\x82\x93', '\xe3\x82\x8d\xe3\x81\x86\xe3\x81\x9d\xe3\x81\x8f', '\xe3\x82\x8d\xe3\x81\x8f\xe3\x81\x8b\xe3\x82\x99', '\xe3\x82\x8d\xe3\x81\x93\xe3\x81\xa4', '\xe3\x82\x8d\xe3\x81\x97\xe3\x82\x99\xe3\x81\x86\xe3\x82\x89', '\xe3\x82\x8d\xe3\x81\x97\xe3\x82\x85\xe3\x81\xa4', '\xe3\x82\x8d\xe3\x81\x9b\xe3\x82\x93', '\xeF.F..FE
======================================================================
ERROR: test_vectors (__main__.MnemonicTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_mnemonic.py", line 50, in test_vectors
    self._check_list(lang, vectors[lang])
  File "test_mnemonic.py", line 42, in _check_list
    self.assertIs(mnemo.check(v[1]), True)
  File "/.../posita/python-mnemonic/mnemonic/mnemonic.py", line 142, in check
    if self.detect_language(mnemonic.replace('\xe3\x80\x80', ' ')) == 'japanese':
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)

======================================================================
FAIL: test_lengths (__main__.MnemonicTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_mnemonic.py", line 83, in test_lengths
    self.assertListEqual(words, [])
AssertionError: Lists differ: ['\xe3\x81\x82\xe3\x81\x84\xe3... != []

First list contains 2048 additional elements.
First extra element 0:
あいこくしん

Diff is 111841 characters long. Set self.maxDiff to None to see it.

======================================================================
FAIL: test_root_len (__main__.MnemonicTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_mnemonic.py", line 129, in test_root_len
    self.assertEqual(problems_found, 0)
AssertionError: 2004 != 0

======================================================================
FAIL: test_sorted_unique (__main__.MnemonicTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_mnemonic.py", line 108, in test_sorted_unique
    self.assertListEqual(unique, mnemo.wordlist)
AssertionError: Lists differ: ['\xe3\x81\x82\xe3\x81\x84\xe3... != ['\xe3\x81\x82\xe3\x81\x84\xe3...

First differing element 20:
あっしゅく
あつい

Diff is 127522 characters long. Set self.maxDiff to None to see it.

======================================================================
FAIL: test_validchars (__main__.MnemonicTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_mnemonic.py", line 93, in test_validchars
    self.assertIn(l, 'abcdefghijklmnopqrstuvwxyz')
AssertionError: '\xaf' not found in 'abcdefghijklmnopqrstuvwxyz'

----------------------------------------------------------------------
Ran 11 tests in 26.582s

FAILED (failures=4, errors=1)
3\x82\x8d\xe3\x81\xa6\xe3\x82\x93', '\xe3\x82\x8d\xe3\x82\x81\xe3\x82\x93', '\xe3\x82\x8d\xe3\x82\x8c\xe3\x81\xa4', '\xe3\x82\x8d\xe3\x82\x93\xe3\x81\x8d\xe3\x82\x99', '\xe3\x82\x8d\xe3\x82\x93\xe3\x81\xaf\xe3\x82\x9a', '\xe3\x82\x8d\xe3\x82\x93\xe3\x81\xb5\xe3\x82\x99\xe3\x82\x93', '\xe3\x82\x8d\xe3\x82\x93\xe3\x82\x8a']
Duplicate prefix ろ<E3> for words ['\xe3\x82\x8d\xe3\x81\x86\xe3\x81\x8b', '\xe3\x82\x8d\xe3\x81\x86\xe3\x81\x93\xe3\x82\x99', '\xe3\x82\x8d\xe3\x81\x86\xe3\x81\x97\xe3\x82\x99\xe3\x82\x93', '\xe3\x82\x8d\xe3\x81\x86\xe3\x81\x9d\xe3\x81\x8f', '\xe3\x82\x8d\xe3\x81\x8f\xe3\x81\x8b\xe3\x82\x99', '\xe3\x82\x8d\xe3\x81\x93\xe3\x81\xa4', '\xe3\x82\x8d\xe3\x81\x97\xe3\x82\x99\xe3\x81\x86\xe3\x82\x89', '\xe3\x82\x8d\xe3\x81\x97\xe3\x82\x85\xe3\x81\xa4', '\xe3\x82\x8d\xe3\x81\x9b\xe3\x82\x93', '\xe3\x82\x8d\xe3\x81\xa6\xe3\x82\x93', '\xe3\x82\x8d\xe3\x82\x81\xe3\x82\x93', '\xe3\x82\x8d\xe3\x82\x8c\xe3\x81\xa4', '\xe3\x82\x8d\xe3\x82\x93\xe3\x81\x8d\xe3\x82\x99', '\xe3\x82\x8d\xe3\x82\x93\xe3\x81\xaf\xe3\x82\x9a', '\xe3\x82\x8d\xe3\x82\x93\xe3\x81\xb5\xe3\x82\x99\xe3\x82\x93', '\xe3\x82\x8d\xe3\x82\x93\xe3\x82\x8a']
...
Duplicate prefix わ<E3> for words ['\xe3\x82\x8f\xe3\x81\x8b\xe3\x81\x99', '\xe3\x82\x8f\xe3\x81\x8b\xe3\x82\x81', '\xe3\x82\x8f\xe3\x81\x8b\xe3\x82\x84\xe3\x81\xbe', '\xe3\x82\x8f\xe3\x81\x8b\xe3\x82\x8c\xe3\x82\x8b', '\xe3\x82\x8f\xe3\x81\x97\xe3\x81\xa4', '\xe3\x82\x8f\xe3\x81\x97\xe3\x82\x99\xe3\x81\xbe\xe3\x81\x97', '\xe3\x82\x8f\xe3\x81\x99\xe3\x82\x8c\xe3\x82\x82\xe3\x81\xae', '\xe3\x82\x8f\xe3\x82\x89\xe3\x81\x86', '\xe3\x82\x8f\xe3\x82\x8c\xe3\x82\x8b']
------------------------------------
Test of sorted and unique wordlists:
Language 'english'
Language 'japanese'
Language 'english'
Language 'japanese'
ERROR: InvocationError: '/.../posita/python-mnemonic/.tox/py27/bin/python test_mnemonic.py'
___________________________________ summary ____________________________________
ERROR:   py27: commands failed

to_entropy function return 'Failed checksum'

Hi,

I try mnemonic and bitcoinlib and i found this problem.

C:\temp>python
Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

import mnemonic
lang = mnemonic.Mnemonic('english')

lang.to_entropy('mother derive history rapid clean donor nature desert pair dolphin tower volume')
bytearray(b"\x90'm\xb0\xd8\xf2\xa4\x82\xa4\xd9\xdd\x9f\x08\x1b\x98\xfa")

lang.to_entropy('mother derive history rapid clean donor nature desert pair dolphin volume tower')
Traceback (most recent call last):
File "", line 1, in
File "D:\Python38\lib\site-packages\mnemonic\mnemonic.py", line 173, in to_entropy
raise ValueError("Failed checksum.")
ValueError: Failed checksum.

The only thing i did was reverse the last 2 words.

Why reversing 2 words created an exception in the to_entropy () function?

Thank's

Make new PyPi release

Hi,

I noticed that in this commit the external pbkdf2 dependency was rightly dropped.

However, the code on PyPi still has the dependency even on the latest release there (0.18).

I would like to use mnemonic from PyPi without forcing my project to also require pbkdf2 as a child dependency.

I would appreciate it if someone could take a bit to make sure everything is ready and push a new release to PyPi.

Don't forget to bump the version, it appears the dependency was removed without bumping the setup.py version on this repo

screenshot

Please add BIP32 xprv to test vectors.

I understand BIP32 is not technically part of mnemonic generation, but there have been multiple occasions where someone has run vectors on BIP39 and run vectors on BIP32, then wonders why they are wrong and it turns out they didn't feed the seed from BIP39 into BIP32 correctly.

Seeing as Trezor uses the BIP39 in order to generate BIP32 xprv, I think it would help tremendously if you would include BIP32 xprv in each test vector.

Thank you.

Incompatible with Python3

Currently, this package fails to run with Python 3, due at least to the use of longs in the secretsharing package:

Traceback (most recent call last):
  File "test_mnemonic.py", line 31, in <module>
    from mnemonic import Mnemonic
  File "/.../posita/python-mnemonic/mnemonic/__init__.py", line 2, in <module>
    from .shamir import Shamir
  File "/.../posita/python-mnemonic/mnemonic/shamir.py", line 23, in <module>
    from secretsharing import secret_int_to_points, points_to_secret_int
  File "/.../posita/python-mnemonic/.tox/py34/lib/python3.4/site-packages/secretsharing/__init__.py", line 12, in <module>
    from .sharing import *
  File "/.../posita/python-mnemonic/.tox/py34/lib/python3.4/site-packages/secretsharing/sharing.py", line 14, in <module>
    from .primes import get_large_enough_prime
  File "/.../posita/python-mnemonic/.tox/py34/lib/python3.4/site-packages/secretsharing/primes.py", line 35, in <module>
    STANDARD_PRIMES = calculate_mersenne_primes() + [
  File "/.../posita/python-mnemonic/.tox/py34/lib/python3.4/site-packages/secretsharing/primes.py", line 25, in calculate_mersenne_primes
    prime = long(1)
NameError: name 'long' is not defined

new release

Hi,

It seems latest version is 0.20 which uses os.urandom to generate initial entropy, which is not suited for this.

Latest commits containing usage of secure module is not released, can anybody make a quick release, using secure module to generate real random entropy is important.

Protocol Question

Hi if I use this as the ETH derivation path prefix, what is the limit of accounts i can generate from a single mnemonic seed phrase?

ETH_DERIVATION_PATH_PREFIX = "m/44'/60'/0'/"
for i in range(100):
    key = (mnemonic_utils.mnemonic_to_private_key(wordList, f"{ETH_DERIVATION_PATH_PREFIX}{i}"))

Include vectors.json in sdist

vectors.json is needed for users to run all the tests.

This is useful for Linux distroes that redistribute packages built from sdist that want to run the tests as part of the packaging.

Create requirements file for pip

For example:

$ pip install -r requirements.txt

You can generate that by pip freeze. E.g.

$ pip freeze | egrep "^(bip32|pbkd)"
bip32utils==0.3.post3
pbkdf2==1.3

Issue with french wordlist accents

I think there is an issue with the french wordlist and accents on letters.

If you take the first word with an accent in the list: académie (line 19 in this file)

The in this library is actually composed of e (U+0065 LATIN SMALL LETTER E) and ◌́ (U+0301 COMBINING ACUTE ACCENT).

On french keyboards (AZERTY layout), é as displayed under key "2" is a different character (U+00C9 LATIN SMALL LETTER E WITH ACUTE).

I think that the french wordlist é should be the same as the one on the keyboard. If you have to type your mnemonic on a keyboard you will be using the keyboard letter, not the one with the modifier.

Maybe I missed something but I think the right thing to do is to switch the U+0065 and U+0301 with U+00C9 on french.txt. I can make a pull request to fix this if you are interested.

Edit: it also fails for e with grave

Example code:

>>> s = mnemonic.Mnemonic("french").generate()
>>> s
'brèche wagon image doyen garantir subtil adhésif asphalte invoquer homard inonder huileux'
>>> s.split()[0] == "brèche"
False

End user request: execute from command line.

I installed the package & can run the test_mnemonic.py & test_shamir.py scripts fine; they produce successful command line output.

How do I use mnemonic.py directly from the command line?

E.g. I want to do:

% echo "76DB6A517B1DBFE8D21F9C2701E8F92C1FDD3876A51E97A08FF24142BEDA2AD3" | python mnemonic.py

and obtain a wordlist output at the command line. (64 ascii hex characters = 256 bits of entropy)

mnemonic.py produces no output at the command line. Am I doing something wrong or is there something missing, e.g. this is not designed to produce command-line output?

If it's trivial or easy to implement please revise so that the script can produce direct command-line output for people who want to run this in CLI-only environments.

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.