// Copyright (c) 2016-2020 The Hush developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html #ifndef ZC_INCREMENTALMERKLETREE_H_ #define ZC_INCREMENTALMERKLETREE_H_ #include #include #include #include #include "uint256.h" #include "serialize.h" #include "Zcash.h" #include "zcash/util.h" namespace libzcash { class MerklePath { public: std::vector> authentication_path; std::vector index; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { std::vector> pathBytes; uint64_t indexInt; if (ser_action.ForRead()) { READWRITE(pathBytes); READWRITE(indexInt); MerklePath &us = *(const_cast(this)); for (size_t i = 0; i < pathBytes.size(); i++) { us.authentication_path.push_back(convertBytesVectorToVector(pathBytes[i])); us.index.push_back((indexInt >> ((pathBytes.size() - 1) - i)) & 1); } } else { assert(authentication_path.size() == index.size()); pathBytes.resize(authentication_path.size()); for (size_t i = 0; i < authentication_path.size(); i++) { pathBytes[i].resize((authentication_path[i].size()+7)/8); for (unsigned int p = 0; p < authentication_path[i].size(); p++) { pathBytes[i][p / 8] |= authentication_path[i][p] << (7-(p % 8)); } } indexInt = convertVectorToInt(index); READWRITE(pathBytes); READWRITE(indexInt); } } MerklePath() { } MerklePath(std::vector> authentication_path, std::vector index) : authentication_path(authentication_path), index(index) { } }; template class EmptyMerkleRoots { public: EmptyMerkleRoots() { } Hash empty_root(size_t depth) const { return Hash::EmptyRoot(depth); } template friend bool operator==(const EmptyMerkleRoots& a, const EmptyMerkleRoots& b); private: std::array empty_roots; }; template bool operator==(const EmptyMerkleRoots& a, const EmptyMerkleRoots& b) { return a.empty_roots == b.empty_roots; } template class IncrementalWitness; template class IncrementalMerkleTree { friend class IncrementalWitness; public: BOOST_STATIC_ASSERT(Depth >= 1); IncrementalMerkleTree() { } size_t DynamicMemoryUsage() const { return 32 + // left 32 + // right parents.size() * 32; // parents } size_t size() const; void append(Hash obj); Hash root() const { return root(Depth, std::deque()); } Hash last() const; IncrementalWitness witness() const { return IncrementalWitness(*this); } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(left); READWRITE(right); READWRITE(parents); wfcheck(); } static Hash empty_root() { return emptyroots.empty_root(Depth); } template friend bool operator==(const IncrementalMerkleTree& a, const IncrementalMerkleTree& b); private: static EmptyMerkleRoots emptyroots; boost::optional left; boost::optional right; // Collapsed "left" subtrees ordered toward the root of the tree. std::vector> parents; MerklePath path(std::deque filler_hashes = std::deque()) const; Hash root(size_t depth, std::deque filler_hashes = std::deque()) const; bool is_complete(size_t depth = Depth) const; size_t next_depth(size_t skip) const; void wfcheck() const; }; template bool operator==(const IncrementalMerkleTree& a, const IncrementalMerkleTree& b) { return (a.emptyroots == b.emptyroots && a.left == b.left && a.right == b.right && a.parents == b.parents); } template class IncrementalWitness { friend class IncrementalMerkleTree; public: // Required for Unserialize() IncrementalWitness() {} MerklePath path() const { return tree.path(partial_path()); } // Return the element being witnessed (should be a note // commitment!) Hash element() const { return tree.last(); } uint64_t position() const { return tree.size() - 1; } Hash root() const { return tree.root(Depth, partial_path()); } void append(Hash obj); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(tree); READWRITE(filled); READWRITE(cursor); cursor_depth = tree.next_depth(filled.size()); } template friend bool operator==(const IncrementalWitness& a, const IncrementalWitness& b); private: IncrementalMerkleTree tree; std::vector filled; boost::optional> cursor; size_t cursor_depth = 0; std::deque partial_path() const; IncrementalWitness(IncrementalMerkleTree tree) : tree(tree) {} }; template bool operator==(const IncrementalWitness& a, const IncrementalWitness& b) { return (a.tree == b.tree && a.filled == b.filled && a.cursor == b.cursor && a.cursor_depth == b.cursor_depth); } class SHA256Compress : public uint256 { public: SHA256Compress() : uint256() {} SHA256Compress(uint256 contents) : uint256(contents) { } static SHA256Compress combine( const SHA256Compress& a, const SHA256Compress& b, size_t depth ); static SHA256Compress uncommitted() { return SHA256Compress(); } static SHA256Compress EmptyRoot(size_t); }; class PedersenHash : public uint256 { public: PedersenHash() : uint256() {} PedersenHash(uint256 contents) : uint256(contents) { } static PedersenHash combine( const PedersenHash& a, const PedersenHash& b, size_t depth ); static PedersenHash uncommitted(); static PedersenHash EmptyRoot(size_t); }; template EmptyMerkleRoots IncrementalMerkleTree::emptyroots; } // end namespace `libzcash` typedef libzcash::IncrementalMerkleTree SproutMerkleTree; typedef libzcash::IncrementalMerkleTree SproutTestingMerkleTree; typedef libzcash::IncrementalWitness SproutWitness; typedef libzcash::IncrementalWitness SproutTestingWitness; typedef libzcash::IncrementalMerkleTree SaplingMerkleTree; typedef libzcash::IncrementalMerkleTree SaplingTestingMerkleTree; typedef libzcash::IncrementalWitness SaplingWitness; typedef libzcash::IncrementalWitness SaplingTestingWitness; #endif /* ZC_INCREMENTALMERKLETREE_H_ */