How 2 trillion of dollars are secured by 12 words ? Mnemonics | Bip39

web3d3v
Coinmonks
3 min readMay 9, 2022

--

Live Colab notebook here. Github repo here.

To start with are going need cryptographically secure source of randomness. At least 128 bits of it.

# valid entropy bit sizes [128, 160, 192, 224, 256]
entropyBitSize = 128
# secure source of randomness
entropyBytes = os.urandom(entropyBitSize // 8) # Byte has 8 bits
print(“Entropy:”, entropyBytes.hex())

Convert our entropy bytes to bit array so its easier to work with.

from bitarray import bitarray
entropyBits = bitarray()
entropyBits.frombytes(entropyBytes)
print(“Entropy bits:”, entropyBits)

We need to add checksum bits at the of our are entropy. Check sum is first `checkSumLen` bits of `sha256` hash of our entropy bytes.

# checksum length depends on the length of entropy
checksumLen = entropyBitSize // 32
print(“checksum size:”, checksumLen)
# We need to take a hash of our entropy
hashBytes = hashlib.sha256(entropyBytes).digest()
print(“hashed bytes:”, hashBytes.hex())
hashBits = bitarray()
hashBits.frombytes(hashBytes)
checksum = hashBits[:checksumLen]
print(“checksum bits:”, checksum)
# Add checksum bits at the end of entropy
entropyBits.extend(checksum)
print(“entropy length:”, len(entropyBits))

Group `entropyBits` to gruops of 11 bits. And convert them to integers. These integers

# Get indexed from bits
indexes = list()
from bitarray.util import ba2int
for idx in range(len(entropyBits) // 11):
startIdx = idx * 11
endIdx = startIdx + 11
wordIndex = ba2int(entropyBits[startIdx:endIdx])
indexes.append(wordIndex)
print(indexes)

Bip39 is standard, it defines the list of 2024 words. We load the words into an array.

# Load bip 39 words
fileObj = open(“bip-0039/english.txt”, “r”)
words = fileObj.read().splitlines()
fileObj.close()
print(“words len:”, len(words))

We map the indexes from entropy to words.

# Map indexes onto words
mnemonic = list(map(lambda idx: words[idx] , indexes))
print(“mnemonic:”, mnemonic)

Add optional password.

# Generate salt
password = “”
salt = “mnemonic” + password

At long last we derive a seed.

# Finally, we derive seed
mnemonicStr = ‘ ‘.join(mnemonic)
seed = hashlib.pbkdf2_hmac(
“sha512”,
mnemonicStr.encode(“utf-8”),
salt.encode(“utf-8”),
2048
)
print(“seed len:”, len(seed))
print(“seed hex:”, seed.hex())
print(“priv key:”, seed[0:32].hex())
print(“chain co:”, seed[32:64].hex())

First 32 bytes of it are our master private key, and second 32 bytes are chain code. How you derive wallet private key and address is for another post.

Some of you might say, wait thats it? Those 128 random bits, as gorgeous as they are, is all that secures all of crypto. What if some else gets same entropy as me by chance ? 128 bits gives you 2¹²⁸ number. That is greater than number of start in the universe. If you use 24 words. You are approaching nubmers greater than nubmer of atoms in the universe. Chances of that quiet lituraly astronomical. In any case entirety of encryption, every time you login somewhere, works similar way, so dont worry about it. It works.

All of the above is all and well but how do you make easy to use for normal people? Well check out the video on the top of the post.

Live Colab notebook here. Github repo here.

Join Coinmonks Telegram Channel and Youtube Channel learn about crypto trading and investing

Also, Read

--

--