Skip to main content

Cryptography Primitives for Blockchain

Blockchains replace trusted institutions with math. Four primitives carry almost all of the weight: hash functions, digital signatures, Merkle commitments, and (increasingly) zero-knowledge proofs.

1. Cryptographic Hash Functions

A hash H(x) maps arbitrary bytes to a fixed-size digest. Required properties:

PropertyMeaningWhy the chain needs it
DeterministicSame input, same outputAll nodes compute the same block hash
Pre-image resistanceCannot find x from H(x)Addresses do not reveal public keys until spent
Second pre-image resistanceGiven x, cannot find y != x with same hashCannot forge a replacement block
Collision resistanceCannot find any x != y with H(x)=H(y)Merkle roots uniquely commit to tx sets
Avalanche effect1 bit flip changes ~50% of outputTampering is obvious
ChainHashNote
BitcoinSHA-256 (double: SHA256(SHA256(x)))Double hashing mitigates length-extension attacks
EthereumKeccak-256Not NIST SHA3-256 (different padding) - a classic bug source
Filecoin / IPFSSHA2-256 multihashSelf-describing via multihash
Zcash/ZK systemsPoseidon, Pedersen, MiMCAlgebraic hashes cheap inside circuits
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;

public final class Sha256Demo {
public static String sha256Hex(String input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
return HexFormat.of().formatHex(md.digest(input.getBytes(StandardCharsets.UTF_8)));
}

public static void main(String[] args) throws Exception {
System.out.println(sha256Hex("hello"));
System.out.println(sha256Hex("hellp")); // completely different digest
}
}

2. Proof of Work as Hash Puzzle

Miners search for a nonce such that H(header || nonce) < target. Expected work is 2^256 / target hashes. The network retargets difficulty (Bitcoin: every 2016 blocks, ~2 weeks) to keep ~10 min block time.

public static long mine(String headerData, int leadingZeroBits) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
for (long nonce = 0; ; nonce++) {
byte[] d = md.digest((headerData + nonce).getBytes(StandardCharsets.UTF_8));
if (leadingZeros(d) >= leadingZeroBits) {
return nonce;
}
}
}

private static int leadingZeros(byte[] d) {
int bits = 0;
for (byte b : d) {
if (b == 0) { bits += 8; continue; }
bits += Integer.numberOfLeadingZeros(b & 0xFF) - 24;
break;
}
return bits;
}

3. Digital Signatures

A key pair (sk, pk); sign(sk, msg) -> sig; verify(pk, msg, sig) -> bool. Ownership on chain is the ability to produce a valid signature.

SchemeUsed byProperty
ECDSA secp256k1Bitcoin, Ethereum EOAsNeeds a secret random nonce k; reused/biased k leaks the private key (Sony PS3, Android 2013 wallets)
EdDSA (Ed25519)Solana, Cardano, SSHDeterministic nonce; fast batch verification
Schnorr (BIP-340)Bitcoin TaprootLinear -> key/signature aggregation (MuSig2)
BLS12-381Ethereum consensusSignatures aggregate into one -> thousands of validator votes verified as one

Ethereum address derivation

privateKey (256-bit random)
-> publicKey = privateKey * G (secp256k1 point, 64 bytes uncompressed)
-> keccak256(publicKey) (32 bytes)
-> last 20 bytes (address, EIP-55 checksum casing)

Replay protection: EIP-155 includes chainId in the signed payload so a signature valid on Ethereum mainnet is invalid on a fork or L2. Always use typed transactions (EIP-2718/1559) and EIP-712 for structured off-chain signing.

Wallet Key Hierarchy (BIP-32/39/44)

12/24-word mnemonic (BIP-39) -- PBKDF2-HMAC-SHA512, 2048 rounds + optional passphrase --> 512-bit seed
-> master key (BIP-32 HMAC-SHA512 "Bitcoin seed")
-> m/44'/60'/0'/0/0 first Ethereum account (BIP-44, coin type 60)
-> m/44'/0'/0'/0/0 first Bitcoin account

