"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MerkleTree = exports.pedersenLeftRight = void 0; // @ts-ignore const bb_js_1 = require("@aztec/bb.js"); // @ts-ignore -- no types async function pedersenLeftRight(barretenberg, left, right) { let leftBuffer = bb_js_1.Fr.fromBufferReduce(Buffer.from(left.slice(2), 'hex')); let rightBuffer = bb_js_1.Fr.fromBufferReduce(Buffer.from(right.slice(2), 'hex')); let hashRes = await barretenberg.pedersenHashWithHashIndex([leftBuffer, rightBuffer], 0); return hashRes.toString(); } exports.pedersenLeftRight = pedersenLeftRight; class MerkleTree { constructor(levels, barretenberg, defaultLeaves = [], hashLeftRight = pedersenLeftRight) { this.zeroValue = "0x016a430aa58685aba1311244a973a3bc358859da86784be51094368e8fb6f720"; // sha256("Momiji") % Fr.MODULUS this.getAllLeaves = () => Array.from(this.storage.values()).slice(0, 2 ** this.levels); this.levels = levels; this.hashLeftRight = hashLeftRight; this.storage = new Map(); this.zeros = []; this.totalLeaves = 0; this.barretenberg = barretenberg; this.defaultLeaves = defaultLeaves; } async init() { // build zeros depends on tree levels let currentZero = this.zeroValue; this.zeros.push(currentZero); for (let i = 0; i < this.levels; i++) { currentZero = await this.hashLeftRight(this.barretenberg, currentZero, currentZero); this.zeros.push(currentZero); } if (this.defaultLeaves.length > 0) { this.totalLeaves = this.defaultLeaves.length; // store leaves with key value pair let level = 0; this.defaultLeaves.forEach((leaf, index) => { this.storage.set(MerkleTree.indexToKey(level, index), leaf); }); // build tree with initial leaves level++; let numberOfNodesInLevel = Math.ceil(this.totalLeaves / 2); for (level; level <= this.levels; level++) { for (let i = 0; i < numberOfNodesInLevel; i++) { const leftKey = MerkleTree.indexToKey(level - 1, 2 * i); const rightKey = MerkleTree.indexToKey(level - 1, 2 * i + 1); const left = this.storage.get(leftKey); const right = this.storage.get(rightKey) || this.zeros[level - 1]; if (!left) throw new Error("leftKey not found"); const node = await this.hashLeftRight(this.barretenberg, left, right); this.storage.set(MerkleTree.indexToKey(level, i), node); } numberOfNodesInLevel = Math.ceil(numberOfNodesInLevel / 2); } } } static indexToKey(level, index) { return `${level}-${index}`; } getIndex(leaf) { for (const [key, value] of this.storage) { if (value === leaf) { return Number(key.split("-")[1]); } } return -1; } root() { return this.storage.get(MerkleTree.indexToKey(this.levels, 0)) || this.zeros[this.levels]; } async proof(indexOfLeaf) { let pathElements = []; let pathIndices = []; const leaf = this.storage.get(MerkleTree.indexToKey(0, indexOfLeaf)); if (!leaf) throw new Error("leaf not found"); // store sibling into pathElements and target's indices into pathIndices const handleIndex = (level, currentIndex, siblingIndex) => { const siblingValue = this.storage.get(MerkleTree.indexToKey(level, siblingIndex)) || this.zeros[level]; pathElements.push(siblingValue); pathIndices.push(currentIndex % 2); }; await this.traverse(indexOfLeaf, handleIndex); return { root: this.root(), pathElements, pathIndices, leaf: leaf, }; } async insert(leaf) { const index = this.totalLeaves; await this.update(index, leaf, true); this.totalLeaves++; } async update(index, newLeaf, isInsert = false) { if (!isInsert && index >= this.totalLeaves) { throw Error("Use insert method for new elements."); } else if (isInsert && index < this.totalLeaves) { throw Error("Use update method for existing elements."); } let keyValueToStore = []; let currentElement = newLeaf; const handleIndex = async (level, currentIndex, siblingIndex) => { const siblingElement = this.storage.get(MerkleTree.indexToKey(level, siblingIndex)) || this.zeros[level]; let left; let right; if (currentIndex % 2 === 0) { left = currentElement; right = siblingElement; } else { left = siblingElement; right = currentElement; } keyValueToStore.push({ key: MerkleTree.indexToKey(level, currentIndex), value: currentElement, }); currentElement = await this.hashLeftRight(this.barretenberg, left, right); }; await this.traverse(index, handleIndex); // push root to the end keyValueToStore.push({ key: MerkleTree.indexToKey(this.levels, 0), value: currentElement, }); keyValueToStore.forEach((o) => { this.storage.set(o.key, o.value); }); } // traverse from leaf to root with handler for target node and sibling node async traverse(indexOfLeaf, handler) { let currentIndex = indexOfLeaf; for (let i = 0; i < this.levels; i++) { let siblingIndex; if (currentIndex % 2 === 0) { siblingIndex = currentIndex + 1; } else { siblingIndex = currentIndex - 1; } await handler(i, currentIndex, siblingIndex); currentIndex = Math.floor(currentIndex / 2); } } } exports.MerkleTree = MerkleTree;