diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cc3c13..9dee7c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 1.0.3 + +- Added `StandardMerkleTree.verify` static method for verification of a proof for given root, leaf, and leaf encoding. + ## 1.0.2 - Added `StandardMerkleTree` methods `verify` and `verifyMultiProof`. diff --git a/README.md b/README.md index 8122a23..9eaad47 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,14 @@ Creates a standard merkle tree out of an array of the elements in the tree, alon > **Note** > Consider reading the array of elements from a CSV file for easy interoperability with spreadsheets or other data processing pipelines. +### `StandardMerkleTree.verify` + +```typescript +const verified = StandardMerkleTree.verify(root, ['address', 'uint'], [alice, '100'], proof); +``` + +Returns a boolean that is `true` when the proof verifies that the value is contained in the tree given only the proof, merkle root, and encoding. + ### `tree.root` ```typescript diff --git a/src/standard.test.ts b/src/standard.test.ts index 51887e6..5a18d25 100644 --- a/src/standard.test.ts +++ b/src/standard.test.ts @@ -32,6 +32,26 @@ describe('standard merkle tree', () => { } }); + it('generates valid single proofs for all leaves from root and encoding', () => { + const { t } = characters('abcdef'); + + for (const [, leaf] of t.entries()) { + const proof = t.getProof(leaf); + + assert(StandardMerkleTree.verify(t.root, ['string'], leaf, proof)); + } + }); + + it('rejects invalid proof using static verify method', () => { + const { t } = characters('abcdef'); + const { t: fakeTree } = characters('xyz'); + + const testLeaf = ['x']; + const proof = fakeTree.getProof(testLeaf); + + assert(!StandardMerkleTree.verify(t.root, ['string'], testLeaf, proof)); + }); + it('generates valid multiproofs', () => { const { t, l } = characters('abcdef'); diff --git a/src/standard.ts b/src/standard.ts index 7528058..8b61694 100644 --- a/src/standard.ts +++ b/src/standard.ts @@ -28,7 +28,7 @@ export class StandardMerkleTree { private readonly values: { value: T, treeIndex: number }[], private readonly leafEncoding: string[], ) { - this.hashLookup = + this.hashLookup = Object.fromEntries(values.map(({ value }, valueIndex) => [ hex(standardLeafHash(value, leafEncoding)), valueIndex, @@ -61,6 +61,11 @@ export class StandardMerkleTree { ); } + static verify(root: string, leafEncoding: string[], leaf: T, proof: string[]): boolean { + const impliedRoot = processProof(standardLeafHash(leaf, leafEncoding), proof.map(hexToBytes)); + return equalsBytes(impliedRoot, hexToBytes(root)); + } + dump(): StandardMerkleTreeData { return { format: 'standard-v1',