6

Quote from BIP 32:

One weakness that may not be immediately obvious, is that knowledge of a parent extended public key plus any non-hardened private key descending from it is equivalent to knowing the parent extended private key (and thus every private and public key descending from it).

How is this done?

7

First we must understand how BIP 32 derives non-hardened private and public keys.

From BIP 32, deriving a child private key from an extended parent private key:

let I = HMAC-SHA512(Key = cpar, Data = serP(point(kpar))) || ser32(i)).

Split I into two 32-byte sequences, IL and IR.

The returned child key Ki is parse256(IL) + kpar (mod n).

The private key is thus the parent private key plus the first 256 bits of the HMAC-SHA512 function where the key is the chaincode of the parent private key and the hashed data is the concatenation of the serialization of the public key that corresponds to the extended private key and the child key index. The important thing here to note is that the HMAC-SHA512 hash is a hash of the public key, not the private key.

From BIP 32, deriving a child public key from an extended parent public key:

let I = HMAC-SHA512(Key = cpar, Data = serP(Kpar) || ser32(i)).

Split I into two 32-byte sequences, IL and IR.

The returned child key Ki is point(parse256(IL)) + Kpar.

The child public key is the parent public key added with the public key generated from the first 256 bits of the HMAC-SHA512 function where the key is the chaincode of the parent key and data is the concatenation of the parent public key with the index of the child public key.

Notice how when deriving the child private key and the child public key you are actually hashing the same thing? You are performing the HMAC-SHA512 function with the same key (the chaincode of the parent keys) and the same data (the concatenation of the parent public key and the index of the child key). The first 256 bits of that hash become a private key of sorts, and that private key is added to the master private key to become the actual child private key. Its public key is calculated and added with the parent public key to become the child public key.

So to get the master private key, all we need to do is take the child private key that we now have, and subtract from it the private key produced by the HMAC-SHA512 function. To do that, we need three things, the chaincode, the parent public key, and the child key index.

The chaincode and parent public key come from the extended parent public key (xpub) as it encodes both the chaincode and the public key in it.

The child key index can be trivially found by deriving child public keys from the parent public key until we get the public key which corresponds to the child private key that we have and save the key index.

With these three things, we can perform the HMAC-SHA512 function and get the 512 bit hash. Now we can take the child private key and subtract from it the integer that is the first 256 bits of the hash we just generated. Our result is the parent private key. Combine that with the chaincode that we retrieved from the extended parent public key and we have ourselves the extended parent private key.


This technique only applies to non-hardened derivation. Hardened derivation protects against this because it generates the child private key by hashing the parent private key. However this also means that you cannot generate the child public key from the parent public key.

  • Can you clarify how this topic is a duplicate of my question here: bitcoin.stackexchange.com/questions/57023/… The topic is similar but your answer, while great here, wouldn't be suitable for my question. – Erwin Mayer Jul 25 '17 at 4:38
  • You are asking how to get the extended master private key from the master public key and child private key. The steps to do so are explained here. The only other addition to your question is about WIF and xpub format. Those are just encodings of binary data, so just decode them to get the raw values and perform the operations described in this answer. – Andrew Chow Jul 25 '17 at 4:49
  • Thanks, how to go from a BIP32 seed to a xpub address using Python is precisely my question (sorry if this looks trivial to you), since pybitcointools already has a convenience function to perform the key derivation you outline in your answer (but it requires keys in xpub format). My understanding, at least on Stackoverflow, is that a question should be marked as duplicate only if it can be fully satisfied by the answer of another question, which doesn't seem to be the case here. – Erwin Mayer Jul 26 '17 at 1:33
  • That may have been the question you intended to ask, but that was not that question that was actually asked. Your question was "Recover the extended BIP32 master private key ..." not "How to get the xprv from a wif key". Your question really shouldn't mention "recover extended master private key" at all as that is unrelated to what you actually want to know about. – Andrew Chow Jul 26 '17 at 1:42

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.