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