diff --git a/16_7_Integrating_Libwally_and_Bitcoin-CLI.md b/16_7_Integrating_Libwally_and_Bitcoin-CLI.md index 5bb6d3f..b0204ba 100644 --- a/16_7_Integrating_Libwally_and_Bitcoin-CLI.md +++ b/16_7_Integrating_Libwally_and_Bitcoin-CLI.md @@ -172,7 +172,7 @@ Voila! That's the power of Libwally with `bitcoin-cli`. Obviously, you can also pass around a PSBT using the functions described in [§16.4](16_4_Using_PSBTs_in_Libwally.md) and that's a more sustainable methodlogy in the modern-day usage of Bitcoin, but in either example, the methodology of passing transactions from `bitcoin-cli` to Libwally code and back should be similarly. -## Importing & Experting BIP39 Seeds +## Importing & Exporting BIP39 Seeds Unfortunately, not all interactions go as smoothly. For example, it would be nice if you could either export an HD seed from `bitcoin-cli`, to generate the mnemonic phrase with Libwally, or to generate a seed from a mneomnic phrase on Libwally, and then import it into `bitcoin-cli`. Unfortunately, neither of these is possible at this time. A mneomnic phrase is translated into a seed using HMAC-SHA512, which means the result is 512 bits. However, `bitcoin-cli` exports HD seeds (using `dumpwallet`) and imports HD seeds (using `sethdseed`) with a length of 256 bits. Until that is changed, never the twain shall meet (and when that does change, there will be another notable improvement in the integration between `bitcoin-cli` and Libwally). @@ -180,6 +180,100 @@ Unfortunately, not all interactions go as smoothly. For example, it would be nic > :book: ***What's the difference between Entropy & Raw Entropy?*** Not all entropy is the same. When you input entropy into a command that creates a mnemonic seed, it has to a specific, well-understand length. Changing raw entropy into entropy requires massaging the raw entropy until it's the right length and format, and at that point you could reuse that (non-raw) entropy to always recreate the same mnemonics (which is why it's effectively the same thing as a seed at that point, but raw entropy isn't). +# Importing Private Keys + +Fortunately, you can do much the same thing by importing a private key generated in Libwally. Take a look at [genhd-for-import.c](src/16_7_genhd_for_import.c), a simplified version of the `genhd` program from [§16.3](16_3_Using_BIP32_in_Libwally.md) that also uses the `jansson` library from [§15.1](15_1_Accessing_Bitcoind_with_C.md). + +Be sure to compile the new code with the `jansson` library, and installing it per §15.1. +``` +$ cc genhd-for-import.c -lwallycore -lsodium -ljansson -o genhd-for-import +``` +When you run the new program, it'll give you a nicely output list of everything: +``` +$ ./genhd-for-import +{ + "mnemonic": "rotate proof kitten age exit master old verb course sea mean address", + "account-xprv": "tprv8xf6jjUuuKPG4p6erw6TUumrSJPsGH8ZowoAYXFahj3RkZ7za9aW1E2nW2Sj2GsT6JwmPsXaR4jLBZ1XrbMJvNfN6Ruk3tR9bP3hsABFqWD", + "address": "tb1q88sdux8hvt0jf3xhy0c3l3pgyc34m2kq5kylaa", + "derivation": "[m/84h/1h/0h/0/0]" +} +``` +You have the `mnemonic` that you can recover from, an `account-xprv` that you can import, a `derivation` to use for the import, and a sample `address, that you can use for testing the import. + +You can now fall back on lessons learned from [§3.5](03_5_Understanding_the_Descriptor.md) on how to turn that xprv into a descriptor and import it. + +First, you need to figure out the checksum: +``` +$ xprv=tprv8xf6jjUuuKPG4p6erw6TUumrSJPsGH8ZowoAYXFahj3RkZ7za9aW1E2nW2Sj2GsT6JwmPsXaR4jLBZ1XrbMJvNfN6Ruk3tR9bP3hsABFqWD +$ bitcoin-cli getdescriptorinfo "wpkh([d34db33f/84h/1h/0h]$xprv/0/*)" +{ + "descriptor": "wpkh([d34db33f/84'/1'/0']tpubDVM8t9XA3h4vxH8Skam3tKRy1KuoRcKUPFPwq3Ht7zqpb3NmCYQ6Bieeg8XptKHSnKTWWb2MGdZD1tYAWwKBH6H1wissCE38WHcWJKSrTzJ/0/*)#mvvxgk0j", + "checksum": "wgknk6u4", + "isrange": true, + "issolvable": true, + "hasprivatekeys": true +} +``` +Two things to note here: + +1. We made up a fingerprint (`d34db33f`). You can do that, as long as you're consistent (and as long as the original source doesn't have its own fingerprint). +2. We are not going to use the returned `descriptor` line, as that's for a `xpub` address. Instead we'll apply the returned `checksum` to the `xprv` that we already have. + +We then plug that into `importmulti` to import this key into `bitcoin-cli`: +``` +$ cs=wgknk6u4 +$ bitcoin-cli importmulti '''[{ "desc": "wpkh([d34db33f/84h/1h/0h]'$xprv'/0/*)#'$cs'", "timestamp": "now", "range": 10, "watchonly": false, "label": "LibwallyImported", "keypool": false, "rescan": false }]''' +[ + { + "success": true + } +] +``` +Note here that the descriptor here included the path `/0/*` because we wanted the external addresses for this account. We derived the first ten. If we instead wanted the change addresses, we'd use `/1/*`. + +Examining the new `LibwallyImported` label shows ten addresses: +``` +$ bitcoin-cli getaddressesbylabel "LibwallyImported" +{ + "tb1qpgt0wukrm8wz6gdu7jc9ltmrxzagdtflg4huvt": { + "purpose": "receive" + }, + "tb1qyds9q02a03vveu25gewxxssy2uszm0q2v04hhx": { + "purpose": "receive" + }, + "tb1q88sdux8hvt0jf3xhy0c3l3pgyc34m2kq5kylaa": { + "purpose": "receive" + }, + "tb1qg9a7xnm9lkketnfvzkcc7gfwvc9lt4dcsp0zrh": { + "purpose": "receive" + }, + "tb1qfzr0nqcvs73fhkgy7n8zavjzqxvewfzpsn9zkm": { + "purpose": "receive" + }, + "tb1qdlj7n66kzce5sw67twe6zsylcddnn3q7v85uqn": { + "purpose": "receive" + }, + "tb1q39dxeawe4w275tpye8p5tt74g965c534ux0yfc": { + "purpose": "receive" + }, + "tb1qnq2r00894jxucpnkdl2r72arjvj4th8eeysp7j": { + "purpose": "receive" + }, + "tb1q4h399mcz0m7fjz92nhvk5dyww09fpedusr6n7n": { + "purpose": "receive" + }, + "tb1q6squxmxqmca9rqqndp6wz5hng8h6pc6ajpgz8j": { + "purpose": "receive" + }, + "tb1qu23p72l60tc3jktjfdx0zr6tlqtkjfk9xzkrkl": { + "purpose": "receive" + } +} +``` +And the third one on our list indeed matches our sample (`tb1q88sdux8hvt0jf3xhy0c3l3pgyc34m2kq5kylaa`). The import of this private key and the derivation of ten addresses was successful. + +Now, if you look back at [§7.3](07_3_Integrating_with_Hardware_Wallets.md), you'll see this was the same methodology we used to import addresses from a Hardware Wallet (though this time we also imported the private key as proof of concept). The biggest difference is that before the information was created by a black box (literally, a Ledger device), and this time you created the information yourself using Libwally, showing how you can do this sort of work on airgapped or other more remote devices, then bring it over to `bitcoin-cli`. + ## Importing Addresses 3. Importing & Exporting Private Keys