§ 02 · Cryptography
Hash functions
A fingerprint for any data, impossible to fake
On this page 5 sections
A hash functionHash function: A function that turns any data into a fixed-size fingerprint. The same input always gives the same output, a tiny change gives a completely different one, and you can't work backwards. takes any data, a word or a whole block, and produces a short fixed-size fingerprint called a hashHash: The output of a hash function: a short, fixed-size fingerprint of some data, usually shown in hexadecimal..
Pearl uses hashes everywhere: to name transactions and blocks, to chain blocks together, to commit to data without revealing it, and to run its mining lottery. It uses two families. SHA-256SHA-256: A widely used hash function that produces a 256-bit (32-byte) fingerprint. Pearl uses it, as Bitcoin does, for transaction IDs, block hashes and signatures. comes from Bitcoin. BLAKE3BLAKE3: A fast, modern hash function that is built internally as a Merkle tree. Pearl's mining uses it for the job key, the matrix fingerprints, the noise and the lottery tickets. is Pearl’s addition, and it powers the mining.
Try it
Type anything. Watch the hash change completely when you change a single letter, and compare SHA-256, SHA256d and BLAKE3 side by side.
What makes a good hash function?
Five properties. The first three are easy to see; the last two are what make hashes useful for security.
- Deterministic. The same input always gives the same hash, on every computer.
- Fixed size. SHA-256 and BLAKE3 (as Pearl uses it) always give 32 bytes, whether you hash one letter or a gigabyte.
- Avalanche. A tiny change in the input changes about half the output bits. This is the avalanche effectAvalanche effect: The property that changing one bit of a hash function's input flips about half the bits of its output, so similar inputs give unrelated-looking hashes..
- One-way. Given a hash, you can’t find an input that produces it. This is preimage resistancePreimage resistance: The property that, given a hash, you cannot find any input that produces it, short of trying inputs one by one for longer than the universe has existed..
- No collisions. No one can find two different inputs with the same hash. This is collision resistanceCollision resistance: The property that no one can find two different inputs with the same hash. Without it, one signed or committed message could be swapped for another..
Here is the avalanche effect with real numbers. “Pearl” and “pearl” differ in one bit: P is 0x50 and p is 0x70.
| Input | SHA-256 |
|---|---|
Pearl |
72bc556112e9538a2433f0a9b87b032eae43c69e367e9dca1b176929dcf20ed5 |
pearl |
26e3b2a5dc54dd5812fe7e6917172e2c9a70c72a0f5d2e97a5b8eb90434b7ffa |
The two hashes differ in 135 of their 256 bits. Nothing about the second hints that its input was almost the same as the first.
Going deeper How hard is “can’t”?
A 256-bit hash has 2²⁵⁶ possible values, about 10⁷⁷. Finding an input for a given hash means trying inputs at random, about 2²⁵⁶ tries. Finding any collision takes about 2¹²⁸ tries, thanks to the birthday paradox. Both are far beyond all the computers on Earth running for the age of the universe. No shortcut is known for SHA-256 or BLAKE3.
What is SHA-256, and what is SHA256d?
SHA-256 is the hash function Bitcoin is built on, standardised by NIST. It chops the input into 64-byte blocks and stirs each one through 64 rounds of mixing. Pearl uses it exactly as Bitcoin does.
SHA256dSHA256d: SHA-256 applied twice: the hash of the hash. Pearl's block hashes, transaction IDs, Merkle roots and proof commitments all use it. is SHA-256 applied twice: the hash of the hash. Pearl uses it for transaction IDs, Merkle roots, block hashes and the header’s proof commitment.
Take the real header of block 130,825, all 108 bytes:
-
Hash the header once
SHA-256 of the 108 bytes gives
76db48f729868f9da8ff7dbe1aae143f3322cc64c2ce3602e6091a9fb23c842b. -
Hash that 32-byte result again
SHA-256 of those 32 bytes gives
ae3355eec8af1f407f0e935739615e375f35bedcd556a75e13a093387651c83f. -
Reverse the bytes for display
3fc851763893a0135ea756d5dcbe355f375e613957930e7f401fafc8ee5533ae, the block hash every explorer shows. The reversal is explained on the byte order page.
| 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. |
Why hash twice? Satoshi never said. The usual explanation is that a second round blocks a weakness of SHA-256 called length extension. Whatever the reason, the double hash is part of the format, and Pearl keeps it.
Why did Pearl add BLAKE3?
Because of what mining needs. A Pearl miner commits to two big integer matrices, sometimes gigabytes of data, and must later prove that a couple of rows belonged to them. BLAKE3 was designed in 2020 and has three features that fit:
- It’s a tree. BLAKE3 splits its input into 1 KiB chunks, hashes each, then hashes pairs of results up to a single root. So the BLAKE3 hash of a matrix is the root of a Merkle tree, and a few rows can be proven with a short path of sibling hashes.
- It’s fast and parallel. Chunks can be hashed at the same time on many CPU or GPU cores.
- It has a keyed mode. Given a 32-byte key, BLAKE3 becomes a different function for every key. Pearl keys its hashes with the job keyJob key: A BLAKE3 hash of the block template (the header minus its proof commitment) and the mining settings. All of the puzzle's randomness flows from it, tying the work to one block. or a noise seedNoise seed: One of two random-looking values made from the job key and fingerprints of the two matrices (and, since block 99,000, their sizes). Each seed grows into one noise matrix., so a result from one job means nothing in another. That’s a form of domain separationDomain separation: Mixing a label into a hash so that hashes made for one purpose can never be mistaken for hashes made for another. Tagged hashes and keyed BLAKE3 both do it., like tagged hashes for SHA-256.
The same word gives a different BLAKE3 hash from its SHA-256 hash, of course:
| Input | BLAKE3 |
|---|---|
Pearl |
64c73be7ea8de1a1691ea7f2233e2673e195c7ffc51b9789d234d4b2eabcd1c0 |
pearl/cert-v3/noise-seed/A |
8249406ca0ed15169616f692fcf076f892dbdb2a7023b852f0d47719c390017b |
The second one is real: it’s the salt Pearl’s consensus code has used since block 99,000 to tie matrix A’s noise seed to A’s size. See noise seeds.
Where does Pearl use each hash?
| Purpose | Hash |
|---|---|
| Block hash (the block’s ID) | SHA256d of the 108-byte header |
| Proof commitment in the header | SHA256d of the certificate version and public data |
| Transaction IDs and the Merkle root | SHA256d |
| Signatures, Taproot tweaks, script trees | SHA-256 tagged hashes |
| Job key, matrix fingerprints, noise seeds, noise | BLAKE3, keyed where noted |
The mining ticket (hash_jackpot) |
BLAKE3 keyed with the A-noise seed |
| Inside the zero-knowledge proof | BLAKE3 and Poseidon (a hash built for proofs) |
| Wallet seeds and key derivation (BIP-32/39) | HMAC-SHA512, PBKDF2-SHA512 |
| Key fingerprints in extended keys | RIPEMD-160 of SHA-256 (no Pearl address uses it) |
| Post-quantum XMSS signatures | SHAKE256SHAKE256: A hash function from the SHA-3 family that can produce output of any length. In Pearl it is used only inside XMSS signatures. |
Code: hashing in Pearl and in the browser
pearld’s double hash is a thin wrapper over Go’s crypto/sha256, in
hashfuncs.go (node/chaincfg/chainhash/hashfuncs.go:25-50 at v1.5.2, on GitHub). The block hash is that applied to
the 108 header bytes, in BlockHash() (node/wire/blockheader.go:43-48 at v1.5.2, on GitHub).
In a browser, with the same library this site uses:
import { sha256 } from '@noble/hashes/sha2.js';
import { blake3 } from '@noble/hashes/blake3.js';
const msg = new TextEncoder().encode('Pearl');
sha256(msg); // 72bc5561…dcf20ed5
sha256(sha256(msg)); // SHA256d: 2ec32b95…b184215f
blake3(msg); // 64c73be7…eabcd1c0
blake3(msg, { key }); // keyed mode: key must be exactly 32 bytes