Introduction

Every ten minutes or so, somewhere on Earth, a machine wins Bitcoin's lottery and adds a block to the chain. From the outside it looks like raw waste: warehouses of chips computing trillions of hashes per second, most of them thrown away.

Underneath, though, is one elegant idea. A hash function takes any data and scrambles it into a fixed string of digits. Change the input by one character and the output looks completely different — there is no way to steer it. So miners add a nonce, a throwaway counter, and ask a simple question: does the block's hash start with enough zeros?

Almost always the answer is no, so they bump the nonce and try again. Proof of work is nothing more than this: keep guessing until you stumble onto a hash that clears the bar. Hard to find, trivial to check — and that gap is the whole point.

Mine a Block

Below is a toy block. Pick a difficulty — how many leading zeros the hash must have — then press Mine the block. The computer counts up through nonces, hashing each one, until it finds a hash that clears the bar.

<p class="hint">Mining is a lottery. Fix the block data, then search for a <b>nonce</b> (a counter) so the block's hash starts with enough leading zeros. Verifying a winning nonce is one hash; <b>finding</b> one means trying on average 16^difficulty of them.</p>
<label class="row">Block data
  <input id="data" type="text" value="KIPU block #1" />
</label>
<label class="row">Difficulty (leading zeros)
  <input id="diff" type="range" min="1" max="5" value="2" />
  <span id="diffv" class="pill">2</span>
</label>
<div class="btns">
  <button id="mine" type="button">Mine the block</button>
  <button id="reset" type="button" class="ghost">Reset</button>
