Skip to content

Commit 0cc8480

Browse files
authored
Add invariant validation in processMultiProof (#22)
1 parent 272f93e commit 0cc8480

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 1.0.5
4+
5+
- Make `processMultiProof` more robust by validating invariants.
6+
37
## 1.0.4
48

59
- Added `StandardMerkleTree.verifyMultiProof` static method.

src/core.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import fc from 'fast-check';
22
import assert from 'assert/strict';
33
import { equalsBytes } from 'ethereum-cryptography/utils';
44
import { makeMerkleTree, getProof, processProof, getMultiProof, processMultiProof, isValidMerkleTree, renderMerkleTree } from './core';
5-
import { hex } from './bytes';
5+
import { compareBytes, hex } from './bytes';
6+
import { keccak256 } from 'ethereum-cryptography/keccak';
67

78
const zero = new Uint8Array(32);
89

@@ -72,6 +73,23 @@ describe('core error conditions', () => {
7273
/^Error: Expected non-zero number of nodes$/,
7374
);
7475
});
76+
77+
it('multiproof invariants', () => {
78+
const leaf = keccak256(Uint8Array.of(42));
79+
const tree = makeMerkleTree([leaf, zero]);
80+
81+
const badMultiProof = {
82+
leaves: [128, 129].map(n => keccak256(Uint8Array.of(n))).sort(compareBytes),
83+
proof: [leaf, leaf],
84+
proofFlags: [true, true, false],
85+
};
86+
87+
assert.throws(
88+
() => processMultiProof(badMultiProof),
89+
/^Error: Broken invariant$/,
90+
);
91+
});
92+
7593
});
7694

7795
class PrettyBytes extends Uint8Array {

src/core.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,18 @@ export function processMultiProof(multiproof: MultiProof<Bytes>): Bytes {
120120
const proof = multiproof.proof.concat(); // copy
121121

122122
for (const flag of multiproof.proofFlags) {
123-
const a = stack.shift()!;
124-
const b = flag ? stack.shift()! : proof.shift()!;
123+
const a = stack.shift();
124+
const b = flag ? stack.shift() : proof.shift();
125+
if (a === undefined || b === undefined) {
126+
throw new Error('Broken invariant');
127+
}
125128
stack.push(hashPair(a, b));
126129
}
127130

131+
if (stack.length + proof.length !== 1) {
132+
throw new Error('Broken invariant');
133+
}
134+
128135
return stack.pop() ?? proof.shift()!;
129136
}
130137

0 commit comments

Comments
 (0)