UNPKG

@chainsafe/persistent-merkle-tree

Version:

Merkle tree implemented as a persistent datastructure

148 lines 4.22 kB
export function bitIndexBigInt(v) { return v.toString(2).length - 1; } export function toGindex(depth, index) { const anchor = BigInt(1) << BigInt(depth); if (index >= anchor) { throw new Error(`index ${index} too large for depth ${depth}`); } return anchor | index; } export function toGindexBitstring(depth, index) { const str = index ? Number(index).toString(2) : ""; if (str.length > depth) { throw new Error("index too large for depth"); } return `1${str.padStart(depth, "0")}`; } export function convertGindexToBitstring(gindex) { if (typeof gindex === "string") { if (gindex.length === 0) { throw new Error(ERR_INVALID_GINDEX); } return gindex; } if (gindex < 1) { throw new Error(ERR_INVALID_GINDEX); } return gindex.toString(2); } // Get the depth (root starting at 0) necessary to cover a subtree of `count` elements. // (in out): (0 0), (1 0), (2 1), (3 2), (4 2), (5 3), (6 3), (7 3), (8 3), (9 4) export function countToDepth(count) { if (count <= 1) { return 0; } return (count - BigInt(1)).toString(2).length; } /** * Iterate through Gindexes at a certain depth */ export function iterateAtDepth(depth, startIndex, count) { const anchor = BigInt(1) << BigInt(depth); if (startIndex + count > anchor) { throw new Error("Too large for depth"); } let i = toGindex(depth, startIndex); const last = i + count; return { [Symbol.iterator]() { return { next() { if (i < last) { const value = i; i++; return { done: false, value }; } return { done: true, value: undefined }; }, }; }, }; } /** * Return Gindexes at a certain depth */ export function getGindicesAtDepth(depth, startIndex, count) { const anchor = BigInt(1) << BigInt(depth); if (startIndex + count > anchor) { throw new Error("Too large for depth"); } let gindex = toGindex(depth, BigInt(startIndex)); const gindices = []; for (let i = 0; i < count; i++) { gindices.push(gindex++); } return gindices; } const ERR_INVALID_GINDEX = "Invalid gindex"; export function gindexIterator(gindex) { let bitstring; if (typeof gindex === "string") { if (!gindex.length) { throw new Error(ERR_INVALID_GINDEX); } bitstring = gindex; } else { if (gindex < 1) { throw new Error(ERR_INVALID_GINDEX); } bitstring = gindex.toString(2); } let i = 1; const next = () => { if (i === bitstring.length) { return { done: true, value: undefined }; } const bit = Number(bitstring[i]); i++; return { done: false, value: bit }; }; return { [Symbol.iterator]() { return { next }; }, remainingBitLength() { return bitstring.length - i; }, }; } export function getGindexBits(gindex) { let bitstring; if (typeof gindex === "string") { if (!gindex.length) { throw new Error(ERR_INVALID_GINDEX); } bitstring = gindex; } else { if (gindex < 1) { throw new Error(ERR_INVALID_GINDEX); } bitstring = gindex.toString(2); } const bits = []; for (let i = 1; i < bitstring.length; i++) { bits.push(Number(bitstring[i])); } return bits; } /** * Concatenate Generalized Indices * Given generalized indices i1 for A -> B, i2 for B -> C .... i_n for Y -> Z, returns * the generalized index for A -> Z. */ export function concatGindices(gindices) { return BigInt(gindices.reduce((acc, gindex) => acc + gindex.toString(2).slice(1), "0b1")); } export function gindexSibling(gindex) { return gindex ^ BigInt(1); } export function gindexParent(gindex) { return gindex / BigInt(2); } export function gindexChild(gindex, rightChild) { return gindex * BigInt(2) + BigInt(rightChild); } //# sourceMappingURL=gindex.js.map