UNPKG

@bsv/overlay

Version:
92 lines 3.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BASM_ZERO_HASH = void 0; exports.computeBasmRoot = computeBasmRoot; exports.computeTac = computeTac; exports.extractMerkleProofMetadata = extractMerkleProofMetadata; const node_crypto_1 = require("node:crypto"); exports.BASM_ZERO_HASH = '0000000000000000000000000000000000000000000000000000000000000000'; function sha256d(buffer) { const first = (0, node_crypto_1.createHash)('sha256').update(buffer).digest(); return (0, node_crypto_1.createHash)('sha256').update(first).digest(); } function assertHashHex(hash, label) { if (!/^[0-9a-fA-F]{64}$/.test(hash)) { throw new Error(`${label} must be 32 bytes of hex`); } } function displayHexToInternal(hash) { assertHashHex(hash, 'hash'); return Buffer.from(hash, 'hex').reverse(); } function internalToDisplayHex(hash) { return Buffer.from(hash).reverse().toString('hex'); } function normalizeAdmittedTxids(admitted) { return admitted .map((item, originalIndex) => { if (typeof item === 'string') { return { txid: item, blockIndex: originalIndex }; } return item; }) .sort((a, b) => a.blockIndex - b.blockIndex) .map(item => item.txid.toLowerCase()); } /** * Computes a BRC-136 BASM root from admitted topic txids. * * The API accepts normal display-order txid hex because that is what the BSV * TypeScript stack exposes at its public boundaries. Hashing is performed on * internal byte order as required by the BRC, and the returned root is display * order for JSON/wire compatibility. */ function computeBasmRoot(admitted) { const txids = normalizeAdmittedTxids(admitted); if (txids.length === 0) { return exports.BASM_ZERO_HASH; } let layer = txids.map(txid => displayHexToInternal(txid)); if (layer.length === 1) { return internalToDisplayHex(layer[0]); } while (layer.length > 1) { const next = []; for (let i = 0; i < layer.length; i += 2) { const left = layer[i]; const right = i + 1 < layer.length ? layer[i + 1] : left; next.push(sha256d(Buffer.concat([left, right]))); } layer = next; } return internalToDisplayHex(layer[0]); } /** * Computes the BRC-136 cumulative Topic Anchor Chain hash: * SHA256d(prevTac || blockHash || basmRoot), with all inputs reversed to * internal byte order before hashing and the output returned as display hex. */ function computeTac(prevTac, blockHash, basmRoot) { const input = Buffer.concat([ displayHexToInternal(prevTac.toLowerCase()), displayHexToInternal(blockHash.toLowerCase()), displayHexToInternal(basmRoot.toLowerCase()) ]); return internalToDisplayHex(sha256d(input)); } function extractMerkleProofMetadata(txid, proof) { var _a; if (proof === undefined) { return undefined; } const leaf = (_a = proof.path[0]) === null || _a === void 0 ? void 0 : _a.find(candidate => candidate.hash === txid); if (leaf === undefined) { return undefined; } return { blockHeight: proof.blockHeight, blockIndex: leaf.offset, merkleRoot: proof.computeRoot(txid) }; } //# sourceMappingURL=BASM.js.map