Skip to content

Commit bb44c06

Browse files
committed
stronger typing for optional hashFn
1 parent ed1e96a commit bb44c06

File tree

2 files changed

+32
-17
lines changed

2 files changed

+32
-17
lines changed

src/core.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const checkInternalNode = (tree: unknown[], i: number) => void (isInternalNod
1717
const checkLeafNode = (tree: unknown[], i: number) => void (isLeafNode(tree, i) || throwError('Index is not a leaf'));
1818
const checkValidMerkleNode = (node: BytesLike) => void (isValidMerkleNode(node) || throwError('Merkle tree nodes must be Uint8Array of length 32'));
1919

20+
export function makeMerkleTree(leaves: BytesLike[]): HexString[];
21+
export function makeMerkleTree(leaves: BytesLike[], hash: HashPairFn): HexString[];
2022
export function makeMerkleTree(leaves: BytesLike[], hash?: HashPairFn): HexString[] {
2123
leaves.forEach(checkValidMerkleNode);
2224

@@ -50,6 +52,8 @@ export function getProof(tree: BytesLike[], index: number): HexString[] {
5052
return proof.map(node => toHex(node));
5153
}
5254

55+
export function processProof(leaf: BytesLike, proof: BytesLike[]): HexString;
56+
export function processProof(leaf: BytesLike, proof: BytesLike[], hash: HashPairFn): HexString;
5357
export function processProof(leaf: BytesLike, proof: BytesLike[], hash?: HashPairFn): HexString {
5458
checkValidMerkleNode(leaf);
5559
proof.forEach(checkValidMerkleNode);
@@ -101,6 +105,8 @@ export function getMultiProof(tree: BytesLike[], indices: number[]): MultiProof<
101105
};
102106
}
103107

108+
export function processMultiProof(multiproof: MultiProof<BytesLike>): HexString;
109+
export function processMultiProof(multiproof: MultiProof<BytesLike>, hash: HashPairFn): HexString;
104110
export function processMultiProof(multiproof: MultiProof<BytesLike>, hash?: HashPairFn): HexString {
105111
multiproof.leaves.forEach(checkValidMerkleNode);
106112
multiproof.proof.forEach(checkValidMerkleNode);
@@ -132,6 +138,8 @@ export function processMultiProof(multiproof: MultiProof<BytesLike>, hash?: Hash
132138
return toHex(stack.pop() ?? proof.shift()!);
133139
}
134140

141+
export function isValidMerkleTree(tree: BytesLike[]): boolean;
142+
export function isValidMerkleTree(tree: BytesLike[], hash: HashPairFn): boolean;
135143
export function isValidMerkleTree(tree: BytesLike[], hash?: HashPairFn): boolean {
136144
for (const [i, node] of tree.entries()) {
137145
if (!isValidMerkleNode(node)) {

src/simple.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ export class SimpleMerkleTree {
6060
hashedValues.sort((a, b) => compare(a.hash, b.hash));
6161
}
6262

63-
const tree = makeMerkleTree(hashedValues.map(v => v.hash), hashPair);
63+
const tree = hashPair
64+
? makeMerkleTree(hashedValues.map(v => v.hash), hashPair)
65+
: makeMerkleTree(hashedValues.map(v => v.hash));
6466

6567
const indexedValues = values.map(value => ({ value: toHex(value), treeIndex: 0 }));
6668
for (const [leafIndex, { valueIndex }] of hashedValues.entries()) {
@@ -70,7 +72,9 @@ export class SimpleMerkleTree {
7072
return new SimpleMerkleTree(tree, indexedValues, hashPair);
7173
}
7274

73-
static load(data: MerkleTreeData<BytesLike>, hashPair ?: HashPairFn): SimpleMerkleTree {
75+
static load(data: MerkleTreeData<BytesLike>): SimpleMerkleTree;
76+
static load(data: MerkleTreeData<BytesLike>, hashPair: HashPairFn): SimpleMerkleTree;
77+
static load(data: MerkleTreeData<BytesLike>, hashPair?: HashPairFn): SimpleMerkleTree {
7478
switch (data.format) {
7579
case 'simple-v1':
7680
if (hashPair !== undefined) throwError(`Format '${data.format}' does not support custom hashing functions`);
@@ -89,19 +93,16 @@ export class SimpleMerkleTree {
8993
);
9094
}
9195

92-
static verify(root: BytesLike, leaf: BytesLike, proof: BytesLike[], hashPair ?: HashPairFn): boolean {
93-
return toHex(root) === processProof(leaf, proof, hashPair);
96+
static verify(root: BytesLike, leaf: BytesLike, proof: BytesLike[]): boolean;
97+
static verify(root: BytesLike, leaf: BytesLike, proof: BytesLike[], hashPair: HashPairFn): boolean;
98+
static verify(root: BytesLike, leaf: BytesLike, proof: BytesLike[], hashPair?: HashPairFn): boolean {
99+
return toHex(root) === (hashPair ? processProof(leaf, proof, hashPair) : processProof(leaf, proof));
94100
}
95101

96-
static verifyMultiProof(root: BytesLike, multiproof: MultiProof<BytesLike, BytesLike>, hashPair ?: HashPairFn): boolean {
97-
return toHex(root) === processMultiProof(
98-
{
99-
leaves: multiproof.leaves,
100-
proof: multiproof.proof,
101-
proofFlags: multiproof.proofFlags,
102-
},
103-
hashPair,
104-
);
102+
static verifyMultiProof(root: BytesLike, multiproof: MultiProof<BytesLike, BytesLike>): boolean;
103+
static verifyMultiProof(root: BytesLike, multiproof: MultiProof<BytesLike, BytesLike>, hashPair: HashPairFn): boolean;
104+
static verifyMultiProof(root: BytesLike, multiproof: MultiProof<BytesLike, BytesLike>, hashPair?: HashPairFn): boolean {
105+
return toHex(root) === (hashPair ? processMultiProof(multiproof, hashPair) : processMultiProof(multiproof));
105106
}
106107

107108
dump(): MerkleTreeData<BytesLike> {
@@ -130,8 +131,10 @@ export class SimpleMerkleTree {
130131
for (let i = 0; i < this.values.length; i++) {
131132
this.validateValue(i);
132133
}
133-
if (!isValidMerkleTree(this.tree, this.hashPair)) {
134-
throwError('Merkle tree is invalid');
134+
if (this.hashPair) {
135+
isValidMerkleTree(this.tree, this.hashPair) || throwError('Merkle tree is invalid');
136+
} else {
137+
isValidMerkleTree(this.tree) || throwError('Merkle tree is invalid');
135138
}
136139
}
137140

@@ -184,7 +187,9 @@ export class SimpleMerkleTree {
184187
}
185188

186189
private _verify(leafHash: BytesLike, proof: BytesLike[]): boolean {
187-
return this.root === processProof(leafHash, proof, this.hashPair);
190+
return this.hashPair
191+
? SimpleMerkleTree.verify(this.root, leafHash, proof, this.hashPair)
192+
: SimpleMerkleTree.verify(this.root, leafHash, proof);
188193
}
189194

190195
verifyMultiProof(multiproof: MultiProof<BytesLike, number | BytesLike>): boolean {
@@ -196,7 +201,9 @@ export class SimpleMerkleTree {
196201
}
197202

198203
private _verifyMultiProof(multiproof: MultiProof<BytesLike, BytesLike>): boolean {
199-
return this.root === processMultiProof(multiproof, this.hashPair);
204+
return this.hashPair
205+
? SimpleMerkleTree.verifyMultiProof(this.root, multiproof, this.hashPair)
206+
: SimpleMerkleTree.verifyMultiProof(this.root, multiproof);
200207
}
201208

202209
private validateValue(valueIndex: number): HexString {

0 commit comments

Comments
 (0)