Mnemonics are the private keys, separated into 12 words, that are put together in the same order to create the private key
That's wrong. A mnemonic represents an entropy that is passed to a PBKDF2 key-pulling function with 2048 hashing rounds to generate a 512-bit seed. This germ then acts like a bunch of keys, with which different keys are generated. Review the last section of the answer to see how private keys are generated from the seed.
How are mnemonics generated?
As mentioned above, mnemonics are the representation of entropy along with a checksum. The first step is to make a decision on how much entropy you think is safe for your operations. For example, suppose you chose 128-bit entropy for the time being. The following are the steps to convert this entropy to mnemonics.
- Use a cryptographically safe entropy generator to generate 128-bit entropy.
- Calculate that
- Hang the first
SHA256the entropy at the end of the entropy. In our case we hang for example the first 4 bits of the
SHA256(entropy)to entropy, since our entropy is 128 bits.
- Every word of mnemonic represents 11 bits. So, if you check the word list, you'll find 2048 unique words. Now share the
entropy + checksumin pieces of 11 bits each.
- Map these 11-bit fragments to the words in the lookup table in the word list. Since we used 128 bit entropy, our checksum was 4 bits. Our entropy together with the checksum thus represented a total of 132 bits. So our mnemonics will be 12 words.
If you had used 256 bit entropy, your checksum (256/32 =) would have been 8 bits. That would represent (264/11) = 24 words.
Note that 12/24 words can not be used as mnemonics. Part of the last word generally contains the checksum of the selected words and therefore needs to be calculated. It is also not recommended to generate words directly from thoughts using a secure cryptographic function.
Why do Ledger Mnemonics have 24 words?
That's a creative choice of security. The higher the number of words, the higher the entropy. 24 words result in 256 bit entropy. It is also important to note that a memory phrase can not be used between different numbers of words back and forth. For example, you can not convert a 24-word representation to 12 words and vice versa.
How are these words converted into a private key?
The mnemonic is passed to the key expansion function PBKDF2 with 2048 rounds of hashing. The PBKDF2 feature also provides the ability to use a "salt", which can be an optional passphrase. This passphrase provides an additional layer of security and prevents brute force attacks against lookup tables. The output of this function is a 512-bit start value.
This seed is then passed on
HMAC-SHA512 with key "Bitcoin seed". The resulting hash is used to create the private master key (m) and the main chain code (c). The left 256 bits represent m, while the right 256 bits represent c. The private master key
m is then used to generate the public master key M (M = m * G).
From here there are a number of derivation paths for different purses. The most common method is a hardened derivative method of BIP 44. This is used in the following section. k and K represent the private key or the associated public key.
We would first have to show that we used the GDP 44 derivation path. This can be done with an index number and create a private key one level lower than the private master key. The private child key one level lower:
kchild = kpar + hash(kpar, cpar, i) from where
i is the index number. On the hardened derivative of GDP 44
i will be
0x80000044 (we use the latter 231 half the index number for the hardened derivative). This result gives us a 512-bit number. The left 256 bits represent the private child key, and the right 256 bits represent the child chain code.
The next level represents the coin. That's for Bitcoin
0x80000000 in hardened derivative. Then calculate the private private key and the chain code using the above form.
The next level represents the account. You can use multiple accounts to represent different functions and to improve the management of your funds. You can use the logic above to generate the account's private key and chain code.
From here we no longer use the hardened derivative. The next level represents receiving an address against a change. In this way, you can set different bundles for receiving private keys and different bundles for changing private keys. The function we use to generate the child privately from the parent is:
kchild = kpar + hash(Kpar, cpar, i), Now
i will be
0x00000000 to receive and
0x00000001 for change. Also note that we now have a public key in the hash function instead of a private key.
At the next level, we use these receive and modify key bundles to generate individual private keys. Use the above generate private key and chain code and pass them to the above function
kchild = kpar + hash(Kpar, cpar, i) generate individual keys. Every increment of
i Gives you another private key.
Now use these private keys to generate bitcoin addresses.