Skip to content

Commit 12a3eb8

Browse files
committed
Added merkle proofs
1 parent e51af9e commit 12a3eb8

File tree

3 files changed

+86
-0
lines changed

3 files changed

+86
-0
lines changed

src/merkle.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "common.h"
1919
#include "keccak.h"
2020
#include "merkle.h"
21+
#include "keccak.h"
2122

2223
namespace p2pool {
2324

@@ -115,4 +116,81 @@ void merkle_hash_full_tree(const std::vector<hash>& hashes, std::vector<std::vec
115116
}
116117
}
117118

119+
bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h, std::vector<std::pair<bool, hash>>& proof)
120+
{
121+
if (tree.empty()) {
122+
return false;
123+
}
124+
125+
const std::vector<hash>& hashes = tree[0];
126+
const size_t count = hashes.size();
127+
128+
size_t index = 0;
129+
130+
while ((index < count) && (hashes[index] != h)) {
131+
++index;
132+
}
133+
134+
if (index >= count) {
135+
return false;
136+
}
137+
138+
proof.clear();
139+
140+
if (count == 1) {
141+
return true;
142+
}
143+
else if (count == 2) {
144+
proof.emplace_back(index != 0, hashes[index ^ 1]);
145+
}
146+
else {
147+
size_t cnt = 1;
148+
do { cnt <<= 1; } while (cnt <= count);
149+
cnt >>= 1;
150+
151+
const size_t k = cnt * 2 - count;
152+
153+
if (index >= k) {
154+
index -= k;
155+
const size_t j = (index ^ 1) + k;
156+
if (j >= count) {
157+
return false;
158+
}
159+
proof.emplace_back((index & 1) != 0, hashes[j]);
160+
index = (index >> 1) + k;
161+
}
162+
163+
const size_t n = tree.size();
164+
165+
for (size_t i = 1; cnt >= 2; ++i, index >>= 1, cnt >>= 1) {
166+
const size_t j = index ^ 1;
167+
if ((i >= n) || (j >= tree[i].size())) {
168+
return false;
169+
}
170+
proof.emplace_back((index & 1) != 0, tree[i][j]);
171+
}
172+
}
173+
174+
return true;
175+
}
176+
177+
bool verify_merkle_proof(hash h, const std::vector<std::pair<bool, hash>>& proof, const hash& root)
178+
{
179+
hash tmp[2];
180+
181+
for (size_t i = 0, n = proof.size(); i < n; ++i) {
182+
if (proof[i].first) {
183+
tmp[0] = proof[i].second;
184+
tmp[1] = h;
185+
}
186+
else {
187+
tmp[0] = h;
188+
tmp[1] = proof[i].second;
189+
}
190+
keccak(tmp[0].h, HASH_SIZE * 2, h.h);
191+
}
192+
193+
return (h == root);
194+
}
195+
118196
} // namespace p2pool

src/merkle.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ namespace p2pool {
2121

2222
void merkle_hash(const std::vector<hash>& hashes, hash& root);
2323
void merkle_hash_full_tree(const std::vector<hash>& hashes, std::vector<std::vector<hash>>& tree);
24+
bool get_merkle_proof(const std::vector<std::vector<hash>>& tree, const hash& h, std::vector<std::pair<bool, hash>>& proof);
25+
bool verify_merkle_proof(hash h, const std::vector<std::pair<bool, hash>>& proof, const hash& root);
2426

2527
} // namespace p2pool

tests/src/merkle_tests.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ TEST(merkle, root_hash)
6969
ASSERT_EQ(tmp, tree[i][j]);
7070
}
7171
}
72+
73+
for (const hash& h : hashes) {
74+
std::vector<std::pair<bool, hash>> proof;
75+
ASSERT_TRUE(get_merkle_proof(tree, h, proof));
76+
ASSERT_TRUE(verify_merkle_proof(h, proof, root));
77+
}
7278
};
7379

7480
// 1 leaf

0 commit comments

Comments
 (0)