diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp index 1ce5a9d87e..5f354cbf2c 100644 --- a/src/consensus/merkle.cpp +++ b/src/consensus/merkle.cpp @@ -42,14 +42,32 @@ root. */ +typedef enum { + MERKLE_COMPUTATION_MUTABLE = 0x1, + MERKLE_COMPUTATION_FAST = 0x2 +} merklecomputationopts; + +static void MerkleHash_Hash256(uint256& parent, const uint256& left, const uint256& right) { + CHash256().Write(left.begin(), 32).Write(right.begin(), 32).Finalize(parent.begin()); +} + +static void MerkleHash_Sha256Midstate(uint256& parent, const uint256& left, const uint256& right) { + CSHA256().Write(left.begin(), 32).Write(right.begin(), 32).Midstate(parent.begin(), NULL, NULL); +} + /* This implements a constant-space merkle root/path calculator, limited to 2^32 leaves. */ -static void MerkleComputation(const std::vector& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector* pbranch) { +static void MerkleComputation(const std::vector& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector* pbranch, merklecomputationopts flags) { if (pbranch) pbranch->clear(); if (leaves.size() == 0) { if (pmutated) *pmutated = false; if (proot) *proot = uint256(); return; } + bool fMutable = flags & MERKLE_COMPUTATION_MUTABLE; + void (*MerkleHash)(uint256&, const uint256&, const uint256&) = MerkleHash_Hash256; + if (flags & MERKLE_COMPUTATION_FAST) { + MerkleHash = MerkleHash_Sha256Midstate; + } bool mutated = false; // count is the number of leaves processed so far. uint32_t count = 0; @@ -80,7 +98,7 @@ static void MerkleComputation(const std::vector& leaves, uint256* proot } } mutated |= (inner[level] == h); - CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin()); + MerkleHash(h, inner[level], h); } // Store the resulting hash at inner position level. inner[level] = h; @@ -106,7 +124,9 @@ static void MerkleComputation(const std::vector& leaves, uint256* proot if (pbranch && matchh) { pbranch->push_back(h); } - CHash256().Write(h.begin(), 32).Write(h.begin(), 32).Finalize(h.begin()); + if (fMutable) { + MerkleHash(h, h, h); + } // Increment count to the value it would have if two entries at this // level had existed. count += (((uint32_t)1) << level); @@ -121,7 +141,7 @@ static void MerkleComputation(const std::vector& leaves, uint256* proot matchh = true; } } - CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin()); + MerkleHash(h, inner[level], h); level++; } } @@ -132,13 +152,13 @@ static void MerkleComputation(const std::vector& leaves, uint256* proot uint256 ComputeMerkleRoot(const std::vector& leaves, bool* mutated) { uint256 hash; - MerkleComputation(leaves, &hash, mutated, -1, NULL); + MerkleComputation(leaves, &hash, mutated, -1, NULL, MERKLE_COMPUTATION_MUTABLE); return hash; } std::vector ComputeMerkleBranch(const std::vector& leaves, uint32_t position) { std::vector ret; - MerkleComputation(leaves, NULL, NULL, position, &ret); + MerkleComputation(leaves, NULL, NULL, position, &ret, MERKLE_COMPUTATION_MUTABLE); return ret; } @@ -155,6 +175,46 @@ uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector& leaves) { + uint256 hash; + MerkleComputation(leaves, &hash, NULL, -1, NULL, MERKLE_COMPUTATION_FAST); + return hash; +} + +std::vector ComputeFastMerkleBranch(const std::vector& leaves, uint32_t position) { + std::vector ret; + MerkleComputation(leaves, NULL, NULL, position, &ret, MERKLE_COMPUTATION_FAST); + return ret; +} + +uint256 ComputeFastMerkleRootFromBranch(const uint256& leaf, const std::vector& vMerkleBranch, uint32_t nIndex) { + size_t max = 0; + for (int i = 0; i < 32; ++i) + if (nIndex & ((uint32_t)1)< vMerkleBranch.size()) { + int i; + for (i = max-1; i >= 0; --i) + if (!(nIndex & ((uint32_t)1)<>1) | + ((((uint32_t)1)<< i )-1); + --max; + } + uint256 hash = leaf; + for (std::vector::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) { + if (nIndex & 1) { + MerkleHash_Sha256Midstate(hash, *it, hash); + } else { + MerkleHash_Sha256Midstate(hash, hash, *it); + } + nIndex >>= 1; + } + return hash; +} + uint256 BlockMerkleRoot(const CBlock& block, bool* mutated) { std::vector leaves; diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h index 194aea9b75..576cba9b74 100644 --- a/src/consensus/merkle.h +++ b/src/consensus/merkle.h @@ -16,6 +16,16 @@ uint256 ComputeMerkleRoot(const std::vector& leaves, bool* mutated = NU std::vector ComputeMerkleBranch(const std::vector& leaves, uint32_t position); uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector& branch, uint32_t position); +/* + * Has similar API semantics, but produces Merkle roots and validates + * branches 3x as fast, and without the mutation vulnerability. Cannot + * be substituted for the non-fast variants because the hash values are + * different. + */ +uint256 ComputeFastMerkleRoot(const std::vector& leaves); +std::vector ComputeFastMerkleBranch(const std::vector& leaves, uint32_t position); +uint256 ComputeFastMerkleRootFromBranch(const uint256& leaf, const std::vector& branch, uint32_t position); + /* * Compute the Merkle root of the transactions in a block. * *mutated is set to true if a duplicated subtree was found.