UNPKG

merkle-t

Version:

Merkle Tree with Poseidon Hash in TypeScript

85 lines 3.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MerkleTree = void 0; const poseidon_h_1 = require("poseidon-h"); const utils_1 = require("./utils"); class MerkleTree { constructor(leaves, inputsLength, options) { const log2 = Math.ceil(Math.log2(leaves.length)); if (options?.depth && options.depth < log2) { throw new Error("Depth is less than the number of leaves"); } this.depth = options?.depth ?? log2; this.orderedLeaves = leaves.map((leaf, index) => ({ index, leaf, })); this.zeroHash = (0, poseidon_h_1.poseidon)(Array.from({ length: inputsLength }, () => BigInt(0))); } root() { this.padLeaves(); let root = this.getLeaves(); for (let i = 0; i < this.depth; i++) { root = (0, utils_1.chunk)(root, 2).map(([a, b]) => (0, poseidon_h_1.poseidon)([a, b])); } return root[0]; } prove(merkleLeaf) { this.padLeaves(); const merklePath = this.merklePath(merkleLeaf); let leaves = this.getLeaves(); const merkleWitness = []; for (let i = this.depth; i > 0; i--) { const position = (0, utils_1.toDecimal)(merklePath.slice(0, i)); const sibilingPosition = position + (merklePath[i - 1] === "1" ? -1 : 1); merkleWitness.push(leaves[sibilingPosition]); leaves = (0, utils_1.chunk)(leaves, 2).map(poseidon_h_1.poseidon); } merklePath.reverse(); return { merklePath, merkleWitness, merkleLeaf, merkleRoot: this.root(), }; } static verify(merkleRoot, merkleLeaf, merklePath, merkleWitness) { return this.verifyProof({ merklePath, merkleWitness, merkleLeaf, merkleRoot, }); } static verifyProof(proof) { const { merklePath, merkleWitness, merkleLeaf, merkleRoot } = proof; let current = merkleLeaf; for (const [binary, sibling] of (0, utils_1.zip)(merklePath, merkleWitness)) { current = (0, poseidon_h_1.poseidon)(binary === "0" ? [current, sibling] : [sibling, current]); } return current === merkleRoot; } getLeaves() { this.orderedLeaves.sort((a, b) => a.index - b.index); return this.orderedLeaves.map(({ leaf }) => leaf); } padLeaves() { const diff = Math.pow(2, this.depth) - this.orderedLeaves.length; for (let i = 0; i < diff; i++) { this.orderedLeaves.push({ index: this.orderedLeaves.length, leaf: this.zeroHash, }); } } merklePath(leaf) { const result = this.orderedLeaves.find(({ leaf: l }) => l === leaf); if (!result) { throw new Error("Leaf not found"); } const { index } = result; return (0, utils_1.toBinary)(index, this.depth); } } exports.MerkleTree = MerkleTree; //# sourceMappingURL=tree.js.map