Stretched block hash
Hookedin turns the Bitcoin closing block hash into a fixed 32-character L/H path. The path is generated progressively by repeatedly hashing the previous SHA-256 digest and reading one bit after each stretch interval.
Reference Algorithm
state_0 = bytes(blockHash)
for each of 32 decisions:
repeat hashesPerBisection times:
state = SHA256(state)
append L if the first state bit is 0, otherwise append HThe SHA-256 input is always the previous 32-byte digest. It is not the hex text of that digest, and it is not mixed with the round number, ticket count, or algorithm ID.
Reference JavaScript
async function stretchedBlockHash({
blockHash,
hashesPerBisection
}) {
let state = hexToBytes(blockHash.toLowerCase());
let stretchedHash = "";
for (let decision = 0; decision < 32; decision += 1) {
for (let index = 0; index < hashesPerBisection; index += 1) {
state = await sha256(state);
}
stretchedHash += (state[0] & 0x80) === 0 ? "L" : "H";
}
return {
initialSha256: blockHash.toLowerCase(),
finalSha256: bytesToHex(state),
stretchedHash
};
}
async function sha256(bytes) {
const input = new Uint8Array(bytes);
const digest = await crypto.subtle.digest("SHA-256", input.buffer);
return new Uint8Array(digest);
}
function hexToBytes(hex) {
if (!/^[0-9a-f]{64}$/.test(hex)) {
throw new Error("blockHash must be 64 lowercase hex characters");
}
const bytes = new Uint8Array(hex.length / 2);
for (let index = 0; index < bytes.length; index += 1) {
bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
}
return bytes;
}
function bytesToHex(bytes) {
return Array.from(bytes, (byte) =>
byte.toString(16).padStart(2, "0")
).join("");
}Online Calculator
Browser onlyWinning ticket
Pending
Algorithm
Pending
Stretched hash
Pending
Seed block hash
Pending
Initial SHA-256
Pending
Final SHA-256
Pending
Decisions
Pending