DeutschGitHub
partialpackages/proof-of-work/src

Proof of Work

@ralphschuler/proof-of-work

Mines and verifies SHA-256 prefix proofs with event-loop yielding and cancellation.

SHA-256noncerate limiting

01 · Problem

What is it for?

A computational challenge needs a cheap verifier and a bounded, cancellable search policy.

02 · Mental model

How should you think about it?

Mining performs repeated trials; verification recomputes exactly one candidate digest.

In this repository

Mines and verifies SHA-256 prefix proofs with event-loop yielding and cancellation. Difficulty is measured in repeated hexadecimal prefixes. Protocol challenge encoding and external work budgets remain caller responsibilities.

03 · Control flow

What happens in which order?

  1. Validate the target and difficulty.
  2. Hash a candidate nonce.
  3. Check its prefix.
  4. Yield periodically and inspect cancellation.
  5. Return a matching nonce and digest.

04 · Building blocks

The important contracts

ProofOfWork.mineSearch cooperatively with an optional AbortSignal.
ProofOfWork.validateRecompute one proof and check its target.

05 · Build it yourself

Implement a small core

Start with this small independent implementation, then use the steps below to make its contract explicit.

  1. Validate the target and difficulty.
  2. Hash a candidate nonce.
  3. Check its prefix.
  4. Yield periodically and inspect cancellation.
  5. Return a matching nonce and digest.
Concept sketch · may reference omitted helpers
async function sha256Hex(value: string) {
  const bytes = new TextEncoder().encode(value);
  const digest = await crypto.subtle.digest("SHA-256", bytes);
  return [...new Uint8Array(digest)]
    .map(byte => byte.toString(16).padStart(2, "0"))
    .join("");
}

async function validate(data: string, nonce: number, difficulty: number) {
  if (!Number.isInteger(difficulty) || difficulty < 0 || difficulty > 64) return false;
  const hash = await sha256Hex(data.length + ":" + data + ":" + nonce);
  return hash.startsWith("0".repeat(difficulty));
}

06 · Verify

What should you test?

  • Verify a mined low-difficulty result.
  • Reject altered data, nonce or hash.
  • Abort a long search through a timer and reject impossible target lengths.

Try it yourself

Turn the first verification claim into a failing test, implement the smallest fix, then add a boundary case.

Verify a mined low-difficulty result.

Compare your approach

Your check should fail when the stated invariant is deliberately broken, and pass again after the fix. Keep setup deterministic and assert an observable result.

07 · Limits

Trade-offs and failure modes

  • One hexadecimal zero represents four difficulty bits.
  • High difficulty is deliberately expensive.
  • A real protocol must define unambiguous challenge encoding.
Important

Difficulty is measured in repeated hexadecimal prefixes. Protocol challenge encoding and external work budgets remain caller responsibilities.

08 · Keep exploring

Source code and related ideas

yarn tsx packages/proof-of-work/examples/basic.ts