sparrowwallet / sparrow

Desktop Bitcoin Wallet focused on security and privacy. Free and open source.
https://sparrowwallet.com/
Apache License 2.0
1.34k stars 189 forks source link

Import from extended private key #58

Closed pedromvpg closed 3 years ago

pedromvpg commented 3 years ago

Currently sparrow only allows importing from mnemonic and wallet files. Possible to import from extended private key? no mnemonic?

image

craigraw commented 3 years ago

Not yet - considering implementing support for WIF, but xprv is also possible.

vindard commented 3 years ago

Bump, I could also really use this for shifting some of my wallets across from Electrum

craigraw commented 3 years ago

Implemented in 3fc2127.

Screenshot 2021-04-20 at 08 33 24
edxszymonski commented 1 year ago

Was this feature already removed or it hasn't been actually released? Also, I'm not sure how it actually works. I'm looking for a way to import BIP32 seed exported from Bitcoin Core HD wallet before descriptors were introduced (dumpwallet command, seed is in a form of a WIF key labeled as hdseed).

craigraw commented 1 year ago

This is an old issue, and since it was closed Sparrow supports both xprv and WIF formats. The former represents a BIP32 wallet, containing a chaincode, and the latter a single address wallet. Sparrow can import an xprv as an HD wallet, and can sweep the funds in a WIF to any existing HD wallet. Single address wallets are not supported, and despite the label your WIF key does not represent an 'hdseed'.

edxszymonski commented 1 year ago

OK, I was having trouble finding in the software the feature discussed in this thread. I just discovered it is available in File, New Wallet, New or Imported Software Wallet, Master Private Key (BIP32). However, I find it confusing that it is available there but not in File, Import Wallet.

Using this feature I can import xprv from Bitcoin Core, however, it will not discover the proper addresses (proper as in using the same derivation paths as Bitcoin Core) because, firstly Sparrow seems to be using unhardened derivation and Bitcoin Core BIP32 before introduction of descriptor wallets (I don't know how it is now with descriptors) was using hardened derivation, and secondly Sparrow derives paths following BIP44 (or something similar) I.e. the first address in Bitcoin Core wallet would be at m/0'/0'/0' whereas in Sparrow (assuming, using the discussed feature I add xprv key from dumped wallet of Bitcoin Core and set path as m/0'/0') the first address is at m/0'/0'/0/0.

Unless I am doing something wrong. Also, the WIF I was talking about is just a representation of a BIP32 seed, I am not talking about WIF for a single private key.

Repro steps:

In Bitcoin Core v 23.0.0: File, create wallet, UNcheck "descriptor wallet" option so no checkbox is checked. Go to Windows, Console, dumpwallet "/your/path/walletdumpname.txt" In dumped file find lines that contain "extended private masterkey:" (this contains xprv), "hdseed=1" (this has seed as WIF), "hdkeypath=m/0'/0'/0'" (this is the first address). In my case it was the following (those are just test keys, not used for any transactions and will never be used for such purpose so it is safe to publish them):

extended private masterkey: xprv9s21ZrQH143K3PSVopmfaxUHKnm6vuPrvGDEBEVnH39oByjmQgC2sxHAUFuoe2EHRnvPKb2pwrvHDv3wmMQFgnBUfb7hBHwofdAXFimWqHa hdseed=1: L1si8QBYLZMNvBUfJ2soeYff5Brr4pq8uLrDtm64gMZ2FdVskHKq hdkeypath=m/0'/0'/0': bc1qhlq90h0snaqjm492e5al0regcnn2w9mkhx4all

If you decode seed WIF using e.g. https://www.better-converter.com/Encoders-Decoders/Base58Check-to-Hexadecimal-Decoder you will get hex output 808ae5d175d5c9d4fc8301da4f71189f84ad981069c87259b2852eccaba1e9adfc019e36d2dc. Get rid of first two chars and last ten chars (two chars for compression, eight chars for checksum) and you are left with 64 chars which is 256-bits long BIP32 seed (8ae5d175d5c9d4fc8301da4f71189f84ad981069c87259b2852eccaba1e9adfc). If you run this through HMAC SHA512 as seed and key "Bitcoin seed" (sorry no link, couldn't find a proper online encoder, had to do code it locally) you will get matching xprv9s21ZrQH143K3PSVopmfaxUHKnm6vuPrvGDEBEVnH39oByjmQgC2sxHAUFuoe2EHRnvPKb2pwrvHDv3wmMQFgnBUfb7hBHwofdAXFimWqHa, therefore what we get in Bitcoin Core dumpwallet labeled as hdseed=1 IS a BIP32 seed (see also https://github.com/bitcoin/bitcoin/issues/8684#issuecomment-245603797).

Anyway, if you try importing the xprv above to Sparrow via New or Imported Software Wallet, Master Private Key (BIP32) with Custom Derivation Keystore set to "m/0'/0'" it gets us xpub at "m/0'/0'" of xpub6AHQJKqfwgjP3yx4SE61u3ELuKdUMXrMWpEmuemKzf2B9Hu1D7seFPpBCEwZaRR4v55bc8N3CGTcffcNE6obqtogV6wz4T2aLunT8ZZ2yTS and first address of bc1qnz0j7m9jamhy9gh4segzy4vgrjsfkav9tr9pex at "Derivation: m/0'/0'/0/0" (Receive tab).

If you go to https://iancoleman.io/bip39/ and put our seed of 8ae5d175d5c9d4fc8301da4f71189f84ad981069c87259b2852eccaba1e9adfc into "BIP39 Seed" field (rather unlucky naming, but we are not discussing BIP39 here) you will see we get "BIP32 Root Key" matching the xprv I provided earlier. Scroll down to BIP32 and set Client Bitcoin Core. BIP32 Extended Public Key below matches the xpub from Sparrow. Now go to BIP141 (not BIP32 because it does not support P2WPKH here, BIP141 tab does) set derivation path m/0'/0', script to P2WPKH and select "Use hardened addresses" and the first address at m/0'/0'/0' is bc1qhlq90h0snaqjm492e5al0regcnn2w9mkhx4all matching my dump above. If we uncheck the "Use hardened addresses" and change derivation path to m/0'/0'/0 we get bc1qnz0j7m9jamhy9gh4segzy4vgrjsfkav9tr9pex at m/0'/0'/0/0 that matches what Sparrow produces.

So the main question again is, how to import HD wallet dumped from Bitcoin Core (non-descriptor HD wallet) to Sparrow. I mean, Sparrow imports the xprv properly but derivates addresses diferently. Apologies for the long post but I wanted to explain my whole train of thought so you can point any flaws.

craigraw commented 1 year ago

Sparrow follows BIP32, with external and internal chains mapping to the receive and change addresses respectively. These are specified as unhardened derivations from the default derivation path for a particular script type, as per BIP44, BIP84 etc. The latter can be changed as a custom derivation path, but the former cannot. So whatever custom derivation path you choose, you will always have /0/* and /1/* appended to it for the full address derivation. Without it, the wallet has no ability to select a change address, resulting in potential address reuse.

edxszymonski commented 1 year ago

OK, thanks for the explanation. This does not make me happy as this basically means I cannot access funds from xprv imported from Bitcoin Core but at least I know how it works. I have allowed myself to create a feature request to cover "proper" migration of xprv from Bitcoin Core in the future, in https://github.com/sparrowwallet/sparrow/issues/846