§ 02

§ 02 · Cryptography

Merkle trees

One hash that vouches for thousands, and a short proof for any one of them

A Merkle tree squeezes a whole list of items into one hash, in a way that still lets you prove any single item is on the list.

Every Pearl block uses one. Its transactions are hashed into a tree, and the single hash at the top, the Merkle root, goes into the block header. Change one byte of any transaction and the root changes, so the header vouches for every transaction in the block.

Try it

Add or edit transactions and watch the tree recompute. Click a leaf to see its proof path.

Merkle tree builder

Pair, hash, repeat: many txids become one 32-byte root

1fad76f4e6eccfa580d0001e2b764a4d1ff50558a96f7dd9a78bb18ced5063131fad76f4 coinbase01744c2b9431725b5169245d7b9057d421e6b5bf25fce05818cbaf08c164025f01744c2b tx 1dd6b8f7c597a5473d387379fee85e8d3e9d0a8510e9ec1209debcf1377dd2b57dd6b8f7c tx 24cb8ba415afc98591258733b427d15e19698bb48b850c07c8631fab3829db1b54cb8ba41 tx 375149cb026f2fb1b50f5cea1b4c8e3f03c1c36f8c678cbc05d83df8a9f0e0f2075149cb0 tx 455fd26a7a646df78abc30d4e1dcbb69b218ce2a5677e5465adab5e836a7b974255fd26a7 tx 5f8b682ac2145d11c8416349396156d0f2c2c52f9c91695506cd63902cb8da017f8b682ac83053c79d215153346e8041cfb72ecb6ffa16e3cb3df071b8cef433e9bd913a983053c79c78d3ee1342b1ef1506895314f5dec480faaf50a274a4d9c80567783b56f4b12c78d3ee15bbe61bf5b7102604ac22cfa42fa88c85b4883ba69fe4bee3600e5bda95a92245bbe61bfd989bdca710aaf29cf684945031191ee024376d754cf9cde35ae174e792636d2d989bdcac6c21c0c4204b9f39e17d7f79811aff53eac88ea0d80fcdeffdad96ba3fa8963c6c21c0c Merkle rootCopy of the last node (odd count)copy
Merkle root ✓ matches block 130,827’s header

c6c21c0c4204b9f39e17d7f79811aff53eac88ea0d80fcdeffdad96ba3fa8963

Proof for leaf 0 ✓ verifies

To prove leaf 0 is in the block, send these 3 hashes, not all 6 txids. Hash upward, putting each one on its side:

  1. start1fad76f4e6…506313
  2. me ‖ sibling 01744c2b94…64025f
  3. me ‖ sibling 83053c79d2…d913a9
  4. me ‖ sibling d989bdca71…2636d2
  5. = rootc6c21c0c42…fa8963
Leaves (txids) 6 of 16

Runs in your browser · nothing is sent src/lib/merkle.ts · SHA256d pairs, same as Bitcoin

How is the tree built?

Start with the transaction IDs at the bottom. Then repeat one step until one hash is left:

  1. Pair them up

    Take the hashes two at a time, left to right.

  2. Hash each pair

    Join the two 32-byte hashes (64 bytes, in internal byte order) and take SHA256d. That’s the parent.

  3. Odd one out? Pair it with itself

    If a level has an odd number of hashes, the last one is hashed together with a copy of itself.

tx 0tx 1tx 2tx 3tx 4H01H23H44H0123H4444rootcopycopy
Five transactions. On each level with an odd count, the last hash is paired with a copy of itself (dashed).

The tree is the same as Bitcoin’s, built by the same code inherited from btcd.

What does a real Pearl tree look like?

Block 130,825 has 115 transactions. Here is how its tree shrinks, level by level:

115→58→29→15→8→4→2→1115 \to 58 \to 29 \to 15 \to 8 \to 4 \to 2 \to 1
Block 130,825
Each level halves, rounding up. Three of the levels (115, 29 and 15) are odd, so their last hash is paired with itself.

The one hash left at the top is ab5f7fee74ac4fc304186ab08b556fd03e408576753b1f9ae4574d48251d052a, and that’s exactly what the header stores at bytes 36 to 67 (byte-reversed, as hashes always are):

Block 130,825 · header 108 bytes
00000020 d3221e43dc59c5d0dae1ee53987d6a4abeef42567d682017a6edd6e0de7ac7ab 2a051d25484d57e49a1f3b757685403ed06f558bb06a1804c34fac74ee7f5fab 8393d76a ebd06a17 ce6de312e0e4ca6c862c05835314db00cf02c13a20ea4810940f09b64ed8ba86
Field Bytes Value
Version header.version 4 @0 0x20000000 int32 LE. BIP-9 style 0x20000000 since block 1; no consensus meaning in Pearl.
Previous block header.prevBlock 32 @4 abc77adee0d6eda61720687d5642efbe4a6a7d9853eee1dad0c559dc431e22d3 Hash of the parent block, stored byte-reversed; shown in display order.
Merkle root header.merkleRoot 32 @36 ab5f7fee74ac4fc304186ab08b556fd03e408576753b1f9ae4574d48251d052a Root of the SHA256d Merkle tree of this block’s txids, stored byte-reversed.
Time header.timestamp 4 @68 1792512899 (2026-10-20 16:14:59 UTC) uint32 LE Unix seconds. Must be at least 1 s after the parent and at most 5 min in the future.
Bits header.bits 4 @72 0x176ad0eb Compact target. Difficulty 40208379.91968057. The certificate's jackpot hash (not this header's hash) must meet it.
Proof commitment header.proofCommitment 32 @76 86bad84eb6090f941048ea203ac102cf00db145383052c866ccae4e012e36dce SHA256d(LE32(certificate version) ‖ public data). Replaces Bitcoin’s nonce: Pearl headers have no nonce.
Block hash
3fc851763893a0135ea756d5dcbe355f375e613957930e7f401fafc8ee5533ae
Height
130,825
Time
2026-10-20 16:14:59 UTC
Difficulty
40,208,379.92

