blob: 34f85d01d75bf97b171fa76af04a946370de1056 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014, Regents of the University of California
*
* This file is part of NSL (NDN Signature Logger).
* See AUTHORS.md for complete list of NSL authors and contributors.
*
* NSL is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NSL, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of nsl authors and contributors.
*/
#include "auditor.hpp"
#include <ndn-cxx/util/digest.hpp>
namespace nsl {
bool
Auditor::doesExist(const NonNegativeInteger& seqNo,
ndn::ConstBufferPtr hash,
const NonNegativeInteger& rootNextSeqNo,
ndn::ConstBufferPtr rootHash,
const std::vector<shared_ptr<Data>>& proofs,
const Name& loggerName)
{
BOOST_ASSERT(rootHash != nullptr);
BOOST_ASSERT(hash != nullptr);
std::map<Node::Index, ConstSubTreeBinaryPtr> trees;
if (!loadProof(trees, proofs, loggerName))
return false;
// std::cerr << "Loaded" << std::endl;
size_t rootLevel = 0;
NonNegativeInteger tmpSeqNo = rootNextSeqNo - 1;
while (tmpSeqNo != 0) {
rootLevel++;
tmpSeqNo = tmpSeqNo >> 1;
}
if (rootLevel == 0) { // only one node
// std::cerr << "one level" << std::endl;
if (seqNo != 0)
return false;
auto it = trees.find(Node::Index(0, SubTreeBinary::SUB_TREE_DEPTH - 1));
if (it != trees.end()) {
// std::cerr << "find subtree" << std::endl;
auto node = it->second->getNode(Node::Index(0, 0));
if (node != nullptr && *node->getHash() == *hash && *hash == *rootHash)
return true;
else
return false;
}
else
return false;
}
NonNegativeInteger childSeqMask = 1;
NonNegativeInteger childSeqNo = seqNo;
size_t childLevel = 0;
ndn::ConstBufferPtr childHash = hash;
NonNegativeInteger parentSeqMask = (~0) << 1;
NonNegativeInteger parentSeqNo = childSeqNo & parentSeqMask;
size_t parentLevel = 1;
Node::Index treePeakIndex(0, 0);
ConstSubTreeBinaryPtr subTree;
do { // get parent hash
Node::Index tmpIndex =
SubTreeBinary::toSubTreePeakIndex(Node::Index(childSeqNo, childLevel));
// std::cerr << "peak: " << tmpIndex.level << ", " << tmpIndex.seqNo << std::endl;
if (tmpIndex != treePeakIndex) {
treePeakIndex = tmpIndex;
auto it = trees.find(treePeakIndex);
if (it != trees.end() && it->second != nullptr) {
subTree = it->second;
}
else
return false;
}
// std::cerr << "Hey" << std::endl;
// right child or left child
ndn::util::Sha256 sha256;
if (childSeqMask & seqNo) { // right child
// std::cerr << "right" << std::endl;
// std::cerr << parentSeqNo << ", " << childLevel << std::endl;
auto leftChild = subTree->getNode(Node::Index(parentSeqNo, childLevel));
if (leftChild == nullptr && leftChild->getHash() == nullptr)
return false;
// std::cerr << "found node" << std::endl;
sha256 << parentLevel << parentSeqNo;
sha256.update(leftChild->getHash()->buf(), leftChild->getHash()->size());
sha256.update(childHash->buf(), childHash->size());
}
else { // left child
// std::cerr << "left" << std::endl;
ndn::ConstBufferPtr rightChildHash = Node::getEmptyHash();
if (rootNextSeqNo > childSeqNo + (1 << childLevel)) {
// std::cerr << childSeqNo + (1 << childLevel) << ", " << childLevel << std::endl;
auto rightChild = subTree->getNode(Node::Index(childSeqNo + (1 << childLevel), childLevel));
if (rightChild == nullptr || rightChild->getHash() == nullptr)
return false;
rightChildHash = rightChild->getHash();
// std::cerr << "left done" << std::endl;
}
sha256 << parentLevel << parentSeqNo;
sha256.update(childHash->buf(), childHash->size());
sha256.update(rightChildHash->buf(), rightChildHash->size());
}
childSeqMask = childSeqMask << 1;
childSeqNo = parentSeqNo;
childLevel = parentLevel;
childHash = sha256.computeDigest();
parentSeqMask = parentSeqMask << 1;
parentSeqNo = childSeqNo & parentSeqMask;
parentLevel++;
} while (childLevel < rootLevel);
// std::cerr << "done" << std::endl;
return (*childHash == *rootHash);
}
bool
Auditor::isConsistent(const NonNegativeInteger& oldRootNextSeqNo,
ndn::ConstBufferPtr oldRootHash,
const NonNegativeInteger& newRootNextSeqNo,
ndn::ConstBufferPtr newRootHash,
const std::vector<shared_ptr<Data>>& proofs,
const Name& loggerName)
{
BOOST_ASSERT(oldRootHash != nullptr);
BOOST_ASSERT(newRootHash != nullptr);
if (oldRootNextSeqNo > newRootNextSeqNo)
return false;
std::map<Node::Index, ConstSubTreeBinaryPtr> trees;
if (!loadProof(trees, proofs, loggerName))
return false;
// std::cerr << "1" << std::endl;
// get boundary leaf:
NonNegativeInteger leafSeqNo = oldRootNextSeqNo - 1;
NonNegativeInteger treeSeqNo = leafSeqNo & ((~0) << (SubTreeBinary::SUB_TREE_DEPTH - 1));
auto it = trees.find(Node::Index(treeSeqNo, SubTreeBinary::SUB_TREE_DEPTH - 1));
if (it == trees.end())
return false;
auto leaf = it->second->getNode(Node::Index(leafSeqNo, 0));
if (leaf == nullptr || leaf->getHash() == nullptr)
return false;
if (!doesExist(leafSeqNo, leaf->getHash(), oldRootNextSeqNo, oldRootHash,
proofs, loggerName))
return false;
// std::cerr << "2" << std::endl;
if (oldRootNextSeqNo == newRootNextSeqNo) {
if (*oldRootHash == *newRootHash)
return true;
else
return false;
}
// std::cerr << "3" << std::endl;
if (!doesExist(leafSeqNo, leaf->getHash(), newRootNextSeqNo, newRootHash,
proofs, loggerName))
return false;
// std::cerr << "4" << std::endl;
return true;
}
bool
Auditor::loadProof(std::map<Node::Index, ConstSubTreeBinaryPtr>& trees,
const std::vector<shared_ptr<Data>>& proofs,
const Name& loggerName)
{
try {
for (auto proof : proofs) {
// std::cerr << proof->getName() << std::endl;
auto subtree =
make_shared<SubTreeBinary>(loggerName,
[] (const Node::Index& idx) {},
[] (const Node::Index&,
const NonNegativeInteger& seqNo,
ndn::ConstBufferPtr hash) {});
subtree->decode(*proof);
// std::cerr << subtree->getPeakIndex().level << ", " << subtree->getPeakIndex().seqNo << std::endl;
if (trees.find(subtree->getPeakIndex()) == trees.end())
trees[subtree->getPeakIndex()] = subtree;
else
return false;
}
}
catch (SubTreeBinary::Error& e) {
// std::cerr << e.what() << std::endl;
return false;
}
catch (Node::Error& e) {
// std::cerr << e.what() << std::endl;
return false;
}
catch (tlv::Error&) {
return false;
}
return true;
}
} // namespace nsl