BIP32 Cheat Sheet

Implementation steps with sample code in Elixir for BIP32 HD Wallet standard.


Mnemonic Phrase

This section describes how to go from random entropy to 24 mnemonic words.

  1. Random Entropy

    This is a 256bit number

  2. Build Checksum

    This involves running the 256bit number through SHA256, extracting the first 8 bits and appending them at the end of the 256 bit sequence

  3. Split into 11 bit sequence

    This next step splits the 264 bit sequence into 11 bit sequences (24 of them)

  4. Return 24 word mnemonic

    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.

  1. abandon
  2. ability
  3. able
  4. about
  5. ...

Generate the seed

Stretching the 256bit entropy from menmonic words into 512bit seed

  1. Salt

    Create a salt. If no password is chosen, the salt will be comprised of the string "mnemonic"

  2. Key Stretching

    Create initial PBKDF2 round by passing the entropy as the key and the salt as the data.

  3. Repeat 2048 times

    Repeat this 2048 times. The entropy parameter stays the same, while the data is the xor of the current and previous result

  4. Encode in hexadecimal

    Generally the seed is exported as a hex string.


Anatomy of an exteded key

An extended key is a Base58Check encoded string that encodes a few pieces of information.

  1. Version Number

    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.

  2. Depth

    1 byte that denotes the depth.

  3. Fingerprint

    4 bytes (the first 4 bytes of the SHA256 --> Ripemd160 hash of the parent key)

  4. Index

    4 bytes

  5. Chain Code

    32 bytes

  6. Key

    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.

  • Point multiplication
  • Point addition
  • Modulus the order of the curve

Child Key Derivation (public, non-hardened)

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

  1. Split the derivation path into list of integers.

    This is a non-hardened path so we won't get any ' in the path (ie. m/0/0)

  2. Decode parent extended key

    This will result in a key, chain code, depth, index and version number.

  3. Calculate child fingerprint from parent key

    This is the first 4 bytes of the SHA256 -> RIPEMD160 hash functions.

  4. Increase the depth and index

    Depth increases by 1 while index by the path number currently deriving.

  5. Calculate PBKDF2 HMAC512 of the parent chain code & key + index

    The resulting 512bit number is the child key (first 256bits and the child chain code the rest 256bits)

  6. Use resulting key to perform EC curve multiplication with G to compute 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.

  7. De-compress the parent public key into the X and Y coordinates.
  8. Perform EC point addition of the P(X,Y) and the child public key.

    This step is required to get the X and Y coordinates of the resulting child key.

  9. Check if the resulting X, Y coordinate fall within the curve's finite field.

    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.

  10. Encode resulting data with Base58Check

    The version number used will be the public one.


Child Key Derivation (private, un-hardened)

The private child key derivation is similar to the public one with a few exceptions.

  1. Split the derivation path into list of integers.

    This is a non-hardened path so we won't get any ' in the path (ie. m/0/0)

  2. Decode parent extended key

    This decoded key will have a 0 appended to it and we need to strip that.

  3. Calculate the public key using EC multiplcation.

    This is the first 4 bytes of the SHA256 -> RIPEMD160 hash functions.

  4. Compress the public key obtained in the previous step.

    Depth increases by 1 while index by the path number currently deriving.

  5. Use the compressed public key from previous step to calculate the fingerprint.

    The resulting 512bit number is the child key (first 256bits and the child chain code the rest 256bits)

  6. Calculate depth.

    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.

  7. Use PBKDF2 HMAC512 to calculate child key and chaincode.

    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.

  8. Run the resulting key through mod curve order to ensure the point falls within the finite field.
  9. Encode resulting data with Base58Check

    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

    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

    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.

Child Key Derivation (hardened)

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.

  1. Use resulting key to perform EC curve multiplication with G to compute child public or private key.

    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.


Addresses

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.

  • Bitcoin

    A bitcoin pay-to-hash address is a SHA256 -> RIPEMD160 -> Base58Check of the compressed public key.

  • Ripple

    A ripple address is similarly a SHA256 -> RIPEMD160 -> Base58Check but with a different alphabet than Bitcoin. That's why addresses look different.

  • Ethereum

    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.