How do you prove one transaction is in the block?

With a Merkle proof: the sibling hash at every level on the way up. Given those, anyone can recompute the root and compare it with the header.

Take the payment at position 17 in block 130,825, d919e02a4adfd739ceef31d98803f0ddd24e1b1fa67b0fe572cdec42c1b384c9. Its proof is seven hashes, computed from the block’s real transaction list:

Level Sibling sits on the Sibling hash
0 left 5139cf522ff4838c…fc14ed85 (transaction 16)
1 right ecc4f5b1d4f78465…f598ce3c
2 right cc3ee4c4a2f88632…8ddf8fd2
3 right b574b28183b1846d…932a3f66
4 left 956bdd21491e039c…88544035
5 right d857c044931d768c…fa495f09
6 right 8dfeaffbaa8d5e38…0725ce1c

The first step hashes transaction 16 and the payment together: SHA256d of the pair gives dce385157c7be73e…2d936174. Six more steps and you land on ab5f7fee…251d052a, the root in the header. The check passes.

That’s 7 × 32 = 224 bytes of proof, instead of downloading all 115 transaction IDs (3,680 bytes) or the whole block.

Make a guess

A block with 4,000 transactions would need a proof of how many hashes?

Think of your answer first, then check it.

Answer 12.

Each level halves the count: 4,000 → 2,000 → 1,000 → 500 → 250 → 125 → 63 → 32 → 16 → 8 → 4 → 2 → 1. That’s 12 steps. Proof size grows with the logarithm of the tree size, so doubling the block adds just one hash.

Why not hash all the transactions in one go?

You could. A single SHA256d over every transaction ID in a row would commit to the whole list just as firmly, and the header would still hold one 32-byte hash.

The difference shows up when you want to prove something about one transaction. With a flat hash, the proof is every other transaction ID. With a tree, it’s one sibling per level: 7 hashes for 115 transactions, 12 for 4,000. The header stays 108 bytes no matter how big the block is, and anyone holding it can check a single transaction cheaply.

Pearl’s mining leans on the same advantage, at a much bigger scale: a pool can check two rows of a gigabyte-sized matrix against a 32-byte fingerprint.

Why is pairing with itself a problem?

Because two different lists can then give the same root. A block with transactions [a, b, c] and a block with [a, b, c, c] build identical trees: the lone c is paired with a copy of itself either way.

This was a real Bitcoin bug, CVE-2012-2459. The fix, which Pearl inherits, is simple: a block with a duplicate transaction is invalid. So the trick can’t be used to make a valid block look invalid, or the other way round.

Where else does Pearl use Merkle trees?

The same shape turns up across Pearl, with different hash functions inside:

  • Witness tree. A second tree over the witness transaction IDs (with the coinbase’s set to zero) is committed in the coinbase, exactly as in Bitcoin’s segwit.
  • Script trees. Taproot and P2MR outputs commit to a tree of spending scripts, built with the TapLeaf and TapBranch tagged hashes. A P2MR address carries that tree’s root directly.
  • XMSS keys. A post-quantum XMSS public key contains the root of a tree of 32 one-time keys.
  • Mining matrices. A miner fingerprints each matrix with keyed BLAKE3, which is itself a Merkle tree over 1 KiB chunks. When a ticket wins, the pool receives just the needed rows and columns plus their Merkle paths, and checks them against the fingerprints. See noise seeds.
Code: one step of the tree

pearld joins two hashes and double-hashes them in HashMerkleBranches (node/blockchain/merkle.go:62-70 at v1.5.2, on GitHub):

node/blockchain/merkle.go Go
func HashMerkleBranches(left, right *chainhash.Hash) chainhash.Hash {
	// Concatenate the left and right nodes.
	var hash [chainhash.HashSize * 2]byte
	copy(hash[:chainhash.HashSize], left[:])
	copy(hash[chainhash.HashSize:], right[:])

	return chainhash.DoubleHashRaw(func(w io.Writer) error {
		_, err := w.Write(hash[:])
		return err
	})
}

In JavaScript, with txids in internal byte order:

JavaScript
function merkleRoot(level) {
  while (level.length > 1) {
    const next = [];
    for (let i = 0; i < level.length; i += 2) {
      const right = level[i + 1] ?? level[i];          // odd: pair with itself
      next.push(sha256(sha256(new Uint8Array([...level[i], ...right]))));
    }
    level = next;
  }
  return level[0];
}

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.