Skip to content

Commit 8f6a8d1

Browse files
authored
Merge pull request #1 from webb-tools/fixes
Updates / small fixes
2 parents ef4a03c + 017ab70 commit 8f6a8d1

File tree

6 files changed

+193
-7
lines changed

6 files changed

+193
-7
lines changed

circuits/manyMerkleTree.circom

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ template DualMux() {
5353
// pathIndices input is an array of 0/1 selectors telling whether given pathElement is on the left or right side of merkle path
5454
template ManyMerkleTreeChecker(levels, length) {
5555
signal input leaf;
56-
signal input root;
5756
signal input pathElements[levels];
5857
signal input pathIndices[levels];
5958
signal input roots[length];

contracts/Bridge.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ contract Bridge is Pausable, AccessControl, SafeMath {
356356
IUpdateExecute anchorHandler = IUpdateExecute(handler);
357357
anchorHandler.update(resourceID, destinationChainID, updateNonce, msg.sender, data);
358358

359-
emit Deposit(destinationChainID, resourceID, updateNonce);
359+
emit Update(destinationChainID, resourceID, updateNonce);
360360
}
361361

362362
/**

contracts/interfaces/IExecutor.sol

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Copyright 2021 Webb Technologies
3+
* SPDX-License-Identifier: LGPL-3.0-only
4+
*/
5+
6+
pragma solidity ^0.8.0;
7+
8+
/**
9+
@title Interface for handler contracts that support deposits and deposit executions.
10+
@author ChainSafe Systems.
11+
*/
12+
interface IExecutor {
13+
/**
14+
@notice It is intended that proposals are executed by the Bridge contract.
15+
@param data Consists of additional data needed for a specific deposit execution.
16+
*/
17+
function executeProposal(bytes32 resourceID, bytes calldata data) external;
18+
}

contracts/trees/MerkleTreeMiMC.sol

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* Copyright 2021 Webb Technologies
3+
* SPDX-License-Identifier: LGPL-3.0-only
4+
*/
5+
6+
pragma solidity ^0.8.0;
7+
8+
import "./MerkleTreeWithHistory.sol";
9+
10+
contract MerkleTreeMiMC is MerkleTreeWithHistory {
11+
constructor(uint32 _levels, IHasher _hasher) MerkleTreeWithHistory(_levels, _hasher) {
12+
for (uint32 i = 0; i < _levels; i++) {
13+
filledSubtrees[i] = zeros(i);
14+
}
15+
16+
roots[0] = zeros(_levels - 1);
17+
}
18+
19+
/**
20+
@dev Hash 2 tree leaves, returns MiMC(_left, _right)
21+
*/
22+
function hashLeftRight(
23+
IHasher _hasher,
24+
bytes32 _left,
25+
bytes32 _right
26+
) override public pure returns (bytes32) {
27+
require(uint256(_left) < FIELD_SIZE, "_left should be inside the field");
28+
require(uint256(_right) < FIELD_SIZE, "_right should be inside the field");
29+
uint256 R = uint256(_left);
30+
uint256 C = 0;
31+
(R, C) = _hasher.hash(R, C);
32+
R = addmod(R, uint256(_right), FIELD_SIZE);
33+
(R, C) = _hasher.hash(R, C);
34+
return bytes32(R);
35+
}
36+
37+
/// @dev provides Zero (Empty) elements for a MiMC MerkleTree. Up to 32 levels
38+
function zeros(uint256 i) override public pure returns (bytes32) {
39+
if (i == 0) return bytes32(0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c);
40+
else if (i == 1) return bytes32(0x256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d);
41+
else if (i == 2) return bytes32(0x1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c200);
42+
else if (i == 3) return bytes32(0x20121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb);
43+
else if (i == 4) return bytes32(0x0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c9);
44+
else if (i == 5) return bytes32(0x24ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb54959);
45+
else if (i == 6) return bytes32(0x1ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c);
46+
else if (i == 7) return bytes32(0x19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4);
47+
else if (i == 8) return bytes32(0x261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff80);
48+
else if (i == 9) return bytes32(0x0058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c007);
49+
else if (i == 10) return bytes32(0x1f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e30);
50+
else if (i == 11) return bytes32(0x1bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e5);
51+
else if (i == 12) return bytes32(0x0ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f);
52+
else if (i == 13) return bytes32(0x1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd);
53+
else if (i == 14) return bytes32(0x133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb108);
54+
else if (i == 15) return bytes32(0x13e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b6);
55+
else if (i == 16) return bytes32(0x1eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db61854);
56+
else if (i == 17) return bytes32(0x0da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea);
57+
else if (i == 18) return bytes32(0x24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d);
58+
else if (i == 19) return bytes32(0x198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc05);
59+
else if (i == 20) return bytes32(0x29d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d4);
60+
else if (i == 21) return bytes32(0x19be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b2967);
61+
else if (i == 22) return bytes32(0x1ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc3453);
62+
else if (i == 23) return bytes32(0x10c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c48);
63+
else if (i == 24) return bytes32(0x0ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd1);
64+
else if (i == 25) return bytes32(0x019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c);
65+
else if (i == 26) return bytes32(0x2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce99);
66+
else if (i == 27) return bytes32(0x2eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f354);
67+
else if (i == 28) return bytes32(0x002df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d);
68+
else if (i == 29) return bytes32(0x104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f427);
69+
else if (i == 30) return bytes32(0x1f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb);
70+
else if (i == 31) return bytes32(0x2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc);
71+
else revert("Index out of bounds");
72+
}
73+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* Copyright 2021 Webb Technologies
3+
* SPDX-License-Identifier: LGPL-3.0-only
4+
*/
5+
6+
pragma solidity ^0.8.0;
7+
8+
interface IHasher {
9+
function hash(uint256 in_xL, uint256 in_xR) external pure returns (uint256 xL, uint256 xR);
10+
}
11+
12+
abstract contract MerkleTreeWithHistory {
13+
uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
14+
uint256 public constant ZERO_VALUE = 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE
15+
IHasher public immutable hasher;
16+
uint32 public immutable levels;
17+
18+
// the following variables are made public for easier testing and debugging and
19+
// are not supposed to be accessed in regular code
20+
21+
// filledSubtrees and roots could be bytes32[size], but using mappings makes it cheaper because
22+
// it removes index range check on every interaction
23+
mapping(uint256 => bytes32) public filledSubtrees;
24+
mapping(uint256 => bytes32) public roots;
25+
uint32 public constant ROOT_HISTORY_SIZE = 30;
26+
uint32 public currentRootIndex = 0;
27+
uint32 public nextIndex = 0;
28+
29+
constructor(uint32 _levels, IHasher _hasher) {
30+
require(_levels > 0, "_levels should be greater than zero");
31+
require(_levels < 32, "_levels should be less than 32");
32+
levels = _levels;
33+
hasher = _hasher;
34+
}
35+
36+
/** @dev this function is defined in a child contract */
37+
function hashLeftRight(IHasher _hasher, bytes32 _left, bytes32 _right) public virtual returns (bytes32);
38+
39+
function _insert(bytes32 _leaf) internal returns (uint32 index) {
40+
uint32 _nextIndex = nextIndex;
41+
require(_nextIndex != uint32(2)**levels, "Merkle tree is full. No more leaves can be added");
42+
uint32 currentIndex = _nextIndex;
43+
bytes32 currentLevelHash = _leaf;
44+
bytes32 left;
45+
bytes32 right;
46+
47+
for (uint32 i = 0; i < levels; i++) {
48+
if (currentIndex % 2 == 0) {
49+
left = currentLevelHash;
50+
right = zeros(i);
51+
filledSubtrees[i] = currentLevelHash;
52+
} else {
53+
left = filledSubtrees[i];
54+
right = currentLevelHash;
55+
}
56+
currentLevelHash = hashLeftRight(hasher, left, right);
57+
currentIndex /= 2;
58+
}
59+
60+
uint32 newRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE;
61+
currentRootIndex = newRootIndex;
62+
roots[newRootIndex] = currentLevelHash;
63+
nextIndex = _nextIndex + 1;
64+
return _nextIndex;
65+
}
66+
67+
/**
68+
@dev Whether the root is present in the root history
69+
*/
70+
function isKnownRoot(bytes32 _root) public view returns (bool) {
71+
if (_root == 0) {
72+
return false;
73+
}
74+
uint32 _currentRootIndex = currentRootIndex;
75+
uint32 i = _currentRootIndex;
76+
do {
77+
if (_root == roots[i]) {
78+
return true;
79+
}
80+
if (i == 0) {
81+
i = ROOT_HISTORY_SIZE;
82+
}
83+
i--;
84+
} while (i != _currentRootIndex);
85+
return false;
86+
}
87+
88+
/**
89+
@dev Returns the last root
90+
*/
91+
function getLastRoot() public view returns (bytes32) {
92+
return roots[currentRootIndex];
93+
}
94+
95+
/** @dev this function is defined in a child contract */
96+
function zeros(uint256 i) public virtual pure returns (bytes32);
97+
}

test/merkleTree/MerkleTreeWithHistory.test.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,14 @@ contract('MerkleTreeWithHistory', (accounts) => {
6767
assert(MerkleTree.index_to_key('test', 5, 20), 'test_tree_5_20')
6868
});
6969

70-
it.only('tests insert', async () => {
71-
hasherInstance = await MiMC.new()
70+
it('tests insert', async () => {
71+
hasher = new hasherImpl()
7272
tree = new MerkleTree(2, null, prefix)
7373
await tree.insert(toFixedHex('5'))
7474
let { root, path_elements } = await tree.path(0);
75-
console.log(root, path_elements);
76-
const calculated_root = hasherInstance.MiMCSponge(
75+
const calculated_root = hasher.hash(
7776
null,
78-
hasherInstance.MiMCSponge(null, '5', path_elements[0]),
77+
hasher.hash(null, '5', path_elements[0]),
7978
path_elements[1]
8079
);
8180
// console.log(root)

0 commit comments

Comments
 (0)