Update lib

This commit is contained in:
Rodrigo Q. Saramago 2022-08-22 22:28:14 +02:00
parent df1bee33f9
commit fb8974a0a0
No known key found for this signature in database
GPG Key ID: 9B36B2525704A359
5 changed files with 169 additions and 2 deletions

36
lib/BaseTree.d.ts vendored
View File

@ -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;

View File

@ -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++) {

View File

@ -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;
/**
* 🪓

View File

@ -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
View File

@ -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;