def mnemonic_from_entropy(entropy: Entropy,
                          version_str: str = "standard",
                          lang: str = "en") -> Mnemonic:
    """Convert input entropy to Electrum versioned mnemonic sentence.

    Input entropy can be expressed as
    binary 0/1 string, bytes-like, or integer.

    In the case of binary 0/1 string and bytes-like,
    leading zeros are considered redundant padding.
    """

    if version_str not in _MNEMONIC_VERSIONS:
        err_msg = f"unknown electrum mnemonic version: '{version_str}'; "
        err_msg += f"not in {list(_MNEMONIC_VERSIONS.keys())}"
        raise BTClibValueError(err_msg)
    version = _MNEMONIC_VERSIONS[version_str]

    bin_str_entropy = bin_str_entropy_from_entropy(entropy)
    int_entropy = int(bin_str_entropy, 2)
    base = WORDLISTS.language_length(lang)
    while True:
        # electrum considers entropy as integer, losing any leading zero
        # so the value of bin_str_entropy before the while must be updated
        nbits = int_entropy.bit_length()
        bin_str_entropy = bin_str_entropy_from_entropy(int_entropy, nbits)
        indexes = wordlist_indexes_from_bin_str_entropy(bin_str_entropy, base)
        mnemonic = mnemonic_from_indexes(indexes, lang)
        # version validity check
        s = hmac.new(b"Seed version", mnemonic.encode(), sha512).hexdigest()
        if s.startswith(version):
            return mnemonic
        # next trial
        int_entropy += 1
示例#2
0
def mnemonic_from_entropy(entropy: Optional[Entropy] = None,
                          lang: str = "en") -> Mnemonic:
    """Convert input entropy to BIP39 checksummed mnemonic sentence.

    Input entropy can be expressed as
    binary 0/1 string, bytes-like, or integer;
    it must be 128, 160, 192, 224, or 256 bits.

    In the case of binary 0/1 string and bytes-like,
    leading zeros are not considered redundant padding.

    In the case of integer, where leading zeros cannot be represented,
    if the bit length is not an allowed value, then the binary 0/1
    string is padded with leading zeros up to the next allowed bit
    length; if the integer bit length is longer than the maximum
    length, then only the leftmost bits are retained.
    """

    if entropy is None or entropy == "":
        entropy = secrets.randbits(128)
    bin_str_entropy, checksum = _entropy_checksum(entropy)
    base = WORDLISTS.language_length(lang)
    indexes = wordlist_indexes_from_bin_str_entropy(bin_str_entropy + checksum,
                                                    base)
    return mnemonic_from_indexes(indexes, lang)
示例#3
0
def test_indexes() -> None:
    for entropy in ("0", "00000000000"):
        indexes = wordlist_indexes_from_bin_str_entropy(entropy, 2048)
        assert indexes == [0]
    entropy = "000000000000"
    indexes = wordlist_indexes_from_bin_str_entropy(entropy, 2048)
    assert indexes == [0, 0]

    test_vector = [
        [1268, 535, 810, 685, 433, 811, 1385, 1790, 421, 570, 567, 1313],
        [0, 0, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 0],
        [0, 0, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047, 0],
    ]
    for indx in test_vector:
        entropy = bin_str_entropy_from_wordlist_indexes(indx, 2048)
        indexes = wordlist_indexes_from_bin_str_entropy(entropy, 2048)
        assert indexes == indx