-
Notifications
You must be signed in to change notification settings - Fork 295
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Compute function tree root in ts. (#3326)
One step closer to not needing circuits.wasm. * This creates a new class `MerkleTreeRootCalculator`. It wouldn't have had to exist except for the fact that the zero leaf of the function tree is the hash of a zeroed function leaf (5 fields) rather than just a 0 buffer. Kinda annoying. Needed? * I tried putting the class in the merkle-tree package, but worryingly that created a circular dependency because everything depends on this generic "types" catch all package, and it depends on circuits... Seems sus. For now the class sits next to where it's used in `abis`. * When performing a naive tree hash, this actually beats the wasm performance by around 5%. Perhaps due to the wasm always computing the zero leaf. Assuming that's the reason, the performance is equal despite overhead of calling into wasm (so we can assume such overheads are negligible). * The algorithm performs much better than the wasm version however, when the tree is not full, as it leverages zero layer caches to not have to hash the entire tree. The test adds 4 leaves to a 16 leaf tree, and as expected is 4 times faster. Just for clarity, this still uses wasm, but it uses bb.js wasm and at a lower level. Just calling `pedersenHash`.
- Loading branch information
1 parent
b4c967b
commit 48d8c7f
Showing
6 changed files
with
74 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
yarn-project/circuits.js/src/abis/merkle_tree_root_calculator.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
import { MerkleTreeRootCalculator } from './merkle_tree_root_calculator.js'; | ||
|
||
describe('merkle tree root calculator', () => { | ||
it('should correctly handle no leaves', () => { | ||
// Height of 3 is 8 leaves. | ||
const calculator = new MerkleTreeRootCalculator(4); | ||
const expected = calculator.computeTreeRoot(new Array(8).fill(new Fr(0)).map(fr => fr.toBuffer())); | ||
expect(calculator.computeTreeRoot()).toEqual(expected); | ||
}); | ||
|
||
it('should correctly leverage zero hashes', () => { | ||
const calculator = new MerkleTreeRootCalculator(4); | ||
const leaves = Array.from({ length: 5 }).map((_, i) => new Fr(i).toBuffer()); | ||
const padded = [...leaves, ...new Array(3).fill(Buffer.alloc(32))]; | ||
const expected = calculator.computeTreeRoot(padded); | ||
const result = calculator.computeTreeRoot(leaves); | ||
expect(result).not.toBeUndefined(); | ||
expect(result).toEqual(expected); | ||
}); | ||
|
||
it('should correctly handle non default zero leaf', () => { | ||
const zeroLeaf = new Fr(666).toBuffer(); | ||
const calculator = new MerkleTreeRootCalculator(4, zeroLeaf); | ||
const leaves = Array.from({ length: 5 }).map((_, i) => new Fr(i).toBuffer()); | ||
const padded = [...leaves, ...new Array(3).fill(zeroLeaf)]; | ||
const expected = calculator.computeTreeRoot(padded); | ||
expect(calculator.computeTreeRoot(leaves)).toEqual(expected); | ||
}); | ||
}); |
33 changes: 33 additions & 0 deletions
33
yarn-project/circuits.js/src/abis/merkle_tree_root_calculator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { pedersenHash } from '@aztec/foundation/crypto'; | ||
|
||
/** | ||
* Calculates the root of a merkle tree. | ||
*/ | ||
export class MerkleTreeRootCalculator { | ||
private zeroHashes: Buffer[]; | ||
|
||
constructor(private height: number, zeroLeaf = Buffer.alloc(32)) { | ||
this.zeroHashes = Array.from({ length: height }).reduce( | ||
(acc: Buffer[], _, i) => [...acc, pedersenHash([acc[i], acc[i]])], | ||
[zeroLeaf], | ||
); | ||
} | ||
|
||
computeTreeRoot(leaves: Buffer[] = []) { | ||
if (leaves.length === 0) { | ||
return this.zeroHashes[this.zeroHashes.length - 1]; | ||
} | ||
|
||
for (let i = 0; i < this.height; ++i) { | ||
let j = 0; | ||
for (; j < leaves.length / 2; ++j) { | ||
const l = leaves[j * 2]; | ||
const r = leaves[j * 2 + 1] || this.zeroHashes[i]; | ||
leaves[j] = pedersenHash([l, r]); | ||
} | ||
leaves = leaves.slice(0, j); | ||
} | ||
|
||
return leaves[0]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters