Test old tree along with new tree as much as possible.

This commit is contained in:
Sean Bowe 2016-04-03 15:39:08 -06:00
parent 434f328446
commit 482aefbd0d
2 changed files with 185 additions and 18 deletions

View File

@ -18,6 +18,7 @@ using namespace json_spirit;
extern Array read_json(const std::string& jsondata);
#include "zcash/IncrementalMerkleTree.hpp"
#include "zerocash/IncrementalMerkleTree.h"
//#define PRINT_JSON 1
@ -41,15 +42,109 @@ void expect_test_vector(T& it, const U& expected)
#endif
}
BOOST_FIXTURE_TEST_SUITE(merkle_tests, BasicTestingSetup)
/*
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<std::vector<bool>> index;
bool witnessed;
BOOST_AUTO_TEST_CASE(tree_test_vectors)
{
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)));
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<unsigned char> newrt_v(32);
tree->getRootValue(newrt_v);
return uint256(newrt_v);
}
void append(uint256 obj) {
std::vector<bool> new_index;
std::vector<unsigned char> obj_bv(obj.begin(), obj.end());
std::vector<bool> 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<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 B, typename C>
void expect_ser_test_vector(B& b, const C& c, const OldIncrementalMerkleTree& tree) {
// Don't perform serialization tests on the old tree.
}
template<typename Tree, typename Witness>
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();
@ -57,7 +152,7 @@ BOOST_AUTO_TEST_CASE(tree_test_vectors)
uint256 test_commitment = uint256S("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
ZCTestingIncrementalMerkleTree tree;
Tree tree;
// The root of the tree at this point is expected to be null.
BOOST_CHECK(tree.root().IsNull());
@ -65,7 +160,7 @@ BOOST_AUTO_TEST_CASE(tree_test_vectors)
// 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<ZCTestingIncrementalWitness> witnesses;
vector<Witness> witnesses;
for (size_t i = 0; i < 16; i++) {
// Witness here
@ -78,10 +173,10 @@ BOOST_AUTO_TEST_CASE(tree_test_vectors)
expect_test_vector(root_iterator, tree.root());
// Check serialization of tree
expect_test_vector(ser_iterator, tree);
expect_ser_test_vector(ser_iterator, tree, tree);
bool first = true; // The first witness can never form a path
BOOST_FOREACH(ZCTestingIncrementalWitness& wit, witnesses)
BOOST_FOREACH(Witness& wit, witnesses)
{
// Append the same commitment to all the witnesses
wit.append(test_commitment);
@ -91,11 +186,65 @@ BOOST_AUTO_TEST_CASE(tree_test_vectors)
} else {
auto path = wit.path();
expect_test_vector(path_iterator, 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<default_r1cs_ppzksnark_pp> FieldT;
protoboard<FieldT> pb;
pb_variable_array<FieldT> positions;
digest_variable<FieldT> commitment(pb, 256, "commitment");
digest_variable<FieldT> root(pb, 256, "root");
positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "pos");
merkle_authentication_path_variable<FieldT, sha256_two_to_one_hash_gadget<FieldT>> authvars(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "auth");
merkle_tree_check_read_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT>> 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<bool> commitment_bv;
{
std::vector<unsigned char> 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<bool> root_bv;
{
uint256 witroot = wit.root();
std::vector<unsigned char> 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_test_vector(witness_ser_iterator, wit);
expect_ser_test_vector(witness_ser_iterator, wit, tree);
BOOST_CHECK(wit.root() == tree.root());
@ -103,15 +252,31 @@ BOOST_AUTO_TEST_CASE(tree_test_vectors)
}
}
// Tree should be full now
BOOST_CHECK_THROW(tree.append(uint256()), std::runtime_error);
// 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(ZCTestingIncrementalWitness& wit, witnesses)
{
BOOST_CHECK_THROW(wit.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)
{
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<ZCTestingIncrementalMerkleTree, ZCTestingIncrementalWitness>(root_tests, ser_tests, witness_ser_tests, path_tests);
test_tree<OldIncrementalMerkleTree, OldIncrementalMerkleTree>(root_tests, ser_tests, witness_ser_tests, path_tests);
}
BOOST_AUTO_TEST_CASE( deserializeInvalid ) {
ZCIncrementalMerkleTree newTree;

View File

@ -26,6 +26,8 @@ public:
READWRITE(index);
}
MerklePath() { }
MerklePath(std::vector<std::vector<bool>> authentication_path, std::vector<bool> index)
: authentication_path(authentication_path), index(index) { }
};