Bitcoin as a Chessboard

21 May 2026  ·  12 min read  ·  Bitcoin × Chess

Quick Answer

A real chess position with the standard 32-piece army carries about 148 bits of combinatorial information. Two such positions together comfortably exceed 256 bits — the exact size of a Bitcoin private key. The mapping is a clean combinatorial bijection: every 128-bit half corresponds to exactly one legal placement, and every legal placement decodes to exactly one 128-bit half.

Try it live

See your Bitcoin key as a chess position

Open the Bitcoin Chessboard Converter

100% client-side · open-source maths · for education and art only

There is something quietly perfect about the fact that the most popular board game in history and the most successful cryptocurrency in history share exactly the same information capacity. This article explains why — and shows you how to convert between the two yourself.

1. Why 256 bits fit on 64 squares

Bitcoin private keys are integers on the secp256k1 elliptic curve. The valid range is [1, n−1], where n ≈ 2256 − 232 − 977. In practice, almost every 256-bit string is a valid key — the chance of landing in the forbidden zone is about 1 in 2224, which has never happened in the history of Bitcoin and almost certainly never will.

A chessboard has 8 × 8 = 64 squares, but not every square arrangement is a legal chess position. The standard army has exactly 32 pieces (2 kings, 2 queens, 4 rooks, 4 bishops with one of each colour per side, 4 knights, 16 pawns). Counting how many ways these pieces can be placed on 64 squares — with the constraint that pawns sit only on ranks 2 through 7 — yields approximately 2148 distinct positions. One board therefore holds 148 bits; two boards hold roughly 296 bits, which comfortably absorb the 256 bits of a private key.

log₂(positions per board) ≈ 148 bits   ·   2 boards ≈ 296 bits   ≥   256 bits = 1 Bitcoin private key ✓

2. The 32-piece standard-army schema

Instead of inventing new pieces, the visualiser sticks to the standard 32-piece army familiar to every chess player. Every encoded board contains exactly: 1 white king, 1 black king, 1 white queen, 1 black queen, 2 rooks of each colour, 2 bishops of each colour (one on a light square and one on a dark square), 2 knights of each colour, and 8 pawns of each colour. The full constraint list is:

  • All 32 pieces are present (no captures, no promotions).
  • Pawns occupy any squares on ranks 2 through 7 (never the back ranks).
  • Each side's two bishops sit on opposite-coloured squares (one light-square bishop, one dark-square bishop) — exactly as in any standard opening.

These three constraints define the precise set of positions over which the bijection is built. The numerical placement order used by the algorithm is fixed (kings, queens, rooks, bishops, knights, pawns) so that encoder and decoder agree on the digit weights.

3. Anatomy of a Bitcoin private key

A raw private key is just 32 random bytes. To make it easy to transport between wallets, Bitcoin defines the WIF (Wallet Import Format):

WIF = Base58Check(
    0x80 (network byte — mainnet)
    ‖ key (32 bytes)
    ‖ 0x01 (compressed flag)
    ‖ checksum (4 bytes = first 4 of double-SHA-256)
)

Mainnet vs testnet — a common confusion. The 32-byte private key itself is just a number; it is identical on every Bitcoin network. The only difference is the visible encoding: WIF uses prefix 0x80 on mainnet and 0xEF on testnet, addresses use bc1… / 1… vs tb1… / m… / n…. The chessboard encodes the key, not the network — so the same two positions produce both addresses, depending only on how you choose to print them. Our converter shows mainnet outputs because that is what people recognise.

For our purposes, only the middle 32 bytes matter — that is what we paint onto the board. The prefix, flag and checksum are added automatically when displaying the WIF.

4. From key to address: ECDSA → HASH160

Given the private key k, the corresponding public key is the elliptic-curve point P = k · G, where G is the fixed generator point of secp256k1. This step is one-way: recovering k from P is the discrete-log problem, which is computationally infeasible.

Then the address is computed as:

pubkey = compress(k · G) # 33 bytes
hash160 = RIPEMD-160(SHA-256(pubkey)) # 20 bytes

legacy_address = Base58Check(0x00 ‖ hash160)
segwit_address = Bech32('bc', 0, hash160)

5. Checksums: Base58Check vs Bech32

Base58Check (used by legacy addresses and WIF keys) appends a 4-byte truncated double-SHA-256 to the payload, then encodes the whole thing in a 58-character alphabet (no 0, O, I, l to reduce confusion). Any single typo has roughly a 1 in 232 chance of producing a "valid" string — practically zero.

