merkle-t
Version:
Merkle Tree with Poseidon Hash in TypeScript
85 lines • 3.08 kB
JavaScript
;
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