Skip to content

Commit 41c785d

Browse files
committed
Merge pull request google#1061 from AlCutter/split_smt_and_verifiable_map
Split out VerifiableMap from SparseMerkleTree.
2 parents 72d5367 + 89ac279 commit 41c785d

File tree

8 files changed

+219
-66
lines changed

8 files changed

+219
-66
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
/cpp/merkletree/serial_hasher_test
5959
/cpp/merkletree/sparse_merkle_tree_test
6060
/cpp/merkletree/tree_hasher_test
61+
/cpp/merkletree/verifiable_map_test
6162
/cpp/monitor/database_test
6263
/cpp/monitoring/counter_test
6364
/cpp/monitoring/gauge_test

Makefile.am

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ TESTS = \
8989
cpp/merkletree/serial_hasher_test \
9090
cpp/merkletree/sparse_merkle_tree_test \
9191
cpp/merkletree/tree_hasher_test \
92+
cpp/merkletree/verifiable_map_test \
9293
cpp/monitor/database_test \
9394
cpp/monitoring/counter_test \
9495
cpp/monitoring/gauge_test \
@@ -163,6 +164,7 @@ cpp_libcore_a_SOURCES = \
163164
cpp/merkletree/serial_hasher.cc \
164165
cpp/merkletree/sparse_merkle_tree.cc \
165166
cpp/merkletree/tree_hasher.cc \
167+
cpp/merkletree/verifiable_map.cc \
166168
cpp/monitoring/gcm/exporter.cc \
167169
cpp/monitoring/monitoring.cc \
168170
cpp/monitoring/prometheus/exporter.cc \
@@ -773,6 +775,14 @@ cpp_merkletree_tree_hasher_test_SOURCES = \
773775
cpp/util/util.cc \
774776
cpp/merkletree/tree_hasher_test.cc
775777

778+
cpp_merkletree_verifiable_map_test_LDADD = \
779+
cpp/libcore.a \
780+
cpp/libtest.a \
781+
$(libevent_LIBS)
782+
cpp_merkletree_verifiable_map_test_SOURCES = \
783+
cpp/util/util.cc \
784+
cpp/merkletree/verifiable_map_test.cc
785+
776786
cpp_util_sync_task_test_LDADD = \
777787
cpp/libcore.a \
778788
cpp/libtest.a \

cpp/merkletree/sparse_merkle_tree.cc

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,11 @@ void SparseMerkleTree::EnsureHaveLevel(size_t level) {
4545
}
4646

4747

