Loading Hookedin
Fetching the latest round and receipt data.
Fetching the latest round and receipt data.
Convert a Bitcoin block hash into the exact 8-digit draw. The digits fill from right to left as the browser works.
A round closes at a fixed Bitcoin block height. Once that block exists, Hookedin stores its 32-byte block hash on the settled round and uses it as the public seed. The round number selects which closing block and ticket ledger to verify; the hash chain itself uses only the block hash and the configured draw constants.
Verification starts with the block hash bytes, runs SHA-256 100,000 times for each decimal digit, converts each digest to a decimal digit with modulo 10, and prepends each digit. After 8 digits, that fixed-width decimal string is read as the zero-based winning ticket. The winning slip is the paid slip whose inclusive ticket range contains that number.
import { createHash } from "node:crypto";
const roundNumber = Number(process.argv[2] ?? "24");
const blockHash = (process.argv[3] ?? "374fb91afe0e6edb3c54c655bcba9803fa9e5022cfb3b8f2062863c9de28a55a")
.trim()
.toLowerCase();
const ticketDigits = 8;
const hashesPerDigit = 100000;
const algorithm = "hookedin:v12-bitcoin-hash-draw-static-ticket-digits";
if (!Number.isInteger(roundNumber) || roundNumber < 1) {
throw new Error("roundNumber must be a positive integer");
}
if (!/^[0-9a-f]{64}$/.test(blockHash)) {
throw new Error("block hash must be a 64-character hex string");
}
let state = Buffer.from(blockHash, "hex");
let drawDigits = "";
for (let digitIndex = 0; digitIndex < ticketDigits; digitIndex += 1) {
for (let hashIndex = 0; hashIndex < hashesPerDigit; hashIndex += 1) {
state = createHash("sha256").update(state).digest();
}
drawDigits = decimalDigitFromDigest(state) + drawDigits;
}
console.log(JSON.stringify({
algorithm,
roundNumber,
blockHash,
ticketDigits,
hashesPerDigit,
drawDigits,
winningTicket: BigInt(drawDigits).toString(),
finalSha256: Buffer.from(state).toString("hex")
}, null, 2));
function decimalDigitFromDigest(bytes) {
let remainder = 0;
for (const byte of bytes) {
remainder = (remainder * 256 + byte) % 10;
}
return String(remainder);
}