Bech32 (BIP-173, used by SegWit) is much smarter: it uses a 30-bit BCH polynomial code over GF(32). It detects any single-symbol error with probability 1, and any pair of symbol errors with probability ≥ 1 − 2−30. Bech32 also uses a 32-symbol alphabet that maps perfectly to the 32 light squares on a chess board — a curious coincidence we exploit in the address-board section below.

6. The bijection in code

Each board represents a 128-bit half of the key (low half on board 1, high half on board 2). Because the schema only admits a fixed set of legal positions, the bijection cannot be a simple per-square lookup — it is a combinatorial unranking. Place pieces in a fixed order (kings, queens, rooks, bishops, knights, pawns); for each step, choose k squares out of the remaining n empty squares; the choice index acts as a digit in a mixed-radix system whose base at each step is C(n, k) for that step.

// encode 128-bit BigInt x into a board
let rem = x;
for (const step of placementOrder) { // WK, BK, WQ, BQ, WR, BR, …
  const base = C(step.n, step.k);
  const digit = rem % base;
  rem = rem / base;
  placeOnSquares(unrankCombo(digit, step.n, step.k), step.piece);
}

// decode \u2014 Horner with the same bases in reverse
let x = 0n;
for (let i = steps.length - 1; i >= 0; i--) {
  x = steps[i].digit + steps[i].base * x;
}

Bishops are handled with a slightly different step: each side picks one light-square bishop out of the available light squares and one dark-square bishop out of the available dark squares, so the base at that step is nL × nD. Pawns are restricted to ranks 2\u20137 by filtering the remaining empty squares before the binomial choice. The full algorithm is implemented in roughly 40 lines of pure JavaScript using BigInt; you can read it directly in the page source of the converter.

7. The visualiser: two boards, editable FENs

The converter on this site renders both halves as real chess diagrams using chessboard.js with the Wikipedia piece set \u2014 the same library and graphics used by the league's Vote Chess room. The board on the left holds the low 128 bits of the key, the one on the right holds the high 128 bits. A copy of the position in FEN notation appears below each board in an editable input.

You can paste any FEN you like. The board re-renders immediately so you can always see the position, and the input border turns green or red depending on whether the position fits the bijection schema:

  • Green border: the position has the full 32-piece army, pawns on ranks 2\u20137 and bishops on opposite colours \u2014 the Bitcoin key updates instantly.
  • Red border: the FEN parses but the position cannot encode a key (missing pieces, a pawn on rank 1 or 8, two bishops on the same colour, etc.). The board still shows it for inspection; only the key remains unchanged.

A small copy-to-clipboard button beside each FEN input copies the position string for sharing or storage. The "Famous positions" picker, the random-board button and the PNG / share buttons all go through the same render pipeline, so anything that appears on a board can be exported back as FEN at any time.

8. Applications

  • Chess paper wallet. Print the position, slip it inside a chess opening book on your shelf. Plausible deniability + zero electronics + human-readable.
  • Generative art. Mint chessboards as NFTs that are also valid Bitcoin keys. Each piece-arrangement is provably unique.
  • Vanity boards. Brute-force boards that decode to addresses starting with chosen letters (bc1q… → "bc1qchess…").
  • Education. A chessboard is the most viscerally satisfying way to teach the size of cryptographic key spaces.
  • Memorisation. Chess players memorise hundreds of positions effortlessly. A board is vastly easier to remember than a 52-character WIF string.

9. Security considerations

  • Never use a key generated in any public-facing tool to store real funds.
  • Remember that the private key is the same number on mainnet and testnet — only the visible encoding changes. A board that derives a valid mainnet address also derives the corresponding testnet address.
  • Use crypto.getRandomValues() (or hardware RNG) — never Math.random() — to generate keys.
  • All cryptography must run client-side. The server should never see the key.

10. Frequently asked questions

Can two different keys ever produce the same chessboard?

No. The mapping is a perfect bijection over 2256 elements — each board corresponds to exactly one 256-bit number, and vice versa. The only edge case is the tiny set of bit-strings that fall outside [1, n−1]; these are not valid Bitcoin keys and we reject them.

Could a famous chess game's final position decode to a real Bitcoin address?

Mathematically yes — every legal position decodes to some 256-bit number and therefore some private key. Whether that key controls a non-zero balance is a brute-force search problem. With ~10⁹ active Bitcoin addresses out of 2160 total, the chance of any given board hitting a funded address is astronomically small (~10⁻³⁹). But "discover" mode is a fun thought experiment.

What libraries are used in the converter?

The converter loads @noble/secp256k1 and @noble/hashes — both are pure-JS, zero-dependency, audited libraries by Paul Miller. Base58Check and Bech32 are implemented inline in ~80 lines.

Ready to see your key as a position?

Open the interactive converter

Comments 0

Be the first to comment!

Log in to join the discussion.