diff --git a/lib/FixedMerkleTree.js b/lib/FixedMerkleTree.js index 0f12a93..f734768 100644 --- a/lib/FixedMerkleTree.js +++ b/lib/FixedMerkleTree.js @@ -95,7 +95,10 @@ class MerkleTree extends BaseTree_1.BaseTree { * otherwise the tree state will be invalid */ static deserialize(data, hashFunction) { - return new MerkleTree(data.levels, data._layers[0], { hashFunction, zeroElement: data._zeros[0] }); + const instance = Object.assign(Object.create(this.prototype), data); + instance._hashFn = hashFunction || simpleHash_1.default; + instance.zeroElement = instance._zeros[0]; + return instance; } toString() { return JSON.stringify(this.serialize()); diff --git a/lib/PartialMerkleTree.js b/lib/PartialMerkleTree.js index bc04346..4d03d6a 100644 --- a/lib/PartialMerkleTree.js +++ b/lib/PartialMerkleTree.js @@ -91,14 +91,15 @@ class PartialMerkleTree extends BaseTree_1.BaseTree { pathIndices[level] = elIndex % 2; const leafIndex = elIndex ^ 1; if (leafIndex < this._layers[level].length) { - const [proofPos, proofEl] = this._proofMap.get(level); - pathElements[level] = (_a = this._layers[level][leafIndex]) !== null && _a !== void 0 ? _a : (proofPos === leafIndex ? proofEl : null); + pathElements[level] = this._layers[level][leafIndex]; pathPositions[level] = leafIndex; } else { pathElements[level] = this._zeros[level]; pathPositions[level] = 0; } + const [proofPos, proofEl] = this._proofMap.get(level); + pathElements[level] = (_a = pathElements[level]) !== null && _a !== void 0 ? _a : (proofPos === leafIndex ? proofEl : this._zeros[level]); elIndex >>= 1; } return { @@ -127,27 +128,22 @@ class PartialMerkleTree extends BaseTree_1.BaseTree { this._buildTree(); } serialize() { - const leaves = this.layers[0].slice(this._edgeLeaf.index); return { _edgeLeafProof: this._edgeLeafProof, _edgeLeaf: this._edgeLeaf, - _edgeElementsCount: this._layers[0].length, - levels: this.levels, - leaves, + _layers: this._layers, _zeros: this._zeros, + levels: this.levels, }; } static deserialize(data, hashFunction) { - const edge = { - edgePath: data._edgeLeafProof, - edgeElement: data._edgeLeaf.data, - edgeIndex: data._edgeLeaf.index, - edgeElementsCount: data._edgeElementsCount, - }; - return new PartialMerkleTree(data.levels, edge, data.leaves, { - hashFunction, - zeroElement: data._zeros[0], - }); + const instance = Object.assign(Object.create(this.prototype), data); + instance._hashFn = hashFunction || simpleHash_1.default; + instance._initialRoot = data._edgeLeafProof.pathRoot; + instance.zeroElement = instance._zeros[0]; + instance._leavesAfterEdge = instance._layers[0].slice(data._edgeLeaf.index); + instance._createProofMap(); + return instance; } toString() { return JSON.stringify(this.serialize()); diff --git a/lib/index.d.ts b/lib/index.d.ts index 7c12bf1..b1c2abc 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -18,8 +18,7 @@ export declare type SerializedTreeState = { }; export declare type SerializedPartialTreeState = { levels: number; - leaves: Element[]; - _edgeElementsCount: number; + _layers: Element[][]; _zeros: Array; _edgeLeafProof: ProofPath; _edgeLeaf: LeafWithIndex; diff --git a/package-lock.json b/package-lock.json index 82f312d..b2da3d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "fixed-merkle-tree", - "version": "0.7.1", + "version": "0.7.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3b2eda7..ebc00dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fixed-merkle-tree", - "version": "0.7.2", + "version": "0.7.3", "description": "Fixed depth merkle tree implementation with sequential inserts", "repository": "https://github.com/tornadocash/fixed-merkle-tree.git", "main": "lib/index.js", diff --git a/src/FixedMerkleTree.ts b/src/FixedMerkleTree.ts index 4177531..4f1cfa4 100644 --- a/src/FixedMerkleTree.ts +++ b/src/FixedMerkleTree.ts @@ -106,7 +106,10 @@ export default class MerkleTree extends BaseTree { * otherwise the tree state will be invalid */ static deserialize(data: SerializedTreeState, hashFunction?: HashFunction): MerkleTree { - return new MerkleTree(data.levels, data._layers[0], { hashFunction, zeroElement: data._zeros[0] }) + const instance: MerkleTree = Object.assign(Object.create(this.prototype), data) + instance._hashFn = hashFunction || defaultHash + instance.zeroElement = instance._zeros[0] + return instance } toString() { diff --git a/src/PartialMerkleTree.ts b/src/PartialMerkleTree.ts index 074ab90..3fdc339 100644 --- a/src/PartialMerkleTree.ts +++ b/src/PartialMerkleTree.ts @@ -113,13 +113,14 @@ export class PartialMerkleTree extends BaseTree { pathIndices[level] = elIndex % 2 const leafIndex = elIndex ^ 1 if (leafIndex < this._layers[level].length) { - const [proofPos, proofEl] = this._proofMap.get(level) - pathElements[level] = this._layers[level][leafIndex] ?? (proofPos === leafIndex ? proofEl : null) + pathElements[level] = this._layers[level][leafIndex] pathPositions[level] = leafIndex } else { pathElements[level] = this._zeros[level] pathPositions[level] = 0 } + const [proofPos, proofEl] = this._proofMap.get(level) + pathElements[level] = pathElements[level] ?? (proofPos === leafIndex ? proofEl : this._zeros[level]) elIndex >>= 1 } return { @@ -152,28 +153,23 @@ export class PartialMerkleTree extends BaseTree { } serialize(): SerializedPartialTreeState { - const leaves = this.layers[0].slice(this._edgeLeaf.index) return { _edgeLeafProof: this._edgeLeafProof, _edgeLeaf: this._edgeLeaf, - _edgeElementsCount: this._layers[0].length, - levels: this.levels, - leaves, + _layers: this._layers, _zeros: this._zeros, + levels: this.levels, } } static deserialize(data: SerializedPartialTreeState, hashFunction?: HashFunction): PartialMerkleTree { - const edge: TreeEdge = { - edgePath: data._edgeLeafProof, - edgeElement: data._edgeLeaf.data, - edgeIndex: data._edgeLeaf.index, - edgeElementsCount: data._edgeElementsCount, - } - return new PartialMerkleTree(data.levels, edge, data.leaves, { - hashFunction, - zeroElement: data._zeros[0], - }) + const instance: PartialMerkleTree = Object.assign(Object.create(this.prototype), data) + instance._hashFn = hashFunction || defaultHash + instance._initialRoot = data._edgeLeafProof.pathRoot + instance.zeroElement = instance._zeros[0] + instance._leavesAfterEdge = instance._layers[0].slice(data._edgeLeaf.index) + instance._createProofMap() + return instance } toString() { diff --git a/src/index.ts b/src/index.ts index 21c799a..0b33901 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,8 +22,7 @@ export type SerializedTreeState = { export type SerializedPartialTreeState = { levels: number - leaves: Element[] - _edgeElementsCount: number + _layers: Element[][] _zeros: Array _edgeLeafProof: ProofPath _edgeLeaf: LeafWithIndex diff --git a/test/partialMerkleTree.spec.ts b/test/partialMerkleTree.spec.ts index a625ae4..2d8e892 100644 --- a/test/partialMerkleTree.spec.ts +++ b/test/partialMerkleTree.spec.ts @@ -276,7 +276,7 @@ describe('PartialMerkleTree', () => { partialTree.insert(10) dst.insert(10) - + assert.deepStrictEqual(partialTree.path(6), dst.path(6)) should().equal(partialTree.root, dst.root) }) }) @@ -285,12 +285,12 @@ describe('PartialMerkleTree', () => { const { partialTree } = getTestTrees(5, [1, 2, 3, 4, 5, 6, 7, 8, 9], 5) const str = partialTree.toString() const dst = PartialMerkleTree.deserialize(JSON.parse(str)) - should().equal(partialTree.root, dst.root) - + assert.deepStrictEqual(partialTree.path(6), dst.path(6)) partialTree.insert(10) dst.insert(10) - should().equal(partialTree.root, dst.root) + assert.deepStrictEqual(partialTree.path(6), dst.path(6)) + assert.deepStrictEqual(partialTree.root, dst.root) }) }) })