The mnemonic is the wallet. Anyone with it controls every derived account.

4. Merkle Trees

A binary tree of hashes whose root commits to an entire list. Proving that one element is included needs only log2(n) sibling hashes.

Blockchain Core Mechanics

Merkle RootH(AB)H(CD)H(tx A)H(tx B)H(tx C)H(tx D)Click a leaf. Proof for tx A = [H(tx B), H(CD)] β†’ log2(4) = 2 hashes

A light client holding only block headers can verify a transaction with O(log n) sibling hashes against the header Merkle root, without downloading the block body (SPV).

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;

public final class Merkle {
public static byte[] root(List<byte[]> leaves) throws Exception {
if (leaves.isEmpty()) throw new IllegalArgumentException("empty");
MessageDigest md = MessageDigest.getInstance("SHA-256");
List<byte[]> level = new ArrayList<>();
for (byte[] l : leaves) level.add(md.digest(l));
while (level.size() > 1) {
List<byte[]> next = new ArrayList<>();
for (int i = 0; i < level.size(); i += 2) {
byte[] left = level.get(i);
byte[] right = (i + 1 < level.size()) ? level.get(i + 1) : left; // Bitcoin duplicates last node
md.update(left);
md.update(right);
next.add(md.digest());
}
level = next;
}
return level.get(0);
}
}

Gotcha (CVE-2012-2459): Bitcoin's "duplicate last node" rule lets two different transaction lists share a Merkle root. Domain-separate leaves from inner nodes (0x00 || leaf, 0x01 || left || right) in your own designs, as RFC 6962 (Certificate Transparency) does.

Merkle Patricia Trie (Ethereum state)

Ethereum commits state (address -> account) in a Modified Merkle Patricia Trie with hex-nibble keys. Its root appears in every block header (stateRoot, transactionsRoot, receiptsRoot). It supports proofs of inclusion and non-inclusion (eth_getProof, EIP-1186), which light clients and bridges use. Verkle trees (EIP-6800) will shrink proofs from ~kB to ~150 bytes to enable stateless clients.

5. Zero-Knowledge Proofs (ZKPs)

Prove "I know w such that C(x, w) = true" without revealing w.

SystemTrusted setupProof sizeVerifyQuantum-safeUsed by
Groth16 (SNARK)Per-circuit~200 B~1 ms (3 pairings)NoZcash Sapling, Tornado Cash
PLONK / Halo2Universal / none~1 kBmsNozkSync, Scroll, Aztec
STARKNone (hash-based)50-200 kBms-ishYesStarkNet

Applications: validity rollups (prove a batch of 1000s of txs executed correctly), private transfers, identity ("over 18" without birthdate), zkBridges.

Senior Gotchas

  1. Never roll your own crypto. Use audited libraries (libsecp256k1, BouncyCastle, noble-curves).
  2. Randomness: Weak RNG in key/nonce generation has drained real wallets (Profanity vanity-address exploit, 2022). Use the OS CSPRNG (SecureRandom, /dev/urandom).
  3. Signature malleability: ECDSA (r, s) and (r, n-s) both verify. Bitcoin (BIP-62/146 low-S, SegWit) and OpenZeppelin ECDSA.recover enforce canonical low-S; never use a raw signature as a unique ID.
  4. ecrecover returns address(0) on failure - always check it; an unchecked zero address has authorised withdrawals.
  5. Hash length extension: never build MACs as SHA256(key || msg); use HMAC.
  6. Quantum: Shor breaks ECDSA/BLS; hash-based and lattice signatures (SLH-DSA, ML-DSA) are the migration targets. Addresses that have never revealed their public key are safer.

Next: Ledger Models.

πŸ“–
Track Page Progress0 / 635 Read
Knowledge Base Completion0%