</div>
<div class="status" id="status">Pick a difficulty, then mine.</div>
<div class="hash" id="hash"></div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .8rem; line-height: 1.45; }
.row { display: flex; align-items: center; gap: .6rem; font-size: .9rem; font-weight: 600;
       color: #1d3557; margin: .5rem 0; flex-wrap: wrap; }
input[type=text] { font: 500 14px ui-monospace, monospace; padding: .4rem .6rem;
       border: 1px solid #cdd9e3; border-radius: 8px; flex: 1; min-width: 140px; }
input[type=range] { flex: 1; min-width: 120px; }
.pill { display: inline-flex; min-width: 1.6em; justify-content: center; background: #e8eef3;
       color: #1d3557; border: 1px solid #cdd9e3; border-radius: 6px; padding: .1rem .4rem; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; margin: .7rem 0 .4rem; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
         background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
button:disabled { opacity: .55; cursor: default; }
.status { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.work { color: #b5651d; }
.hash { font: 600 14px ui-monospace, monospace; word-break: break-all; margin-top: .3rem;
        background: #f3f5f8; border: 1px solid #e1e7ee; border-radius: 8px; padding: .6rem; min-height: 1.2em; }
.hash b { color: #0a7d33; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// A toy proof-of-work. Real Bitcoin uses double SHA-256; here we use a small deterministic hash so it runs in the sandbox with no imports. The IDEA is identical: a hash is easy to compute and easy to verify, but to make it start with D leading zero hex digits you must keep trying nonces — on average 16^D attempts. Raising the difficulty by one multiplies the expected work by 16.
// 32-bit FNV-1a style mix, rendered as 8 hex digits. Avalanche-like: tiny input changes scatter the output, so the only way to a "lucky" hash is to search.
function toyHash(str){
  let h = 0x811c9dc5 >>> 0;
  for(let i=0;i<str.length;i++){
    h ^= str.charCodeAt(i);
    h = Math.imul(h, 0x01000193) >>> 0;
  }
  // extra scramble so leading digits look random
  h ^= h >>> 15; h = Math.imul(h, 0x2c1b3c6d) >>> 0;
  h ^= h >>> 12; h = Math.imul(h, 0x297a2d39) >>> 0;
  h ^= h >>> 15;
  return (h >>> 0).toString(16).padStart(8,'0');
}

const $ = id => document.getElementById(id);
function setStatus(t,cls){ const s=$('status'); s.textContent=t; s.className='status '+cls; }

$('diff').addEventListener('input', ()=>{ $('diffv').textContent=$('diff').value; });

function mine(){
  const data = $('data').value;
  const diff = +$('diff').value;
  const target = '0'.repeat(diff);
  setStatus('Mining… searching for a winning nonce.','work');
  $('mine').disabled = true; $('hash').innerHTML='';
  // Defer so the "Mining…" message paints before the loop runs.
  setTimeout(()=>{
    let nonce = 0, hash = '';
    const CAP = 8000000; // safety bound
    while(nonce < CAP){
      hash = toyHash(data + '|' + nonce);
      if(hash.startsWith(target)) break;
      nonce++;
    }
    $('mine').disabled = false;
    if(hash.startsWith(target)){
      $('hash').innerHTML = '<b>'+hash.slice(0,diff)+'</b>'+hash.slice(diff);
      setStatus(fmt('Mined! nonce=%nonce% found after %nonce%%v% tries (expected ~%pow%).', { nonce: nonce, v: 1, pow: Math.pow(16,diff) }),'ok');
      console.log('nonce',nonce,'hash',hash,'tries',nonce+1,'expected',Math.pow(16,diff));
    } else {
      setStatus('No nonce under the cap — raise the cap or lower difficulty.','work');
    }
  }, 30);
}

$('mine').addEventListener('click', mine);
$('reset').addEventListener('click', ()=>{
  $('data').value='KIPU block #1'; $('diff').value=2; $('diffv').textContent='2';
  $('hash').innerHTML=''; setStatus('Pick a difficulty, then mine.','');
});
Result
Console

Watch the asymmetry. Checking the winning nonce is one hash: you can confirm it in an instant. Finding it took the machine many tries — and each extra zero of difficulty multiplies the expected work by 16, because a hex hash starts with a zero only one time in sixteen. Real Bitcoin tunes this knob so that, no matter how much hardware joins, a block still takes about ten minutes.

The Real Complexity

How hard is mining, really? Not the hardware — the math.

  • Checking a candidate block is one hash evaluation: compute it, count the zeros, done.
  • Finding a qualifying nonce has no known shortcut. A good hash function is one-way — given the desired output (many leading zeros) you cannot run it backwards to recover an input. All you can do is brute force: try nonces until one works.
  • The work is tunable. Requiring D leading zeros means each guess succeeds with probability 1/16D16^{D}, so a miner expects about 16D16^{D} attempts. Bitcoin adjusts D every 2016 blocks to hold the ten-minute pace.
  • It is not proven impossible. Proof of work leans on a belief — that SHA-256 has no exploitable structure — the same kind of unproven hardness assumption that underlies modern cryptography. Like factoring, no fast attack is known, but none has been ruled out either.

That is the punchline: security here is not a theorem but a bet that searching is the only option. If someone found a way to invert the hash — the way a P vs NP collapse might make hard searches easy — the lottery would stop being a lottery.

Where It Matters

"Make the honest cost cheap and the attacker's cost ruinous" is a pattern that shows up far beyond cryptocurrency:

  • Securing blockchains: rewriting history would mean re-mining every block faster than the whole network — proof of work makes that economically hopeless.
  • Fighting spam and abuse: the original idea, Hashcash (Adam Back, 1997), asked email senders to burn a little computation per message — trivial for one email, crushing for a spammer sending millions.
  • Rate limiting and anti-bot: client puzzles slow down floods of requests without a central gatekeeper.
  • Timestamping and fairness: because the work is unpredictable, no one can pre-compute the future, which makes proof of work a rough public clock.

Understand why a qualifying nonce is hard to find and you have met the deeper theme of this site — the gap between checking an answer and discovering one, the same gap behind factoring and P vs NP.

Conclusion

Proof of work hides a beautiful trick: a puzzle that is brutal to solve yet effortless to check, with a difficulty dial that keeps the solving time steady no matter how much hardware shows up. The mountains of mining gear are not solving anything deep — they are simply guessing nonces, fast, until one clears the bar.

So the next time you hear that Bitcoin "wastes" energy, remember what the energy buys: a number anyone can verify in a single hash but that, as far as we know, no one can find except by searching. It is intractability, rented by the block — and like P vs NP, we believe the shortcut isn't there, but we have never been able to prove it.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/bitcoin-proof-of-work/Content licensed under CC BY-NC 4.0.