§ 07

§ 07 · Blocks

Block hash

A block's ID, and why on Pearl it looks completely random

Every block has a name: its block hash. It’s a 32-byte fingerprint of the header, written as 64 hex digits, and it’s how everyone refers to a block.

If you know Bitcoin, you know block hashes as long strings that start with a row of zeros, because in Bitcoin the hash is the proof of work. Pearl block hashes don’t look like that. They look completely random, because on Pearl the block hash has only one job: to be the block’s ID.

Try it

Hash anything with SHA256d. Change one character and watch about half the bits of the output flip.

Hash playground

Change one letter and the whole fingerprint changes

SHA256d SHA-256 twice: txids, block hashes

2ec32b953f6a93c4a34869c936e7af1e9ca052bad616574340af3f60b184215f

Avalanche SHA256d · 256 bits

122 of 256 bits changed

compared with “pearl”

Runs in your browser · nothing is sent src/lib/hash.ts · raw output order

How is it computed?

Hash the 108-byte header with SHA-256, hash the result with SHA-256 again (SHA256d), and reverse the 32 bytes for display:

block hash=reverse⁡(SHA256⁡(SHA256⁡(header108)))\text{block hash} = \operatorname{reverse}\big(\operatorname{SHA256}(\operatorname{SHA256}(\text{header}_{108}))\big)
Block 130,827 · header 108 bytes
00000020 999c961b04d94b8b21134e862dc31d5fa56cf9d1f027adb2a0cf95c6525c55eb 6389faa36bd9daffdefc800dea88ac3ef5af1198f7d7179ef3b904420c1cc2c6 1a96d76a a6f36a17 4d52a3fd32160cb032e22edf76912f67dfb1b88946a215281f203836c77ae649
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 eb555c52c695cfa0b2ad27f0d1f96ca55f1dc32d864e13218b4bd9041b969c99 Hash of the parent block, stored byte-reversed; shown in display order.
Merkle root header.merkleRoot 32 @36 c6c21c0c4204b9f39e17d7f79811aff53eac88ea0d80fcdeffdad96ba3fa8963 Root of the SHA256d Merkle tree of this block’s txids, stored byte-reversed.
Time header.timestamp 4 @68 1792513562 (2026-10-20 16:26:02 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 0x176af3a6 Compact target. Difficulty 40157376.49334089. The certificate's jackpot hash (not this header's hash) must meet it.
Proof commitment header.proofCommitment 32 @76 49e67ac73638201f2815a24689b8b1df672f9176df2ee232b00c1632fda3524d SHA256d(LE32(certificate version) ‖ public data). Replaces Bitcoin’s nonce: Pearl headers have no nonce.
Block hash
1df2f2c1bf39b1a444e622c1788c11736da2f91f4e9a875a38dc23063c6d45b9
Height
130,827
Time
2026-10-20 16:26:02 UTC
Difficulty
40,157,376.49

For block 130,827, SHA256d of those 108 bytes comes out as b9456d3c…c1f2f21d in internal byte order. Reversed, that’s the hash every explorer shows:

1df2f2c1bf39b1a444e622c1788c11736da2f91f4e9a875a38dc23063c6d45b9

The algorithm is Bitcoin’s, unchanged. Only the input is longer: 108 bytes instead of 80.

Why doesn’t it start with zeros?

Because nothing requires it to. Here are four real Pearl block hashes:

Block Block hash
1 a09851a4761539d170f7dfe7531864ae92879b02bbe999a6c238f63745a69726
120,000 a5f57e441de1da43a27b4bee471c7a7bdd8e36664050385bf0a1b760d2a84b7d
130,825 3fc851763893a0135ea756d5dcbe355f375e613957930e7f401fafc8ee5533ae
130,827 1df2f2c1bf39b1a444e622c1788c11736da2f91f4e9a875a38dc23063c6d45b9

In Bitcoin, a miner keeps changing the header until its hash, read as a number, is below the target. Pearl miners never do that. The number that has to beat the target is a different hash, a BLAKE3 ticket called hash_jackpot, stored inside the block’s certificate. See tickets and target.

