§ 04

§ 04 · Keys & addresses

Extended keys

A key plus a chain code, which together grow a whole tree

An extended key is a key that can have children. It carries the key itself plus 32 extra bytes, the chain code, and with both you can compute a whole family of related keys.

That’s how one 12-word backup covers thousands of addresses. The seed makes one master extended key. The master makes children, the children make grandchildren, and each address sits at a fixed spot in that tree. Pearl writes these keys as zprv (private) and zpub (public).

Try it

Type a phrase and watch the master key, the account key and the first addresses appear.

Seed words

12 words → seed → keys → prl1 addresses, the way Oyster does it

Never type a real seed phrase into any website, this one included. Anyone with your 12 words owns your coins. This tool is for learning: use the test words or a phrase it generates, and never send funds to these addresses.

Network
Hardened derivation

Valid: 12 known words and the checksum matches.

  1. 1

    Words → bits 11 bits each

    Each word is a position in a list of 2,048 (2¹¹). 12 × 11 = 132 bits: 128 random bits, then 4 bits of checksum.

    1. 1abandon 00000000000
    2. 2abandon 00000000000
    3. 3abandon 00000000000
    4. 4abandon 00000000000
    5. 5abandon 00000000000
    6. 6abandon 00000000000
    7. 7abandon 00000000000
    8. 8abandon 00000000000
    9. 9abandon 00000000000
    10. 10abandon 00000000000
    11. 11abandon 00000000000
    12. 12about 00000000011

    Entropy (128 bits): 0000000000000000…00000000 · checksum = first 4 bits of SHA-256(entropy) = 0011, matching the last 4 bits of word 12.

  2. 2

    Seed 64 bytes

    PBKDF2-HMAC-SHA512(words, “mnemonic”, 2,048 rounds)

    5eb00bbd dcf06908 4889a8ab 91555681 65f5c453 ccb85e70 811aaed6 f6da5fc1 9a5ac40b 389cd370 d086206d ec8aa6c4 3daea669 0f20ad3d 8d48b2d2 ce9e38e4

    2,048 rounds make each guess slow on purpose. Pearl wallets use no extra passphrase.

  3. 3

    Master key m

    HMAC-SHA512(“Bitcoin seed”, seed) → private key ‖ chain code

    private key
    1837c1be8e2995ec11cda2b066151be2cfb48adf9e47b151d46adab3a21cdf67
    chain code
    7923408dadd3c7b56eed15567707ae5e5dca089de972e07f3b860450e2a3b70e
    fingerprint
    73c5da0a

    The HMAC key is still the text “Bitcoin seed”, unchanged from Bitcoin.

  4. 4

    Down the path m/86'/808276'/0'/0/i

    1. mmaster73c5da0a
    2. 86'purpose: BIP-86 Taproot4e83b613
    3. 808276'coin: “PRL” as decimal ASCIIf124e0d0
    4. 0'account 073bf7af8
    5. 0receive (1 = change)edfa853f

    An apostrophe means hardened: the child is made from the parent’s private key, so the parent’s public key can’t derive it, and a leaked child key can’t expose the parent.

  5. 5

    Account key zpub

    The public half of m/86'/808276'/0', as Oyster shows it (zprv for the private half). It can make every address without being able to spend.

    zpub6s66goCpFBSqGDZyyD6a1Xf8C5TseQYcPFQNpjMzFeTCZpZD6ShaEzAKqv8tDiv81N1RmPyRTu1D65iQv59c7wHZyCbQmnaARE7P6UFNJeG

  6. 6

    First receive addresses BIP-86 Taproot

    1. /0/0prl1pr6yuq8u2r95wjzzgpdy8cpnncpl7l8zgy6x5q0367pnc53s2famqg7pt74
    2. /0/1prl1pyx3nlscz8rvsxqhcjtyqt2g5szuk9ss7m5saszu3afwwhvn9zp2sz62rhm
    3. /0/2prl1pfrfqcvcmghjc3mpsazm9p9ktttyuewzlfmn40dzkwh0muejgkr3sfx9jwd
    4. /0/3prl1prmdvgxfgzmqzq5dj58enw6y7c55wpsfdpr0af7t79x65z6gmms8q4qa93j
    5. /0/4prl1pc9xyu484gw5wsnq7hg00733jlcr4ethphyxmavynyl8me0q7ec7q6qu3wx

Oyster and standard BIP-32 give the same addresses for this phrase, as for almost every phrase. Try “A phrase where Oyster differs”.

Runs in your browser · nothing is sent or saved src/lib/hd.ts · keys.ts · bech32m.ts

How is the master key made?

With one HMAC. The seed from the 12 words is hashed with HMAC-SHA512, using a fixed key, and the 64-byte result is cut in half:

I=HMAC-SHA512(key=Bitcoin seed, data=seed),k=I0..31, c=I32..63I = \text{HMAC-SHA512}(\text{key} = \text{Bitcoin seed},\ \text{data} = \text{seed}), \quad k = I_{0..31},\ c = I_{32..63}

Yes, the key is still the text “Bitcoin seed”. Pearl kept BIP-32’s constant unchanged. For the standard test phrase “abandon … about”:

Value
Seed 5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4
Master private key k (left half) 1837c1be8e2995ec11cda2b066151be2cfb48adf9e47b151d46adab3a21cdf67
Master chain code c (right half) 7923408dadd3c7b56eed15567707ae5e5dca089de972e07f3b860450e2a3b70e
Master public key (compressed) 03d902f35f560e0470c63313c7369168d9d7df2d49bf295fd9fb7cb109ccee0494
Master fingerprint 73c5da0a

