|
| 1 | +# 10.4: Exporting Secrets from Bitcoin Core |
| 2 | + |
| 3 | +We've spent three sections importing a secret into Bitcoin Core. We're |
| 4 | +now going to reverse course and see how to export a secret. (It's a |
| 5 | +lot easier!) |
| 6 | + |
| 7 | +## Reset Your Wallet |
| 8 | + |
| 9 | +We're going to continue working in |
| 10 | +[mainnet](https://learningbitcoin.blockchaincommons.com/10_3_Importing_Secrets_to_Bitcoin_Core/#use-mainnet) |
| 11 | +for this example, but you should use a Bitcoin Core-generated wallet, |
| 12 | +not the descriptor-based wallet we imported in the last section. |
| 13 | + |
| 14 | +Unload your "seed" wallet from the last section or create a new "" |
| 15 | +wallet depending on what you've done to date with Bitcoin Core. |
| 16 | + |
| 17 | +``` |
| 18 | +bitcoin-cli unloadwallet "seed" |
| 19 | +
|
| 20 | +| { |
| 21 | +| } |
| 22 | +
|
| 23 | +bitcoin-cli listwallets |
| 24 | +
|
| 25 | +| [ |
| 26 | +| "" |
| 27 | +| ] |
| 28 | +``` |
| 29 | + |
| 30 | +## Understand What You Can Export |
| 31 | + |
| 32 | +It would be ideal to export seeds or seed phrases, but Bitcoin Core |
| 33 | +doesn't currently support doing so. |
| 34 | + |
| 35 | +That leaves you with two options: |
| 36 | + |
| 37 | +1. Export a master private key, which can be used to recreate all descriptors. |
| 38 | +2. Export individual descriptors. |
| 39 | + |
| 40 | +The first option makes it easy to store just a tiny bit of information |
| 41 | +and restore everything from it, but you have to know what derivation |
| 42 | +paths your addresses are attached to (or else, you have to check |
| 43 | +addresses for every possible derivation path when you import). |
| 44 | + |
| 45 | +The second option requires more data storage, but ensures that you |
| 46 | +have the precise data on the accounts (derivation paths) where you |
| 47 | +might have funds. |
| 48 | + |
| 49 | +## Understand Bitcoin Core Outputs |
| 50 | + |
| 51 | +The `listdescriptors` RPC command is what you use to retrieve |
| 52 | +information about your keys and descriptors for export. You've seen it a number |
| 53 | +of times: |
| 54 | + |
| 55 | +``` |
| 56 | +bitcoin-cli listdescriptors |
| 57 | +
|
| 58 | +| { |
| 59 | +| "wallet_name": "", |
| 60 | +| "descriptors": [ |
| 61 | +| { |
| 62 | +| "desc": "pkh([3ce1d173/44h/0h/0h]xpub6BxVLeeQGSK4tVGLLZopaabNwFUZe223FfLCAa3PWNxpwqnCcZVRvDNH13fKh4Ea5w785U9a7u1LX5Tu9m9gpdi2i5PEE6aMNvXGi2LuKdV/0/*)#q8nl9w4h", |
| 63 | +| "timestamp": 1779999396, |
| 64 | +| "active": true, |
| 65 | +| "internal": false, |
| 66 | +| "range": [ |
| 67 | +| 0, |
| 68 | +| 999 |
| 69 | +| ], |
| 70 | +| "next": 0, |
| 71 | +| "next_index": 0 |
| 72 | +| }, |
| 73 | +| { |
| 74 | +| "desc": "pkh([3ce1d173/44h/0h/0h]xpub6BxVLeeQGSK4tVGLLZopaabNwFUZe223FfLCAa3PWNxpwqnCcZVRvDNH13fKh4Ea5w785U9a7u1LX5Tu9m9gpdi2i5PEE6aMNvXGi2LuKdV/1/*)#3nk7cm90", |
| 75 | +| "timestamp": 1779999396, |
| 76 | +| "active": true, |
| 77 | +| "internal": true, |
| 78 | +| "range": [ |
| 79 | +| 0, |
| 80 | +| 999 |
| 81 | +| ], |
| 82 | +| "next": 0, |
| 83 | +| "next_index": 0 |
| 84 | +| }, |
| 85 | +| { |
| 86 | +| "desc": "sh(wpkh([3ce1d173/49h/0h/0h]xpub6BopUUpLTpQDti8eEjdRKhp1bGcxHXJ9Mvdm23iSPSPh84ofH6icrDg8sH4kowsZEDcYynaHPqVS4mvrMvgHpi2sNKSBEG9s11SeR9yfvJ2/0/*))#32q0qkdf", |
| 87 | +| "timestamp": 1779999396, |
| 88 | +| "active": true, |
| 89 | +| "internal": false, |
| 90 | +| "range": [ |
| 91 | +| 0, |
| 92 | +| 999 |
| 93 | +| ], |
| 94 | +| "next": 0, |
| 95 | +| "next_index": 0 |
| 96 | +| }, |
| 97 | +| |
| 98 | +| ... |
| 99 | +| ] |
| 100 | +| } |
| 101 | +... |
| 102 | +
|
| 103 | +By default, each descriptor shown by `listdescriptors` contains the |
| 104 | +account public key for that descriptor. You'll note that they're the |
| 105 | +same for the external and internal descriptors for the address, but |
| 106 | +when you move on to a different derivation path, they're different. |
| 107 | +
|
| 108 | +So the public keys for the two `44h/0h/0h` addresses are |
| 109 | +`xpub6BxVLe...` while the public key for the `49h/0h/0h` address is |
| 110 | +`xpub6BopUU...`. You know that these addresses are account keys |
| 111 | +because the account derivation path is given before the key in the |
| 112 | +brackets. |
| 113 | +
|
| 114 | +Now, public keys aren't at all useful if you're trying to backup your |
| 115 | +secrets. Fortunately, `listdescriptors` will give you private keys if |
| 116 | +you add a `true` argument (which sets the `private` named argument to |
| 117 | +true). |
| 118 | +
|
| 119 | +``` |
| 120 | +bitcoin-cli -rpcwallet="" listdescriptors true |
| 121 | + |
| 122 | +| { |
| 123 | +| "wallet_name": "", |
| 124 | +| "descriptors": [ |
| 125 | +| { |
| 126 | +| "desc": "pkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/44h/0h/0h/0/*)#e0uydrgt", |
| 127 | +| "timestamp": 1779999396, |
| 128 | +| "active": true, |
| 129 | +| "internal": false, |
| 130 | +| "range": [ |
| 131 | +| 0, |
| 132 | +| 999 |
| 133 | +| ], |
| 134 | +| "next": 0, |
| 135 | +| "next_index": 0 |
| 136 | +| }, |
| 137 | +| { |
| 138 | +| "desc": "pkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/44h/0h/0h/1/*)#gme9skcn", |
| 139 | +| "timestamp": 1779999396, |
| 140 | +| "active": true, |
| 141 | +| "internal": true, |
| 142 | +| "range": [ |
| 143 | +| 0, |
| 144 | +| 999 |
| 145 | +| ], |
| 146 | +| "next": 0, |
| 147 | +| "next_index": 0 |
| 148 | +| }, |
| 149 | +| { |
| 150 | +| "desc": "sh(wpkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/49h/0h/0h/0/*))#pfqdkhdr", |
| 151 | +| "timestamp": 1779999396, |
| 152 | +| "active": true, |
| 153 | +| "internal": false, |
| 154 | +| "range": [ |
| 155 | +| 0, |
| 156 | +| 999 |
| 157 | +| ], |
| 158 | +| "next": 0, |
| 159 | +| "next_index": 0 |
| 160 | +| }, |
| 161 | +| |
| 162 | +| ... |
| 163 | +| |
| 164 | +| ] |
| 165 | +| } |
| 166 | +``` |
| 167 | +
|
| 168 | +You'll note that the [bracketed] prefix is now gone. Instead, the |
| 169 | +entire derivation path appears _after_ the key (which is now a private |
| 170 | +key). That means that you're now seeing the master private key, before |
| 171 | +any derivation occurs. As you'd expect, that master key is exactly the |
| 172 | +same for each of the accounts (derivation paths). |
| 173 | +
|
| 174 | +It's great that Bitcoin Core gives you access to the master private |
| 175 | +key. |
| 176 | +
|
| 177 | +It's not great that it shows the underived master key in each of its |
| 178 | +account descriptors, because that means that if any of them is |
| 179 | +compromised, they all are. (But we can use `keytool` to change what we |
| 180 | +store, which we'll do in the next section.) |
| 181 | +
|
| 182 | +### Testing Derivation |
| 183 | +
|
| 184 | +If you're ever unsure of what Bitcoin Core (or any other Bitcoin |
| 185 | +program) is showing you, then you can always use `keytool` to test |
| 186 | +your understanding. |
| 187 | +
|
| 188 | +In this case, we think we understand that `xprv9s21Zr...` is a master |
| 189 | +private key and ``xpub6BxVLe...` is an account public key, derived |
| 190 | +from it for `44h/0h/0h`. You can verify that by inputting the |
| 191 | +(purported) master key into `keytool` and verifying that the account |
| 192 | +public key for `44h/0h/0h` is what you expect. |
| 193 | +
|
| 194 | +``` |
| 195 | +keytool --master-key xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4 --account-derivation-path "m/44h/0h/0h" account-pub-key-base58 |
| 196 | + |
| 197 | +| xpub6BxVLeeQGSK4tVGLLZopaabNwFUZe223FfLCAa3PWNxpwqnCcZVRvDNH13fKh4Ea5w785U9a7u1LX5Tu9m9gpdi2i5PEE6aMNvXGi2LuKdV |
| 198 | +``` |
| 199 | +
|
| 200 | +It is! |
| 201 | +
|
| 202 | +## Store Your Data |
| 203 | +
|
| 204 | +You can now collect the information you'd need to restore this |
| 205 | +data. `jq` can be used to pull out the whole list of descriptors: |
| 206 | +
|
| 207 | +``` |
| 208 | +DESCS=$(bitcoin-cli listdescriptors true | jq -r '.descriptors[].desc') |
| 209 | +DESC_ARRAY=($DESCS) |
| 210 | + |
| 211 | +for ((i = 0; i < 8; i++)); do |
| 212 | + echo "$i: ${DESC_ARRAY[$i]}"; |
| 213 | +done |
| 214 | + |
| 215 | +| 0: pkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/44h/0h/0h/0/*)#e0uydrgt |
| 216 | +| 1: pkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/44h/0h/0h/1/*)#gme9skcn |
| 217 | +| 2: sh(wpkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/49h/0h/0h/0/*))#pfqdkhdr |
| 218 | +| 3: sh(wpkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/49h/0h/0h/1/*))#82ggd6xh |
| 219 | +| 4: tr(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/86h/0h/0h/0/*)#q58cmp0l |
| 220 | +| 5: tr(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/86h/0h/0h/1/*)#3qzex5l8 |
| 221 | +| 6: wpkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/84h/0h/0h/0/*)#u8jwrsql |
| 222 | +| 7: wpkh(xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/84h/0h/0h/1/*)#dnh079s8 |
| 223 | +``` |
| 224 | +
|
| 225 | +Since all of the descriptors include the master private key, you can |
| 226 | +retrieve it from any of them. |
| 227 | +
|
| 228 | +``` |
| 229 | +MP_KEY=$(echo ${DESC_ARRAY[0]} | awk -F"[()]" '{print $2}') |
| 230 | +echo $MP_KEY |
| 231 | + |
| 232 | +| xprv9s21ZrQH143K4YGw3kaAmh3ezx1Xo4AanFmnX8TbaGghuNxXP9MDt2rPrLDyouX5kg9fiDJn7BELPnWRKwtVFn6aUBaNYJC9Mu6s39DnAo4/44h/0h/0h/0/* |
| 233 | +``` |
| 234 | +
|
| 235 | +## Summary: Exporting Secrets from Bitcoin Core |
| 236 | +
|
| 237 | +Bitcoin Core doesn't currently allow you to export the seed. However, |
| 238 | +you can export either your master private key or your descriptors from |
| 239 | +the `listdescriptors` command |
| 240 | +
|
| 241 | +## What's Next? |
| 242 | +
|
| 243 | +Conclude "Exploring the Ecosystem" with [§10.5: Storing Secrets with |
| 244 | +Envelope](0_5_Storing_Secrets_with_Envelope.md). |
| 245 | +
|
| 246 | +
|
| 247 | +
|
| 248 | +
|
0 commit comments