为什么 btclib.mnemonic_from_raw_entropy 声称我传递给它的熵少于 128 位?

Why does btclib.mnemonic_from_raw_entropy claim I passed it less than 128 bits of entropy?

我正在做的是生成 'dummy' 个钱包,从原始熵中检索助记密码和钱包,这是使用 secrets.randbits(128) 生成的——生成有效的 bip39 密钥对。

我得到的错误是这样的:

ValueError: 125 bits provided; expected: (128, 160, 192, 224, 256)

它可以在 122 到 127 位之间变化。它通常对连续多个错误表示相同数量的位,即 125 bits provided 3 次,然后切换到 122 bits provided 2 次,然后在第 6 次尝试时工作。

我正在使用 btclib – 完整的功能是

def create_passphrase():
    memo = bip39.mnemonic_from_raw_entropy(secrets.randbits(128) , 'en')

    print(mnemo) 
    return mnemo

抱歉,如果我遗漏了一些明显的东西。

这是 btclib 中的错误。

函数bip39.mnemonic_from_raw_entropy() calls bip39.entropy_from_raw_entropy(), which calls entropy.str_from_entropy().

当使用整数作为其 entr 参数调用 entropy.str_from_entropy() 时,它会尝试将该整数转换为表示位的字符串,here:

        entr = bin(entr)[2:] # remove '0b'

这是错误的:任何传入的整数,如果它真的是随机的,只有大约一半的时间被转换为预期的位数。要了解原因,请考虑这些随机数据示例(为简单起见,我将使用 8 位而不是 128 位,但原理是相同的):

>>> bin(0b10001011)[2:]
'10001011'
>>> bin(0b01010110)[2:]
'1010110'
>>> bin(0b00111011)[2:]
'111011'

如您所见,btclib 使用的转换方法会去除所有前导零,从而导致生成长度错误的字符串。

解决方法可能是自己将 secrets.randbits(128) 的结果转换为适当的字符串,然后传递:

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

…假设 btclib 中没有其他错误等着咬你。

感谢您的报告。

丢失前导零符合 Electrum entropy->mnemonic 行为,但导致了 BIP39 的错误。

现在在 master 分支上修复了: https://github.com/dginst/btclib/commit/f0f802ef3e31ae74e84964f0ec04d1180f42da27