48-
void SparseMerkleTree::SetLeafByHash(const string& key, const string& data) {
49-
serial_hasher_->Reset();
50-
serial_hasher_->Update(key);
51-
return SetLeaf(PathFromBytes(serial_hasher_->Final()), data);
52-
}
53-
54-
5548
void SparseMerkleTree::SetLeaf(const Path& path, const string& data) {
5649
CHECK_EQ(treehasher_.DigestSize(), path.size());
5750
// Mark the tree dirty:
5851
root_hash_.clear();
52+
string leaf_hash(treehasher_.HashLeaf(data));
5953

6054
IndexType node_index(0);
6155
for (int depth(0); depth <= kDigestSizeBits; ++depth) {
@@ -64,29 +58,29 @@ void SparseMerkleTree::SetLeaf(const Path& path, const string& data) {
6458
auto it(tree_[depth].find(node_index));
6559
if (it == tree_[depth].end()) {
6660
CHECK(tree_[depth]
67-
.emplace(make_pair(node_index, TreeNode(path, data)))
61+
.emplace(make_pair(node_index, TreeNode(path, leaf_hash)))
6862
.second);
6963
return;
7064
} else if (it->second.type_ == TreeNode::INTERNAL) {
7165
// Mark the internal node hash dirty
72-
it->second.hash_.reset();
73-
} else if (it->second.leaf_->path_ == path) {
66+
it->second.hash_.clear();
67+
} else if (*it->second.path_ == path) {
7468
// replacement
7569
CHECK_EQ(TreeNode::LEAF, it->second.type_);
76-
it->second.leaf_->value_ = data;
70+
it->second.hash_ = std::move(leaf_hash);
7771
return;
7872
} else {
7973
// restructure: push the existing node down a level and replace this one
8074
// with an INTERNAL node
8175
CHECK_LT(depth, kDigestSizeBits);
8276
EnsureHaveLevel(depth + 1);
8377
IndexType child_index((node_index << 1) +
84-
PathBit(it->second.leaf_->path_, depth + 1));
78+
PathBit(*it->second.path_, depth + 1));
8579
CHECK(tree_[depth + 1]
8680
.emplace(make_pair(child_index, std::move(it->second)))
8781
.second);
8882
it->second.type_ = TreeNode::INTERNAL;
89-
it->second.leaf_.reset();
83+
it->second.hash_.clear();
9084
}
9185
node_index <<= 1;
9286
}
@@ -129,22 +123,21 @@ string SparseMerkleTree::CalculateSubtreeHash(size_t depth, IndexType index) {
129123
if (it != tree_[depth].end()) {
130124
switch (it->second.type_) {
131125
case TreeNode::INTERNAL: {
132-
if (it->second.hash_) {
133-
return *(it->second.hash_);
126+
if (!it->second.hash_.empty()) {
127+
return it->second.hash_;
134128
}
135129
IndexType left_child_index(index << 1);
136130
const string left(CalculateSubtreeHash(depth + 1, left_child_index));
137131
const string right(
138132
CalculateSubtreeHash(depth + 1, left_child_index + 1));
139-
it->second.hash_.reset(
140-
new string(treehasher_.HashChildren(left, right)));
141-
return *(it->second.hash_);
133+
it->second.hash_.assign(treehasher_.HashChildren(left, right));
134+
return it->second.hash_;
142135
}
143136

144137
case TreeNode::LEAF: {
145-
string ret(treehasher_.HashLeaf(it->second.leaf_->value_));
138+
string ret(it->second.hash_);
146139
for (int i(kDigestSizeBits - 1); i > depth; --i) {
147-
if (PathBit(it->second.leaf_->path_, i) == 0) {
140+
if (PathBit(*(it->second.path_), i) == 0) {
148141
ret = treehasher_.HashChildren(ret, null_hashes_->at(i));
149142
} else {
150143
ret = treehasher_.HashChildren(null_hashes_->at(i), ret);
@@ -178,29 +171,28 @@ std::vector<string> SparseMerkleTree::InclusionProof(const Path& path) {
178171

179172
string SparseMerkleTree::TreeNode::DebugString() const {
180173
ostringstream os;
181-
os << "[TreeNode ";
174+
os << "[TreeNode type: ";
182175
switch (type_) {
183176
case INTERNAL:
184-
os << "INTL hash: ";
185-
if (hash_) {
186-
os << util::ToBase64(*hash_);
187-
} else {
188-
os << "(unset)";
189-
}
177+
os << "I";
190178
break;
191179
case LEAF:
192-
os << "LEAF leaf: ";
193-
os << leaf_->DebugString();
180+
os << "L";
194181
break;
195182
}
196-
os << "]";
197-
return os.str();
198-
}
199183

184+
os << " hash: ";
185+
if (!hash_.empty()) {
186+
os << util::ToBase64(hash_);
187+
} else {
188+
os << "(unset)";
189+
}
200190

201-
string SparseMerkleTree::Leaf::DebugString() const {
202-
ostringstream os;
203-
os << "[Leaf path: " << path_ << " value: " << value_ << "]";
191+
if (path_) {
192+
os << " path: ";
193+
os << *path_;
194+
}
195+
os << "]";
204196
return os.str();
205197
}
206198

cpp/merkletree/sparse_merkle_tree.h

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class SerialHasher;
2020
// Visible out here because it's useful for testing too.
2121
const std::vector<std::string>* GetNullHashes(const TreeHasher& hasher);
2222

23+
2324
// Implementation of a Sparse Merkle Tree.
2425
//
2526
// The design is inspired by the tree described in
@@ -146,13 +147,6 @@ class SparseMerkleTree {
146147
return treehasher_.HashLeaf(data);
147148
}
148149

149-
// Add a new leaf to the hash tree. Stores the hash of the leaf data in the
150-
// tree structure at path |Hash(key)|, does not store the data itself.
151-
//
152-
// @param data Binary input blob
153-
// @param path Binary path of node to set.
154-
virtual void SetLeafByHash(const std::string& key, const std::string& data);
155-
156150
// Add a new leaf to the hash tree. Stores the hash of the leaf data in the
157151
// tree structure, does not store the data itself.
158152
//
@@ -188,34 +182,19 @@ class SparseMerkleTree {
188182
// TODO(alcutter): BIGNUM probably.
189183
typedef uint64_t IndexType;
190184

191-
struct Leaf {
192-
Leaf(const Path& path, const std::string& value)
193-
: path_(path), value_(value) {
194-
}
195-
196-
std::string DebugString() const;
197-
198-
const Path path_;
199-
std::string value_;
200-
};
201-
202185
struct TreeNode {
203-
TreeNode() : type_(INTERNAL), hash_(nullptr) {
204-
}
205-
TreeNode(const std::string& hash)
206-
: type_(INTERNAL), hash_(new std::string(hash)) {
186+
TreeNode(const std::string& hash) : type_(INTERNAL), hash_(hash) {
207187
}
208188

209-
TreeNode(const Path& path, const std::string& leaf_value)
210-
: type_(LEAF), leaf_(new Leaf(path, leaf_value)) {
189+
TreeNode(const Path& path, const std::string& leaf_hash)
190+
: type_(LEAF), path_(new Path(path)), hash_(leaf_hash) {
211191
}
212192

213193
std::string DebugString() const;
214194

215195
enum { INTERNAL, LEAF } type_;
216-
// TODO(alcutter): sort this out
217-
std::unique_ptr<std::string> hash_;
218-
std::unique_ptr<Leaf> leaf_;
196+
std::unique_ptr<Path> path_;
197+
std::string hash_;
219198
};
220199

221200
std::string CalculateSubtreeHash(size_t depth, IndexType index);
@@ -260,4 +239,13 @@ inline int PathBit(const SparseMerkleTree::Path& path, size_t bit) {
260239
return (path[bit / 8] & (1 << (7 - bit % 8))) == 0 ? 0 : 1;
261240
}
262241

242+
243+
struct PathHasher {
244+
size_t operator()(const SparseMerkleTree::Path& p) const {
245+
return std::hash<std::string>()(
246+
std::string(reinterpret_cast<const char*>(p.data()), p.size()));
247+
}
248+
};
249+
250+
263251
#endif // CERT_TRANS_MERKLETREE_SPARSE_MERKLE_TREE_H

cpp/merkletree/sparse_merkle_tree_test.cc

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
namespace {
1616

1717
using cert_trans::ScopedBIGNUM;
18+
using std::fill;
1819
using std::lower_bound;
1920
using std::map;
2021
using std::mt19937;
@@ -192,6 +193,13 @@ class SparseMerkleTreeTest : public testing::Test {
192193
return ret;
193194
}
194195

196+
SparseMerkleTree::Path PathFromString(const string& s) {
197+
SparseMerkleTree::Path ret;
198+
CHECK_LE(s.size(), ret.size());
199+
fill(copy(s.begin(), s.end(), ret.begin()), ret.end(), 0);
200+
return ret;
201+
}
202+
195203
TreeHasher tree_hasher_;
196204
SparseMerkleTree tree_;
197205
mt19937 rand_;
@@ -311,22 +319,22 @@ TEST_F(SparseMerkleTreeTest, DISABLED_SMTMemTest) {
311319
}
312320

313321

314-
TEST_F(SparseMerkleTreeTest, TestSetLeafByHash) {
322+
TEST_F(SparseMerkleTreeTest, TestSetLeaf) {
315323
tree_.CurrentRoot();
316324
LOG(INFO) << "Tree@0:";
317325
LOG(INFO) << tree_.Dump();
318326

319-
tree_.SetLeafByHash("one", "one");
327+
tree_.SetLeaf(PathFromString("one"), "one");
320328
tree_.CurrentRoot();
321329
LOG(INFO) << "Tree@1:";
322330
LOG(INFO) << tree_.Dump();
323331

324-
tree_.SetLeafByHash("two", "two");
332+
tree_.SetLeaf(PathFromString("two"), "two");
325333
tree_.CurrentRoot();
326334
LOG(INFO) << "Tree@2:";
327335
LOG(INFO) << tree_.Dump();
328336

329-
tree_.SetLeafByHash("three", "three");
337+
tree_.SetLeaf(PathFromString("three"), "three");
330338
tree_.CurrentRoot();
331339
LOG(INFO) << "Tree@3:";
332340
LOG(INFO) << tree_.Dump();

cpp/merkletree/verifiable_map.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include <array>
2+
#include <string>
3+
4+
#include "merkletree/verifiable_map.h"
5+
6+
7+
using std::string;
8+
using std::unique_ptr;
9+
using std::vector;
10+
using util::Status;
11+
using util::StatusOr;
12+
13+
14+
namespace cert_trans {
15+
16+
17+
VerifiableMap::VerifiableMap(SerialHasher* hasher)
18+
: hasher_model_(CHECK_NOTNULL(hasher)->Create()), merkle_tree_(hasher) {
19+
}
20+
21+
22+
void VerifiableMap::Set(const string& key, const string& value) {
23+
const SparseMerkleTree::Path path(PathFromKey(key));
24+
merkle_tree_.SetLeaf(path, value);
25+
values_[path] = value;
26+
}
27+
28+
29+
StatusOr<string> VerifiableMap::Get(const string& key) const {
30+
const SparseMerkleTree::Path path(PathFromKey(key));
31+
const auto it(values_.find(path));
32+
if (it == values_.end()) {
33+
return Status(util::error::NOT_FOUND, "No such entry.");
34+
}
35+
return it->second;
36+
}
37+
38+
39+
vector<string> VerifiableMap::InclusionProof(const string& key) {
40+
return merkle_tree_.InclusionProof(PathFromKey(key));
41+
}
42+
43+
44+
SparseMerkleTree::Path VerifiableMap::PathFromKey(const string& key) const {
45+
unique_ptr<SerialHasher> h(hasher_model_->Create());
46+
h->Update(key);
47+
return PathFromBytes(h->Final());
48+
}
49+
50+
} // namespace cert_trans

cpp/merkletree/verifiable_map.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#ifndef CERT_TRANS_MERKLETREE_VERIFIABLE_MAP_H_
2+
#define CERT_TRANS_MERKLETREE_VERIFIABLE_MAP_H_
3+
4+
#include <string>
5+
#include <unordered_map>
6+
#include <vector>
7+
8+
#include "base/macros.h"
9+
#include "merkletree/sparse_merkle_tree.h"
10+
#include "util/statusor.h"
11+
12+
namespace cert_trans {
13+
14+
15+
// Implements a Verifiable Map using a SparseMerkleTree and hashmap.
16+
class VerifiableMap {
17+
public:
18+
VerifiableMap(SerialHasher* hasher);
19+
20+
std::string CurrentRoot() {
21+
return merkle_tree_.CurrentRoot();
22+
}
23+
24+
void Set(const std::string& key, const std::string& value);
25+
26+
util::StatusOr<std::string> Get(const std::string& key) const;
27+
28+
std::vector<std::string> InclusionProof(const std::string& key);
29+
30+
private:
31+
SparseMerkleTree::Path PathFromKey(const std::string& key) const;
32+
33+
std::unique_ptr<SerialHasher> hasher_model_;
34+
SparseMerkleTree merkle_tree_;
35+
36+
// TODO(alcutter): allow arbitrary stores here.
37+
std::unordered_map<SparseMerkleTree::Path, std::string, PathHasher> values_;
38+
39+
DISALLOW_COPY_AND_ASSIGN(VerifiableMap);
40+
};
41+
42+
43+
} // namespace cert_trans
44+
45+
#endif // CERT_TRANS_MERKLETREE_VERIFIABLE_MAP_H_

0 commit comments

Comments
 (0)