2016-04-28 09:04:24 -07:00
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
2016-04-27 10:01:50 -07:00
|
|
|
#include "test/data/merkle_roots.json.h"
|
|
|
|
#include "test/data/merkle_serialization.json.h"
|
|
|
|
#include "test/data/merkle_witness_serialization.json.h"
|
|
|
|
#include "test/data/merkle_path.json.h"
|
2016-11-14 09:13:06 -08:00
|
|
|
#include "test/data/merkle_commitments.json.h"
|
2021-06-22 16:20:39 -07:00
|
|
|
#include "test/data/merkle_roots_orchard.h"
|
2016-04-27 10:01:50 -07:00
|
|
|
|
2018-04-17 21:59:41 -07:00
|
|
|
#include "test/data/merkle_roots_sapling.json.h"
|
|
|
|
#include "test/data/merkle_serialization_sapling.json.h"
|
|
|
|
#include "test/data/merkle_witness_serialization_sapling.json.h"
|
|
|
|
#include "test/data/merkle_path_sapling.json.h"
|
|
|
|
#include "test/data/merkle_commitments_sapling.json.h"
|
|
|
|
|
2016-04-27 10:01:50 -07:00
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#include "utilstrencodings.h"
|
|
|
|
#include "version.h"
|
|
|
|
#include "serialize.h"
|
|
|
|
#include "streams.h"
|
|
|
|
|
2016-06-28 09:08:50 -07:00
|
|
|
#include "zcash/IncrementalMerkleTree.hpp"
|
|
|
|
#include "zcash/util.h"
|
|
|
|
|
2016-04-27 10:01:50 -07:00
|
|
|
|
2016-08-16 13:08:59 -07:00
|
|
|
#include "json_test_vectors.h"
|
2016-04-27 10:01:50 -07:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
template<>
|
2018-08-01 09:52:58 -07:00
|
|
|
void expect_deser_same(const SproutTestingWitness& expected)
|
2016-04-27 10:01:50 -07:00
|
|
|
{
|
|
|
|
// Cannot check this; IncrementalWitness cannot be
|
|
|
|
// deserialized because it can only be constructed by
|
|
|
|
// IncrementalMerkleTree, and it does not yet have a
|
|
|
|
// canonical serialized representation.
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A, typename B, typename C>
|
|
|
|
void expect_ser_test_vector(B& b, const C& c, const A& tree) {
|
|
|
|
expect_test_vector<B, C>(b, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Tree, typename Witness>
|
2016-11-14 09:13:06 -08:00
|
|
|
void test_tree(
|
2017-01-06 10:15:56 -08:00
|
|
|
UniValue commitment_tests,
|
|
|
|
UniValue root_tests,
|
|
|
|
UniValue ser_tests,
|
|
|
|
UniValue witness_ser_tests,
|
2019-06-25 07:39:16 -07:00
|
|
|
UniValue path_tests
|
2016-11-14 09:13:06 -08:00
|
|
|
)
|
|
|
|
{
|
2017-01-07 01:11:31 -08:00
|
|
|
size_t witness_ser_i = 0;
|
|
|
|
size_t path_i = 0;
|
2016-04-27 10:01:50 -07:00
|
|
|
|
|
|
|
Tree tree;
|
|
|
|
|
2016-05-04 08:15:14 -07:00
|
|
|
// The root of the tree at this point is expected to be the root of the
|
|
|
|
// empty tree.
|
|
|
|
ASSERT_TRUE(tree.root() == Tree::empty_root());
|
2016-04-27 10:01:50 -07:00
|
|
|
|
2016-11-15 11:17:19 -08:00
|
|
|
// The tree doesn't have a 'last' element added since it's blank.
|
|
|
|
ASSERT_THROW(tree.last(), std::runtime_error);
|
|
|
|
|
2016-12-16 12:50:55 -08:00
|
|
|
// The tree is empty.
|
|
|
|
ASSERT_TRUE(tree.size() == 0);
|
|
|
|
|
2016-04-27 10:01:50 -07:00
|
|
|
// We need to witness at every single point in the tree, so
|
|
|
|
// that the consistency of the tree and the merkle paths can
|
|
|
|
// be checked.
|
|
|
|
vector<Witness> witnesses;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 16; i++) {
|
2017-01-07 01:11:31 -08:00
|
|
|
uint256 test_commitment = uint256S(commitment_tests[i].get_str());
|
2016-11-14 09:13:06 -08:00
|
|
|
|
2016-04-27 10:01:50 -07:00
|
|
|
// Witness here
|
|
|
|
witnesses.push_back(tree.witness());
|
|
|
|
|
|
|
|
// Now append a commitment to the tree
|
|
|
|
tree.append(test_commitment);
|
|
|
|
|
2016-12-16 12:50:55 -08:00
|
|
|
// Size incremented by one.
|
|
|
|
ASSERT_TRUE(tree.size() == i+1);
|
|
|
|
|
2016-11-14 09:13:06 -08:00
|
|
|
// Last element added to the tree was `test_commitment`
|
|
|
|
ASSERT_TRUE(tree.last() == test_commitment);
|
|
|
|
|
2016-04-27 10:01:50 -07:00
|
|
|
// Check tree root consistency
|
2017-01-07 01:11:31 -08:00
|
|
|
expect_test_vector(root_tests[i], tree.root());
|
2016-04-27 10:01:50 -07:00
|
|
|
|
|
|
|
// Check serialization of tree
|
2017-01-07 01:11:31 -08:00
|
|
|
expect_ser_test_vector(ser_tests[i], tree, tree);
|
2016-04-27 10:01:50 -07:00
|
|
|
|
|
|
|
bool first = true; // The first witness can never form a path
|
2017-06-01 18:18:57 -07:00
|
|
|
for (Witness& wit : witnesses)
|
2016-04-27 10:01:50 -07:00
|
|
|
{
|
|
|
|
// Append the same commitment to all the witnesses
|
|
|
|
wit.append(test_commitment);
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
ASSERT_THROW(wit.path(), std::runtime_error);
|
2016-11-15 11:17:19 -08:00
|
|
|
ASSERT_THROW(wit.element(), std::runtime_error);
|
2016-04-27 10:01:50 -07:00
|
|
|
} else {
|
|
|
|
auto path = wit.path();
|
2018-04-17 21:59:41 -07:00
|
|
|
expect_test_vector(path_tests[path_i++], path);
|
2016-04-27 10:01:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check witness serialization
|
2017-01-07 01:11:31 -08:00
|
|
|
expect_ser_test_vector(witness_ser_tests[witness_ser_i++], wit, tree);
|
2016-04-27 10:01:50 -07:00
|
|
|
|
|
|
|
ASSERT_TRUE(wit.root() == tree.root());
|
|
|
|
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-04 17:26:33 -07:00
|
|
|
{
|
2016-04-27 10:01:50 -07:00
|
|
|
// Tree should be full now
|
|
|
|
ASSERT_THROW(tree.append(uint256()), std::runtime_error);
|
|
|
|
|
2017-06-01 18:18:57 -07:00
|
|
|
for (Witness& wit : witnesses)
|
2016-04-27 10:01:50 -07:00
|
|
|
{
|
|
|
|
ASSERT_THROW(wit.append(uint256()), std::runtime_error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-09 13:10:08 -08:00
|
|
|
#define MAKE_STRING(x) std::string((x), (x)+sizeof(x))
|
|
|
|
|
2016-04-27 10:01:50 -07:00
|
|
|
TEST(merkletree, vectors) {
|
2017-02-09 13:10:08 -08:00
|
|
|
UniValue root_tests = read_json(MAKE_STRING(json_tests::merkle_roots));
|
|
|
|
UniValue ser_tests = read_json(MAKE_STRING(json_tests::merkle_serialization));
|
|
|
|
UniValue witness_ser_tests = read_json(MAKE_STRING(json_tests::merkle_witness_serialization));
|
|
|
|
UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path));
|
|
|
|
UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments));
|
2016-04-27 10:01:50 -07:00
|
|
|
|
2018-08-01 09:52:58 -07:00
|
|
|
test_tree<SproutTestingMerkleTree, SproutTestingWitness>(
|
2018-04-17 21:59:41 -07:00
|
|
|
commitment_tests,
|
|
|
|
root_tests,
|
|
|
|
ser_tests,
|
|
|
|
witness_ser_tests,
|
2019-06-25 07:39:16 -07:00
|
|
|
path_tests
|
2018-04-17 21:59:41 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-05-06 13:26:54 -07:00
|
|
|
TEST(merkletree, SaplingVectors) {
|
2018-04-17 21:59:41 -07:00
|
|
|
UniValue root_tests = read_json(MAKE_STRING(json_tests::merkle_roots_sapling));
|
|
|
|
UniValue ser_tests = read_json(MAKE_STRING(json_tests::merkle_serialization_sapling));
|
|
|
|
UniValue witness_ser_tests = read_json(MAKE_STRING(json_tests::merkle_witness_serialization_sapling));
|
|
|
|
UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path_sapling));
|
|
|
|
UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments_sapling));
|
|
|
|
|
2018-08-01 09:52:58 -07:00
|
|
|
test_tree<SaplingTestingMerkleTree, SaplingTestingWitness>(
|
2018-04-17 21:59:41 -07:00
|
|
|
commitment_tests,
|
|
|
|
root_tests,
|
|
|
|
ser_tests,
|
|
|
|
witness_ser_tests,
|
2019-06-25 07:39:16 -07:00
|
|
|
path_tests
|
2018-04-17 21:59:41 -07:00
|
|
|
);
|
2016-04-27 10:01:50 -07:00
|
|
|
}
|
|
|
|
|
2016-05-04 08:15:14 -07:00
|
|
|
TEST(merkletree, emptyroots) {
|
|
|
|
libzcash::EmptyMerkleRoots<64, libzcash::SHA256Compress> emptyroots;
|
2019-09-13 08:12:05 -07:00
|
|
|
std::array<libzcash::SHA256Compress, 65> computed;
|
2016-05-04 08:15:14 -07:00
|
|
|
|
2019-09-13 08:12:05 -07:00
|
|
|
computed.at(0) = libzcash::SHA256Compress::uncommitted();
|
|
|
|
ASSERT_TRUE(emptyroots.empty_root(0) == computed.at(0));
|
|
|
|
for (size_t d = 1; d <= 64; d++) {
|
|
|
|
computed.at(d) = libzcash::SHA256Compress::combine(computed.at(d-1), computed.at(d-1), d-1);
|
|
|
|
ASSERT_TRUE(emptyroots.empty_root(d) == computed.at(d));
|
2016-05-04 08:15:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Double check that we're testing (at least) all the empty roots we'll use.
|
|
|
|
ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 64);
|
|
|
|
}
|
|
|
|
|
2018-05-06 13:26:54 -07:00
|
|
|
TEST(merkletree, EmptyrootsSapling) {
|
2018-04-17 21:59:41 -07:00
|
|
|
libzcash::EmptyMerkleRoots<62, libzcash::PedersenHash> emptyroots;
|
2019-09-13 08:12:05 -07:00
|
|
|
std::array<libzcash::PedersenHash, 63> computed;
|
2018-04-17 21:59:41 -07:00
|
|
|
|
2019-09-13 08:12:05 -07:00
|
|
|
computed.at(0) = libzcash::PedersenHash::uncommitted();
|
|
|
|
ASSERT_TRUE(emptyroots.empty_root(0) == computed.at(0));
|
|
|
|
for (size_t d = 1; d <= 62; d++) {
|
|
|
|
computed.at(d) = libzcash::PedersenHash::combine(computed.at(d-1), computed.at(d-1), d-1);
|
|
|
|
ASSERT_TRUE(emptyroots.empty_root(d) == computed.at(d));
|
2018-04-17 21:59:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Double check that we're testing (at least) all the empty roots we'll use.
|
|
|
|
ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 62);
|
|
|
|
}
|
|
|
|
|
2016-05-04 08:15:14 -07:00
|
|
|
TEST(merkletree, emptyroot) {
|
2019-05-10 11:58:11 -07:00
|
|
|
// This literal is the depth-29 empty tree root with the bytes reversed to
|
2016-05-04 08:15:14 -07:00
|
|
|
// account for the fact that uint256S() loads a big-endian representation of
|
|
|
|
// an integer which converted to little-endian internally.
|
2016-06-15 14:31:14 -07:00
|
|
|
uint256 expected = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
|
2016-05-04 08:15:14 -07:00
|
|
|
|
2018-08-01 09:31:09 -07:00
|
|
|
ASSERT_TRUE(SproutMerkleTree::empty_root() == expected);
|
2016-05-04 08:15:14 -07:00
|
|
|
}
|
|
|
|
|
2018-05-06 13:26:54 -07:00
|
|
|
TEST(merkletree, EmptyrootSapling) {
|
2019-05-10 11:58:11 -07:00
|
|
|
// This literal is the depth-32 empty tree root with the bytes reversed to
|
2018-04-17 21:59:41 -07:00
|
|
|
// account for the fact that uint256S() loads a big-endian representation of
|
|
|
|
// an integer which converted to little-endian internally.
|
2018-05-17 16:45:08 -07:00
|
|
|
uint256 expected = uint256S("3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb");
|
2018-04-17 21:59:41 -07:00
|
|
|
|
2018-08-01 09:31:09 -07:00
|
|
|
ASSERT_TRUE(SaplingMerkleTree::empty_root() == expected);
|
2018-04-17 21:59:41 -07:00
|
|
|
}
|
|
|
|
|
2016-04-27 10:01:50 -07:00
|
|
|
TEST(merkletree, deserializeInvalid) {
|
|
|
|
// attempt to deserialize a small tree from a serialized large tree
|
|
|
|
// (exceeds depth well-formedness check)
|
2018-08-01 09:31:09 -07:00
|
|
|
SproutMerkleTree newTree;
|
2016-04-27 10:01:50 -07:00
|
|
|
|
|
|
|
for (size_t i = 0; i < 16; i++) {
|
|
|
|
newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"));
|
|
|
|
}
|
|
|
|
|
|
|
|
newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"));
|
|
|
|
|
|
|
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
ss << newTree;
|
|
|
|
|
2018-08-01 09:52:58 -07:00
|
|
|
SproutTestingMerkleTree newTreeSmall;
|
2016-04-27 10:01:50 -07:00
|
|
|
ASSERT_THROW({ss >> newTreeSmall;}, std::ios_base::failure);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(merkletree, deserializeInvalid2) {
|
|
|
|
// the most ancestral parent is empty
|
|
|
|
CDataStream ss(
|
|
|
|
ParseHex("0155b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3000100"),
|
|
|
|
SER_NETWORK,
|
|
|
|
PROTOCOL_VERSION
|
|
|
|
);
|
|
|
|
|
2018-08-01 09:31:09 -07:00
|
|
|
SproutMerkleTree tree;
|
2016-04-27 10:01:50 -07:00
|
|
|
ASSERT_THROW(ss >> tree, std::ios_base::failure);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(merkletree, deserializeInvalid3) {
|
|
|
|
// left doesn't exist but right does
|
|
|
|
CDataStream ss(
|
|
|
|
ParseHex("000155b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e300"),
|
|
|
|
SER_NETWORK,
|
|
|
|
PROTOCOL_VERSION
|
|
|
|
);
|
|
|
|
|
2018-08-01 09:31:09 -07:00
|
|
|
SproutMerkleTree tree;
|
2016-04-27 10:01:50 -07:00
|
|
|
ASSERT_THROW(ss >> tree, std::ios_base::failure);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(merkletree, deserializeInvalid4) {
|
|
|
|
// left doesn't exist but a parent does
|
|
|
|
CDataStream ss(
|
|
|
|
ParseHex("000001018695873d63ec0bceeadb5bf4ccc6723ac803c1826fc7cfb34fc76180305ae27d"),
|
|
|
|
SER_NETWORK,
|
|
|
|
PROTOCOL_VERSION
|
|
|
|
);
|
|
|
|
|
2018-08-01 09:31:09 -07:00
|
|
|
SproutMerkleTree tree;
|
2016-04-27 10:01:50 -07:00
|
|
|
ASSERT_THROW(ss >> tree, std::ios_base::failure);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(merkletree, testZeroElements) {
|
|
|
|
for (int start = 0; start < 20; start++) {
|
2018-08-01 09:31:09 -07:00
|
|
|
SproutMerkleTree newTree;
|
2016-04-27 10:01:50 -07:00
|
|
|
|
2018-08-01 09:31:09 -07:00
|
|
|
ASSERT_TRUE(newTree.root() == SproutMerkleTree::empty_root());
|
2016-04-27 10:01:50 -07:00
|
|
|
|
|
|
|
for (int i = start; i > 0; i--) {
|
|
|
|
newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint256 oldroot = newTree.root();
|
|
|
|
|
|
|
|
// At this point, appending tons of null objects to the tree
|
|
|
|
// should preserve its root.
|
|
|
|
|
|
|
|
for (int i = 0; i < 100; i++) {
|
|
|
|
newTree.append(uint256());
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT_TRUE(newTree.root() == oldroot);
|
|
|
|
}
|
2016-04-28 09:04:24 -07:00
|
|
|
}
|
2021-06-17 11:22:26 -07:00
|
|
|
|
|
|
|
TEST(orchardMerkleTree, emptyroot) {
|
2021-06-28 12:23:46 -07:00
|
|
|
// This literal is the depth-32 empty tree root with the bytes reversed, to
|
2021-06-17 11:22:26 -07:00
|
|
|
// account for the fact that uint256S() loads a big-endian representation of
|
2021-06-28 12:23:46 -07:00
|
|
|
// an integer, which is converted to little-endian internally.
|
2021-06-17 11:22:26 -07:00
|
|
|
uint256 expected = uint256S("2fd8e51a03d9bbe2dd809831b1497aeb68a6e37ddf707ced4aa2d8dff13529ae");
|
|
|
|
|
2021-07-19 18:59:21 -07:00
|
|
|
ASSERT_EQ(OrchardMerkleFrontier::empty_root(), expected);
|
2021-06-17 11:22:26 -07:00
|
|
|
}
|
2021-06-22 16:20:39 -07:00
|
|
|
|
|
|
|
TEST(orchardMerkleTree, appendBundle) {
|
2021-07-19 18:59:21 -07:00
|
|
|
OrchardMerkleFrontier newTree;
|
2021-06-22 16:20:39 -07:00
|
|
|
|
2021-07-19 18:59:21 -07:00
|
|
|
ASSERT_EQ(newTree.root(), OrchardMerkleFrontier::empty_root());
|
2021-06-22 16:20:39 -07:00
|
|
|
|
|
|
|
for (int i = 0; i < 1; i++) {
|
|
|
|
CDataStream ssBundleData(merkle_roots_orchard[i].bundle, SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
OrchardBundle b;
|
|
|
|
ssBundleData >> b;
|
|
|
|
newTree.AppendBundle(b);
|
|
|
|
|
|
|
|
uint256 anchor(merkle_roots_orchard[i].anchor);
|
|
|
|
|
|
|
|
ASSERT_EQ(newTree.root(), anchor);
|
2022-03-02 13:55:35 -08:00
|
|
|
|
|
|
|
// Sanity check roundtrip serialization of the updated tree
|
|
|
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
|
|
|
ss << newTree;
|
|
|
|
|
|
|
|
OrchardMerkleFrontier readBack;
|
|
|
|
ss >> readBack;
|
|
|
|
|
|
|
|
EXPECT_NE(newTree.root(), OrchardMerkleFrontier::empty_root());
|
|
|
|
EXPECT_EQ(newTree.root(), readBack.root());
|
2021-06-22 16:20:39 -07:00
|
|
|
}
|
|
|
|
}
|