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.
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?
- Validate the target and difficulty.
- Hash a candidate nonce.
- Check its prefix.
- Yield periodically and inspect cancellation.
- 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.
- Validate the target and difficulty.
- Hash a candidate nonce.
- Check its prefix.
- Yield periodically and inspect cancellation.
- Return a matching nonce and digest.
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.
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