How to derive the private key associated with a Coinbase multi-sig vault address When I created a multi-sig vault on Coinbase, I obtained:


A master public key in BIP32 extended format, of depth 0, parent fingerprint 00000000 and child index 0.
A private key in WIF format ("user seed"), which I don't know if it has been hardened, derived from a public key, nor the depth or index.


I am trying to prove ownership of an address derived from the master public key at index 14. So using bip32.org I have been able to derive the public key in BIP32 extended format at index m/14, that corresponds exactly to the address for which I need to prove ownership.

My objective now is therefore to derive the private key for which the address is the same as the address of the derived public key at index m/14, based on the information I have. If possible with pybitcointools.

I tried asking a more general question here, but it was a good case of XY problem (I asked about my attempted solution rather than actual problem).
I did some digging into Coinbase's offline multisig tool to figure out what the user seed actually was and their derivation paths. It turns out the user seed is just that, a seed that is used to get the Master Private Key. This is done by hashing it with HMAC-SHA512 where the key is the string Bitcoin seed and the data is the binary form of the user seed (which means decode it and get the binary data). 

To do this with pybitcointools, we first decode the WIF user seed with decode_privkey and re-encode it with encode_privkey in order to get the binary form. Then we pass that into bip32_master_key to get the bip32 master key from that seed. And from there, just call bip32_ckd to get the extended private key of whichever index child we want. Lastly we extract the actual private key with bip32_bin_extract_key and encode that with encode_privkey in order to get it into WIF form which can be imported and used in other wallet software.

The below code does all of this for you and will print out the extended master private key derived from the seed, the extended public key derived from the master key (which should match the public key you have), the extended child private key, and that child key in WIF.

Replace the values for USER_PUB, USER_SEED, and I with your actual user public key, user seed, and child index that you want. The values I have here are real and will work.

from pybitcointools.deterministic import bip32_ckd, bip32_master_key, bip32_bin_extract_key, bip32_privtopub
from pybitcointools.main import decode_privkey, encode_privkey

USER_PUB = 'xpub661MyMwAqRbcEzdGMFKZXuVwbyHY2zKhiw6YFTrULfNBF53QVfXyoAiKMZKWkQA5444NXtLj9HPmgyN1xLCiJJ9dKAy4nLZJ87trHRnwUDb'
USER_SEED = 'L3XCYcQ2pwY3YTuwyPXzWsvVtGnCp4zL2ajP3XQt2pVhPuKiVM7r'
I = 14

user_seed = encode_privkey(decode_privkey(USER_SEED), 'bin')
priv = bip32_master_key(user_seed)
derived_pub = bip32_privtopub(priv)
child_priv = bip32_ckd(priv, I)
assert USER_PUB == derived_pub
print "Master Private Key corresponding to seed: " + priv
print "Master Public Key corresponding to seed: " + derived_pub
print "Extended Private key at index " + str(I) + ": " + child_priv
print "WIF format of that key: " + encode_privkey(bip32_bin_extract_key(child_priv), 'wif_compressed')