@bsv/overlay
Version:
BSV Blockchain Overlay Services Engine
92 lines • 3.31 kB
JavaScript
;
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