The fingerprint is the first 4 bytes of HASH160 (RIPEMD-160 of SHA-256) of the compressed public key. It’s one of the few places RIPEMD-160 survives in Pearl.

What’s inside an extended key?

78 bytes, always in the same order:

An extended key, before Base58Check
Field Size Description
version 4 Says private or public, and which network. 04b2430c = zprv on mainnet.
depth 1 How many steps below the master: 0 for the master, 3 for an account key.
parent fingerprint 4 First 4 bytes of HASH160 of the parent's public key. Zero for the master.
child number 4 Which child of the parent this is, big-endian. Hardened children have the top bit set.
chain code 32 The extra 32 bytes needed to derive children.
key 33 00 ‖ 32-byte private key (zprv), or the 33-byte compressed public key (zpub).

Here is the test phrase’s master zprv, byte by byte:

Master zprv of the BIP-39 test phrase 78 bytes
04b2430c 00 00000000 00000000 7923408dadd3c7b56eed15567707ae5e5dca089de972e07f3b860450e2a3b70e 001837c1be8e2995ec11cda2b066151be2cfb48adf9e47b151d46adab3a21cdf67
Field Bytes Value
version (zprv) 4 @0 04b2430c
depth 1 @4 0: the master
parent fingerprint 4 @5 none: the master has no parent
child number 4 @9 00000000
chain code 32 @13 7923408dadd3c7b56eed15567707ae5e5dca089de972e07f3b860450e2a3b70e
key (00 ‖ private key) 33 @45 001837c1be8e2995ec11cda2b066151be2cfb48adf9e47b151d46adab3a21cdf67
Computed with this site's library; Pearl's own code prints the same zprv. A public test key: never use it.

Add a 4-byte checksum (the first 4 bytes of SHA256d of the 78 bytes) and write it in Base58Check:

zprvAWgYBBk7JR8Gjrh4UJQ2uJdG1r3WNRRfURiABBE3RvMXYSrRJL62XuezvGdPvG6GFBZduosCc1YP5wixPox7zhZLfiUm8aunE96BBa4Kei5

Drop the private key, put the public key in its place, switch the version to 04b24746, and you get the matching zpub:

zpub6jftahH18ngZxLmXaKw3GSZzZsszmt9WqedkyZdezFtWRFBZqsQH5hyUmb4pCEeZGmVfQuP5bedXTB8is6fTv19U1GQRyQUKQGUTzyHACMF

Why does Pearl use “z” prefixes?

Because Pearl’s developers picked existing version bytes. The comment in Pearl’s network settings reads “Using BIP-84 (SegWit) versions for Taproot-only wallet”.

Network Private Public Prefix
mainnet 04b2430c 04b24746 zprv / zpub
testnet, testnet2, regtest 045f18bc 045f1cf6 vprv / vpub
Bitcoin Taproot, for comparison 0488ade4 0488b21e xprv / xpub

The version bytes only change the label. Re-encode the master key above with Bitcoin’s xprv bytes and you get BIP-86’s official test-vector root, xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu. Same key, same chain code.

How are children derived?

Each child comes from one HMAC-SHA512, keyed with the parent’s chain code. There are two kinds.

  1. Normal child (index below 2³¹)

    Data = parent’s compressed public key ‖ index (4 bytes, big-endian). The left half of the HMAC, added to the parent private key mod n, is the child private key; the right half is the child chain code.
  2. Hardened child (index 2³¹ and up)

    Data = 00 ‖ parent’s private key ‖ index. Same split. Because the private key goes in, only someone holding it can derive a hardened child.

Normal children have a useful property: the same addition works on public keys. A zpub can derive every normal child’s public key without any private key. That’s what makes watch-only wallets possible.

Hardened children, marked with ’ in paths (86'), block that. They also limit the damage of a leak, as the next section explains. Which levels are hardened is set by the derivation path.

Pearl’s account key

Oyster’s default account sits at m/86’/808276’/0’. For the test phrase, its extended public key is:

zpub6s66goCpFBSqGDZyyD6a1Xf8C5TseQYcPFQNpjMzFeTCZpZD6ShaEzAKqv8tDiv81N1RmPyRTu1D65iQv59c7wHZyCbQmnaARE7P6UFNJeG

That’s exactly the key a real Oyster wallet stores in its database for account 0. From it, anyone can compute every receive address (/0/i) and change address (/1/i) in the account, but no private key.

What can go wrong with extended keys?

  • A zprv is the whole wallet. Treat it like the 12 words.
  • A zpub is your whole history. It shows every address, past and future, in its branch. Share it only with software you trust.
  • A zpub plus one child private key is the whole branch. For normal (non-hardened) children, the parent’s private key is just the child’s private key minus a value anyone with the zpub can compute. BIP-32 calls this out; hardened levels contain the damage to one account.
Code: master key in JavaScript

Using @noble/hashes:

JavaScript
import { hmac } from '@noble/hashes/hmac.js';
import { sha512 } from '@noble/hashes/sha2.js';

const I = hmac(sha512, new TextEncoder().encode('Bitcoin seed'), seed);   // seed: Uint8Array(64)
const masterKey = I.slice(0, 32);   // 1837c1be… for the test phrase
const chainCode = I.slice(32);      // 7923408d…

The codex

Suggested

Up and down arrows move through the results, Enter opens one, Escape closes. Anywhere on the site, slash or Command K opens this search, and the square brackets [ and ] go to the previous and next page.