mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-20 13:37:28 +02:00
Add fast Merkle branch functions.
A fast Merkle branch uses midstate to perform a single SHA-256 compression per branch, and is not vulnerable to CVE-2012-2459. It produces different hashes though, so can only be used for new hash trees going forward.
This commit is contained in:
parent
29ad41dd56
commit
3518ae82d6
2 changed files with 76 additions and 6 deletions
|
|
@ -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<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector<uint256>* pbranch) {
|
||||
static void MerkleComputation(const std::vector<uint256>& leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector<uint256>* 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<uint256>& 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<uint256>& 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<uint256>& 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<uint256>& leaves, uint256* proot
|
|||
|
||||
uint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated) {
|
||||
uint256 hash;
|
||||
MerkleComputation(leaves, &hash, mutated, -1, NULL);
|
||||
MerkleComputation(leaves, &hash, mutated, -1, NULL, MERKLE_COMPUTATION_MUTABLE);
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position) {
|
||||
std::vector<uint256> 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<uint2
|
|||
return hash;
|
||||
}
|
||||
|
||||
uint256 ComputeFastMerkleRoot(const std::vector<uint256>& leaves) {
|
||||
uint256 hash;
|
||||
MerkleComputation(leaves, &hash, NULL, -1, NULL, MERKLE_COMPUTATION_FAST);
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::vector<uint256> ComputeFastMerkleBranch(const std::vector<uint256>& leaves, uint32_t position) {
|
||||
std::vector<uint256> ret;
|
||||
MerkleComputation(leaves, NULL, NULL, position, &ret, MERKLE_COMPUTATION_FAST);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint256 ComputeFastMerkleRootFromBranch(const uint256& leaf, const std::vector<uint256>& vMerkleBranch, uint32_t nIndex) {
|
||||
size_t max = 0;
|
||||
for (int i = 0; i < 32; ++i)
|
||||
if (nIndex & ((uint32_t)1)<<i)
|
||||
max = i + 1;
|
||||
while (max > vMerkleBranch.size()) {
|
||||
int i;
|
||||
for (i = max-1; i >= 0; --i)
|
||||
if (!(nIndex & ((uint32_t)1)<<i))
|
||||
break;
|
||||
if (i < 0)
|
||||
return uint256();
|
||||
nIndex = (((((uint32_t)1)<<(i+1))-1)>>1) |
|
||||
((((uint32_t)1)<< i )-1);
|
||||
--max;
|
||||
}
|
||||
uint256 hash = leaf;
|
||||
for (std::vector<uint256>::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<uint256> leaves;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,16 @@ uint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated = NU
|
|||
std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position);
|
||||
uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector<uint256>& 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<uint256>& leaves);
|
||||
std::vector<uint256> ComputeFastMerkleBranch(const std::vector<uint256>& leaves, uint32_t position);
|
||||
uint256 ComputeFastMerkleRootFromBranch(const uint256& leaf, const std::vector<uint256>& 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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue