New implementation of incremental merkle tree

This is a new implementation of the incremental merkle tree used by our
scheme to witness commitments to spendable value. It serves as a fixed-sized
accumulator.

This new construction has a much simpler API surface area, avoids memory
safety issues, remains pruned at all times, avoids serialization edge cases,
has more efficient insertion, and is abstract over the depth and hash
function used at the type level.

Further, it lays the groundwork for efficient "fast-forwarding" of witnesses
into the tree as the treestate is updated.
This commit is contained in:
Sean Bowe
2016-03-28 02:40:21 -06:00
parent 291b191bd7
commit e1ff849d8d
12 changed files with 889 additions and 5 deletions

View File

@@ -0,0 +1,129 @@
#ifndef ZCINCREMENTALMERKLETREE_H_
#define ZCINCREMENTALMERKLETREE_H_
#include <deque>
#include <boost/optional.hpp>
#include <boost/static_assert.hpp>
#include "uint256.h"
#include "serialize.h"
static const unsigned int INCREMENTAL_MERKLE_TREE_DEPTH = 20;
static const unsigned int INCREMENTAL_MERKLE_TREE_DEPTH_TESTING = 4;
namespace libzcash {
class MerklePath {
public:
std::vector<std::vector<bool>> authentication_path;
std::vector<bool> index;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(authentication_path);
READWRITE(index);
}
MerklePath(std::vector<std::vector<bool>> authentication_path, std::vector<bool> index)
: authentication_path(authentication_path), index(index) { }
};
template<size_t Depth, typename Hash>
class IncrementalWitness;
template<size_t Depth, typename Hash>
class IncrementalMerkleTree {
friend class IncrementalWitness<Depth, Hash>;
public:
BOOST_STATIC_ASSERT(Depth >= 1);
IncrementalMerkleTree() { }
void append(Hash obj);
Hash root() const {
return root(Depth, std::deque<Hash>());
}
IncrementalWitness<Depth, Hash> witness() const {
return IncrementalWitness<Depth, Hash>(*this);
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(left);
READWRITE(right);
READWRITE(parents);
wfcheck();
}
private:
boost::optional<Hash> left;
boost::optional<Hash> right;
std::vector<boost::optional<Hash>> parents;
MerklePath path(std::deque<Hash> filler_hashes = std::deque<Hash>()) const;
Hash root(size_t depth, std::deque<Hash> filler_hashes = std::deque<Hash>()) const;
bool is_complete(size_t depth = Depth) const;
size_t next_depth(size_t skip) const;
void wfcheck() const;
};
template <size_t Depth, typename Hash>
class IncrementalWitness {
friend class IncrementalMerkleTree<Depth, Hash>;
public:
MerklePath path() const {
return tree.path(uncle_train());
}
Hash root() const {
return tree.root(Depth, uncle_train());
}
void append(Hash obj);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(tree);
READWRITE(filled);
READWRITE(cursor);
cursor_depth = tree.next_depth(filled.size());
}
private:
IncrementalMerkleTree<Depth, Hash> tree;
std::vector<Hash> filled;
boost::optional<IncrementalMerkleTree<Depth, Hash>> cursor;
size_t cursor_depth;
std::deque<Hash> uncle_train() const;
IncrementalWitness(IncrementalMerkleTree<Depth, Hash> tree) : tree(tree) {}
};
class SHA256Compress : public uint256 {
public:
SHA256Compress() : uint256() {}
SHA256Compress(uint256 contents) : uint256(contents) { }
static SHA256Compress combine(const SHA256Compress& a, const SHA256Compress& b);
};
} // end namespace `libzcash`
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> ZCIncrementalMerkleTree;
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> ZCTestingIncrementalMerkleTree;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> ZCIncrementalWitness;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> ZCTestingIncrementalWitness;
#endif /* ZCINCREMENTALMERKLETREE_H_ */