What I am doing is generating 'dummy' wallets, retrieving both a mnemonic passphrase and wallet from raw entropy, which is generated using secrets.randbits(128)
– resulting in a valid bip39 pair of keys.
The error I get is along these lines:
ValueError: 125 bits provided; expected: (128, 160, 192, 224, 256)
It can vary from 122 to 127 bits. It usually says the same amount of bits for multiple errors in a row, i.e. 125 bits provided
for 3 times, then switching to 122 bits provided
for 2 times, then working at the 6th try.
I am using btclib – the full function is
def create_passphrase():
memo = bip39.mnemonic_from_raw_entropy(secrets.randbits(128) , 'en')
print(mnemo)
return mnemo
Sorry if I am missing something obvious.
This is a bug in btclib.
The function bip39.mnemonic_from_raw_entropy()
calls bip39.entropy_from_raw_entropy()
, which calls entropy.str_from_entropy()
.
When entropy.str_from_entropy()
is called with an integer as its entr
argument, it attempts to convert that integer into a string representing the bits, here:
entr = bin(entr)[2:] # remove '0b'
This is broken: any integer passed in will, if it's truly random, only be converted to the number of bits expected about half the time. To see why, consider these examples of random data (I'll use 8 bits rather than 128 for simplicity's sake, but the principle is the same):
>>> bin(0b10001011)[2:]
'10001011'
>>> bin(0b01010110)[2:]
'1010110'
>>> bin(0b00111011)[2:]
'111011'
As you can see, the conversion method used by btclib strips off any leading zeroes, leading to a string of the wrong length being produced.
A workaround might be to convert the result of secrets.randbits(128)
to an appropriate string yourself, and pass that:
def create_passphrase(bits=128):
bitstring = f'{secrets.randbits(bits):0{bits}b}'
memo = bip39.mnemonic_from_raw_entropy(bitstring , 'en')
print(memo)
return memo
… assuming that there aren't other bugs in btclib waiting to bite you.