§ 12

§ 12 · Networking

Magic bytes and ports

PRLM: a network name that never crosses the wire in the clear

Pearl isn’t one network but several: the real one, mainnet, plus test networks whose coins are worthless. They run the same software. Something has to keep them from mixing, so that a test block never ends up on the real chain.

In Bitcoin, that something is the magic bytes: four bytes that open every message, saying which network it belongs to. Pearl has magic bytes too, “PRLM” for mainnet. But you will never see them on the wire. Pearl encrypts every connection, so the magic does its job in a quieter place.

Try it

Type 50524C4D as hex and flip the byte order. You get 4D4C5250: the same number, stored the way pearld stores it.

Hex converter

Decimal, hex and binary, and the bytes in both orders

Big-endian as written
0001ff0b
Little-endian as stored
0bff0100
Runs in your browser · nothing is sent src/lib/bytes.ts

What are Pearl’s magic bytes?

Each network has a 4-byte number, chosen so that its hex spells letters:

Network Magic (number) As text Bytes on disk P2P port RPC port
Mainnet 0x50524C4D PRLM 4d 4c 52 50 44108 44107
Testnet 0x50524C31 PRL1 31 4c 52 50 44110 44109
Testnet2 0x50524C32 PRL2 32 4c 52 50 44112 44111
Regtest 0x50524C52 PRLR 52 4c 52 50 18444 18334
Simnet 0x50524C53 PRLS 53 4c 52 50 18555 18556
Signet 0x40CF030A (none) 0a 03 cf 40 38333 38332

0x50 0x52 0x4C is ASCII for “PRL”, and the last byte names the network: M for mainnet, 1 and 2 for the testnets, R for regtest, S for simnet. Signet’s magic is derived from a hash of its challenge script instead, as in Bitcoin.

Why are the bytes backwards?

Because pearld writes the magic as a 4-byte little-endian number, smallest byte first, exactly as Bitcoin does with its own magic (0xD9B4BEF9, written f9 be b4 d9). So 0x50524C4D becomes 4d 4c 52 50, which as ASCII reads “MLRP”. Byte order is explained on byte order.

Where do the magic bytes appear?

Not on the network. Pearl peers only speak BIP-324 encrypted transport, and BIP-324 messages have no plaintext header at all: no magic, no command name, no checksum. To anyone watching, a Pearl connection is a stream of random-looking bytes.

The magic shows up in two places instead:

  • In the key derivation. When two nodes set up encryption, they turn their shared secret into keys with HKDF, salted with the text pearl_v2_shared_secret followed by the magic’s four bytes.
  • On disk. pearld’s block files store each block after the network’s magic, as Bitcoin nodes do.

Here is mainnet’s salt, as pearld builds it:

BIP-324 HKDF salt, mainnet 26 bytes
706561726c5f76325f7368617265645f736563726574 4d4c5250
Field Bytes Value
"pearl_v2_shared_secret" 22 @0 22 bytes of ASCII text
Magic, little-endian 4 @22 0x50524C4D, "PRLM"
26 bytes: the ASCII text pearl_v2_shared_secret, then the magic in little-endian order. Bitcoin's uses bitcoin_v2_shared_secret and f9 be b4 d9.

Then how are networks kept apart?

By that salt. A mainnet node and a testnet node that connect by mistake each derive their encryption keys with their own magic in the salt: 4d4c5250 against 314c5250. Their keys don’t match, so neither can decrypt the other, and the connection fails before a single real message. In Bitcoin’s old v1 protocol the same job is done by checking the magic at the start of each message; in Pearl it is done by cryptography.

Each network also has its own ports, its own genesis block and its own address prefix (prl1… on mainnet, tprl1… on testnet), so even outside the wire protocol the networks rarely look alike.

Which ports does Pearl use?

On mainnet:

Peer-to-peer
44108
open to the internet for incoming peers
pearld RPC
44107
local commands; keep it private
Oyster wallet RPC
44207
the wallet daemon

A node only needs the P2P port open to accept incoming peers. It can run perfectly well with only outgoing connections; it just won’t be listed by the DNS seeds, which only hand out nodes reachable on 44108.

Make a guess

A firewall vendor wants to block Bitcoin and Pearl traffic by spotting magic bytes in packets. Which one can it catch that way?

Think of your answer first, then check it.

Answer Only Bitcoin's v1 connections.

Bitcoin’s unencrypted v1 messages start with f9 be b4 d9. Pearl never sends v1 messages, and its encrypted stream contains no fixed bytes to match. A firewall could still block port 44108, or guess from traffic patterns, but not from the magic.

Code: magic values and the salt

From protocol.go (node/wire/protocol.go:133-152 at v1.5.2, on GitHub):

node/wire/protocol.go Go
MainNet  PearlNet = 0x50524C4D // "PRLM" in ASCII
RegTest  PearlNet = 0x50524C52 // "PRLR" in ASCII
TestNet  PearlNet = 0x50524C31 // "PRL1" in ASCII
TestNet2 PearlNet = 0x50524C32 // "PRL2" in ASCII
SigNet   PearlNet = 0x40CF030A
SimNet   PearlNet = 0x50524C53 // "PRLS" in ASCII

And the salt, from transport.go (node/v2transport/transport.go:194-200 at v1.5.2, on GitHub):

node/v2transport/transport.go Go
salt := []byte("pearl_v2_shared_secret")
var magic [4]byte
binary.LittleEndian.PutUint32(magic[:], uint32(net))
salt = append(salt, magic[:]...)

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.