From 4f05e84d725db350d690803ed536807d30092c80 Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Sat, 9 Jul 2022 02:44:31 -0400 Subject: [PATCH 01/11] add updateLeaf to library and tester contracts --- .../contracts/IncrementalBinaryTree.sol | 60 +++++++++++++-- .../contracts/IncrementalQuinTree.sol | 77 +++++++++++++++++-- .../test/IncrementalBinaryTreeTest.sol | 27 ++++++- .../test/IncrementalQuinTreeTest.sol | 14 ++++ yarn.lock | 2 +- 5 files changed, 164 insertions(+), 16 deletions(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol index 0b9cc4f..3658c5d 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol @@ -31,8 +31,14 @@ library IncrementalBinaryTree { uint8 depth, uint256 zero ) public { - require(zero < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); - require(depth > 0 && depth <= MAX_DEPTH, "IncrementalBinaryTree: tree depth must be between 1 and 32"); + require( + zero < SNARK_SCALAR_FIELD, + "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" + ); + require( + depth > 0 && depth <= MAX_DEPTH, + "IncrementalBinaryTree: tree depth must be between 1 and 32" + ); self.depth = depth; @@ -48,8 +54,14 @@ library IncrementalBinaryTree { /// @param self: Tree data. /// @param leaf: Leaf to be inserted. function insert(IncrementalTreeData storage self, uint256 leaf) public { - require(leaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); - require(self.numberOfLeaves < 2**self.depth, "IncrementalBinaryTree: tree is full"); + require( + leaf < SNARK_SCALAR_FIELD, + "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" + ); + require( + self.numberOfLeaves < 2**self.depth, + "IncrementalBinaryTree: tree is full" + ); uint256 index = self.numberOfLeaves; uint256 hash = leaf; @@ -69,6 +81,38 @@ library IncrementalBinaryTree { self.numberOfLeaves += 1; } + /// @dev Updates a leaf in the tree. + /// @param self: Tree data. + /// @param leaf: Leaf to be updated. + /// @param proofSiblings: Array of the sibling nodes of the proof of membership. + /// @param proofPathIndices: Path of the proof of membership. + function update( + IncrementalTreeData storage self, + uint256 leaf, + uint256[] calldata proofSiblings, + uint8[] calldata proofPathIndices + ) public { + + uint256 hash = leaf; + for (uint8 i = 0; i < self.depth; i++) { + if (proofPathIndices[i] == 0) { + if (proofSiblings[i] == self.lastSubtrees[i][1]) { + self.lastSubtrees[i][0] = hash; + } + + hash = PoseidonT3.poseidon([hash, proofSiblings[i]]); + } else { + if (proofSiblings[i] == self.lastSubtrees[i][0]) { + self.lastSubtrees[i][1] = hash; + } + + hash = PoseidonT3.poseidon([proofSiblings[i], hash]); + } + } + + self.root = hash; + } + /// @dev Removes a leaf from the tree. /// @param self: Tree data. /// @param leaf: Leaf to be removed. @@ -118,9 +162,13 @@ library IncrementalBinaryTree { uint256[] calldata proofSiblings, uint8[] calldata proofPathIndices ) private view returns (bool) { - require(leaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); require( - proofPathIndices.length == self.depth && proofSiblings.length == self.depth, + leaf < SNARK_SCALAR_FIELD, + "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" + ); + require( + proofPathIndices.length == self.depth && + proofSiblings.length == self.depth, "IncrementalBinaryTree: length of path is not correct" ); diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol index 1934237..84e50c9 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol @@ -31,8 +31,14 @@ library IncrementalQuinTree { uint8 depth, uint256 zero ) public { - require(zero < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); - require(depth > 0 && depth <= MAX_DEPTH, "IncrementalQuinTree: tree depth must be between 1 and 32"); + require( + zero < SNARK_SCALAR_FIELD, + "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" + ); + require( + depth > 0 && depth <= MAX_DEPTH, + "IncrementalQuinTree: tree depth must be between 1 and 32" + ); self.depth = depth; @@ -54,8 +60,14 @@ library IncrementalQuinTree { /// @param self: Tree data. /// @param leaf: Leaf to be inserted. function insert(IncrementalTreeData storage self, uint256 leaf) public { - require(leaf < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); - require(self.numberOfLeaves < 5**self.depth, "IncrementalQuinTree: tree is full"); + require( + leaf < SNARK_SCALAR_FIELD, + "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD" + ); + require( + self.numberOfLeaves < 5**self.depth, + "IncrementalQuinTree: tree is full" + ); uint256 index = self.numberOfLeaves; uint256 hash = leaf; @@ -79,6 +91,50 @@ library IncrementalQuinTree { self.numberOfLeaves += 1; } + /// @dev Updates a leaf in the tree. + /// @param self: Tree data. + /// @param leaf: Leaf to be updated. + /// @param proofSiblings: Array of the sibling nodes of the proof of membership. + /// @param proofPathIndices: Path of the proof of membership. + function update( + IncrementalTreeData storage self, + uint256 leaf, + uint256[4][] calldata proofSiblings, + uint8[] calldata proofPathIndices + ) public { + require( + verify(self, leaf, proofSiblings, proofPathIndices), + "IncrementalQuinTree: leaf is not part of the tree" + ); + + uint256 hash = self.zeroes[0]; + + for (uint8 i = 0; i < self.depth; i++) { + uint256[5] memory nodes; + + for (uint8 j = 0; j < 5; j++) { + if (j < proofPathIndices[i]) { + nodes[j] = proofSiblings[i][j]; + } else if (j == proofPathIndices[i]) { + nodes[j] = hash; + } else { + nodes[j] = proofSiblings[i][j - 1]; + } + } + + if ( + nodes[0] == self.lastSubtrees[i][0] || + nodes[4] == self.lastSubtrees[i][4] + ) { + self.lastSubtrees[i][proofPathIndices[i]] = hash; + } + + hash = PoseidonT6.poseidon(nodes); + } + + self.root = hash; + } + /// @dev Removes a leaf from the tree. /// @param self: Tree data. /// @param leaf: Leaf to be removed. @@ -110,7 +166,10 @@ library IncrementalQuinTree { } } - if (nodes[0] == self.lastSubtrees[i][0] || nodes[4] == self.lastSubtrees[i][4]) { + if ( + nodes[0] == self.lastSubtrees[i][0] || + nodes[4] == self.lastSubtrees[i][4] + ) { self.lastSubtrees[i][proofPathIndices[i]] = hash; } @@ -132,9 +191,13 @@ library IncrementalQuinTree { uint256[4][] calldata proofSiblings, uint8[] calldata proofPathIndices ) private view returns (bool) { - require(leaf < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); require( - proofPathIndices.length == self.depth && proofSiblings.length == self.depth, + leaf < SNARK_SCALAR_FIELD, + "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD" + ); + require( + proofPathIndices.length == self.depth && + proofSiblings.length == self.depth, "IncrementalQuinTree: length of path is not correct" ); diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol index 1594e35..1f658d5 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol @@ -9,6 +9,7 @@ contract IncrementalBinaryTreeTest { event TreeCreated(bytes32 id, uint8 depth); event LeafInserted(bytes32 indexed treeId, uint256 leaf, uint256 root); + event LeafUpdated(bytes32 indexed treeId, uint256 leaf, uint256 root); event LeafRemoved(bytes32 indexed treeId, uint256 leaf, uint256 root); mapping(bytes32 => IncrementalTreeData) public trees; @@ -22,20 +23,42 @@ contract IncrementalBinaryTreeTest { } function insertLeaf(bytes32 _treeId, uint256 _leaf) external { - require(trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist"); + require( + trees[_treeId].depth != 0, + "BinaryTreeTest: tree does not exist" + ); trees[_treeId].insert(_leaf); emit LeafInserted(_treeId, _leaf, trees[_treeId].root); } + function updateLeaf( + bytes32 _treeId, + uint256 _leaf, + uint256[] calldata _proofSiblings, + uint8[] calldata _proofPathIndices + ) external { + require( + trees[_treeId].depth != 0, + "BinaryTreeTest: tree does not exist" + ); + + trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); + + emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); + } + function removeLeaf( bytes32 _treeId, uint256 _leaf, uint256[] calldata _proofSiblings, uint8[] calldata _proofPathIndices ) external { - require(trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist"); + require( + trees[_treeId].depth != 0, + "BinaryTreeTest: tree does not exist" + ); trees[_treeId].remove(_leaf, _proofSiblings, _proofPathIndices); diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol index 62f7060..090af54 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol @@ -9,6 +9,7 @@ contract IncrementalQuinTreeTest { event TreeCreated(bytes32 id, uint8 depth); event LeafInserted(bytes32 indexed treeId, uint256 leaf, uint256 root); + event LeafUpdated(bytes32 indexed treeId, uint256 leaf, uint256 root); event LeafRemoved(bytes32 indexed treeId, uint256 leaf, uint256 root); mapping(bytes32 => IncrementalTreeData) public trees; @@ -29,6 +30,19 @@ contract IncrementalQuinTreeTest { emit LeafInserted(_treeId, _leaf, trees[_treeId].root); } + function updateLeaf( + bytes32 _treeId, + uint256 _leaf, + uint256[4][] calldata _proofSiblings, + uint8[] calldata _proofPathIndices + ) external { + require(trees[_treeId].depth != 0, "QuinTreeTest: tree does not exist"); + + trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); + + emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); + } + function removeLeaf( bytes32 _treeId, uint256 _leaf, diff --git a/yarn.lock b/yarn.lock index fb3fdf0..5412021 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8834,7 +8834,7 @@ __metadata: dependencies: bn.js: ^4.11.8 ethereumjs-util: ^6.0.0 - checksum: 03127d09960e5f8a44167463faf25b2894db2f746376dbb8195b789ed11762f93db9c574eaa7c498c400063508e9dfc1c80de2edf5f0e1406b25c87d860ff2f1 + checksum: ae074be0bb012857ab5d3ae644d1163b908a48dd724b7d2567cfde309dc72222d460438f2411936a70dc949dc604ce1ef7118f7273bd525815579143c907e336 languageName: node linkType: hard From ffee1e67c1d9b600d34915b2abeb6aca5bfa7934 Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Sat, 9 Jul 2022 03:15:53 -0400 Subject: [PATCH 02/11] binary tree test cases --- .../contracts/IncrementalBinaryTree.sol | 6 +++- .../test/IncrementalBinaryTreeTest.ts | 35 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol index 3658c5d..b33f54f 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol @@ -92,7 +92,11 @@ library IncrementalBinaryTree { uint256[] calldata proofSiblings, uint8[] calldata proofPathIndices ) public { - + require( + leaf < SNARK_SCALAR_FIELD, + "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" + ); + uint256 hash = leaf; for (uint8 i = 0; i < self.depth; i++) { if (proofPathIndices[i] == 0) { diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts index 2d338d7..6256e0e 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts @@ -83,6 +83,40 @@ describe("IncrementalBinaryTreeTest", () => { await expect(transaction).to.be.revertedWith("IncrementalBinaryTree: tree is full") }) + it("Should not update a leaf if the tree does not exist", async () => { + const treeId = ethers.utils.formatBytes32String("none") + + const transaction = contract.updateLeaf(treeId, leaf, [0, 1], [0, 1]) + }) + + it("Should not update a leaf if its value is > SNARK_SCALAR_FIELD", async () => { + const leaf = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495618") + + const transaction = contract.updateLeaf(treeId, leaf, [0, 1], [0, 1]) + + await expect(transaction).to.be.revertedWith("IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD") + }) + + it("Should update a leaf", async () => { + const treeId = ethers.utils.formatBytes32String("tree2") + const tree = createTree(depth, 0) + for (let i = 0; i < 4; i += 1) + tree.insert(BigInt(i + 1)) + + const leaf = BigInt(22) + tree.update(2, leaf) + const { root, pathIndices, siblings } = tree.createProof(2) + const transaction = contract.updateLeaf( + treeId, + leaf, + siblings.map((s) => s[0]), + pathIndices + ) + + await expect(transaction).to.emit(contract, "LeafUpdated").withArgs(treeId, leaf, root); + + }) + it("Should not remove a leaf if the tree does not exist", async () => { const treeId = ethers.utils.formatBytes32String("none") @@ -111,7 +145,6 @@ describe("IncrementalBinaryTreeTest", () => { await contract.insertLeaf(treeId, BigInt(3)) const { siblings, pathIndices, root } = tree.createProof(0) - const transaction = contract.removeLeaf( treeId, BigInt(1), From af55619367befb0f07cff7057fa4fbf059befd8d Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Sat, 9 Jul 2022 04:01:02 -0400 Subject: [PATCH 03/11] quin tree update tests --- .../contracts/IncrementalQuinTree.sol | 6 ++-- .../test/IncrementalBinaryTreeTest.sol | 1 - .../test/IncrementalBinaryTreeTest.ts | 5 +-- .../test/IncrementalQuinTreeTest.ts | 31 ++++++++++++++++++- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol index 84e50c9..f5b0811 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol @@ -103,11 +103,11 @@ library IncrementalQuinTree { uint8[] calldata proofPathIndices ) public { require( - verify(self, leaf, proofSiblings, proofPathIndices), - "IncrementalQuinTree: leaf is not part of the tree" + leaf < SNARK_SCALAR_FIELD, + "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD" ); - uint256 hash = self.zeroes[0]; + uint256 hash = leaf; for (uint8 i = 0; i < self.depth; i++) { uint256[5] memory nodes; diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol index 1f658d5..f8b942d 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol @@ -43,7 +43,6 @@ contract IncrementalBinaryTreeTest { trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist" ); - trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts index 6256e0e..9aa4a0e 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts @@ -87,6 +87,8 @@ describe("IncrementalBinaryTreeTest", () => { const treeId = ethers.utils.formatBytes32String("none") const transaction = contract.updateLeaf(treeId, leaf, [0, 1], [0, 1]) + + await expect(transaction).to.be.revertedWith("BinaryTreeTest: tree does not exist") }) it("Should not update a leaf if its value is > SNARK_SCALAR_FIELD", async () => { @@ -103,7 +105,7 @@ describe("IncrementalBinaryTreeTest", () => { for (let i = 0; i < 4; i += 1) tree.insert(BigInt(i + 1)) - const leaf = BigInt(22) + const leaf = BigInt(1337) tree.update(2, leaf) const { root, pathIndices, siblings } = tree.createProof(2) const transaction = contract.updateLeaf( @@ -114,7 +116,6 @@ describe("IncrementalBinaryTreeTest", () => { ) await expect(transaction).to.emit(contract, "LeafUpdated").withArgs(treeId, leaf, root); - }) it("Should not remove a leaf if the tree does not exist", async () => { diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts index 950ef55..bf178d5 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts @@ -86,6 +86,36 @@ describe("IncrementalQuinTreeTest", () => { await expect(transaction).to.be.revertedWith("IncrementalQuinTree: tree is full") }) + it("Should not update a leaf if the tree does not exist", async () => { + const treeId = ethers.utils.formatBytes32String("none") + + const transaction = contract.updateLeaf(treeId, leaf, [[0, 1, 2, 3]], [0]) + + await expect(transaction).to.be.revertedWith("QuinTreeTest: tree does not exist") + }) + + it("Should not update a leaf if its value is > SNARK_SCALAR_FIELD", async () => { + const leaf = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495618") + + const transaction = contract.updateLeaf(treeId, leaf, [[0, 1, 2, 3]], [0]) + + await expect(transaction).to.be.revertedWith("IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD") + }) + + it("Should update a leaf", async () => { + const treeId = ethers.utils.formatBytes32String("tree2") + const tree = createTree(depth, 0, 5) + for (let i = 0; i < 6; i += 1) + tree.insert(BigInt(i + 1)) + + const leaf = BigInt(1337) + tree.update(2, leaf) + const { pathIndices, siblings, root } = tree.createProof(2) + const transaction = contract.updateLeaf(treeId, leaf, siblings, pathIndices) + + await expect(transaction).to.emit(contract, "LeafUpdated").withArgs(treeId, leaf, root) + }) + it("Should not remove a leaf if the tree does not exist", async () => { const treeId = ethers.utils.formatBytes32String("none") @@ -114,7 +144,6 @@ describe("IncrementalQuinTreeTest", () => { await contract.insertLeaf(treeId, BigInt(3)) const { siblings, pathIndices, root } = tree.createProof(0) - const transaction = contract.removeLeaf(treeId, BigInt(1), siblings, pathIndices) await expect(transaction).to.emit(contract, "LeafRemoved").withArgs(treeId, BigInt(1), root) From 79221fcc05dcab297d838143f0e27ce3742bdc54 Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Sat, 9 Jul 2022 04:02:28 -0400 Subject: [PATCH 04/11] prettier --- .../contracts/IncrementalBinaryTree.sol | 35 ++++----------- .../contracts/IncrementalQuinTree.sol | 43 ++++--------------- .../test/IncrementalBinaryTreeTest.sol | 15 ++----- .../test/IncrementalBinaryTreeTest.ts | 9 ++-- .../test/IncrementalQuinTreeTest.ts | 3 +- 5 files changed, 25 insertions(+), 80 deletions(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol index b33f54f..3b5052e 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol @@ -31,14 +31,8 @@ library IncrementalBinaryTree { uint8 depth, uint256 zero ) public { - require( - zero < SNARK_SCALAR_FIELD, - "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" - ); - require( - depth > 0 && depth <= MAX_DEPTH, - "IncrementalBinaryTree: tree depth must be between 1 and 32" - ); + require(zero < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); + require(depth > 0 && depth <= MAX_DEPTH, "IncrementalBinaryTree: tree depth must be between 1 and 32"); self.depth = depth; @@ -54,14 +48,8 @@ library IncrementalBinaryTree { /// @param self: Tree data. /// @param leaf: Leaf to be inserted. function insert(IncrementalTreeData storage self, uint256 leaf) public { - require( - leaf < SNARK_SCALAR_FIELD, - "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" - ); - require( - self.numberOfLeaves < 2**self.depth, - "IncrementalBinaryTree: tree is full" - ); + require(leaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); + require(self.numberOfLeaves < 2**self.depth, "IncrementalBinaryTree: tree is full"); uint256 index = self.numberOfLeaves; uint256 hash = leaf; @@ -92,11 +80,8 @@ library IncrementalBinaryTree { uint256[] calldata proofSiblings, uint8[] calldata proofPathIndices ) public { - require( - leaf < SNARK_SCALAR_FIELD, - "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" - ); - + require(leaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); + uint256 hash = leaf; for (uint8 i = 0; i < self.depth; i++) { if (proofPathIndices[i] == 0) { @@ -166,13 +151,9 @@ library IncrementalBinaryTree { uint256[] calldata proofSiblings, uint8[] calldata proofPathIndices ) private view returns (bool) { + require(leaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); require( - leaf < SNARK_SCALAR_FIELD, - "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" - ); - require( - proofPathIndices.length == self.depth && - proofSiblings.length == self.depth, + proofPathIndices.length == self.depth && proofSiblings.length == self.depth, "IncrementalBinaryTree: length of path is not correct" ); diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol index f5b0811..5d9109c 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol @@ -31,14 +31,8 @@ library IncrementalQuinTree { uint8 depth, uint256 zero ) public { - require( - zero < SNARK_SCALAR_FIELD, - "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD" - ); - require( - depth > 0 && depth <= MAX_DEPTH, - "IncrementalQuinTree: tree depth must be between 1 and 32" - ); + require(zero < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); + require(depth > 0 && depth <= MAX_DEPTH, "IncrementalQuinTree: tree depth must be between 1 and 32"); self.depth = depth; @@ -60,14 +54,8 @@ library IncrementalQuinTree { /// @param self: Tree data. /// @param leaf: Leaf to be inserted. function insert(IncrementalTreeData storage self, uint256 leaf) public { - require( - leaf < SNARK_SCALAR_FIELD, - "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD" - ); - require( - self.numberOfLeaves < 5**self.depth, - "IncrementalQuinTree: tree is full" - ); + require(leaf < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); + require(self.numberOfLeaves < 5**self.depth, "IncrementalQuinTree: tree is full"); uint256 index = self.numberOfLeaves; uint256 hash = leaf; @@ -102,10 +90,7 @@ library IncrementalQuinTree { uint256[4][] calldata proofSiblings, uint8[] calldata proofPathIndices ) public { - require( - leaf < SNARK_SCALAR_FIELD, - "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD" - ); + require(leaf < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); uint256 hash = leaf; @@ -122,10 +107,7 @@ library IncrementalQuinTree { } } - if ( - nodes[0] == self.lastSubtrees[i][0] || - nodes[4] == self.lastSubtrees[i][4] - ) { + if (nodes[0] == self.lastSubtrees[i][0] || nodes[4] == self.lastSubtrees[i][4]) { self.lastSubtrees[i][proofPathIndices[i]] = hash; } @@ -166,10 +148,7 @@ library IncrementalQuinTree { } } - if ( - nodes[0] == self.lastSubtrees[i][0] || - nodes[4] == self.lastSubtrees[i][4] - ) { + if (nodes[0] == self.lastSubtrees[i][0] || nodes[4] == self.lastSubtrees[i][4]) { self.lastSubtrees[i][proofPathIndices[i]] = hash; } @@ -191,13 +170,9 @@ library IncrementalQuinTree { uint256[4][] calldata proofSiblings, uint8[] calldata proofPathIndices ) private view returns (bool) { + require(leaf < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); require( - leaf < SNARK_SCALAR_FIELD, - "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD" - ); - require( - proofPathIndices.length == self.depth && - proofSiblings.length == self.depth, + proofPathIndices.length == self.depth && proofSiblings.length == self.depth, "IncrementalQuinTree: length of path is not correct" ); diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol index f8b942d..d3c97c9 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol @@ -23,10 +23,7 @@ contract IncrementalBinaryTreeTest { } function insertLeaf(bytes32 _treeId, uint256 _leaf) external { - require( - trees[_treeId].depth != 0, - "BinaryTreeTest: tree does not exist" - ); + require(trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist"); trees[_treeId].insert(_leaf); @@ -39,10 +36,7 @@ contract IncrementalBinaryTreeTest { uint256[] calldata _proofSiblings, uint8[] calldata _proofPathIndices ) external { - require( - trees[_treeId].depth != 0, - "BinaryTreeTest: tree does not exist" - ); + require(trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist"); trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); @@ -54,10 +48,7 @@ contract IncrementalBinaryTreeTest { uint256[] calldata _proofSiblings, uint8[] calldata _proofPathIndices ) external { - require( - trees[_treeId].depth != 0, - "BinaryTreeTest: tree does not exist" - ); + require(trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist"); trees[_treeId].remove(_leaf, _proofSiblings, _proofPathIndices); diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts index 9aa4a0e..b0ad131 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts @@ -87,7 +87,7 @@ describe("IncrementalBinaryTreeTest", () => { const treeId = ethers.utils.formatBytes32String("none") const transaction = contract.updateLeaf(treeId, leaf, [0, 1], [0, 1]) - + await expect(transaction).to.be.revertedWith("BinaryTreeTest: tree does not exist") }) @@ -102,9 +102,8 @@ describe("IncrementalBinaryTreeTest", () => { it("Should update a leaf", async () => { const treeId = ethers.utils.formatBytes32String("tree2") const tree = createTree(depth, 0) - for (let i = 0; i < 4; i += 1) - tree.insert(BigInt(i + 1)) - + for (let i = 0; i < 4; i += 1) tree.insert(BigInt(i + 1)) + const leaf = BigInt(1337) tree.update(2, leaf) const { root, pathIndices, siblings } = tree.createProof(2) @@ -115,7 +114,7 @@ describe("IncrementalBinaryTreeTest", () => { pathIndices ) - await expect(transaction).to.emit(contract, "LeafUpdated").withArgs(treeId, leaf, root); + await expect(transaction).to.emit(contract, "LeafUpdated").withArgs(treeId, leaf, root) }) it("Should not remove a leaf if the tree does not exist", async () => { diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts index bf178d5..97bb78c 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts @@ -105,8 +105,7 @@ describe("IncrementalQuinTreeTest", () => { it("Should update a leaf", async () => { const treeId = ethers.utils.formatBytes32String("tree2") const tree = createTree(depth, 0, 5) - for (let i = 0; i < 6; i += 1) - tree.insert(BigInt(i + 1)) + for (let i = 0; i < 6; i += 1) tree.insert(BigInt(i + 1)) const leaf = BigInt(1337) tree.update(2, leaf) From d3c8fa7acb1162d6d322f6e83757bbe1a1db423b Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Sat, 9 Jul 2022 04:05:19 -0400 Subject: [PATCH 05/11] readme update --- packages/incremental-merkle-tree.sol/contracts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/README.md b/packages/incremental-merkle-tree.sol/contracts/README.md index 17d46a2..b67eb80 100644 --- a/packages/incremental-merkle-tree.sol/contracts/README.md +++ b/packages/incremental-merkle-tree.sol/contracts/README.md @@ -39,7 +39,7 @@ ✔️ [IncrementalBinaryTree](https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol) (Poseidon)\ ✔️ [IncrementalQuinTree](https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol) (Poseidon) -> The methods of each library are always the same (i.e `insert`, `remove`, `verify`). +> The methods of each library are always the same (i.e `insert`, `update`, `remove`, `verify`). --- From 43f19247b1582d128b856530ac84f39ed0825b3e Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Sun, 10 Jul 2022 00:13:30 -0400 Subject: [PATCH 06/11] add version --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 1fc7a61..c2a0257 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "zk-kit", "description": "A monorepo of reusable JS libraries for zero-knowledge technologies.", + "version": "0.1.1", "license": "MIT", "repository": "git@github.com:privacy-scaling-explorations/zk-kit.git", "homepage": "https://github.com/privacy-scaling-explorations/zk-kit", From 299c522ba9aa74102f8da3e3ca28e46eac36093c Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Sun, 10 Jul 2022 00:20:20 -0400 Subject: [PATCH 07/11] update @zk-kit/incremental-merkle-tree.sol readme --- .../contracts/README.md | 14 ++++++++++++++ .../contracts/test/IncrementalBinaryTreeTest.sol | 1 + 2 files changed, 15 insertions(+) diff --git a/packages/incremental-merkle-tree.sol/contracts/README.md b/packages/incremental-merkle-tree.sol/contracts/README.md index b67eb80..4fc6260 100644 --- a/packages/incremental-merkle-tree.sol/contracts/README.md +++ b/packages/incremental-merkle-tree.sol/contracts/README.md @@ -74,6 +74,7 @@ contract Example { event TreeCreated(bytes32 id, uint8 depth); event LeafInserted(bytes32 indexed treeId, uint256 leaf, uint256 root); + event LeadUpdated(bytes32 indexed treeId, uint256 leaf, uint256 root); event LeafRemoved(bytes32 indexed treeId, uint256 leaf, uint256 root); mapping(bytes32 => IncrementalTreeData) public trees; @@ -94,6 +95,19 @@ contract Example { emit LeafInserted(_treeId, _leaf, trees[_treeId].root); } + function updateLeaf( + bytes32 _treeId, + uint256 _leaf, + uint256[] calldata _proofSiblings, + uint8[] calldata _proofPathIndices + ) external { + require(trees[_treeId].depth != 0, "Example: tree does not exist"); + + trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); + + emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); + } + function removeLeaf( bytes32 _treeId, uint256 _leaf, diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol index d3c97c9..aeb6bc5 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol @@ -37,6 +37,7 @@ contract IncrementalBinaryTreeTest { uint8[] calldata _proofPathIndices ) external { require(trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist"); + trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); From dd002e51fec75a89a2e4328a98c774361d21c157 Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Mon, 11 Jul 2022 14:51:34 -0400 Subject: [PATCH 08/11] prettier 2 --- packages/incremental-merkle-tree.sol/contracts/README.md | 2 +- .../contracts/test/IncrementalBinaryTreeTest.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/README.md b/packages/incremental-merkle-tree.sol/contracts/README.md index 4fc6260..03d769a 100644 --- a/packages/incremental-merkle-tree.sol/contracts/README.md +++ b/packages/incremental-merkle-tree.sol/contracts/README.md @@ -102,7 +102,7 @@ contract Example { uint8[] calldata _proofPathIndices ) external { require(trees[_treeId].depth != 0, "Example: tree does not exist"); - + trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol index aeb6bc5..85e54b6 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol @@ -37,7 +37,7 @@ contract IncrementalBinaryTreeTest { uint8[] calldata _proofPathIndices ) external { require(trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist"); - + trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); From 62ee8bf642047db2e984a727aab89279487da258 Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Fri, 15 Jul 2022 15:52:51 -0400 Subject: [PATCH 09/11] add previous leaf verification to update function --- .../contracts/IncrementalBinaryTree.sol | 12 ++++++---- .../contracts/IncrementalQuinTree.sol | 12 ++++++---- .../test/IncrementalBinaryTreeTest.sol | 4 ++-- .../test/IncrementalQuinTreeTest.sol | 4 ++-- .../test/IncrementalBinaryTreeTest.ts | 24 ++++++++++++++++--- .../test/IncrementalQuinTreeTest.ts | 19 ++++++++++++--- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol index 3b5052e..1e1c867 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol @@ -71,18 +71,22 @@ library IncrementalBinaryTree { /// @dev Updates a leaf in the tree. /// @param self: Tree data. - /// @param leaf: Leaf to be updated. + /// @param leaf: [0] = existing leaf to replace, [1] = new leaf to insert /// @param proofSiblings: Array of the sibling nodes of the proof of membership. /// @param proofPathIndices: Path of the proof of membership. function update( IncrementalTreeData storage self, - uint256 leaf, + uint256[2] calldata leaf, uint256[] calldata proofSiblings, uint8[] calldata proofPathIndices ) public { - require(leaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); + require( + verify(self, leaf[0], proofSiblings, proofPathIndices), + "IncrementalBinaryTree: provided current leaf not found" + ); + require(leaf[1] < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); - uint256 hash = leaf; + uint256 hash = leaf[1]; for (uint8 i = 0; i < self.depth; i++) { if (proofPathIndices[i] == 0) { if (proofSiblings[i] == self.lastSubtrees[i][1]) { diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol index 5d9109c..c85a9b8 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol @@ -81,18 +81,22 @@ library IncrementalQuinTree { /// @dev Updates a leaf in the tree. /// @param self: Tree data. - /// @param leaf: Leaf to be updated. + /// @param leaf: [0] = existing leaf to replace, [1] = new leaf to insert /// @param proofSiblings: Array of the sibling nodes of the proof of membership. /// @param proofPathIndices: Path of the proof of membership. function update( IncrementalTreeData storage self, - uint256 leaf, + uint256[2] calldata leaf, uint256[4][] calldata proofSiblings, uint8[] calldata proofPathIndices ) public { - require(leaf < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); + require( + verify(self, leaf[0], proofSiblings, proofPathIndices), + "IncrementalQuinTree: provided current leaf not found" + ); + require(leaf[1] < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); - uint256 hash = leaf; + uint256 hash = leaf[1]; for (uint8 i = 0; i < self.depth; i++) { uint256[5] memory nodes; diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol index 85e54b6..d3c12d6 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol @@ -32,7 +32,7 @@ contract IncrementalBinaryTreeTest { function updateLeaf( bytes32 _treeId, - uint256 _leaf, + uint256[2] calldata _leaf, uint256[] calldata _proofSiblings, uint8[] calldata _proofPathIndices ) external { @@ -40,7 +40,7 @@ contract IncrementalBinaryTreeTest { trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); - emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); + emit LeafUpdated(_treeId, _leaf[1], trees[_treeId].root); } function removeLeaf( diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol index 090af54..1cf1dfc 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol @@ -32,7 +32,7 @@ contract IncrementalQuinTreeTest { function updateLeaf( bytes32 _treeId, - uint256 _leaf, + uint256[2] calldata _leaf, uint256[4][] calldata _proofSiblings, uint8[] calldata _proofPathIndices ) external { @@ -40,7 +40,7 @@ contract IncrementalQuinTreeTest { trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); - emit LeafUpdated(_treeId, _leaf, trees[_treeId].root); + emit LeafUpdated(_treeId, _leaf[1], trees[_treeId].root); } function removeLeaf( diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts index b0ad131..0c2072f 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts @@ -86,7 +86,7 @@ describe("IncrementalBinaryTreeTest", () => { it("Should not update a leaf if the tree does not exist", async () => { const treeId = ethers.utils.formatBytes32String("none") - const transaction = contract.updateLeaf(treeId, leaf, [0, 1], [0, 1]) + const transaction = contract.updateLeaf(treeId, [leaf, leaf], [0, 1], [0, 1]) await expect(transaction).to.be.revertedWith("BinaryTreeTest: tree does not exist") }) @@ -94,11 +94,29 @@ describe("IncrementalBinaryTreeTest", () => { it("Should not update a leaf if its value is > SNARK_SCALAR_FIELD", async () => { const leaf = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495618") - const transaction = contract.updateLeaf(treeId, leaf, [0, 1], [0, 1]) + const transaction = contract.updateLeaf(treeId, [leaf, leaf], [0, 1], [0, 1]) await expect(transaction).to.be.revertedWith("IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD") }) + it("Should not update a leaf if wrong current leaf is given", async () => { + const treeId = ethers.utils.formatBytes32String("tree2") + const tree = createTree(depth, 0) + for (let i = 0; i < 4; i += 1) tree.insert(BigInt(i + 1)) + + const leaf = BigInt(1337) + tree.update(2, leaf) + const { pathIndices, siblings } = tree.createProof(2) + const transaction = contract.updateLeaf( + treeId, + [leaf, leaf], + siblings.map((s) => s[0]), + pathIndices + ) + + await expect(transaction).to.be.revertedWith("IncrementalBinaryTree: provided current leaf not found") + }) + it("Should update a leaf", async () => { const treeId = ethers.utils.formatBytes32String("tree2") const tree = createTree(depth, 0) @@ -109,7 +127,7 @@ describe("IncrementalBinaryTreeTest", () => { const { root, pathIndices, siblings } = tree.createProof(2) const transaction = contract.updateLeaf( treeId, - leaf, + [BigInt(3), leaf], siblings.map((s) => s[0]), pathIndices ) diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts index 97bb78c..74dcede 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts @@ -89,7 +89,7 @@ describe("IncrementalQuinTreeTest", () => { it("Should not update a leaf if the tree does not exist", async () => { const treeId = ethers.utils.formatBytes32String("none") - const transaction = contract.updateLeaf(treeId, leaf, [[0, 1, 2, 3]], [0]) + const transaction = contract.updateLeaf(treeId, [leaf, leaf], [[0, 1, 2, 3]], [0]) await expect(transaction).to.be.revertedWith("QuinTreeTest: tree does not exist") }) @@ -97,11 +97,24 @@ describe("IncrementalQuinTreeTest", () => { it("Should not update a leaf if its value is > SNARK_SCALAR_FIELD", async () => { const leaf = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495618") - const transaction = contract.updateLeaf(treeId, leaf, [[0, 1, 2, 3]], [0]) + const transaction = contract.updateLeaf(treeId, [leaf, leaf], [[0, 1, 2, 3]], [0]) await expect(transaction).to.be.revertedWith("IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD") }) + it("Should not update a leaf if wrong current leaf is given", async () => { + const treeId = ethers.utils.formatBytes32String("tree2") + const tree = createTree(depth, 0, 5) + for (let i = 0; i < 6; i += 1) tree.insert(BigInt(i + 1)) + + const leaf = BigInt(1337) + tree.update(2, leaf) + const { pathIndices, siblings } = tree.createProof(2) + const transaction = contract.updateLeaf(treeId, [leaf, leaf], siblings, pathIndices) + + await expect(transaction).to.be.revertedWith("IncrementalQuinTree: provided current leaf not found") + }) + it("Should update a leaf", async () => { const treeId = ethers.utils.formatBytes32String("tree2") const tree = createTree(depth, 0, 5) @@ -110,7 +123,7 @@ describe("IncrementalQuinTreeTest", () => { const leaf = BigInt(1337) tree.update(2, leaf) const { pathIndices, siblings, root } = tree.createProof(2) - const transaction = contract.updateLeaf(treeId, leaf, siblings, pathIndices) + const transaction = contract.updateLeaf(treeId, [BigInt(3), leaf], siblings, pathIndices) await expect(transaction).to.emit(contract, "LeafUpdated").withArgs(treeId, leaf, root) }) From acabc97cecd4e4664c041c3e082042ce04ae1d86 Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Fri, 15 Jul 2022 15:55:14 -0400 Subject: [PATCH 10/11] remove package version --- .../contracts/test/IncrementalBinaryTreeTest.sol | 7 ++++--- .../contracts/test/IncrementalQuinTreeTest.sol | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol index d3c12d6..95e863a 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalBinaryTreeTest.sol @@ -32,15 +32,16 @@ contract IncrementalBinaryTreeTest { function updateLeaf( bytes32 _treeId, - uint256[2] calldata _leaf, + uint256 _leaf, + uint256 _newLeaf, uint256[] calldata _proofSiblings, uint8[] calldata _proofPathIndices ) external { require(trees[_treeId].depth != 0, "BinaryTreeTest: tree does not exist"); - trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); + trees[_treeId].update(_leaf, _newLeaf, _proofSiblings, _proofPathIndices); - emit LeafUpdated(_treeId, _leaf[1], trees[_treeId].root); + emit LeafUpdated(_treeId, _newLeaf, trees[_treeId].root); } function removeLeaf( diff --git a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol index 1cf1dfc..be65cea 100644 --- a/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol +++ b/packages/incremental-merkle-tree.sol/contracts/test/IncrementalQuinTreeTest.sol @@ -32,15 +32,16 @@ contract IncrementalQuinTreeTest { function updateLeaf( bytes32 _treeId, - uint256[2] calldata _leaf, + uint256 _leaf, + uint256 _newLeaf, uint256[4][] calldata _proofSiblings, uint8[] calldata _proofPathIndices ) external { require(trees[_treeId].depth != 0, "QuinTreeTest: tree does not exist"); - trees[_treeId].update(_leaf, _proofSiblings, _proofPathIndices); + trees[_treeId].update(_leaf, _newLeaf, _proofSiblings, _proofPathIndices); - emit LeafUpdated(_treeId, _leaf[1], trees[_treeId].root); + emit LeafUpdated(_treeId, _newLeaf, trees[_treeId].root); } function removeLeaf( From 9d74c4eff766203dd2a2765fcef82ad6cc54cf1b Mon Sep 17 00:00:00 2001 From: Jack Gilcrest Date: Fri, 15 Jul 2022 16:01:00 -0400 Subject: [PATCH 11/11] update api according to git comment specs --- .../contracts/IncrementalBinaryTree.sol | 14 ++++++++------ .../contracts/IncrementalQuinTree.sol | 14 ++++++++------ .../test/IncrementalBinaryTreeTest.ts | 12 +++++++----- .../test/IncrementalQuinTreeTest.ts | 10 +++++----- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol index 1e1c867..098baac 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalBinaryTree.sol @@ -71,22 +71,24 @@ library IncrementalBinaryTree { /// @dev Updates a leaf in the tree. /// @param self: Tree data. - /// @param leaf: [0] = existing leaf to replace, [1] = new leaf to insert + /// @param leaf: Leaf to be updated. + /// @param newLeaf: New leaf. /// @param proofSiblings: Array of the sibling nodes of the proof of membership. /// @param proofPathIndices: Path of the proof of membership. function update( IncrementalTreeData storage self, - uint256[2] calldata leaf, + uint256 leaf, + uint256 newLeaf, uint256[] calldata proofSiblings, uint8[] calldata proofPathIndices ) public { require( - verify(self, leaf[0], proofSiblings, proofPathIndices), - "IncrementalBinaryTree: provided current leaf not found" + verify(self, leaf, proofSiblings, proofPathIndices), + "IncrementalBinaryTree: leaf is not part of the tree" ); - require(leaf[1] < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); + require(newLeaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD"); - uint256 hash = leaf[1]; + uint256 hash = newLeaf; for (uint8 i = 0; i < self.depth; i++) { if (proofPathIndices[i] == 0) { if (proofSiblings[i] == self.lastSubtrees[i][1]) { diff --git a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol index c85a9b8..c294cb3 100644 --- a/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol +++ b/packages/incremental-merkle-tree.sol/contracts/IncrementalQuinTree.sol @@ -81,22 +81,24 @@ library IncrementalQuinTree { /// @dev Updates a leaf in the tree. /// @param self: Tree data. - /// @param leaf: [0] = existing leaf to replace, [1] = new leaf to insert + /// @param leaf: Leaf to be updated. + /// @param newLeaf: New leaf. /// @param proofSiblings: Array of the sibling nodes of the proof of membership. /// @param proofPathIndices: Path of the proof of membership. function update( IncrementalTreeData storage self, - uint256[2] calldata leaf, + uint256 leaf, + uint256 newLeaf, uint256[4][] calldata proofSiblings, uint8[] calldata proofPathIndices ) public { require( - verify(self, leaf[0], proofSiblings, proofPathIndices), - "IncrementalQuinTree: provided current leaf not found" + verify(self, leaf, proofSiblings, proofPathIndices), + "IncrementalQuinTree: leaf is not part of the tree" ); - require(leaf[1] < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); + require(newLeaf < SNARK_SCALAR_FIELD, "IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD"); - uint256 hash = leaf[1]; + uint256 hash = newLeaf; for (uint8 i = 0; i < self.depth; i++) { uint256[5] memory nodes; diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts index 0c2072f..a96e1fc 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalBinaryTreeTest.ts @@ -86,7 +86,7 @@ describe("IncrementalBinaryTreeTest", () => { it("Should not update a leaf if the tree does not exist", async () => { const treeId = ethers.utils.formatBytes32String("none") - const transaction = contract.updateLeaf(treeId, [leaf, leaf], [0, 1], [0, 1]) + const transaction = contract.updateLeaf(treeId, leaf, leaf, [0, 1], [0, 1]) await expect(transaction).to.be.revertedWith("BinaryTreeTest: tree does not exist") }) @@ -94,7 +94,7 @@ describe("IncrementalBinaryTreeTest", () => { it("Should not update a leaf if its value is > SNARK_SCALAR_FIELD", async () => { const leaf = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495618") - const transaction = contract.updateLeaf(treeId, [leaf, leaf], [0, 1], [0, 1]) + const transaction = contract.updateLeaf(treeId, leaf, leaf, [0, 1], [0, 1]) await expect(transaction).to.be.revertedWith("IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD") }) @@ -109,12 +109,13 @@ describe("IncrementalBinaryTreeTest", () => { const { pathIndices, siblings } = tree.createProof(2) const transaction = contract.updateLeaf( treeId, - [leaf, leaf], + leaf, + leaf, siblings.map((s) => s[0]), pathIndices ) - await expect(transaction).to.be.revertedWith("IncrementalBinaryTree: provided current leaf not found") + await expect(transaction).to.be.revertedWith("IncrementalBinaryTree: leaf is not part of the tree") }) it("Should update a leaf", async () => { @@ -127,7 +128,8 @@ describe("IncrementalBinaryTreeTest", () => { const { root, pathIndices, siblings } = tree.createProof(2) const transaction = contract.updateLeaf( treeId, - [BigInt(3), leaf], + BigInt(3), + leaf, siblings.map((s) => s[0]), pathIndices ) diff --git a/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts b/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts index 74dcede..32556d4 100644 --- a/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts +++ b/packages/incremental-merkle-tree.sol/test/IncrementalQuinTreeTest.ts @@ -89,7 +89,7 @@ describe("IncrementalQuinTreeTest", () => { it("Should not update a leaf if the tree does not exist", async () => { const treeId = ethers.utils.formatBytes32String("none") - const transaction = contract.updateLeaf(treeId, [leaf, leaf], [[0, 1, 2, 3]], [0]) + const transaction = contract.updateLeaf(treeId, leaf, leaf, [[0, 1, 2, 3]], [0]) await expect(transaction).to.be.revertedWith("QuinTreeTest: tree does not exist") }) @@ -97,7 +97,7 @@ describe("IncrementalQuinTreeTest", () => { it("Should not update a leaf if its value is > SNARK_SCALAR_FIELD", async () => { const leaf = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495618") - const transaction = contract.updateLeaf(treeId, [leaf, leaf], [[0, 1, 2, 3]], [0]) + const transaction = contract.updateLeaf(treeId, leaf, leaf, [[0, 1, 2, 3]], [0]) await expect(transaction).to.be.revertedWith("IncrementalQuinTree: leaf must be < SNARK_SCALAR_FIELD") }) @@ -110,9 +110,9 @@ describe("IncrementalQuinTreeTest", () => { const leaf = BigInt(1337) tree.update(2, leaf) const { pathIndices, siblings } = tree.createProof(2) - const transaction = contract.updateLeaf(treeId, [leaf, leaf], siblings, pathIndices) + const transaction = contract.updateLeaf(treeId, leaf, leaf, siblings, pathIndices) - await expect(transaction).to.be.revertedWith("IncrementalQuinTree: provided current leaf not found") + await expect(transaction).to.be.revertedWith("IncrementalQuinTree: leaf is not part of the tree") }) it("Should update a leaf", async () => { @@ -123,7 +123,7 @@ describe("IncrementalQuinTreeTest", () => { const leaf = BigInt(1337) tree.update(2, leaf) const { pathIndices, siblings, root } = tree.createProof(2) - const transaction = contract.updateLeaf(treeId, [BigInt(3), leaf], siblings, pathIndices) + const transaction = contract.updateLeaf(treeId, BigInt(3), leaf, siblings, pathIndices) await expect(transaction).to.emit(contract, "LeafUpdated").withArgs(treeId, leaf, root) })