I am puzzled by the hardened key derivation from a watch-only BIP44 wallet.
Let me first explain what I am trying to do.
- I am implementing a 2-of-3 multisig scheme
- I am using Bcoin node and wallet
- All 3 keys are externally generated
- I want to use Bcoin watch-only wallet
ts to create addresses and scripts
This is what I have done so far:
- Created 3 xprv keys and xpubs keys using this tool here
- I used custome path
m/44'/0'/0'to have hardened keys because Bcoin wallet requires BIP44 hardened keys
- I created 3 watch-only wallets using the
- Then I added each of the keys as shared keys to each other (I only really have to do this for one wallet)
The code is as below:
const HSM_accountKey = "xpub_HSM...." const IC_accountKey = "xpub_IC..." const Paper_accountKey = "xpub_Paper..." const result_wallet_HSM = await walletClient.createWallet('wallet_HSM', options_wallet); const result_wallet_IC = await walletClient.createWallet('wallet_IC', options_wallet); const result_wallet_Paper = await walletClient.createWallet('wallet_Paper', options_wallet); const wallet_IC_account = await wallet_IC.getAccount('default'); const wallet_Paper_account = await wallet_Paper.getAccount('default'); const result_addkey1 = await wallet_HSM.addSharedKey('default', wallet_IC_account.accountKey); const result_addkey2 = await wallet_HSM.addSharedKey('default', wallet_Paper_account.accountKey);
Now I have created a watch-only 2-of-3 multisig wallet. What I want to do now is to create addresses. I do not want to derive more child extended keys. I only need one derivation level. Now I want to create multisig addresses for my users.
// Create addresses from each wallet const wallet_HSM_address = await wallet_HSM.createAddress('default'); const wallet_IC_address = await wallet_IC.createAddress('default'); const wallet_Paper_address = await wallet_Paper.createAddress('default'); // Keyrings for script generation const keyring_HSM = KeyRing.fromJSON(wallet_HSM_address); const keyring_IC = KeyRing.fromJSON(wallet_IC_address); const keyring_Paper = KeyRing.fromJSON(wallet_Paper_address); //Get the pubkeys from each wallet const pubKeys = [keyring_HSM.publicKey, keyring_HSM.publicKey, keyring_Paper.publicKey]; const multiSigScript = Script.fromMultisig(m, n, pubKeys); const receivingAddress = multiSigScript.getAddress().toBase58(network);
I have a feeling that I am going about this step in a round-about way but you get what I am trying to do.
To re-state, what I want to do now is to create individual receiving addresses for my users and the corresponding P2SH scripts.
Now, this is what I need help understanding.
- According to BIP32, you cannot derive hardened public keys with CDKpub. You need the xprv to derive child keys.
- However, from what I have done, I can derive child public keys. I have sent tesetnet coins to these addresses (
receivingAddressin the code above) and they work. The wallet receives coins.
- How then, was the watch-only wallet able to create hardened child public keys? I did not input
xprvto the wallet.
- Or, is it that I am NOT creating hardened child public keys when I used the path
m/44'/0'/0'? Is the
receivingAddressI am creating in the above code not a hardened one? Meaning that if someone is able to find the child private keys of one user and the
xpub, they will be able to derive all the chile private keys?
My apologies for the long question. I am a bit confused as to how the wallets are able to create child public keys without having any private key in the wallet.