blob: be9c2d3d15de337cd72fc58a7fc93577fe7aa809 [file] [log] [blame]
Yingdi Yu0c3e5912015-03-17 14:22:38 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California
4 *
5 * This file is part of NSL (NDN Signature Logger).
6 * See AUTHORS.md for complete list of NSL authors and contributors.
7 *
8 * NSL is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * NSL, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of nsl authors and contributors.
20 */
21
22#include "sub-tree-binary.hpp"
23
24#include <ndn-cxx/util/digest.hpp>
25#include <ndn-cxx/util/crypto.hpp>
26#include <ndn-cxx/security/digest-sha256.hpp>
27
28namespace nsl {
29
30const time::milliseconds SubTreeBinary::INCOMPLETE_FRESHNESS_PERIOD(60000);
31const std::string SubTreeBinary::COMPONENT_COMPLETE("complete");
32const ssize_t SubTreeBinary::OFFSET_ROOTHASH = -1;
33const ssize_t SubTreeBinary::OFFSET_COMPLETE = -2;
34const ssize_t SubTreeBinary::OFFSET_SEQNO = -3;
35const ssize_t SubTreeBinary::OFFSET_LEVEL = -4;
36const size_t SubTreeBinary::N_LOGGER_SUFFIX = 4;
37const size_t SubTreeBinary::SUB_TREE_DEPTH = 6;
38
39
40SubTreeBinary::SubTreeBinary(const Name& loggerName,
41 const CompleteCallback& completeCallback,
42 const RootUpdateCallback& rootUpdateCallback)
43 : m_loggerName(loggerName)
44 , m_completeCallback(completeCallback)
45 , m_rootUpdateCallback(rootUpdateCallback)
46{
47}
48
49SubTreeBinary::SubTreeBinary(const Name& loggerName,
50 const Node::Index& peakIndex,
51 const CompleteCallback& completeCallback,
52 const RootUpdateCallback& rootUpdateCallback)
53 : m_loggerName(loggerName)
54 , m_completeCallback(completeCallback)
55 , m_rootUpdateCallback(rootUpdateCallback)
56{
57 initialize(peakIndex);
58}
59
60const NonNegativeInteger&
61SubTreeBinary::getNextLeafSeqNo() const
62{
63 if (m_actualRoot != nullptr)
64 return m_actualRoot->getLeafSeqNo();
65
66 return m_peakIndex.seqNo;
67}
68
69ndn::ConstBufferPtr
70SubTreeBinary::getRootHash() const
71{
72 if (m_actualRoot != nullptr)
73 return m_actualRoot->getHash();
74
75 return nullptr;
76}
77
78ConstNodePtr
79SubTreeBinary::getNode(const Node::Index& index) const
80{
81 auto it = m_nodes.find(index);
82 if (it != m_nodes.end()) {
83 return it->second;
84 }
85
86 return nullptr;
87}
88
89bool
90SubTreeBinary::addLeaf(NodePtr leaf)
91{
92 // sanity check: must be a valid leaf
93 if (leaf->getIndex().level != m_leafLevel ||
94 leaf->getIndex().seqNo < m_minSeqNo ||
95 leaf->getIndex().seqNo >= m_maxSeqNo)
96 return false;
97
98 // sanity check: must be the expected next leaf
99 if (leaf->getIndex().seqNo != m_pendingLeafSeqNo ||
100 !m_isPendingLeafEmpty)
101 return false;
102
103 // add the leaf
104 m_nodes[leaf->getIndex()] = leaf;
105
106 // update actual root (guarantee we will have a root)
107 updateActualRoot(leaf);
108
109 // update nodes and their hashes
110 updateParentNode(leaf);
111
112 if (leaf->isFull()) {
113 m_pendingLeafSeqNo = leaf->getIndex().seqNo + leaf->getIndex().range;
114 m_isPendingLeafEmpty = true;
115 }
116 else {
117 m_isPendingLeafEmpty = false;
118 }
119
120 return true;
121}
122
123bool
124SubTreeBinary::updateLeaf(const NonNegativeInteger& nextSeqNo, ndn::ConstBufferPtr hash)
125{
126 // std::cerr << "NextSeqNo: " << nextSeqNo << std::endl;
127 // std::cerr << "minSeqNo: " << m_minSeqNo << std::endl;
128 // std::cerr << "maxSeqNo: " << m_maxSeqNo << std::endl;
129
130 // sanity check
131 if (nextSeqNo < m_minSeqNo || nextSeqNo > m_maxSeqNo)
132 return false;
133
134 // std::cerr << "2" << std::endl;
135 // determine leaf index
136 NonNegativeInteger leafSeqNo = ((nextSeqNo - 1) >> m_leafLevel) << m_leafLevel;
137 if (m_pendingLeafSeqNo != leafSeqNo)
138 return false;
139
140 Node::Index index(leafSeqNo, m_leafLevel);
141 auto leaf = m_nodes[index];
142
143 if (leaf == nullptr) {
144 leaf = make_shared<Node>(leafSeqNo, m_leafLevel, nextSeqNo, hash);
145 m_nodes[index] = leaf;
146 updateActualRoot(leaf);
147 }
148 else {
149 leaf->setLeafSeqNo(nextSeqNo);
150 leaf->setHash(hash);
151 }
152
153 if (nextSeqNo == leafSeqNo + (1 << m_leafLevel)) {
154 m_pendingLeafSeqNo = nextSeqNo;
155 m_isPendingLeafEmpty = true;
156 }
157
158 updateParentNode(leaf);
159
160 return true;
161}
162
163bool
164SubTreeBinary::isFull() const
165{
166 if (m_actualRoot != nullptr &&
167 m_actualRoot->getIndex() == m_peakIndex &&
168 m_actualRoot->isFull())
169 return true;
170
171 return false;
172}
173
174shared_ptr<Data>
175SubTreeBinary::encode() const
176{
177 if (m_actualRoot == nullptr) {
178 auto emptyData = make_shared<Data>();
179 // Name
180 Name emptyName = m_loggerName;
181 emptyName.appendNumber(m_peakIndex.level)
182 .appendNumber(m_peakIndex.seqNo)
183 .appendNumber(m_peakIndex.seqNo)
184 .append(Node::getEmptyHash()->buf(), Node::getEmptyHash()->size());
185 emptyData->setName(emptyName);
186
187 // MetaInfo
188 emptyData->setFreshnessPeriod(time::milliseconds(0));
189
190 // Signature
191 ndn::DigestSha256 sig;
192 emptyData->setSignature(sig);
193
194 Block sigValue(tlv::SignatureValue,
195 ndn::crypto::sha256(emptyData->wireEncode().value(),
196 emptyData->wireEncode().value_size() -
197 emptyData->getSignature().getValue().size()));
198 emptyData->setSignatureValue(sigValue);
199
200 emptyData->wireEncode();
201
202 return emptyData;
203 }
204
205 // Name
206 Name dataName = m_loggerName;
207 dataName.appendNumber(m_actualRoot->getIndex().level)
208 .appendNumber(m_actualRoot->getIndex().seqNo);
209 if (isFull())
210 dataName.append(COMPONENT_COMPLETE.c_str());
211 else
212 dataName.appendNumber(m_actualRoot->getLeafSeqNo());
213 dataName.append(m_actualRoot->getHash()->buf(), m_actualRoot->getHash()->size());
214
215 auto data = make_shared<Data>(dataName);
216
217 // MetaInfo
218 if (!isFull())
219 data->setFreshnessPeriod(INCOMPLETE_FRESHNESS_PERIOD);
220
221 // Content
222 auto buffer = make_shared<ndn::Buffer>();
223 NonNegativeInteger range = 1 << m_leafLevel;
224 for (NonNegativeInteger i = m_minSeqNo; i < m_maxSeqNo; i += range) {
225 auto it = m_nodes.find(Node::Index(i, m_leafLevel));
226 if (it == m_nodes.end())
227 break;
228
229 auto leaf = it->second;
230 if (leaf == nullptr)
231 break;
232 BOOST_ASSERT(leaf->getHash() != nullptr);
233 BOOST_ASSERT(leaf->getHash()->size() == 32);
234 buffer->insert(buffer->end(), leaf->getHash()->begin(), leaf->getHash()->end());
235 }
236 data->setContent(buffer->buf(), buffer->size());
237
238 // Signature
239 ndn::DigestSha256 sig;
240 data->setSignature(sig);
241
242 Block sigValue(tlv::SignatureValue,
243 ndn::crypto::sha256(data->wireEncode().value(),
244 data->wireEncode().value_size() -
245 data->getSignature().getValue().size()));
246 data->setSignatureValue(sigValue);
247
248 data->wireEncode();
249 return data;
250}
251
252void
253SubTreeBinary::decode(const Data& data)
254{
255 bool isComplete = false;
256 NonNegativeInteger nextSeqNo;
257 ndn::ConstBufferPtr rootHash;
258 NonNegativeInteger seqNo;
259 size_t level;
260
261 const Name& dataName = data.getName();
262
263 if (!m_loggerName.isPrefixOf(dataName))
264 throw Error("decode: logger name does not match");
265
266 if (m_loggerName.size() + N_LOGGER_SUFFIX != dataName.size())
267 throw Error("decode: data name does not follow the naming convention");
268
269 try {
270 if (dataName.get(OFFSET_COMPLETE).toUri() == COMPONENT_COMPLETE)
271 isComplete = true;
272 else
273 nextSeqNo = dataName.get(OFFSET_COMPLETE).toNumber();
274
275 rootHash = make_shared<ndn::Buffer>(dataName.get(OFFSET_ROOTHASH).value(),
276 dataName.get(OFFSET_ROOTHASH).value_size());
277
278 seqNo = dataName.get(OFFSET_SEQNO).toNumber();
279 level = dataName.get(OFFSET_LEVEL).toNumber();
280 }
281 catch (tlv::Error&) {
282 throw Error("decode: logger name encoding error");
283 }
284
285 if (seqNo == 0) {
286 size_t peakLevel = 0;
287 if (level % (SUB_TREE_DEPTH - 1) != 0)
288 peakLevel = ((level + SUB_TREE_DEPTH - 1) / (SUB_TREE_DEPTH - 1)) * (SUB_TREE_DEPTH - 1);
289 else
290 peakLevel = level;
291
292 if (nextSeqNo == 1 << peakLevel)
293 peakLevel = peakLevel + SUB_TREE_DEPTH - 1;
294
295 initialize(Node::Index(seqNo, peakLevel));
296 }
297 else
298 initialize(Node::Index(seqNo, level));
299
300 if (isComplete)
301 nextSeqNo = seqNo + (1 << level);
302 else if (nextSeqNo == seqNo) // empty tree
303 return;
304
305 if (rootHash->size() != 32)
306 throw Error("decode: wrong root hash size");
307
308 if (nextSeqNo <= seqNo || nextSeqNo > seqNo + (1 << level))
309 throw Error("decode: wrong current leaf SeqNo");
310
311 int nLeaves = (nextSeqNo - seqNo - 1) / (1 << m_leafLevel) + 1;
312
313 // std::cerr << data.getName() << std::endl;
314 // std::cerr << nextSeqNo << std::endl;
315 // std::cerr << nLeaves * 32 << std::endl;
316 // std::cerr << data.getContent().value_size() << std::endl;
317
318 if (nLeaves * 32 != data.getContent().value_size())
319 throw Error("decode: inconsistent content");
320
321 const uint8_t* offset = data.getContent().value();
322 NonNegativeInteger seqNoInterval = 1 << m_leafLevel;
323 int i = 0;
324 for (; i < nLeaves - 1; i++) {
325 auto node = make_shared<Node>(seqNo + (i * seqNoInterval),
326 m_peakIndex.level + 1 - SUB_TREE_DEPTH,
327 seqNo + (i * seqNoInterval) + seqNoInterval,
328 make_shared<ndn::Buffer>(offset + (i * 32), 32));
329 addLeaf(node);
330 }
331
332 auto node = make_shared<Node>(seqNo + (i * seqNoInterval),
333 m_peakIndex.level + 1 - SUB_TREE_DEPTH,
334 nextSeqNo,
335 make_shared<ndn::Buffer>(offset + (i * 32), 32));
336 addLeaf(node);
337
338 if (*rootHash != *getRoot()->getHash())
339 throw Error("decode: Inconsistent hash");
340}
341
342Node::Index
343SubTreeBinary::toSubTreePeakIndex(const Node::Index& index, bool notRoot)
344{
345 size_t peakLevel =
346 ((index.level + SUB_TREE_DEPTH - 1) / (SUB_TREE_DEPTH - 1)) * (SUB_TREE_DEPTH - 1);
347
348 size_t leafLevel = peakLevel + 1 - SUB_TREE_DEPTH;
349
350 if (index.level % (SUB_TREE_DEPTH - 1) == 0 && index.level > 0 && !notRoot) {
351 peakLevel -= (SUB_TREE_DEPTH - 1);
352 leafLevel -= (SUB_TREE_DEPTH - 1);
353 }
354
355 NonNegativeInteger peakSeqNo = (index.seqNo >> peakLevel) << peakLevel;
356
357 return Node::Index(peakSeqNo, peakLevel);
358}
359
360void
361SubTreeBinary::initialize(const Node::Index& peakIndex)
362{
363 m_peakIndex = peakIndex;
364
365 if (peakIndex.level + 1 < SUB_TREE_DEPTH ||
366 peakIndex.level % (SUB_TREE_DEPTH - 1) != 0)
367 throw Error("SubTreeBinary: peak level does not match the depth");
368
369 m_leafLevel = peakIndex.level + 1 - SUB_TREE_DEPTH;
370
371 m_minSeqNo = peakIndex.seqNo;
372 m_maxSeqNo = peakIndex.seqNo + peakIndex.range;
373
374 m_pendingLeafSeqNo = m_minSeqNo;
375 m_isPendingLeafEmpty = true;
376}
377
378
379
380void
381SubTreeBinary::updateActualRoot(NodePtr node)
382{
383 if (m_actualRoot == nullptr) {
384 // if actual root is not set yet
385 if (node->getIndex().seqNo == 0) { // root sub-tree
386 m_actualRoot = node;
387 m_rootUpdateCallback(node->getIndex(), node->getLeafSeqNo(), node->getHash());
388 return;
389 }
390 else {
391 m_actualRoot = make_shared<Node>(m_peakIndex.seqNo, m_peakIndex.level);
392 m_nodes[m_actualRoot->getIndex()] = m_actualRoot;
393 return;
394 }
395 }
396
397 if (m_actualRoot->getIndex() == m_peakIndex)
398 return;
399
400 if ((node->getIndex().seqNo >> m_actualRoot->getIndex().level) != 0) {
401 // a new actual root at a higher is needed
402 m_actualRoot = make_shared<Node>(m_minSeqNo, m_actualRoot->getIndex().level + 1);
403 m_nodes[m_actualRoot->getIndex()] = m_actualRoot;
404 return;
405 }
406}
407
408void
409SubTreeBinary::updateParentNode(NodePtr node)
410{
411 if (node->getIndex() == m_actualRoot->getIndex()) { // root does not have a parent
412 return;
413 }
414
415 size_t parentLevel = node->getIndex().level + 1;
416 NodePtr parentNode;
417
418 if ((node->getIndex().seqNo >> node->getIndex().level) % 2 == 0) { // left child
419 // parent may not exist
420 Node::Index parentIndex(node->getIndex().seqNo, parentLevel);
421 parentNode = m_nodes[parentIndex];
422
423 ndn::util::Sha256 sha256;
424 sha256 << parentIndex.level << parentIndex.seqNo;
425 sha256.update(node->getHash()->buf(), node->getHash()->size());
426 sha256.update(Node::getEmptyHash()->buf(), Node::getEmptyHash()->size());
427
428 if (parentNode == nullptr) {
429 parentNode = make_shared<Node>(node->getIndex().seqNo,
430 parentLevel,
431 node->getLeafSeqNo(),
432 sha256.computeDigest());
433 }
434 else {
435 parentNode->setHash(sha256.computeDigest());
436 parentNode->setLeafSeqNo(node->getLeafSeqNo());
437 }
438
439 m_nodes[parentNode->getIndex()] = parentNode;
440 }
441 else { // right child
442 // parent must exist
443 NonNegativeInteger parentSeqNo = node->getIndex().seqNo - node->getIndex().range;
444
445 Node::Index parentIndex(parentSeqNo, parentLevel);
446 Node::Index siblingIndex(parentSeqNo, parentLevel - 1);
447
448 parentNode = m_nodes[parentIndex];
449 auto siblingNode = m_nodes[siblingIndex];
450
451 ndn::util::Sha256 sha256;
452 sha256 << parentNode->getIndex().level << parentNode->getIndex().seqNo;
453 sha256.update(siblingNode->getHash()->buf(), siblingNode->getHash()->size());
454 sha256.update(node->getHash()->buf(), node->getHash()->size());
455
456 parentNode->setHash(sha256.computeDigest());
457 parentNode->setLeafSeqNo(node->getLeafSeqNo());
458 }
459
460 if (parentNode->getIndex() == m_actualRoot->getIndex()) { // reach root
461 m_rootUpdateCallback(parentNode->getIndex(),
462 parentNode->getLeafSeqNo(),
463 parentNode->getHash());
464 if (parentNode->getIndex() == m_peakIndex && parentNode->isFull())
465 m_completeCallback(parentNode->getIndex());
466 }
467 else
468 updateParentNode(parentNode);
469}
470
471} // namespace nsl