HD wallets with 32 bytes public or private backups for master and subkeys
MIT License
BIP32 [1] relies on extended keys to derive new keys. Extended keys are 78 bytes long, but only key and chaincode (64 or 65 bytes) are used to derive new keys.
It is possible to define HD wallets with the same features as BIP32 that does not need the chaincode.
Let G
be the secp256k1 generator.
Let i
be the child index.
Let (p, P=pG)
and (p_i, P_i=p_iG)
be the parent and i-th child keypairs
respectively.
Let h
be an adequately strong hash function which converts its output to
integer.
Define private and public child derivation as follow:
p_i(p, i) = (i < 2^31) p + h(pG, i)
(i >= 2^31) h(p, i)
P_i(P, i) = (i < 2^31) P + h(P, i)G
(i >= 2^31) not possible
Notes:
Multisig wallets need to backup the other parties extended public keys. For instance, the backup can be an output descriptor with a xprv and multiple xpub. Using the above derivation scheme reduces the length of the descriptor that should be backed up or passed around (e.g. to a hardware device). With some additional work 32 bytes pubkeys can be used.
Most Bitcoin wallets allow restoring only from 12 or 24-words (BIP39 [4]) mnemonics, which map to 16 or 32 bytes sequences respectively.
From the mnemonic a tree of BIP32 exteneded keys is derived using a non-reversable function. However each BIP32 extended key needs at least 64 bytes to be represented, making unfeasible the usage of standard such as BIP39.
This led to the arise of proposal such as BIP85 [5], which allows to derive BIP39 mnemonics and other common backups from a BIP32 extended key.
The above derivation scheme allows intermediate user-friendly backups. Suppose you have a master keypair, it's possible to harden derive child keys and use them as a separate wallet with a common backup. Each child key can be used as master key for another child wallet with the master key still being able to spend such funds (same as BIP32). But contrary to BIP32 each child wallet has a 32 bytes backup. Which optionally can be mapped to a, for instance, 24 word BIP39 mnemonic. This allows to maintain the same UX for child wallets.
Since pubkeys can have the same length, it is possible to backup or share pubkeys with a similar technique.
A possible use case: Alice wants to teach to her unexperienced son Bob how to
use a Bitcoin wallet. She already has a wallet with master private key a
,
let i = 2^31
(i.e. 0_h
), she derives b = a_i = h(a, i)
, maps b
to the
backup expected by the wallet (e.g. mnemonic) and gives the backup to Bob.
Bob can use his wallet as a normal wallet, while Alice can monitor Bob's
transaction and eventually she can move coins in his place.
BIP32 is used by almost every existing wallets.
Suppose an attacker knows a child private key p_i
, its index i<2^31
and its
parent public key P
. If the above derivation scheme is used, it can compute
the parent private key p
. If using BIP32, it cannot, but it could if it knew
the chaincode.
However most wallets derive scriptpubkeys from keys from the same depth, so the
parent public key is never published on the blockchain. If the parent public
key is kept as secret as BIP32 extended keys are, then the situation is
analogous to BIP32's.
A simplified python example is provided.
Install package:
pip install .
Run tests:
python3 -m unittest discover -v
ecc.py
module was copied and adapted from BIP340's pure python reference
implementation [5].
[1] https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
[2] https://blockstream.com/sidechains.pdf Appendix A
[3] https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-January/015614.html
[4] https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
[5] https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki
[6] https://github.com/bitcoin/bips/blob/master/bip-0340/reference.py