From BIP32:
We represent an extended private key as (k, c), with k the normal
private key, and c the chain code. An extended public key is
represented as (K, c), with K = point(k) and c the chain code.
point(p): returns the coordinate pair resulting from EC point
multiplication (repeated application of the EC group operation) of the
secp256k1 base point with the integer p.ser256(p): serializes the integer p as a 32-byte sequence,
most significant byte first.serP(P): serializes the coordinate pair P = (x,y) as a byte
sequence using SEC1’s compressed form: (0x02 or 0x03) ||
ser256(x), where the header byte depends on the parity of
the omitted y coordinate.
Extended public and private keys are serialized as follows:
- 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public, 0x04358394 private)
- 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ….
- 4 bytes: the fingerprint of the parent’s key (0x00000000 if master key)
- 4 bytes: child number. This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key)
- 32 bytes: the chain code
- 33 bytes: the public key or private key data (serP(K) for public keys, 0x00 || ser256(k) for private keys)
This 78 byte structure can be encoded like other Bitcoin data in
Base58, by first adding 32 checksum bits (derived from the double
SHA-256 checksum), and then converting to the Base58 representation.
This results in a Base58-encoded string of up to 112 characters.
Thus the extended public key (xpub) can be derived from the extended private key (xprv) as follows:
- Convert the xprv from Base58 to bytes and extract the private key from the last 33 bytes (ignoring the checksum).
- Calculate the public key from the private key as per point(p).
- Serialize the result:
- 4 bytes: 0x0488B21E (mainnet) or 0x043587CF (testnet)
- 41 bytes: depth, parent fingerprint, child number and chain code are the same as in the xprv
- 33 bytes: public key serialized using serP(K)
- Add the 4-byte checksum and convert to Base58.










