Trying to convert hexadecimal string of entropy to seed sentence with the below snippet. Failing the first test with 16 zero bytes. It seems that my function came to conclusion that checksum is '1011' yet it should by '0011' (by this page for instance) therefore I do have a mistake in seed sentence where my last word is on index 13 (accuse) and correct word is on index 3 (about). What is broken in my function? Also, there is not much of an implementation details in bip39, if you know about some resources (not just core codebase) they'd be warmly welcome!

import hashlib
import requests
import unicodedata

def get_word_list():
    url = "https://raw.githubusercontent.com/"
    uri = "bitcoin/bips/master/bip-0039/english.txt"
    return requests.get(url + uri).text.split()

def checksum_length(entropy_bits: int) -> int:
    return int(entropy_bits / 32)

def mnemonic_from_entropy(entropy: str) -> str:
    word_list = get_word_list()
    entropy_bits = len(entropy) * 4
    entropy_bytes = bytes.fromhex(entropy)
    entropy_int = int.from_bytes(entropy_bytes, byteorder="big")
    sha256_entropy_bytes = hashlib.sha256(entropy_bytes).digest()
    sha256_entropy_int = int.from_bytes(sha256_entropy_bytes, "big")
    checksum_bit_length = checksum_length(entropy_bits=entropy_bits)
    checksum = bin(sha256_entropy_int)[2:2 + checksum_bit_length]
    entropy_checksum = bin(entropy_int)[2:] + checksum
    entropy_checksum = entropy_checksum.zfill(entropy_bits + checksum_bit_length)
    bin_indexes = re.findall("." * 11, entropy_checksum)
    indexes = [int(index, 2) for index in bin_indexes]
    mnemonic_lst = [word_list[index] for index in indexes]
    mnemonic_sentence = unicodedata.normalize("NFKD", " ".join(mnemonic_lst))
    return mnemonic_sentence

if __name__ == "__main__":

  • Your desired test vector can also be calculated as follows: % echo 00000000000000000000000000000000 | bx mnemonic-new abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about – skaht Mar 6 '20 at 18:58

you need to remove python binary denominator '0b' and then zero fill the binary representation of sha256 digest to 256bits --> then it works

checksum = bin(sha256_entropy_int)[2:].zfill(256)[:checksum_bit_length]

also there is a reference implementation mentioned in the bip (must have missed it initially)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.