Skip to content

Commit 9e392ad

Browse files
Merge pull request #75 from kleros/feat/merkle-library
Feat/merkle library
2 parents 4e5daa6 + 9d3c1d3 commit 9e392ad

File tree

4 files changed

+514
-0
lines changed

4 files changed

+514
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/**
4+
* @authors: [@shotaronowhere]
5+
* @reviewers: []
6+
* @auditors: []
7+
* @bounties: []
8+
* @deployments: []
9+
*/
10+
11+
pragma solidity ^0.8.0;
12+
13+
/**
14+
* @title MerkleProof
15+
* @author Shotaro N. - <shawtarohgn@gmail.com>
16+
* @dev A set of funcitons to verify merkle proofs.
17+
*/
18+
contract MerkleProof {
19+
/** @dev Validates membership of leaf in merkle tree with merkle proof.
20+
* @param proof The merkle proof.
21+
* @param leaf The leaf to validate membership in merkle tree.
22+
* @param merkleRoot The root of the merkle tree.
23+
*/
24+
function validateProof(
25+
bytes32[] memory proof,
26+
bytes32 leaf,
27+
bytes32 merkleRoot
28+
) internal pure returns (bool) {
29+
return (merkleRoot == calculateRoot(proof, leaf));
30+
}
31+
32+
/** @dev Validates membership of leaf in merkle tree with merkle proof.
33+
* @param proof The merkle proof.
34+
* @param data The data to validate membership in merkle tree.
35+
* @param merkleRoot The root of the merkle tree.
36+
*/
37+
function validateProof(
38+
bytes32[] memory proof,
39+
bytes memory data,
40+
bytes32 merkleRoot
41+
) public pure returns (bool) {
42+
return validateProof(proof, keccak256(data), merkleRoot);
43+
}
44+
45+
/** @dev Calculates merkle root from proof.
46+
* @param proof The merkle proof.
47+
* @param leaf The leaf to validate membership in merkle tree..
48+
*/
49+
function calculateRoot(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
50+
uint256 proofLength = proof.length;
51+
require(proofLength <= 64, "Invalid Proof");
52+
bytes32 h = leaf;
53+
for (uint256 i = 0; i < proofLength; i++) {
54+
bytes32 proofElement = proof[i];
55+
// effecient hash
56+
if (proofElement > h)
57+
assembly {
58+
mstore(0x00, h)
59+
mstore(0x20, proofElement)
60+
h := keccak256(0x00, 0x40)
61+
}
62+
else
63+
assembly {
64+
mstore(0x00, proofElement)
65+
mstore(0x20, h)
66+
h := keccak256(0x00, 0x40)
67+
}
68+
}
69+
return h;
70+
}
71+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/**
4+
* @authors: [@shotaronowhere]
5+
* @reviewers: []
6+
* @auditors: []
7+
* @bounties: []
8+
* @deployments: []
9+
*/
10+
11+
pragma solidity ^0.8.0;
12+
13+
/**
14+
* @title MerkleTreeHistory
15+
* @author Shotaro N. - <shawtarohgn@gmail.com>
16+
* @dev An efficient append only merkle tree with history.
17+
*/
18+
contract MerkleTreeHistory {
19+
// ***************************** //
20+
// * Storage * //
21+
// ***************************** //
22+
23+
// merkle tree representation
24+
// supports 2^64 messages.
25+
bytes32[64] public branch;
26+
uint256 public count;
27+
28+
// block number => merkle root history
29+
mapping(uint256 => bytes32) private history;
30+
31+
// ************************************* //
32+
// * State Modifiers * //
33+
// ************************************* //
34+
35+
/** @dev Append data into merkle tree.
36+
* `O(log(n))` where
37+
* `n` is the number of leaves.
38+
* Note: Although each insertion is O(log(n)),
39+
* Complexity of n insertions is O(n).
40+
* @param data The data to insert in the merkle tree.
41+
*/
42+
function append(bytes memory data) public {
43+
bytes32 leaf = keccak256(data);
44+
count += 1;
45+
uint256 size = count;
46+
uint256 hashBitField = (size ^ (size - 1)) & size;
47+
48+
for (uint256 height = 0; height < 64; height++) {
49+
if ((hashBitField & 1) == 1) {
50+
branch[height] = leaf;
51+
return;
52+
}
53+
bytes32 node = branch[height];
54+
// effecient hash
55+
if (node > leaf)
56+
assembly {
57+
mstore(0x00, leaf)
58+
mstore(0x20, node)
59+
leaf := keccak256(0x00, 0x40)
60+
}
61+
else
62+
assembly {
63+
mstore(0x00, node)
64+
mstore(0x20, leaf)
65+
leaf := keccak256(0x00, 0x40)
66+
}
67+
hashBitField /= 2;
68+
}
69+
}
70+
71+
/** @dev Saves the merkle root state in history and resets.
72+
* `O(log(n))` where
73+
* `n` is the number of leaves.
74+
*/
75+
function reset() internal {
76+
history[block.number] = getMerkleRoot();
77+
count = 0;
78+
}
79+
80+
/** @dev Gets the merkle root history
81+
* `O(log(n))` where
82+
* `n` is the number of leaves.
83+
* @param blocknumber requested blocknumber.
84+
*/
85+
function getMerkleRootHistory(uint256 blocknumber) public view returns (bytes32) {
86+
if (blocknumber == block.number) return getMerkleRoot();
87+
88+
return history[blocknumber];
89+
}
90+
91+
/** @dev Gets the current merkle root.
92+
* `O(log(n))` where
93+
* `n` is the number of leaves.
94+
*/
95+
function getMerkleRoot() public view returns (bytes32) {
96+
bytes32 node;
97+
uint256 size = count;
98+
uint256 height = 0;
99+
bool isFirstHash = true;
100+
while (size > 0) {
101+
// avoid redundant calculation
102+
if ((size & 1) == 1) {
103+
if (isFirstHash) {
104+
node = branch[height];
105+
isFirstHash = false;
106+
} else {
107+
bytes32 hash = branch[height];
108+
// effecient hash
109+
if (hash > node)
110+
assembly {
111+
mstore(0x00, node)
112+
mstore(0x20, hash)
113+
node := keccak256(0x00, 0x40)
114+
}
115+
else
116+
assembly {
117+
mstore(0x00, hash)
118+
mstore(0x20, node)
119+
node := keccak256(0x00, 0x40)
120+
}
121+
}
122+
}
123+
size /= 2;
124+
height++;
125+
}
126+
return node;
127+
}
128+
}

0 commit comments

Comments
 (0)