§ 04 · Keys & addresses
Private key
A very large random number
On this page 6 sections
A private keyPrivate key: A huge random number (256 bits) that only you should know. It lets you sign transactions that spend your coins, so whoever has it controls them. is a whole number, chosen at random from a range so large that nobody will ever pick the same one twice.
That’s all it is. There’s no file format, no account and no password inside it. The number lets you make signaturesSignature: Proof, made with a private key, that the key's owner approved one exact transaction. Anyone can check it with the public key, and it is useless for any other transaction. that spend coins, so whoever knows it owns the coins. Everything else in this group, from the public key to the prl1 address, is computed from it.
Try it
Generate a key, or type one in, and follow it down to an address.
How big is the range?
A valid key is any whole number from 1 up to, but not including, a constant called n:
n is the number of points on the secp256k1secp256k1: The particular elliptic curve Bitcoin uses. Pearl uses exactly the same curve for its keys and Schnorr signatures. curve’s group, the same constant Bitcoin uses:
115792089237316195423570985008687907852837564279074904382605163141518161494337
That’s 78 digits, about . It is a tiny bit less than , so every key fits in 32 bytes.
- Size
- 32 bytes
- 256 bits
- Smallest
- 1
- 0 is rejected
- Largest
- n − 1
- …5e8cd0364140 in hex
- Size
- 32 bytes
- Type
- Unsigned integer
- Format
- Big-endian
- Range
- 1 to n − 1
Note the byte order. Pearl stores most numbers little-endian, smallest byte first. Keys are the exception: like Bitcoin, they are written biggest byte first, the way you’d write the number by hand.
Make a guess
If a billion computers each tried a billion keys a second, how long until they hit one that's already in use?
Think of your answer first, then check it.
Answer Far longer than the age of the universe.
A billion times a billion is 10¹⁸ guesses a second. Even with 10¹⁰ keys in use, each guess has about a 10⁻⁶⁷ chance of hitting one. The danger is never guessing. It’s a key that wasn’t really random, or one that leaked.
How does a Pearl wallet pick a key?
Not one by one. A Pearl wallet draws randomness once, when you create it, and derives every key from that.
-
128 random bits
Oyster callshdkeychain.GenerateSeed(RecommendedSeedLen), which Pearl sets to 16 bytes, read from the computer’s secure random number generator. -
12 words
Those bits become a 12-word mnemonicMnemonic: The 12 English words a Pearl wallet shows you when it is created. They encode the random number every key comes from, so anyone who has them controls the coins., your backup. -
A seed, then a tree
The words become a 64-byte seed, and the seed becomes a tree of keys, one per address.
So the random part is the 128 bits behind the 12 words. Every private key in the wallet is a deterministic function of them, which is why the words are all you need to restore. The mnemonic page and derivation paths show the arithmetic.
What does a private key look like?
The same number can be written several ways. Here is one key, the example from the Bitcoin wiki’s WIF page. It is public, so never use it.
| Format | The same key |
|---|---|
| Hex (32 bytes) | 0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d |
| Decimal | 5500171714335001507730457227127633683517613019341760098818554179534751705629 |
| WIF, compressed | KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617 |
| WIF, uncompressed | 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ |
What is WIF?
- Size
- 51 or 52 characters
- Type
- Base58Check text
- Format
- version ‖ key ‖ [01] ‖ checksum
WIFWIF: A way to write one private key as text, starting with K, L or 5 on mainnet. A Pearl WIF string is identical to Bitcoin's for the same key, so it doesn't say which coin it belongs to. (Wallet Import Format) is how you move a single key between programs. It adds a version byte in front, an optional 0x01 “compressed” flag behind, and a 4-byte checksum, then writes the lot in Base58CheckBase58Check: A text encoding with 58 easy-to-read characters and a 4-byte double-SHA-256 checksum. Pearl uses it only for WIF private keys and zprv/zpub extended keys, never for addresses..
| Field | Size | Description |
|---|---|---|
| version | 1 | 0x80 on mainnet, 0xef on testnet and regtest. The same bytes as Bitcoin. |
| key | 32 | The private key, big-endian. |
| compressed flag | 1 | 0x01: the matching public key is used in its 33-byte compressed form. Omitted for the old uncompressed form. |
| checksum | 4 | The first 4 bytes of SHA256d of everything before it. |
Build the WIF by hand
- Put the pieces together:
80‖0c28fca3…9d72aa1d‖01, 34 bytes. - Hash twice: SHA256d of those 34 bytes is
a62019d20340a1de1b5f254f07f2f6c96ad5165218459ab4f3c8f5a7c0e12183. - Keep the first 4 bytes,
a62019d2, as the checksum and append them: 38 bytes. - Write the 38 bytes in Base58:
KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617.
Without the 01 flag, the checksum is 507a5b8d and the result is 5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ, exactly the string on the Bitcoin wiki.
Mainnet compressed keys start with K or L, uncompressed ones with 5. Test networks give c (or 9). Pearl wallets always use compressed keys.
Where does Pearl use a private key?
- Signing spends. Every Pearl spend is signed with a 64-byte Schnorr signature. For a normal Taproot address, the key that signs is not d itself but the tweaked key d + t (with d negated first if needed). The Taproot tweak page works this out for key 1: the signing key ends in
…30e8instead of…0001. - Exporting and importing. OysterOyster: Pearl's reference wallet program, which runs in the background and is driven by the oystercli command line. It is derived from btcwallet, and the Pearl Desktop Wallet uses it under the hood.’s
dumpprivkeywrites a key as WIF, andimportprivkeyreads one. The exported key is the internal, untweaked one. - Signing messages. Two different schemes exist, described below.
Signing messages with a Pearl key
Oyster signmessage / verifymessage. Works for Taproot addresses only. The code calls it “BIP-322 Simple
Signature”, but it is not standard BIP-322: it signs a little virtual transaction whose output is OP_RETURN <your message>, so messages longer than 80 bytes fail. Signing “Hello World” with key 1’s address gives a base64 witness
starting AUCP…. It will not verify in Bitcoin BIP-322 tools.
pearld signmessagewithprivkey. Takes a WIF and makes an old-style compact ECDSA signature over
SHA256d(varstr(“Pearl Signed Message:\n”) ‖ varstr(message)). For “Hello World” that digest is
8b208026794816c66d92f5d2dae08c55cacdf0cad6eef279b83495c1de675ac4. The node’s matching verifymessage is disabled
at v1.5.2, so nothing on Pearl verifies these signatures.
Neither scheme touches the chain. Transactions use Schnorr signatures only.
How do you keep it safe?
- Never type it into a website. No legitimate Pearl service needs your private key, a WIF or your 12 words.
- Back up the words, not the keys. One 12-word backup covers every key the wallet will ever make.
- Remember the famous keys are public. Private key 1, the wiki key above and the BIP-39 test phrase are on this page because everyone knows them. Coins sent to them are gone the moment a bot notices.
Code: make a valid key in JavaScript
A key is just 32 random bytes that land in the valid range. Rejection sampling keeps the distribution uniform:
const n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
function randomPrivateKey() {
for (;;) {
const bytes = crypto.getRandomValues(new Uint8Array(32));
const d = BigInt('0x' + [...bytes].map((b) => b.toString(16).padStart(2, '0')).join(''));
if (d >= 1n && d < n) return bytes; // fails about once in 2^128 tries
}
} For real funds, let a wallet do this. Its keys come from the seed, so they can be restored.