From 6850b45e4dceffa811ab7906e8884e18fb0ff845 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 27 Apr 2016 11:01:50 -0600 Subject: [PATCH] Move incremental merkle tree tests to zcash-gtest. --- src/Makefile.test.include | 7 +- src/gtest/test_merkletree.cpp | 417 +++++++++++++++++++++++++++++++++- src/test/merkle_tests.cpp | 400 -------------------------------- 3 files changed, 418 insertions(+), 406 deletions(-) delete mode 100644 src/test/merkle_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index f6065de59..e5656eaac 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -82,8 +82,7 @@ BITCOIN_TESTS =\ test/uint256_tests.cpp \ test/univalue_tests.cpp \ test/util_tests.cpp \ - test/sha256compress_tests.cpp \ - test/merkle_tests.cpp + test/sha256compress_tests.cpp if ENABLE_WALLET BITCOIN_TESTS += \ @@ -95,12 +94,12 @@ endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bitcoin_CPPFLAGS = $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ - $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(LIBZEROCASH) $(LIBZEROCASH_LIBS) + $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif -test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) +test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBZEROCASH) $(LIBZEROCASH_LIBS) test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) diff --git a/src/gtest/test_merkletree.cpp b/src/gtest/test_merkletree.cpp index ca7b23b3b..a22885ff3 100644 --- a/src/gtest/test_merkletree.cpp +++ b/src/gtest/test_merkletree.cpp @@ -1,5 +1,418 @@ #include -TEST(tautologies, eight_eq_eight) { - ASSERT_EQ(8, 8); +#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" + +#include + +#include + +#include "utilstrencodings.h" +#include "version.h" +#include "serialize.h" +#include "streams.h" + +#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" +#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" +#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" + +#include + +#include "json/json_spirit_reader_template.h" +#include "json/json_spirit_utils.h" +#include "json/json_spirit_writer_template.h" + +using namespace json_spirit; +Array +read_json(const std::string& jsondata) +{ + Value v; + + if (!read_string(jsondata, v) || v.type() != array_type) + { + ADD_FAILURE(); + return Array(); + } + return v.get_array(); +} + +#include "zcash/IncrementalMerkleTree.hpp" +#include "zerocash/IncrementalMerkleTree.h" +#include "zerocash/utils/util.h" + +//#define PRINT_JSON 1 + +using namespace std; +using namespace libzerocash; +using namespace libsnark; + +template +void expect_deser_same(const T& expected) +{ + CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION); + ss1 << expected; + + auto serialized_size = ss1.size(); + + T object; + ss1 >> object; + + CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); + ss2 << object; + + ASSERT_TRUE(serialized_size == ss2.size()); + ASSERT_TRUE(memcmp(&*ss1.begin(), &*ss2.begin(), serialized_size) == 0); +} + +template<> +void expect_deser_same(const ZCTestingIncrementalWitness& expected) +{ + // 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<> +void expect_deser_same(const libzcash::MerklePath& expected) +{ + // This deserialization check is pointless for MerklePath, + // since we only serialize it to check it against test + // vectors. See `expect_test_vector` for that. Also, + // it doesn't seem that vector can be properly + // deserialized by Bitcoin's serialization code. +} + +template +void expect_test_vector(T& it, const U& expected) +{ + expect_deser_same(expected); + + CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION); + ss1 << expected; + + #ifdef PRINT_JSON + std::cout << "\t\"" ; + std::cout << HexStr(ss1.begin(), ss1.end()) << "\",\n"; + #else + std::string raw = (it++)->get_str(); + CDataStream ss2(ParseHex(raw), SER_NETWORK, PROTOCOL_VERSION); + + ASSERT_TRUE(ss1.size() == ss2.size()); + ASSERT_TRUE(memcmp(&*ss1.begin(), &*ss2.begin(), ss1.size()) == 0); + #endif +} + +/* +This is a wrapper around the old incremental merkle tree which +attempts to mimic the new API as much as possible so that its +behavior can be compared with the test vectors we use. +*/ +class OldIncrementalMerkleTree { +private: + libzerocash::IncrementalMerkleTree* tree; + boost::optional> index; + bool witnessed; + +public: + OldIncrementalMerkleTree() : index(boost::none), witnessed(false) { + this->tree = new IncrementalMerkleTree(INCREMENTAL_MERKLE_TREE_DEPTH_TESTING); + } + + ~OldIncrementalMerkleTree() + { + delete tree; + } + + OldIncrementalMerkleTree (const OldIncrementalMerkleTree& other) : index(boost::none), witnessed(false) + { + this->tree = new IncrementalMerkleTree(INCREMENTAL_MERKLE_TREE_DEPTH_TESTING); + this->tree->setTo(*other.tree); + index = other.index; + witnessed = other.witnessed; + } + + OldIncrementalMerkleTree& operator= (const OldIncrementalMerkleTree& other) + { + OldIncrementalMerkleTree tmp(other); // re-use copy-constructor + *this = std::move(tmp); // re-use move-assignment + return *this; + } + + OldIncrementalMerkleTree& operator= (OldIncrementalMerkleTree&& other) + { + tree->setTo(*other.tree); + index = other.index; + witnessed = other.witnessed; + return *this; + } + + libzcash::MerklePath path() { + assert(witnessed); + + if (!index) { + throw std::runtime_error("can't create an authentication path for the beginning of the tree"); + } + + merkle_authentication_path path(INCREMENTAL_MERKLE_TREE_DEPTH_TESTING); + tree->getWitness(*index, path); + + libzcash::MerklePath ret; + ret.authentication_path = path; + ret.index = *index; + + return ret; + } + + uint256 root() { + std::vector newrt_v(32); + tree->getRootValue(newrt_v); + return uint256(newrt_v); + } + + void append(uint256 obj) { + std::vector new_index; + std::vector obj_bv(obj.begin(), obj.end()); + + std::vector commitment_bv(256); + libzerocash::convertBytesVectorToVector(obj_bv, commitment_bv); + + tree->insertElement(commitment_bv, new_index); + + if (!witnessed) { + index = new_index; + } + } + + OldIncrementalMerkleTree witness() { + OldIncrementalMerkleTree ret; + ret.tree->setTo(*tree); + ret.index = index; + ret.witnessed = true; + + return ret; + } +}; + +template +void expect_ser_test_vector(B& b, const C& c, const A& tree) { + expect_test_vector(b, c); +} + +template +void expect_ser_test_vector(B& b, const C& c, const OldIncrementalMerkleTree& tree) { + // Don't perform serialization tests on the old tree. +} + +template +void test_tree(Array root_tests, Array ser_tests, Array witness_ser_tests, Array path_tests) { + Array::iterator root_iterator = root_tests.begin(); + Array::iterator ser_iterator = ser_tests.begin(); + Array::iterator witness_ser_iterator = witness_ser_tests.begin(); + Array::iterator path_iterator = path_tests.begin(); + + uint256 test_commitment = uint256S("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + + Tree tree; + + // The root of the tree at this point is expected to be null. + ASSERT_TRUE(tree.root().IsNull()); + + // 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 witnesses; + + for (size_t i = 0; i < 16; i++) { + // Witness here + witnesses.push_back(tree.witness()); + + // Now append a commitment to the tree + tree.append(test_commitment); + + // Check tree root consistency + expect_test_vector(root_iterator, tree.root()); + + // Check serialization of tree + expect_ser_test_vector(ser_iterator, tree, tree); + + bool first = true; // The first witness can never form a path + BOOST_FOREACH(Witness& wit, witnesses) + { + // Append the same commitment to all the witnesses + wit.append(test_commitment); + + if (first) { + ASSERT_THROW(wit.path(), std::runtime_error); + } else { + auto path = wit.path(); + + // The old tree has some serious bugs which make it + // fail some of these test vectors. + // + // The new tree is strictly more correct in its + // behavior, as we demonstrate by constructing and + // evaluating the tree over a dummy circuit. + if (typeid(Tree) != typeid(OldIncrementalMerkleTree)) { + expect_test_vector(path_iterator, path); + + typedef Fr FieldT; + + protoboard pb; + pb_variable_array positions; + digest_variable commitment(pb, 256, "commitment"); + digest_variable root(pb, 256, "root"); + positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "pos"); + merkle_authentication_path_variable> authvars(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "auth"); + merkle_tree_check_read_gadget> auth( + pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, positions, commitment, root, authvars, ONE, "path" + ); + commitment.generate_r1cs_constraints(); + root.generate_r1cs_constraints(); + authvars.generate_r1cs_constraints(); + auth.generate_r1cs_constraints(); + + std::vector commitment_bv; + { + std::vector commitment_v(test_commitment.begin(), test_commitment.end()); + convertBytesVectorToVector(commitment_v, commitment_bv); + } + + size_t path_index = libzerocash::convertVectorToInt(path.index); + + commitment.bits.fill_with_bits(pb, bit_vector(commitment_bv)); + positions.fill_with_bits_of_ulong(pb, path_index); + + authvars.generate_r1cs_witness(path_index, path.authentication_path); + auth.generate_r1cs_witness(); + + std::vector root_bv; + { + uint256 witroot = wit.root(); + std::vector root_v(witroot.begin(), witroot.end()); + convertBytesVectorToVector(root_v, root_bv); + } + + root.bits.fill_with_bits(pb, bit_vector(root_bv)); + + ASSERT_TRUE(pb.is_satisfied()); + + root_bv[0] = !root_bv[0]; + root.bits.fill_with_bits(pb, bit_vector(root_bv)); + + ASSERT_TRUE(!pb.is_satisfied()); + } + } + + // Check witness serialization + expect_ser_test_vector(witness_ser_iterator, wit, tree); + + ASSERT_TRUE(wit.root() == tree.root()); + + first = false; + } + } + + // The old tree would silently ignore appending when it was full. + if (typeid(Tree) != typeid(OldIncrementalMerkleTree)) { + // Tree should be full now + ASSERT_THROW(tree.append(uint256()), std::runtime_error); + + BOOST_FOREACH(Witness& wit, witnesses) + { + ASSERT_THROW(wit.append(uint256()), std::runtime_error); + } + } +} + +TEST(merkletree, vectors) { + libsnark::default_r1cs_ppzksnark_pp::init_public_params(); + + Array root_tests = read_json(std::string(json_tests::merkle_roots, json_tests::merkle_roots + sizeof(json_tests::merkle_roots))); + Array ser_tests = read_json(std::string(json_tests::merkle_serialization, json_tests::merkle_serialization + sizeof(json_tests::merkle_serialization))); + Array witness_ser_tests = read_json(std::string(json_tests::merkle_witness_serialization, json_tests::merkle_witness_serialization + sizeof(json_tests::merkle_witness_serialization))); + Array path_tests = read_json(std::string(json_tests::merkle_path, json_tests::merkle_path + sizeof(json_tests::merkle_path))); + + test_tree(root_tests, ser_tests, witness_ser_tests, path_tests); + test_tree(root_tests, ser_tests, witness_ser_tests, path_tests); +} + +TEST(merkletree, deserializeInvalid) { + // attempt to deserialize a small tree from a serialized large tree + // (exceeds depth well-formedness check) + ZCIncrementalMerkleTree newTree; + + for (size_t i = 0; i < 16; i++) { + newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c")); + } + + newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c")); + + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << newTree; + + ZCTestingIncrementalMerkleTree newTreeSmall; + 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 + ); + + ZCIncrementalMerkleTree tree; + 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 + ); + + ZCIncrementalMerkleTree tree; + 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 + ); + + ZCIncrementalMerkleTree tree; + ASSERT_THROW(ss >> tree, std::ios_base::failure); +} + +TEST(merkletree, testZeroElements) { + for (int start = 0; start < 20; start++) { + ZCIncrementalMerkleTree newTree; + + ASSERT_TRUE(newTree.root() == uint256()); + + 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); + } } diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp deleted file mode 100644 index c6b19cf2c..000000000 --- a/src/test/merkle_tests.cpp +++ /dev/null @@ -1,400 +0,0 @@ -#include "test/test_bitcoin.h" - -#include "data/merkle_roots.json.h" -#include "data/merkle_serialization.json.h" -#include "data/merkle_witness_serialization.json.h" -#include "data/merkle_path.json.h" - -#include - -#include - -#include "utilstrencodings.h" -#include "version.h" - -#include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" -using namespace json_spirit; -extern Array read_json(const std::string& jsondata); - -#include "zcash/IncrementalMerkleTree.hpp" -#include "zerocash/IncrementalMerkleTree.h" - -//#define PRINT_JSON 1 - -using namespace std; - -template -void expect_deser_same(const T& expected) -{ - CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION); - ss1 << expected; - - auto serialized_size = ss1.size(); - - T object; - ss1 >> object; - - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << object; - - BOOST_CHECK(serialized_size == ss2.size()); - BOOST_CHECK(memcmp(&*ss1.begin(), &*ss2.begin(), serialized_size) == 0); -} - -template<> -void expect_deser_same(const ZCTestingIncrementalWitness& expected) -{ - // 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<> -void expect_deser_same(const libzcash::MerklePath& expected) -{ - // This deserialization check is pointless for MerklePath, - // since we only serialize it to check it against test - // vectors. See `expect_test_vector` for that. Also, - // it doesn't seem that vector can be properly - // deserialized by Bitcoin's serialization code. -} - -template -void expect_test_vector(T& it, const U& expected) -{ - expect_deser_same(expected); - - CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION); - ss1 << expected; - - #ifdef PRINT_JSON - std::cout << "\t\"" ; - std::cout << HexStr(ss1.begin(), ss1.end()) << "\",\n"; - #else - std::string raw = (it++)->get_str(); - CDataStream ss2(ParseHex(raw), SER_NETWORK, PROTOCOL_VERSION); - - BOOST_CHECK(ss1.size() == ss2.size()); - BOOST_CHECK(memcmp(&*ss1.begin(), &*ss2.begin(), ss1.size()) == 0); - #endif -} - -/* -This is a wrapper around the old incremental merkle tree which -attempts to mimic the new API as much as possible so that its -behavior can be compared with the test vectors we use. -*/ -class OldIncrementalMerkleTree { -private: - libzerocash::IncrementalMerkleTree* tree; - boost::optional> index; - bool witnessed; - -public: - OldIncrementalMerkleTree() : index(boost::none), witnessed(false) { - this->tree = new IncrementalMerkleTree(INCREMENTAL_MERKLE_TREE_DEPTH_TESTING); - } - - ~OldIncrementalMerkleTree() - { - delete tree; - } - - OldIncrementalMerkleTree (const OldIncrementalMerkleTree& other) : index(boost::none), witnessed(false) - { - this->tree = new IncrementalMerkleTree(INCREMENTAL_MERKLE_TREE_DEPTH_TESTING); - this->tree->setTo(*other.tree); - index = other.index; - witnessed = other.witnessed; - } - - OldIncrementalMerkleTree& operator= (const OldIncrementalMerkleTree& other) - { - OldIncrementalMerkleTree tmp(other); // re-use copy-constructor - *this = std::move(tmp); // re-use move-assignment - return *this; - } - - OldIncrementalMerkleTree& operator= (OldIncrementalMerkleTree&& other) - { - tree->setTo(*other.tree); - index = other.index; - witnessed = other.witnessed; - return *this; - } - - libzcash::MerklePath path() { - assert(witnessed); - - if (!index) { - throw std::runtime_error("can't create an authentication path for the beginning of the tree"); - } - - merkle_authentication_path path(INCREMENTAL_MERKLE_TREE_DEPTH_TESTING); - tree->getWitness(*index, path); - - libzcash::MerklePath ret; - ret.authentication_path = path; - ret.index = *index; - - return ret; - } - - uint256 root() { - std::vector newrt_v(32); - tree->getRootValue(newrt_v); - return uint256(newrt_v); - } - - void append(uint256 obj) { - std::vector new_index; - std::vector obj_bv(obj.begin(), obj.end()); - - std::vector commitment_bv(256); - libzerocash::convertBytesVectorToVector(obj_bv, commitment_bv); - - tree->insertElement(commitment_bv, new_index); - - if (!witnessed) { - index = new_index; - } - } - - OldIncrementalMerkleTree witness() { - OldIncrementalMerkleTree ret; - ret.tree->setTo(*tree); - ret.index = index; - ret.witnessed = true; - - return ret; - } -}; - -template -void expect_ser_test_vector(B& b, const C& c, const A& tree) { - expect_test_vector(b, c); -} - -template -void expect_ser_test_vector(B& b, const C& c, const OldIncrementalMerkleTree& tree) { - // Don't perform serialization tests on the old tree. -} - -template -void test_tree(Array root_tests, Array ser_tests, Array witness_ser_tests, Array path_tests) { - Array::iterator root_iterator = root_tests.begin(); - Array::iterator ser_iterator = ser_tests.begin(); - Array::iterator witness_ser_iterator = witness_ser_tests.begin(); - Array::iterator path_iterator = path_tests.begin(); - - uint256 test_commitment = uint256S("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); - - Tree tree; - - // The root of the tree at this point is expected to be null. - BOOST_CHECK(tree.root().IsNull()); - - // 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 witnesses; - - for (size_t i = 0; i < 16; i++) { - // Witness here - witnesses.push_back(tree.witness()); - - // Now append a commitment to the tree - tree.append(test_commitment); - - // Check tree root consistency - expect_test_vector(root_iterator, tree.root()); - - // Check serialization of tree - expect_ser_test_vector(ser_iterator, tree, tree); - - bool first = true; // The first witness can never form a path - BOOST_FOREACH(Witness& wit, witnesses) - { - // Append the same commitment to all the witnesses - wit.append(test_commitment); - - if (first) { - BOOST_CHECK_THROW(wit.path(), std::runtime_error); - } else { - auto path = wit.path(); - - // The old tree has some serious bugs which make it - // fail some of these test vectors. - // - // The new tree is strictly more correct in its - // behavior, as we demonstrate by constructing and - // evaluating the tree over a dummy circuit. - if (typeid(Tree) != typeid(OldIncrementalMerkleTree)) { - expect_test_vector(path_iterator, path); - - typedef Fr FieldT; - - protoboard pb; - pb_variable_array positions; - digest_variable commitment(pb, 256, "commitment"); - digest_variable root(pb, 256, "root"); - positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "pos"); - merkle_authentication_path_variable> authvars(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "auth"); - merkle_tree_check_read_gadget> auth( - pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, positions, commitment, root, authvars, ONE, "path" - ); - commitment.generate_r1cs_constraints(); - root.generate_r1cs_constraints(); - authvars.generate_r1cs_constraints(); - auth.generate_r1cs_constraints(); - - std::vector commitment_bv; - { - std::vector commitment_v(test_commitment.begin(), test_commitment.end()); - convertBytesVectorToVector(commitment_v, commitment_bv); - } - - size_t path_index = libzerocash::convertVectorToInt(path.index); - - commitment.bits.fill_with_bits(pb, bit_vector(commitment_bv)); - positions.fill_with_bits_of_ulong(pb, path_index); - - authvars.generate_r1cs_witness(path_index, path.authentication_path); - auth.generate_r1cs_witness(); - - std::vector root_bv; - { - uint256 witroot = wit.root(); - std::vector root_v(witroot.begin(), witroot.end()); - convertBytesVectorToVector(root_v, root_bv); - } - - root.bits.fill_with_bits(pb, bit_vector(root_bv)); - - BOOST_CHECK(pb.is_satisfied()); - - root_bv[0] = !root_bv[0]; - root.bits.fill_with_bits(pb, bit_vector(root_bv)); - - BOOST_CHECK(!pb.is_satisfied()); - } - } - - // Check witness serialization - expect_ser_test_vector(witness_ser_iterator, wit, tree); - - BOOST_CHECK(wit.root() == tree.root()); - - first = false; - } - } - - // The old tree would silently ignore appending when it was full. - if (typeid(Tree) != typeid(OldIncrementalMerkleTree)) { - // Tree should be full now - BOOST_CHECK_THROW(tree.append(uint256()), std::runtime_error); - - BOOST_FOREACH(Witness& wit, witnesses) - { - BOOST_CHECK_THROW(wit.append(uint256()), std::runtime_error); - } - } -} - -BOOST_FIXTURE_TEST_SUITE(merkle_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(tree_test_vectors) -{ - libsnark::default_r1cs_ppzksnark_pp::init_public_params(); - - Array root_tests = read_json(std::string(json_tests::merkle_roots, json_tests::merkle_roots + sizeof(json_tests::merkle_roots))); - Array ser_tests = read_json(std::string(json_tests::merkle_serialization, json_tests::merkle_serialization + sizeof(json_tests::merkle_serialization))); - Array witness_ser_tests = read_json(std::string(json_tests::merkle_witness_serialization, json_tests::merkle_witness_serialization + sizeof(json_tests::merkle_witness_serialization))); - Array path_tests = read_json(std::string(json_tests::merkle_path, json_tests::merkle_path + sizeof(json_tests::merkle_path))); - - test_tree(root_tests, ser_tests, witness_ser_tests, path_tests); - test_tree(root_tests, ser_tests, witness_ser_tests, path_tests); -} - -BOOST_AUTO_TEST_CASE( deserializeInvalid ) { - // attempt to deserialize a small tree from a serialized large tree - // (exceeds depth well-formedness check) - ZCIncrementalMerkleTree newTree; - - for (size_t i = 0; i < 16; i++) { - newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c")); - } - - newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c")); - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << newTree; - - ZCTestingIncrementalMerkleTree newTreeSmall; - BOOST_CHECK_THROW({ss >> newTreeSmall;}, std::ios_base::failure); -} - -BOOST_AUTO_TEST_CASE( deserializeInvalid2 ) { - // the most ancestral parent is empty - CDataStream ss( - ParseHex("0155b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e3000100"), - SER_NETWORK, - PROTOCOL_VERSION - ); - - ZCIncrementalMerkleTree tree; - BOOST_CHECK_THROW(ss >> tree, std::ios_base::failure); -} - -BOOST_AUTO_TEST_CASE( deserializeInvalid3 ) { - // left doesn't exist but right does - CDataStream ss( - ParseHex("000155b852781b9995a44c939b64e441ae2724b96f99c8f4fb9a141cfc9842c4b0e300"), - SER_NETWORK, - PROTOCOL_VERSION - ); - - ZCIncrementalMerkleTree tree; - BOOST_CHECK_THROW(ss >> tree, std::ios_base::failure); -} - -BOOST_AUTO_TEST_CASE( deserializeInvalid4 ) { - // left doesn't exist but a parent does - CDataStream ss( - ParseHex("000001018695873d63ec0bceeadb5bf4ccc6723ac803c1826fc7cfb34fc76180305ae27d"), - SER_NETWORK, - PROTOCOL_VERSION - ); - - ZCIncrementalMerkleTree tree; - BOOST_CHECK_THROW(ss >> tree, std::ios_base::failure); -} - -BOOST_AUTO_TEST_CASE( testZeroElements ) { - for (int start = 0; start < 20; start++) { - ZCIncrementalMerkleTree newTree; - - BOOST_CHECK(newTree.root() == uint256()); - - 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()); - } - - BOOST_CHECK(newTree.root() == oldroot); - } -} - -BOOST_AUTO_TEST_SUITE_END()