mirror of
https://github.com/tornadocash/fixed-merkle-tree.git
synced 2025-02-14 21:10:44 +01:00
Merge fb8974a0a07077a466ebc2292cc19820bfc23ac2 into 3da67b29ed419525886b3b83f301d2f22a43bdca
This commit is contained in:
commit
ae3d778df3
36
lib/BaseTree.d.ts
vendored
36
lib/BaseTree.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { Element, HashFunction, ProofPath } from './';
|
||||
import { Element, HashFunction, ProofPath, MultiProofPath } from './';
|
||||
export declare class BaseTree {
|
||||
levels: number;
|
||||
protected _hashFn: HashFunction<Element>;
|
||||
@ -37,6 +37,40 @@ export declare class BaseTree {
|
||||
* @returns {{pathElements: Object[], pathIndex: number[]}} An object containing adjacent elements and left-right index
|
||||
*/
|
||||
path(index: number): ProofPath;
|
||||
/**
|
||||
* Return the indices for the next layer in the multiPath calculation
|
||||
* @param {number} indices A list of leaf indices
|
||||
* @returns {number[]} the new list of indices
|
||||
*/
|
||||
static nextLayerMultiPathIndices(indices: number[]): number[];
|
||||
/**
|
||||
* Get merkle path to a list of leaves
|
||||
* @param {number} indices A list of leaf indices to generate path for
|
||||
* @returns {{pathElements: Element[], leafIndices: number[]}} An object containing adjacent elements and leaves indices
|
||||
*/
|
||||
multiPath(indices: number[]): MultiProofPath;
|
||||
/**
|
||||
* Verifies a merkle proof
|
||||
* @param {Element} root the root of the merkle tree
|
||||
* @param {number} levels the number of levels of the tree
|
||||
* @param {HashFunction<Element>} hashFn hash function
|
||||
* @param {Element} leaf the leaf to be verified
|
||||
* @param {Element[]} pathElements adjacent path elements
|
||||
* @param {number[]} pathIndices left-right indices
|
||||
* @returns {Boolean} whether the proof is valid for the given root
|
||||
*/
|
||||
static verifyProof(root: Element, levels: number, hashFn: HashFunction<Element>, leaf: Element, pathElements: Element[], pathIndices: number[]): boolean;
|
||||
/**
|
||||
* Verifies a merkle multiproof
|
||||
* @param {Element} root the root of the merkle tree
|
||||
* @param {number} levels the number of levels of the tree
|
||||
* @param {HashFunction<Element>} hashFn hash function
|
||||
* @param {Element[]} leaves the list of leaves to be verified
|
||||
* @param {Element[]} pathElements multiproof path elements
|
||||
* @param {number[]} leafIndices multiproof leaf indices
|
||||
* @returns {Boolean} whether the proof is valid for the given root
|
||||
*/
|
||||
static verifyMultiProof(root: Element, levels: number, hashFn: HashFunction<Element>, leaves: Element[], pathElements: Element[], leafIndices: number[]): boolean;
|
||||
protected _buildZeros(): void;
|
||||
protected _processNodes(nodes: Element[], layerIndex: number): any[];
|
||||
protected _processUpdate(index: number): void;
|
||||
|
120
lib/BaseTree.js
120
lib/BaseTree.js
@ -117,6 +117,126 @@ class BaseTree {
|
||||
pathRoot: this.root,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Return the indices for the next layer in the multiPath calculation
|
||||
* @param {number} indices A list of leaf indices
|
||||
* @returns {number[]} the new list of indices
|
||||
*/
|
||||
static nextLayerMultiPathIndices(indices) {
|
||||
const nextIndices = new Set();
|
||||
for (let i = 0; i < indices.length; i++) {
|
||||
nextIndices.add(indices[i] >> 1);
|
||||
}
|
||||
return [...nextIndices];
|
||||
}
|
||||
/**
|
||||
* Get merkle path to a list of leaves
|
||||
* @param {number} indices A list of leaf indices to generate path for
|
||||
* @returns {{pathElements: Element[], leafIndices: number[]}} An object containing adjacent elements and leaves indices
|
||||
*/
|
||||
multiPath(indices) {
|
||||
let pathElements = [];
|
||||
let layerIndices = indices;
|
||||
for (let level = 0; level < this.levels; level++) {
|
||||
// find whether there is a neighbor idx that is not in layerIndices
|
||||
const proofElements = layerIndices.reduce((elements, idx) => {
|
||||
const leafIndex = idx ^ 1;
|
||||
if (!layerIndices.includes(leafIndex)) {
|
||||
if (leafIndex < this._layers[level].length) {
|
||||
elements.push(this._layers[level][leafIndex]);
|
||||
}
|
||||
else {
|
||||
elements.push(this._zeros[level]);
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}, []);
|
||||
pathElements = pathElements.concat(proofElements);
|
||||
layerIndices = BaseTree.nextLayerMultiPathIndices(layerIndices);
|
||||
}
|
||||
return {
|
||||
pathElements,
|
||||
leafIndices: indices,
|
||||
pathRoot: this.root,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Verifies a merkle proof
|
||||
* @param {Element} root the root of the merkle tree
|
||||
* @param {number} levels the number of levels of the tree
|
||||
* @param {HashFunction<Element>} hashFn hash function
|
||||
* @param {Element} leaf the leaf to be verified
|
||||
* @param {Element[]} pathElements adjacent path elements
|
||||
* @param {number[]} pathIndices left-right indices
|
||||
* @returns {Boolean} whether the proof is valid for the given root
|
||||
*/
|
||||
static verifyProof(root, levels, hashFn, leaf, pathElements, pathIndices) {
|
||||
const layerProofs = [];
|
||||
for (let level = 0; level < levels; level++) {
|
||||
let elem = level == 0 ? leaf : layerProofs[level - 1];
|
||||
if (pathIndices[level] == 0) {
|
||||
layerProofs[level] = hashFn(elem, pathElements[level]);
|
||||
}
|
||||
else {
|
||||
layerProofs[level] = hashFn(pathElements[level], elem);
|
||||
}
|
||||
}
|
||||
return root === layerProofs[levels - 1];
|
||||
}
|
||||
/**
|
||||
* Verifies a merkle multiproof
|
||||
* @param {Element} root the root of the merkle tree
|
||||
* @param {number} levels the number of levels of the tree
|
||||
* @param {HashFunction<Element>} hashFn hash function
|
||||
* @param {Element[]} leaves the list of leaves to be verified
|
||||
* @param {Element[]} pathElements multiproof path elements
|
||||
* @param {number[]} leafIndices multiproof leaf indices
|
||||
* @returns {Boolean} whether the proof is valid for the given root
|
||||
*/
|
||||
static verifyMultiProof(root, levels, hashFn, leaves, pathElements, leafIndices) {
|
||||
let layerElements = leaves;
|
||||
let layerIndices = leafIndices;
|
||||
const proofElements = pathElements;
|
||||
const layerProofs = [];
|
||||
for (let level = 0; level < levels; level++) {
|
||||
for (let i = 0; i < layerIndices.length; i++) {
|
||||
let layerHash;
|
||||
const elIndex = layerIndices[i];
|
||||
const leafIndex = elIndex ^ 1;
|
||||
if (layerIndices.includes(leafIndex)) {
|
||||
if (elIndex % 2 === 0) {
|
||||
layerHash = hashFn(layerElements[0], layerElements[1]);
|
||||
}
|
||||
else {
|
||||
layerHash = hashFn(layerElements[1], layerElements[0]);
|
||||
}
|
||||
layerElements.splice(0, 2); // remove 1st and 2nd element
|
||||
i++; // skip next idx
|
||||
layerProofs.push(layerHash);
|
||||
}
|
||||
else {
|
||||
if (elIndex % 2 === 0) {
|
||||
layerHash = hashFn(layerElements[0], proofElements[0]);
|
||||
}
|
||||
else {
|
||||
layerHash = hashFn(proofElements[0], layerElements[0]);
|
||||
}
|
||||
layerElements.shift(); // remove 1st element
|
||||
layerProofs.push(layerHash);
|
||||
if (proofElements.shift() === undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
layerIndices = BaseTree.nextLayerMultiPathIndices(layerIndices);
|
||||
layerElements = layerProofs;
|
||||
if (proofElements.length == 0 && layerElements.length == 2) {
|
||||
layerProofs[0] = hashFn(layerProofs[0], layerProofs[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return root === layerProofs[0];
|
||||
}
|
||||
_buildZeros() {
|
||||
this._zeros = [this.zeroElement];
|
||||
for (let i = 1; i <= this.levels; i++) {
|
||||
|
3
lib/FixedMerkleTree.d.ts
vendored
3
lib/FixedMerkleTree.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { Element, HashFunction, MerkleTreeOptions, ProofPath, SerializedTreeState, TreeEdge, TreeSlice } from './';
|
||||
import { Element, HashFunction, MerkleTreeOptions, ProofPath, MultiProofPath, SerializedTreeState, TreeEdge, TreeSlice } from './';
|
||||
import { BaseTree } from './BaseTree';
|
||||
export default class MerkleTree extends BaseTree {
|
||||
constructor(levels: number, elements?: Element[], { hashFunction, zeroElement, }?: MerkleTreeOptions);
|
||||
@ -10,6 +10,7 @@ export default class MerkleTree extends BaseTree {
|
||||
bulkInsert(elements: Element[]): void;
|
||||
indexOf(element: Element, comparator?: <T>(arg0: T, arg1: T) => boolean): number;
|
||||
proof(element: Element): ProofPath;
|
||||
multiProof(elements: Element[]): MultiProofPath;
|
||||
getTreeEdge(edgeIndex: number): TreeEdge;
|
||||
/**
|
||||
* 🪓
|
||||
|
@ -59,6 +59,13 @@ class MerkleTree extends BaseTree_1.BaseTree {
|
||||
const index = this.indexOf(element);
|
||||
return this.path(index);
|
||||
}
|
||||
multiProof(elements) {
|
||||
const indexes = [];
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
indexes.push(this.indexOf(elements[i]));
|
||||
}
|
||||
return this.multiPath(indexes);
|
||||
}
|
||||
getTreeEdge(edgeIndex) {
|
||||
const edgeElement = this._layers[0][edgeIndex];
|
||||
if (edgeElement === undefined) {
|
||||
|
5
lib/index.d.ts
vendored
5
lib/index.d.ts
vendored
@ -29,6 +29,11 @@ export declare type ProofPath = {
|
||||
pathPositions: number[];
|
||||
pathRoot: Element;
|
||||
};
|
||||
export declare type MultiProofPath = {
|
||||
pathElements: Element[];
|
||||
leafIndices: number[];
|
||||
pathRoot: Element;
|
||||
};
|
||||
export declare type TreeEdge = {
|
||||
edgeElement: Element;
|
||||
edgePath: ProofPath;
|
||||
|
5083
package-lock.json
generated
5083
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -26,15 +26,15 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/expect": "^24.3.0",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@types/mocha": "^9.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.12.0",
|
||||
"@typescript-eslint/parser": "^5.12.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai": "^4.3.6",
|
||||
"eslint": "^8.9.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"mocha": "^9.2.2",
|
||||
"mocha": "^10.0.0",
|
||||
"nyc": "^15.1.0",
|
||||
"ts-mocha": "^9.0.2",
|
||||
"typescript": "^4.6.2"
|
||||
"ts-mocha": "^10.0.0",
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
}
|
||||
|
148
src/BaseTree.ts
148
src/BaseTree.ts
@ -1,4 +1,4 @@
|
||||
import { Element, HashFunction, ProofPath } from './'
|
||||
import { Element, HashFunction, ProofPath, MultiProofPath } from './'
|
||||
|
||||
export class BaseTree {
|
||||
levels: number
|
||||
@ -35,7 +35,12 @@ export class BaseTree {
|
||||
* @param fromIndex The index to start the search at. If the index is greater than or equal to the array's length, -1 is returned
|
||||
* @returns {number} Index if element is found, otherwise -1
|
||||
*/
|
||||
static indexOf(elements: Element[], element: Element, fromIndex?: number, comparator?: <T> (arg0: T, arg1: T) => boolean): number {
|
||||
static indexOf(
|
||||
elements: Element[],
|
||||
element: Element,
|
||||
fromIndex?: number,
|
||||
comparator?: <T>(arg0: T, arg1: T) => boolean,
|
||||
): number {
|
||||
if (comparator) {
|
||||
return elements.findIndex((el) => comparator<Element>(element, el))
|
||||
} else {
|
||||
@ -84,7 +89,6 @@ export class BaseTree {
|
||||
this.insert(elements[elements.length - 1])
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change an element in the tree
|
||||
* @param {number} index Index of element to change
|
||||
@ -110,7 +114,7 @@ export class BaseTree {
|
||||
let elIndex = +index
|
||||
const pathElements: Element[] = []
|
||||
const pathIndices: number[] = []
|
||||
const pathPositions: number [] = []
|
||||
const pathPositions: number[] = []
|
||||
for (let level = 0; level < this.levels; level++) {
|
||||
pathIndices[level] = elIndex % 2
|
||||
const leafIndex = elIndex ^ 1
|
||||
@ -131,6 +135,141 @@ export class BaseTree {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the indices for the next layer in the multiPath calculation
|
||||
* @param {number} indices A list of leaf indices
|
||||
* @returns {number[]} the new list of indices
|
||||
*/
|
||||
static nextLayerMultiPathIndices(indices: number[]): number[] {
|
||||
const nextIndices: Set<number> = new Set()
|
||||
for (let i = 0; i < indices.length; i++) {
|
||||
nextIndices.add(indices[i] >> 1)
|
||||
}
|
||||
return [...nextIndices]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get merkle path to a list of leaves
|
||||
* @param {number} indices A list of leaf indices to generate path for
|
||||
* @returns {{pathElements: Element[], leafIndices: number[]}} An object containing adjacent elements and leaves indices
|
||||
*/
|
||||
multiPath(indices: number[]): MultiProofPath {
|
||||
let pathElements: Element[] = []
|
||||
let layerIndices = indices
|
||||
for (let level = 0; level < this.levels; level++) {
|
||||
// find whether there is a neighbor idx that is not in layerIndices
|
||||
const proofElements = layerIndices.reduce((elements, idx) => {
|
||||
const leafIndex = idx ^ 1
|
||||
if (!layerIndices.includes(leafIndex)) {
|
||||
if (leafIndex < this._layers[level].length) {
|
||||
elements.push(this._layers[level][leafIndex])
|
||||
} else {
|
||||
elements.push(this._zeros[level])
|
||||
}
|
||||
}
|
||||
return elements
|
||||
}, [])
|
||||
pathElements = pathElements.concat(proofElements)
|
||||
layerIndices = BaseTree.nextLayerMultiPathIndices(layerIndices)
|
||||
}
|
||||
return {
|
||||
pathElements,
|
||||
leafIndices: indices,
|
||||
pathRoot: this.root,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a merkle proof
|
||||
* @param {Element} root the root of the merkle tree
|
||||
* @param {number} levels the number of levels of the tree
|
||||
* @param {HashFunction<Element>} hashFn hash function
|
||||
* @param {Element} leaf the leaf to be verified
|
||||
* @param {Element[]} pathElements adjacent path elements
|
||||
* @param {number[]} pathIndices left-right indices
|
||||
* @returns {Boolean} whether the proof is valid for the given root
|
||||
*/
|
||||
static verifyProof(
|
||||
root: Element,
|
||||
levels: number,
|
||||
hashFn: HashFunction<Element>,
|
||||
leaf: Element,
|
||||
pathElements: Element[],
|
||||
pathIndices: number[],
|
||||
): boolean {
|
||||
const layerProofs: Element[] = []
|
||||
|
||||
for (let level = 0; level < levels; level++) {
|
||||
let elem = level == 0 ? leaf : layerProofs[level - 1]
|
||||
if (pathIndices[level] == 0) {
|
||||
layerProofs[level] = hashFn(elem, pathElements[level])
|
||||
} else {
|
||||
layerProofs[level] = hashFn(pathElements[level], elem)
|
||||
}
|
||||
}
|
||||
return root === layerProofs[levels - 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a merkle multiproof
|
||||
* @param {Element} root the root of the merkle tree
|
||||
* @param {number} levels the number of levels of the tree
|
||||
* @param {HashFunction<Element>} hashFn hash function
|
||||
* @param {Element[]} leaves the list of leaves to be verified
|
||||
* @param {Element[]} pathElements multiproof path elements
|
||||
* @param {number[]} leafIndices multiproof leaf indices
|
||||
* @returns {Boolean} whether the proof is valid for the given root
|
||||
*/
|
||||
static verifyMultiProof(
|
||||
root: Element,
|
||||
levels: number,
|
||||
hashFn: HashFunction<Element>,
|
||||
leaves: Element[],
|
||||
pathElements: Element[],
|
||||
leafIndices: number[],
|
||||
): boolean {
|
||||
let layerElements: Element[] = leaves
|
||||
let layerIndices: number[] = leafIndices
|
||||
const proofElements: Element[] = pathElements
|
||||
const layerProofs: Element[] = []
|
||||
|
||||
for (let level = 0; level < levels; level++) {
|
||||
for (let i = 0; i < layerIndices.length; i++) {
|
||||
let layerHash: string
|
||||
const elIndex = layerIndices[i]
|
||||
const leafIndex = elIndex ^ 1
|
||||
if (layerIndices.includes(leafIndex)) {
|
||||
if (elIndex % 2 === 0) {
|
||||
layerHash = hashFn(layerElements[0], layerElements[1])
|
||||
} else {
|
||||
layerHash = hashFn(layerElements[1], layerElements[0])
|
||||
}
|
||||
layerElements.splice(0, 2) // remove 1st and 2nd element
|
||||
i++ // skip next idx
|
||||
layerProofs.push(layerHash)
|
||||
} else {
|
||||
if (elIndex % 2 === 0) {
|
||||
layerHash = hashFn(layerElements[0], proofElements[0])
|
||||
} else {
|
||||
layerHash = hashFn(proofElements[0], layerElements[0])
|
||||
}
|
||||
layerElements.shift() // remove 1st element
|
||||
layerProofs.push(layerHash)
|
||||
if (proofElements.shift() === undefined) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
layerIndices = BaseTree.nextLayerMultiPathIndices(layerIndices)
|
||||
layerElements = layerProofs
|
||||
if (proofElements.length == 0 && layerElements.length == 2) {
|
||||
layerProofs[0] = hashFn(layerProofs[0], layerProofs[1])
|
||||
break
|
||||
}
|
||||
}
|
||||
return root === layerProofs[0]
|
||||
}
|
||||
|
||||
protected _buildZeros() {
|
||||
this._zeros = [this.zeroElement]
|
||||
for (let i = 1; i <= this.levels; i++) {
|
||||
@ -165,5 +304,4 @@ export class BaseTree {
|
||||
this._layers[level][index] = this._hashFn(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Element, HashFunction, MerkleTreeOptions, ProofPath, SerializedTreeState, TreeEdge, TreeSlice } from './'
|
||||
import { Element, HashFunction, MerkleTreeOptions, ProofPath, MultiProofPath, SerializedTreeState, TreeEdge, TreeSlice } from './'
|
||||
import defaultHash from './simpleHash'
|
||||
import { BaseTree } from './BaseTree'
|
||||
|
||||
@ -29,7 +29,6 @@ export default class MerkleTree extends BaseTree {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert multiple elements into the tree.
|
||||
* @param {Array} elements Elements to insert
|
||||
@ -70,6 +69,14 @@ export default class MerkleTree extends BaseTree {
|
||||
return this.path(index)
|
||||
}
|
||||
|
||||
multiProof(elements: Element[]): MultiProofPath {
|
||||
const indexes = []
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
indexes.push(this.indexOf(elements[i]))
|
||||
}
|
||||
return this.multiPath(indexes)
|
||||
}
|
||||
|
||||
getTreeEdge(edgeIndex: number): TreeEdge {
|
||||
const edgeElement = this._layers[0][edgeIndex]
|
||||
if (edgeElement === undefined) {
|
||||
|
@ -34,6 +34,13 @@ export type ProofPath = {
|
||||
pathPositions: number[],
|
||||
pathRoot: Element
|
||||
}
|
||||
|
||||
export type MultiProofPath = {
|
||||
pathElements: Element[],
|
||||
leafIndices: number[],
|
||||
pathRoot: Element
|
||||
}
|
||||
|
||||
export type TreeEdge = {
|
||||
edgeElement: Element;
|
||||
edgePath: ProofPath;
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { MerkleTree, PartialMerkleTree, TreeEdge } from '../src'
|
||||
import { assert, should } from 'chai'
|
||||
import { MerkleTree, ProofPath, MultiProofPath, PartialMerkleTree, TreeEdge } from '../src'
|
||||
import { assert, should, expect } from 'chai'
|
||||
import { createHash } from 'crypto'
|
||||
import { it } from 'mocha'
|
||||
import { BaseTree } from '../src/BaseTree'
|
||||
import defaultHash from '../src/simpleHash'
|
||||
|
||||
const sha256Hash = (left, right) => createHash('sha256').update(`${left}${right}`).digest('hex')
|
||||
const ZERO_ELEMENT = '21663839004416932945382355908790599225266501822907911457504978515578255421292'
|
||||
|
||||
describe('MerkleTree', () => {
|
||||
|
||||
describe('#constructor', () => {
|
||||
|
||||
it('should have correct zero root', () => {
|
||||
const tree = new MerkleTree(10, [])
|
||||
return should().equal(tree.root, '3060353338620102847451617558650138132480')
|
||||
@ -207,7 +207,6 @@ describe('MerkleTree', () => {
|
||||
'4986731814143931240516913804278285467648',
|
||||
'1918547053077726613961101558405545328640',
|
||||
'5444383861051812288142814494928935059456',
|
||||
|
||||
])
|
||||
})
|
||||
|
||||
@ -253,7 +252,6 @@ describe('MerkleTree', () => {
|
||||
'4986731814143931240516913804278285467648',
|
||||
'1918547053077726613961101558405545328640',
|
||||
'5444383861051812288142814494928935059456',
|
||||
|
||||
])
|
||||
})
|
||||
})
|
||||
@ -264,6 +262,83 @@ describe('MerkleTree', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#verifyProof', () => {
|
||||
it('should verify a merkle-proof', () => {
|
||||
const leaves = [...Array(16)].map((_, i) => i + 1)
|
||||
const tree = new MerkleTree(4, leaves)
|
||||
const proof: ProofPath = {
|
||||
pathElements: [
|
||||
6,
|
||||
'1177811302158128621769756786551727063040',
|
||||
'81822854828781486047086122479545722339328',
|
||||
'3473994785217814971484840545214368055296'
|
||||
],
|
||||
pathIndices: [ 0, 0, 1, 0 ],
|
||||
pathPositions: [ 5, 3, 0, 1 ],
|
||||
pathRoot: '4813607112316126252402222488335589310464'
|
||||
}
|
||||
|
||||
expect(
|
||||
BaseTree.verifyProof(
|
||||
tree.root,
|
||||
tree.levels,
|
||||
defaultHash,
|
||||
5,
|
||||
proof.pathElements,
|
||||
proof.pathIndices,
|
||||
),
|
||||
).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
describe('#multiproof', () => {
|
||||
it('should return a merkle-multiproof for a range of leaves in a full tree', () => {
|
||||
const leaves = [...Array(8)].map((_, i) => i + 1)
|
||||
const tree = new MerkleTree(3, leaves)
|
||||
assert.deepEqual(tree.multiProof([1, 2, 6]), tree.multiPath([0, 1, 5]))
|
||||
})
|
||||
|
||||
it('should return a merkle-multiproof for a leaf', () => {
|
||||
const tree = new MerkleTree(6, [1])
|
||||
assert.deepEqual(tree.multiProof([1]), tree.multiPath([0]))
|
||||
})
|
||||
|
||||
it('should return a merkle-multiproof for a range of leaves', () => {
|
||||
const tree = new MerkleTree(8, [1, 2, 3, 4])
|
||||
assert.deepEqual(tree.multiProof([2, 4]), tree.multiPath([1, 3]))
|
||||
})
|
||||
})
|
||||
|
||||
describe('#verifyMultiProof', () => {
|
||||
it('should verify a merkle-multiproof for a range of leaves', () => {
|
||||
const leaves = [...Array(16)].map((_, i) => i + 1)
|
||||
const tree = new MerkleTree(4, leaves)
|
||||
const proof: MultiProofPath = {
|
||||
pathElements: [
|
||||
10,
|
||||
13,
|
||||
'4027992409016347597424110157229339967488',
|
||||
'1344833971335891992284786489626349010944',
|
||||
'811683747745882158385481808019325976576',
|
||||
'770507832213726794990007789733078368256',
|
||||
],
|
||||
leafIndices: [2, 3, 8, 13],
|
||||
pathRoot: '4813607112316126252402222488335589310464',
|
||||
}
|
||||
|
||||
expect(
|
||||
BaseTree.verifyMultiProof(
|
||||
tree.root,
|
||||
tree.levels,
|
||||
defaultHash,
|
||||
[3, 4, 9, 14],
|
||||
proof.pathElements,
|
||||
proof.leafIndices,
|
||||
),
|
||||
).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getTreeEdge', () => {
|
||||
it('should return correct treeEdge', () => {
|
||||
const expectedEdge: TreeEdge = {
|
||||
@ -291,6 +366,7 @@ describe('MerkleTree', () => {
|
||||
should().throw(call, 'Element not found')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getTreeSlices', () => {
|
||||
let fullTree: MerkleTree
|
||||
before(async () => {
|
||||
@ -344,7 +420,6 @@ describe('MerkleTree', () => {
|
||||
'4027992409016347597424110157229339967488',
|
||||
'923221781152860005594997320673730232320',
|
||||
'752191049236692618445397735417537626112',
|
||||
|
||||
],
|
||||
[
|
||||
'81822854828781486047086122479545722339328',
|
||||
@ -422,7 +497,6 @@ describe('MerkleTree', () => {
|
||||
dst.insert(10)
|
||||
|
||||
should().equal(src.root, dst.root)
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user