mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-27 16:05:39 +01:00
Merge #13452: rpc: have verifytxoutproof check the number of txns in proof structure
d280617bf5[qa] Add a test for merkle proof malleation (Suhas Daftuar)ed82f17000have verifytxoutproof check the number of txns in proof structure (Gregory Sanders) Pull request description: Recent publication of a weakness in Bitcoin's merkle tree construction demonstrates many SPV applications vulnerable to an expensive to pull off yet still plausible attack: https://bitslog.wordpress.com/2018/06/09/leaf-node-weakness-in-bitcoin-merkle-tree-design/ This change would at least allow `verifytxoutproof` to properly validate that the proof matches a known block, with known number of transactions any time after the full block is processed. This should neuter the attack entirely. The negative is that a header-only processed block/future syncing mode would cause this to fail until the node has imported the data required. related: #13451 `importprunedfunds` needs this check as well. Can expand it to cover this if people like the idea. Tree-SHA512: 0682ec2b622a38b29f3f635323e0a8b6fc071e8a6fd134c954579926ee7b516e642966bafa667016744ce49c16e19b24dbc8801f982a36ad0a6a4aff6d93f82b
This commit is contained in:
@@ -841,6 +841,52 @@ class BlockTransactions():
|
||||
def __repr__(self):
|
||||
return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions))
|
||||
|
||||
class CPartialMerkleTree():
|
||||
def __init__(self):
|
||||
self.nTransactions = 0
|
||||
self.vHash = []
|
||||
self.vBits = []
|
||||
self.fBad = False
|
||||
|
||||
def deserialize(self, f):
|
||||
self.nTransactions = struct.unpack("<i", f.read(4))[0]
|
||||
self.vHash = deser_uint256_vector(f)
|
||||
vBytes = deser_string(f)
|
||||
self.vBits = []
|
||||
for i in range(len(vBytes) * 8):
|
||||
self.vBits.append(vBytes[i//8] & (1 << (i % 8)) != 0)
|
||||
|
||||
def serialize(self):
|
||||
r = b""
|
||||
r += struct.pack("<i", self.nTransactions)
|
||||
r += ser_uint256_vector(self.vHash)
|
||||
vBytesArray = bytearray([0x00] * ((len(self.vBits) + 7)//8))
|
||||
for i in range(len(self.vBits)):
|
||||
vBytesArray[i // 8] |= self.vBits[i] << (i % 8)
|
||||
r += ser_string(bytes(vBytesArray))
|
||||
return r
|
||||
|
||||
def __repr__(self):
|
||||
return "CPartialMerkleTree(nTransactions=%d, vHash=%s, vBits=%s)" % (self.nTransactions, repr(self.vHash), repr(self.vBits))
|
||||
|
||||
class CMerkleBlock():
|
||||
def __init__(self):
|
||||
self.header = CBlockHeader()
|
||||
self.txn = CPartialMerkleTree()
|
||||
|
||||
def deserialize(self, f):
|
||||
self.header.deserialize(f)
|
||||
self.txn.deserialize(f)
|
||||
|
||||
def serialize(self):
|
||||
r = b""
|
||||
r += self.header.serialize()
|
||||
r += self.txn.serialize()
|
||||
return r
|
||||
|
||||
def __repr__(self):
|
||||
return "CMerkleBlock(header=%s, txn=%s)" % (repr(self.header), repr(self.txn))
|
||||
|
||||
|
||||
# Objects that correspond to messages on the wire
|
||||
class msg_version():
|
||||
|
||||
Reference in New Issue
Block a user