Make a guess

If Pearl did compare the block hash with the target, how many leading zero hex digits would block 130,827's hash need?

Think of your answer first, then check it.

Answer At least 18.

Block 130,827’s target is 0000000000000000006af3a6000…: 18 zero hex digits, then 6af3a6. A random hash lands that low about once in 1.13 × 10²² tries. The real hash, 1df2f2c1…, sits about 12% of the way up the whole 256-bit range: an utterly ordinary number. Nobody checks it, so nobody ground it down.

What does the hash cover?

Everything in the header, and through it almost everything in the block:

  • The parent, through the previous-block field, and so, link by link, the whole chain back to genesis.
  • The transactions, through the Merkle root, and their witnesses through the coinbase’s witness commitment (when the block has any witness data).
  • The time and the target, directly.
  • The mining result: through the proof commitment, the mining settings, both matrix fingerprints, the winning ticket, the matrix sizes and the tile position.

One thing is deliberately left out: the zero-knowledge proof bytes. Proofs are randomized, so the same block could carry different valid proofs, and the block hash must not depend on which one.

Where is the block hash used?

As the block’s name, everywhere:

  • The next block stores it in its previous-block field.
  • The certificate stores it too, in internal byte order, and a node rejects a certificate whose stored hash doesn’t match the header’s.
  • Checkpoints in the node software are lists of block hashes: block 120,000 must be a5f57e44…d2a84b7d, and so on every 10,000 blocks.
  • Explorers, wallets and peers ask for blocks by hash.

Why is it still SHA-256?

Because Pearl kept Bitcoin’s hash wherever it kept Bitcoin’s design. Block hashes, transaction IDs, the transaction Merkle tree and the proof commitment all use SHA256d, exactly as Bitcoin’s equivalents do.

BLAKE3 appears only inside the mining puzzle: the job key, the matrix fingerprints, the noise seeds and the tickets. There its strengths matter: it is natively a Merkle tree, so a gigabyte-sized matrix can be committed to and opened a few rows at a time; it is fast on GPUs; and it has a keyed mode. See hash functions.

Why does the certificate repeat the block hash?

So a node can pair a certificate with its header before doing any real work. The first check in certificate verification is simply “does the hash stored in the certificate equal SHA256d of this header?”. A certificate copied onto another header fails at once, before the expensive proof check. Light clients rely on the same pairing: they download each header with its certificate, verify both, and keep only the 108-byte header afterwards.

Can a miner choose its block hash?

Only by changing the block. Any change to the header gives a completely different hash (the avalanche effect), and any change to the first 76 bytes also gives the miner a completely different mining puzzle. Since no rule cares what the hash looks like, there’s no reason to try.

Code: the hash, in Go and JavaScript

BlockHash() (node/wire/blockheader.go:43-48 at v1.5.2, on GitHub) serializes the header and hashes it twice:

node/wire/blockheader.go Go
// BlockHash computes the block identifier hash for the given block header.
func (h *BlockHeader) BlockHash() chainhash.Hash {
	return chainhash.DoubleHashRaw(func(w io.Writer) error {
		return writeBlockHeader(w, 0, h)
	})
}

And checkProofOfWork (node/blockchain/validate.go:309-339 at v1.5.2, on GitHub) never looks at it. It checks the target’s range, then hands the header and certificate to the zero-knowledge verifier. (Its comment still says “the block hash must be less than the claimed target”, a leftover from btcd; the code below the comment verifies the certificate instead.)

In JavaScript, with @noble/hashes:

JavaScript
import { sha256 } from '@noble/hashes/sha2.js';
import { hexToBytes, bytesToHex } from '@noble/hashes/utils.js';

const header = hexToBytes('00000020999c961b…c77ae649');   // all 108 bytes
const hash = bytesToHex(sha256(sha256(header)).reverse()); // '1df2f2c1…3c6d45b9'

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.