-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMerkleSumTree.sol
80 lines (65 loc) · 2.32 KB
/
MerkleSumTree.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
pragma solidity ^0.4.24;
contract MerkleSumTree {
function readUint64(bytes data, uint256 offset) private pure returns (uint64) {
offset += 32;
uint64 result;
assembly {result := div(mload(add(data, offset)), exp(256, 24))}
return result;
}
function readUint8(bytes data, uint256 offset) private pure returns (uint8) {
offset += 32;
uint8 result;
assembly {result := div(mload(add(data, offset)), exp(256, 31))}
return result;
}
function readBytes32(bytes data, uint256 offset) private pure returns (bytes32) {
offset += 32;
bytes32 result;
assembly {result := mload(add(data, offset))}
return result;
}
// Test case:
// proof: 0x000000000000000005efbde2c3aee204a69b7696d4b10ff31137fe78e3946306284f806e2dfc68b80500000000000000000adc1f2cbadf3cf42e13fed7a5bc239fe828329bb0dd8ef456bed7ab94dec6c5980100000000000000b49d7cdd4e64c94f59c5d4c7db419624f7f097c889a5cbdc59980a7fb83733fac7
// rootHash: 0x822d8b8f2bce6889851a8b3862e66ec578b8cf32439e16f26fd66617179008da
// rootSize: 200
// leafHash: 0x183a7d361ca1625fa85289cbdf578effaa4376f038587b9ab574e3fe80e5edc5
// leafStart: 15
// leafEnd: 20
function verify(
bytes proof,
bytes32 rootHash, uint64 rootSize,
bytes32 leafHash, uint64 leafStart, uint64 leafEnd
)
public
pure
returns (bool)
{
require(proof.length % 41 == 0, "Invalid proof.");
// Current bucket
uint64 currSize = leafEnd - leafStart;
bytes32 currHash = leafHash;
uint64 currStart = 0;
uint64 currEnd = rootSize;
uint8 bucketLeftOrRight;
uint64 bucketSize;
bytes32 bucketHash;
uint stepPos = 0;
while(stepPos < proof.length) {
bucketLeftOrRight = readUint8(proof, stepPos);
bucketSize = readUint64(proof, stepPos + 1);
bucketHash = readBytes32(proof, stepPos + 9);
if(bucketLeftOrRight == 0) {
currStart += bucketSize;
currHash = keccak256(abi.encodePacked(bucketSize, bucketHash, currSize, currHash));
}
else {
currEnd -= bucketSize;
currHash = keccak256(abi.encodePacked(currSize, currHash, bucketSize, bucketHash));
}
currSize = currSize + bucketSize;
stepPos += 41;
}
return currHash == rootHash && currSize == rootSize &&
currStart == leafStart && currEnd == leafEnd;
}
}