This section describes how to go from random entropy to 24 mnemonic words.
This is a 256bit number
This involves running the 256bit number through SHA256, extracting the first 8 bits and appending them at the end of the 256 bit sequence
This next step splits the 264 bit sequence into 11 bit sequences (24 of them)
Map each 11 bit value to a word in the predefined dictionary
The dictionary is common across multiple wallets so most of the mnemonic words are inter changeable.
Stretching the 256bit entropy from menmonic words into 512bit seed
Create a salt. If no password is chosen, the salt will be comprised of the string "mnemonic"
Create initial PBKDF2 round by passing the entropy as the key and the salt as the data.
Repeat this 2048 times. The entropy parameter stays the same, while the data is the xor of the current and previous result
Generally the seed is exported as a hex string.
An extended key is a Base58Check encoded string that encodes a few pieces of information.
4 bytes that denote weather we're encoding a public or private key. The version number is what starts an extended by with xpub or xprv. The bytes in the version number combined with the rest of the data produces the xpub/xprv in Base58 encoding.
1 byte that denotes the depth.
4 bytes (the first 4 bytes of the SHA256 --> Ripemd160 hash of the parent key)
4 bytes
32 bytes
33 bytes - If private key it will be prepended with a zero byte
The derivation path includes information about the depth and index for a key.
m/44'/0'/0'
The Depth is how far from the m/ you are. m/0 would be depth 0, m/0/1 would be depth 1.
The Index is the number. m/2 would have an index of 2.
If the index is hardened (') the index is actually 2_147_483_647 + index. m/44' would be index 2_147_483_691.
The derivation path is split into a list of numbers each representing one depth level.
At each subsequent step the previous key and chain code is used and the depth increased by 1.
Elliptical Curve Cryptography
We are using a few operations on the Secp256k1 curve to help us compute keys in our derivations.
A non hardened child key derivation means that we will use the parent's public key to derive the child key. It also means that the index will be at most 2_147_483_647
This is a non-hardened path so we won't get any ' in the path (ie. m/0/0)
This will result in a key, chain code, depth, index and version number.
This is the first 4 bytes of the SHA256 -> RIPEMD160 hash functions.
Depth increases by 1 while index by the path number currently deriving.
The resulting 512bit number is the child key (first 256bits and the child chain code the rest 256bits)
This is the same point multiplication we use to derive a public key from a private key, except this time we use the parent public key to derive a child public key.
This step is required to get the X and Y coordinates of the resulting child key.
The resulting extended by is just the compressed version (just the X coordinate) of the (X,Y) point. We append 02 if the Y coordinate is even or 03 otherwise.
The version number used will be the public one.
The private child key derivation is similar to the public one with a few exceptions.
This is a non-hardened path so we won't get any ' in the path (ie. m/0/0)
This decoded key will have a 0 appended to it and we need to strip that.
This is the first 4 bytes of the SHA256 -> RIPEMD160 hash functions.
Depth increases by 1 while index by the path number currently deriving.
The resulting 512bit number is the child key (first 256bits and the child chain code the rest 256bits)
This is the same point multiplication we use to derive a public key from a private key, except this time we use the parent public key to derive a child public key.
This is the same point multiplication we use to derive a public key from a private key, except this time we use the parent public key to derive a child public key.
We're using the private version number here.
The resulting key will start with xprv
Why hardened and non-hardened paths?
There are use cases for each as well as pros and cons.
Non-hardened derivation is what allows us to generate addresses from a Master Public Key on a live server.
The danger with this method is that if one child private key and the Master Public Key is leaked, an attacker can calculate the parent private key (this compromises the whole HD wallet).
Hardened key derivation is useful when you want to share a hierarchy of private keys and keep them isolated.
You cannot generate child addresses on a hardened path without the private key.
A hardened derivation offsets the index of each path integer by 2^31. All the previous steps apply except that for both private and public derivation the resulting public or private key is calculated using the parent private key. This means that you can't derive a downstream path for a hardened path.
We're using the parent private key to perform this step as stated above. This means that if we have an extended public key and we want to derive a path like m/0' we won't be able to because we don't have access to the private key which is required in this step.
Once we have a way to generate a tree of public keys, getting a blockchain address is only a matter of hashing or encoding it the right way.
A bitcoin pay-to-hash address is a SHA256 -> RIPEMD160 -> Base58Check of the compressed public key.
A ripple address is similarly a SHA256 -> RIPEMD160 -> Base58Check but with a different alphabet than Bitcoin. That's why addresses look different.
Ethereum addresses start from the same precursor as Bitcoin and Ripple, except we use the un-compressed public key (concatenated X and Y), take the Keccak256 hash of that and keep the last 20 bytes.
These are just a few examples of the top 3 coins but this scheme can be extended to support most blockchains out there. This is a list of the supported coins for the BIP44 standard.