Auto merge of #889 - ebfull:new-imt-redux, r=ebfull

Implement and integrate new Incremental Merkle Tree

This supersedes #823.

----

This is an implementation of a new incremental merkle tree with

* no memory safety issues
* a more sensible internal design
* better space efficiency (tree representation, witnessing)
* simpler API

It is intended that this tracks the behavior of the previous tree, which it does, as verified by tests. I even wrote a little circuit for testing that all the paths work.

This PR also integrates the tree into the codebase and deprecates the old tree in almost all of our code. (I left it alone in `zerocashTest` but everything else has been changed.)

This change is compatible with the testnet but you will need to clear your *local* blockchain data out since the serialized representation of the merkle tree is now different.

Closes #517, Closes #519, Closes #591, Closes #460, Closes #473
This commit is contained in:
zkbot
2016-05-03 17:33:27 +00:00
29 changed files with 1389 additions and 464 deletions

View File

@@ -2495,10 +2495,9 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
uint256 commitment = uint256(commitment_v);
assert(pwalletMain != NULL);
libsnark::merkle_authentication_path path(INCREMENTAL_MERKLE_TREE_DEPTH); // We don't care during receive... yet! :)
size_t path_index = 0;
libzcash::MerklePath path;
uint256 anchor;
auto found_in_chain = pwalletMain->WitnessBucketCommitment(commitment, path, path_index, anchor);
auto found_in_chain = pwalletMain->WitnessBucketCommitment(commitment, path, anchor);
CAmount value_of_bucket = decrypted_bucket.getValue();
@@ -2602,14 +2601,13 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
std::vector<unsigned char> commitment_v = input_coin.getCoinCommitment().getCommitmentValue();
uint256 commitment = uint256(commitment_v);
libsnark::merkle_authentication_path path(INCREMENTAL_MERKLE_TREE_DEPTH);
size_t path_index = 0;
libzcash::MerklePath path;
assert(pwalletMain != NULL);
if (!pwalletMain->WitnessBucketCommitment(commitment, path, path_index, anchor)) {
if (!pwalletMain->WitnessBucketCommitment(commitment, path, anchor)) {
throw std::runtime_error("Couldn't find bucket in the blockchain");
}
vpourin.push_back(PourInput(input_coin, zcaddress, path_index, path));
vpourin.push_back(PourInput(input_coin, zcaddress, path));
}
while (vpourin.size() < NUM_POUR_INPUTS) {

View File

@@ -1052,15 +1052,12 @@ bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
}
bool CWallet::WitnessBucketCommitment(uint256 &commitment,
libsnark::merkle_authentication_path& path,
size_t &path_index,
libzcash::MerklePath &path,
uint256 &final_anchor)
{
bool res = false;
std::vector<bool> commitment_index;
CBlockIndex* pindex = chainActive.Genesis();
libzerocash::IncrementalMerkleTree tree(INCREMENTAL_MERKLE_TREE_DEPTH);
ZCIncrementalMerkleTree tree;
boost::optional<ZCIncrementalWitness> witness = boost::none;
uint256 current_anchor;
while (pindex) {
@@ -1073,43 +1070,41 @@ bool CWallet::WitnessBucketCommitment(uint256 &commitment,
{
BOOST_FOREACH(const uint256 &bucket_commitment, pour.commitments)
{
std::vector<bool> commitment_bv(ZC_CM_SIZE * 8);
std::vector<bool> index;
std::vector<unsigned char> commitment_value(bucket_commitment.begin(), bucket_commitment.end());
libzerocash::convertBytesVectorToVector(commitment_value, commitment_bv);
assert(tree.insertElement(commitment_bv, index));
if (witness) {
witness->append(bucket_commitment);
} else {
tree.append(bucket_commitment);
if (bucket_commitment == commitment) {
// We've found it! Now, we construct a witness.
res = true;
commitment_index = index;
if (bucket_commitment == commitment) {
witness = tree.witness();
}
}
}
}
}
{
std::vector<unsigned char> newrt_v(32);
tree.getRootValue(newrt_v);
current_anchor = uint256(newrt_v);
if (witness) {
current_anchor = witness->root();
} else {
current_anchor = tree.root();
}
// Consistency check: we should be able to find the current tree
// in our CCoins view.
libzerocash::IncrementalMerkleTree dummy_tree(INCREMENTAL_MERKLE_TREE_DEPTH);
ZCIncrementalMerkleTree dummy_tree;
assert(pcoinsTip->GetAnchorAt(current_anchor, dummy_tree));
pindex = chainActive.Next(pindex);
}
if (res) {
assert(tree.getWitness(commitment_index, path));
if (witness) {
path = witness->path();
final_anchor = current_anchor;
return true;
}
path_index = libzerocash::convertVectorToInt(commitment_index);
final_anchor = current_anchor;
return res;
return false;
}
/**

View File

@@ -616,7 +616,7 @@ public:
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
void EraseFromWallet(const uint256 &hash);
bool WitnessBucketCommitment(uint256 &commitment, libsnark::merkle_authentication_path& path, size_t &path_index, uint256 &final_anchor);
bool WitnessBucketCommitment(uint256 &commitment, libzcash::MerklePath& path, uint256 &final_anchor);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime);