Version bytes for BIP32 extended public and private keys

This document describes the version bytes used in Electrum for master keys.

Abstract

BIP32 defines a serialization format for extended keys. This serialization includes four bytes allocated as version bytes. We use these version bytes to encode the type of output scripts (scriptPubKeys) a wallet should derive along this HD subtree.

Motivation

Among other changes, the activation of SegWit (BIP141) introduced new output script templates usable on Bitcoin mainnet. This poses a new problem for HD wallets in terms of what type of scripts they should derive from master keys. Previously most wallets offered deriving either P2PKH or multi-signature embedded in BIP16 P2SH outputs, and it was usually deduced from context which of the two should be used. We believe it would be better to have this knowledge explicitly.

Encoding the script type in BIP32 extended keys is beneficial for wallets. For example, a watch-only wallet constructed from an extended public key would otherwise have to either (1) derive all possible scripts in the subtree [1], or (2) prompt the user to enter the script type in a side-channel.

Deriving all possible scripts (1)

  • Potentially wastes resources. Wallets have to monitor more output scripts for incoming transactions.
  • Introduces key-reuse. Public keys are reused for each script type.
  • Becomes an ever-growing barrier for developers of new wallet software to implement detecting and spending from every type of UTXO. Otherwise if they choose not to implement legacy script types that can lead to not discovering funds.

Prompting the user to enter the script type (2) as additional information besides the extended public key just leads to more complex user interfaces and suboptimal experience.

Users directly interact with master public keys, for watch-only wallets, or when specifying cosigners for HD multisig. These keys are commonly serialized as BIP32 extended keys, hence it makes sense to make the encoding of the script type user-visible. As version bytes are already used to encode the network in such a way, this document introduces new constants for version bytes to further encode the script type.

Considerations

Without explicit knowledge of the output script type, wallets have no clear way to communicate to users whether the type of script the user would expect to be derived is supported/implemented. Casual users would simply notice funds missing, if they have prior knowledge of funds at all.

The version byte values defined in BIP32 do not distinguish P2PKH and P2SH-multisig outputs, and to remain backwards compatible, this will not be changed. However this has already resulted in loss of funds in some cases, where e.g. a user restored and received transactions on a watch-only P2PKH wallet from a master public key participating in P2SH-multisig that he had no control over (it was a key of a different cosigner). To try to prevent this kind of situation, e.g. P2WPKH and P2WSH-multisig is distinguished in this document.

Specification

In the table below,

  • P2SH stands for a BIP11 multi-signature script embedded in a BIP16 pay-to-script-hash output
  • P2WPKH stands for pay-to-witness-public-key-hash (witness version 0), as in BIP141
  • P2WPKH-P2SH stands for a P2WPKH script (witness version 0) nested in a BIP16 P2SH output, as in BIP141
  • P2WSH stands for a BIP11 multi-signature pay-to-witness-script-hash (witness version 0) script, as in BIP141
  • P2WSH-P2SH stands for a BIP11 multi-signature pay-to-witness-script-hash (witness version 0) script nested in a BIP16 P2SH output, as in BIP141

Note that an M-of-N multi-signature script is usually constructed from N extended keys (and M is provided in a side-channel). Hence in most cases more than one extended key is needed to create such scripts; this is out of scope of this document.

network script type pub/priv version bytes
human-readable
prefix
mainnet p2pkh or p2sh public 0x0488b21e xpub
mainnet p2pkh or p2sh private 0x0488ade4 xprv
mainnet p2wpkh-p2sh public 0x049d7cb2 ypub
mainnet p2wpkh-p2sh private 0x049d7878 yprv
mainnet p2wsh-p2sh public 0x0295b43f Ypub
mainnet p2wsh-p2sh private 0x0295b005 Yprv
mainnet p2wpkh public 0x04b24746 zpub
mainnet p2wpkh private 0x04b2430c zprv
mainnet p2wsh public 0x02aa7ed3 Zpub
mainnet p2wsh private 0x02aa7a99 Zprv
testnet p2pkh or p2sh public 0x043587cf tpub
testnet p2pkh or p2sh private 0x04358394 tprv
testnet p2wpkh-p2sh public 0x044a5262 upub
testnet p2wpkh-p2sh private 0x044a4e28 uprv
testnet p2wsh-p2sh public 0x024289ef Upub
testnet p2wsh-p2sh private 0x024285b5 Uprv
testnet p2wpkh public 0x045f1cf6 vpub
testnet p2wpkh private 0x045f18bc vprv
testnet p2wsh public 0x02575483 Vpub
testnet p2wsh private 0x02575048 Vprv

Backwards Compatibility

This document is backwards compatible with BIP32; existing extended keys will keep working. Compatibility is intentionally broken in the sense that extended keys derived for newer script types will not have valid BIP32 version bytes.

Footnotes

[1]Which is not even possible, given there are an effectively infinite number of possible scripts. A wallet could however derive scripts for all standard templates.