2017-11-23 11:20:20 -08:00
|
|
|
#ifndef ZC_INCREMENTALMERKLETREE_H_
|
|
|
|
#define ZC_INCREMENTALMERKLETREE_H_
|
2016-03-28 01:40:21 -07:00
|
|
|
|
2018-05-03 03:53:51 -07:00
|
|
|
#include <array>
|
2016-03-28 01:40:21 -07:00
|
|
|
#include <deque>
|
2020-10-20 17:39:13 -07:00
|
|
|
#include <optional>
|
2016-03-28 01:40:21 -07:00
|
|
|
|
|
|
|
#include "uint256.h"
|
|
|
|
#include "serialize.h"
|
|
|
|
|
2016-05-04 17:25:38 -07:00
|
|
|
#include "Zcash.h"
|
2017-12-22 12:44:35 -08:00
|
|
|
#include "zcash/util.h"
|
2016-03-28 01:40:21 -07:00
|
|
|
|
|
|
|
namespace libzcash {
|
|
|
|
|
|
|
|
class MerklePath {
|
|
|
|
public:
|
|
|
|
std::vector<std::vector<bool>> authentication_path;
|
|
|
|
std::vector<bool> index;
|
|
|
|
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
2018-04-15 20:09:19 -07:00
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action) {
|
2017-12-22 12:44:35 -08:00
|
|
|
std::vector<std::vector<unsigned char>> pathBytes;
|
|
|
|
uint64_t indexInt;
|
|
|
|
if (ser_action.ForRead()) {
|
|
|
|
READWRITE(pathBytes);
|
|
|
|
READWRITE(indexInt);
|
|
|
|
MerklePath &us = *(const_cast<MerklePath*>(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);
|
|
|
|
}
|
2016-03-28 01:40:21 -07:00
|
|
|
}
|
2016-04-03 14:39:08 -07:00
|
|
|
|
|
|
|
MerklePath() { }
|
2016-03-28 01:40:21 -07:00
|
|
|
|
|
|
|
MerklePath(std::vector<std::vector<bool>> authentication_path, std::vector<bool> index)
|
|
|
|
: authentication_path(authentication_path), index(index) { }
|
|
|
|
};
|
|
|
|
|
2016-05-04 08:15:14 -07:00
|
|
|
template<size_t Depth, typename Hash>
|
|
|
|
class EmptyMerkleRoots {
|
|
|
|
public:
|
2019-09-12 23:42:32 -07:00
|
|
|
EmptyMerkleRoots() { }
|
|
|
|
Hash empty_root(size_t depth) const {
|
|
|
|
return Hash::EmptyRoot(depth);
|
2016-05-04 08:15:14 -07:00
|
|
|
}
|
2016-08-31 17:47:44 -07:00
|
|
|
template <size_t D, typename H>
|
|
|
|
friend bool operator==(const EmptyMerkleRoots<D, H>& a,
|
|
|
|
const EmptyMerkleRoots<D, H>& b);
|
2016-05-04 08:15:14 -07:00
|
|
|
private:
|
2018-05-03 03:53:51 -07:00
|
|
|
std::array<Hash, Depth+1> empty_roots;
|
2016-05-04 08:15:14 -07:00
|
|
|
};
|
|
|
|
|
2016-08-31 17:47:44 -07:00
|
|
|
template<size_t Depth, typename Hash>
|
|
|
|
bool operator==(const EmptyMerkleRoots<Depth, Hash>& a,
|
|
|
|
const EmptyMerkleRoots<Depth, Hash>& b) {
|
|
|
|
return a.empty_roots == b.empty_roots;
|
|
|
|
}
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
template<size_t Depth, typename Hash>
|
|
|
|
class IncrementalWitness;
|
|
|
|
|
|
|
|
template<size_t Depth, typename Hash>
|
|
|
|
class IncrementalMerkleTree {
|
|
|
|
|
|
|
|
friend class IncrementalWitness<Depth, Hash>;
|
|
|
|
|
|
|
|
public:
|
2020-10-20 11:54:44 -07:00
|
|
|
static_assert(Depth >= 1);
|
2016-03-28 01:40:21 -07:00
|
|
|
|
|
|
|
IncrementalMerkleTree() { }
|
|
|
|
|
2016-06-27 09:52:34 -07:00
|
|
|
size_t DynamicMemoryUsage() const {
|
|
|
|
return 32 + // left
|
|
|
|
32 + // right
|
|
|
|
parents.size() * 32; // parents
|
|
|
|
}
|
|
|
|
|
2016-12-14 18:50:26 -08:00
|
|
|
size_t size() const;
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
void append(Hash obj);
|
|
|
|
Hash root() const {
|
|
|
|
return root(Depth, std::deque<Hash>());
|
|
|
|
}
|
2016-11-05 10:27:23 -07:00
|
|
|
Hash last() const;
|
2016-03-28 01:40:21 -07:00
|
|
|
|
|
|
|
IncrementalWitness<Depth, Hash> witness() const {
|
|
|
|
return IncrementalWitness<Depth, Hash>(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
2018-04-15 20:09:19 -07:00
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action) {
|
2016-03-28 01:40:21 -07:00
|
|
|
READWRITE(left);
|
|
|
|
READWRITE(right);
|
|
|
|
READWRITE(parents);
|
|
|
|
|
|
|
|
wfcheck();
|
|
|
|
}
|
|
|
|
|
2016-05-04 08:15:14 -07:00
|
|
|
static Hash empty_root() {
|
|
|
|
return emptyroots.empty_root(Depth);
|
|
|
|
}
|
|
|
|
|
2016-08-31 17:47:44 -07:00
|
|
|
template <size_t D, typename H>
|
|
|
|
friend bool operator==(const IncrementalMerkleTree<D, H>& a,
|
|
|
|
const IncrementalMerkleTree<D, H>& b);
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
private:
|
2016-05-04 08:15:14 -07:00
|
|
|
static EmptyMerkleRoots<Depth, Hash> emptyroots;
|
2020-10-20 17:44:15 -07:00
|
|
|
std::optional<Hash> left;
|
|
|
|
std::optional<Hash> right;
|
2016-04-29 09:05:06 -07:00
|
|
|
|
|
|
|
// Collapsed "left" subtrees ordered toward the root of the tree.
|
2020-10-20 17:44:15 -07:00
|
|
|
std::vector<std::optional<Hash>> parents;
|
2016-03-28 01:40:21 -07:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2016-08-31 17:47:44 -07:00
|
|
|
template<size_t Depth, typename Hash>
|
|
|
|
bool operator==(const IncrementalMerkleTree<Depth, Hash>& a,
|
|
|
|
const IncrementalMerkleTree<Depth, Hash>& b) {
|
|
|
|
return (a.emptyroots == b.emptyroots &&
|
|
|
|
a.left == b.left &&
|
|
|
|
a.right == b.right &&
|
|
|
|
a.parents == b.parents);
|
|
|
|
}
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
template <size_t Depth, typename Hash>
|
|
|
|
class IncrementalWitness {
|
|
|
|
friend class IncrementalMerkleTree<Depth, Hash>;
|
|
|
|
|
|
|
|
public:
|
2016-08-31 18:00:02 -07:00
|
|
|
// Required for Unserialize()
|
|
|
|
IncrementalWitness() {}
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
MerklePath path() const {
|
2016-04-29 09:05:06 -07:00
|
|
|
return tree.path(partial_path());
|
2016-03-28 01:40:21 -07:00
|
|
|
}
|
|
|
|
|
2016-11-05 10:27:23 -07:00
|
|
|
// Return the element being witnessed (should be a note
|
|
|
|
// commitment!)
|
|
|
|
Hash element() const {
|
|
|
|
return tree.last();
|
|
|
|
}
|
|
|
|
|
2018-07-17 09:34:48 -07:00
|
|
|
uint64_t position() const {
|
|
|
|
return tree.size() - 1;
|
|
|
|
}
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
Hash root() const {
|
2016-04-29 09:05:06 -07:00
|
|
|
return tree.root(Depth, partial_path());
|
2016-03-28 01:40:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void append(Hash obj);
|
|
|
|
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
2018-04-15 20:09:19 -07:00
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action) {
|
2016-03-28 01:40:21 -07:00
|
|
|
READWRITE(tree);
|
|
|
|
READWRITE(filled);
|
|
|
|
READWRITE(cursor);
|
|
|
|
|
|
|
|
cursor_depth = tree.next_depth(filled.size());
|
|
|
|
}
|
|
|
|
|
2016-08-31 17:47:44 -07:00
|
|
|
template <size_t D, typename H>
|
|
|
|
friend bool operator==(const IncrementalWitness<D, H>& a,
|
|
|
|
const IncrementalWitness<D, H>& b);
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
private:
|
|
|
|
IncrementalMerkleTree<Depth, Hash> tree;
|
|
|
|
std::vector<Hash> filled;
|
2020-10-20 17:44:15 -07:00
|
|
|
std::optional<IncrementalMerkleTree<Depth, Hash>> cursor;
|
2016-10-20 11:25:36 -07:00
|
|
|
size_t cursor_depth = 0;
|
2016-04-29 09:05:06 -07:00
|
|
|
std::deque<Hash> partial_path() const;
|
2016-03-28 01:40:21 -07:00
|
|
|
IncrementalWitness(IncrementalMerkleTree<Depth, Hash> tree) : tree(tree) {}
|
|
|
|
};
|
|
|
|
|
2016-08-31 17:47:44 -07:00
|
|
|
template<size_t Depth, typename Hash>
|
|
|
|
bool operator==(const IncrementalWitness<Depth, Hash>& a,
|
|
|
|
const IncrementalWitness<Depth, Hash>& b) {
|
|
|
|
return (a.tree == b.tree &&
|
|
|
|
a.filled == b.filled &&
|
|
|
|
a.cursor == b.cursor &&
|
|
|
|
a.cursor_depth == b.cursor_depth);
|
|
|
|
}
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
class SHA256Compress : public uint256 {
|
|
|
|
public:
|
|
|
|
SHA256Compress() : uint256() {}
|
|
|
|
SHA256Compress(uint256 contents) : uint256(contents) { }
|
|
|
|
|
2018-04-12 16:10:04 -07:00
|
|
|
static SHA256Compress combine(
|
|
|
|
const SHA256Compress& a,
|
|
|
|
const SHA256Compress& b,
|
|
|
|
size_t depth
|
|
|
|
);
|
|
|
|
|
|
|
|
static SHA256Compress uncommitted() {
|
|
|
|
return SHA256Compress();
|
|
|
|
}
|
2019-09-12 23:42:32 -07:00
|
|
|
static SHA256Compress EmptyRoot(size_t);
|
2016-03-28 01:40:21 -07:00
|
|
|
};
|
|
|
|
|
2018-04-14 21:33:41 -07:00
|
|
|
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();
|
2019-09-12 23:42:32 -07:00
|
|
|
static PedersenHash EmptyRoot(size_t);
|
2018-04-14 21:33:41 -07:00
|
|
|
};
|
|
|
|
|
2017-12-22 17:02:44 -08:00
|
|
|
template<size_t Depth, typename Hash>
|
|
|
|
EmptyMerkleRoots<Depth, Hash> IncrementalMerkleTree<Depth, Hash>::emptyroots;
|
|
|
|
|
2016-03-28 01:40:21 -07:00
|
|
|
} // end namespace `libzcash`
|
|
|
|
|
2018-08-01 09:31:09 -07:00
|
|
|
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> SproutMerkleTree;
|
2018-08-01 09:52:58 -07:00
|
|
|
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> SproutTestingMerkleTree;
|
2016-03-28 01:40:21 -07:00
|
|
|
|
2018-08-01 09:41:36 -07:00
|
|
|
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> SproutWitness;
|
2018-08-01 09:52:58 -07:00
|
|
|
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> SproutTestingWitness;
|
2016-03-28 01:40:21 -07:00
|
|
|
|
2018-08-01 09:31:09 -07:00
|
|
|
typedef libzcash::IncrementalMerkleTree<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::PedersenHash> SaplingMerkleTree;
|
2018-08-01 09:52:58 -07:00
|
|
|
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::PedersenHash> SaplingTestingMerkleTree;
|
2018-04-14 21:33:41 -07:00
|
|
|
|
2018-08-01 09:41:36 -07:00
|
|
|
typedef libzcash::IncrementalWitness<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::PedersenHash> SaplingWitness;
|
2018-08-01 09:52:58 -07:00
|
|
|
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::PedersenHash> SaplingTestingWitness;
|
2018-04-14 21:33:41 -07:00
|
|
|
|
2017-11-23 11:20:20 -08:00
|
|
|
#endif /* ZC_INCREMENTALMERKLETREE_H_ */
|