mnemonic.to_private_key(passphrase) always gives the same error

4
closed
ReverseControl
ReverseControl
Posted 8 months ago

mnemonic.to_private_key(passphrase) always gives the same error #232

Bug Report.

Python code:

words  #<--Dictionary with half a million English words
passphrase = " ".join( random.sample( words, 25) )

private_key = mnemonic.to_private_key(passphrase)
my_address  = mnemonic.to_public_key(passphrase)
print("My address: {}".format(my_address))

Error

It does not matter what words are chosen, the error is the same. From the traceback it seems to fail on the last word every time: m_checksum = word_to_index[mnemonic[-1]].

Traceback (most recent call last):

  File "/home/user/.local/lib/python3.8/site-packages/algosdk/mnemonic.py", line 133, in _to_key
    m_checksum = word_to_index[mnemonic[-1]]

KeyError: 'nonslip'


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File "/home/user/.config/spyder-py3/temp.py", line 82, in <module>
    private_key = mnemonic.to_private_key(passphrase)

  File "/home/user/.local/lib/python3.8/site-packages/algosdk/mnemonic.py", line 76, in to_private_key
    key_bytes = _to_key(mnemonic)

  File "/home/user/.local/lib/python3.8/site-packages/algosdk/mnemonic.py", line 136, in _to_key
    raise ValueError(mnemonic)

ValueError: ['damon', 'rainfalls', 'untithability', 'krennerite', 'etheostominae', 'billowing', 'phasmatoid', 'mispassion', 'mundt', 'cispadane', 'reydon', 'olivinitic', 'drakesville', 'rasputin', 'poons', 'calyptriform', 'huddles', 'christening', 'winterizes', 'playwrightess', 'conflagrate', 'detrains', 'croner', 'demised', 'nonslip']

Surely I must be doing something wrong. It should not fail out of the box.

winder
winder
Created 8 months ago

It was nice talking with you the other day. :)

The main problem I see here is that we have a standardized wordlist, it's defined in each SDK, here is pythons.

I don't see any specific mnemonic examples in the developer docs, but it's used in these examples: https://developer.algorand.org/docs/features/accounts/create/#recover-wallet-and-regenerate-account

You can also generate an account using the algokey utility which is part of the node software.

ReverseControl
ReverseControl
Created 8 months ago

Is there any other restrictions on the mnemonic string? I keep getting the following:

Code

from algosdk import mnemonic
import algosdk
import random

#Load Dictionary
words = algosdk.wordlist.word_list_raw().split("\n")

#Create public/private key pair
passphrase = " ".join( random.sample( words, 25) )
skey   = mnemonic.to_private_key(passphrase)
pkey   = mnemonic.to_public_key( passphrase)

Error

---------------------------------------------------------------------------
WrongChecksumError                        Traceback (most recent call last)
/tmp/ipykernel_89549/1976486721.py in <module>
     17 passphrase = " ".join( random.sample( words, 25) )
     18 print(passphrase)
---> 19 skey  = mnemonic.to_private_key(passphrase)
     20 pkey  = mnemonic.to_public_key( passphrase)
     21 

~/.local/lib/python3.8/site-packages/algosdk/mnemonic.py in to_private_key(mnemonic)
     74         str: private key in base64
     75     """
---> 76     key_bytes = _to_key(mnemonic)
     77     key = signing.SigningKey(key_bytes)
     78     return base64.b64encode(key.encode() + key.verify_key.encode()).decode()

~/.local/lib/python3.8/site-packages/algosdk/mnemonic.py in _to_key(mnemonic)
    144     if not m_bytes[-1:len(m_bytes)] == b'\x00':
--> 145         raise error.WrongChecksumError
    146     chksum = _checksum(m_bytes[:constants.key_len_bytes])
    147     if chksum == m_checksum:

WrongChecksumError: checksum failed to validate

I want to create keys from mnemonics. algokey will come in handy later, I am sure. The examples convert keys into mnemonics and back, but never create mnemonics from the word list directly.

ReverseControl
ReverseControl
Created 7 months ago

@winder Any updates?

jasonpaulos
jasonpaulos
Created 7 months ago

@ReverseControl the reason 25 random words is not a valid mnemonic is because the final word is a checksum of the private key. This allows us to identify if a word in the mnemonic has been "corrupted", since then the checksum word won't match.

See the implementation here for more details: https://github.com/algorand/py-algorand-sdk/blob/e444328616d99c88b830366dedcbf75e9795dcb3/algosdk/mnemonic.py#L103