Browse Source

Merge pull request #5992 from zebra-lucky/fix_spv_hash_merkle_root

fix SPV.hash_merkle_root, add tests/test_verifier.py
hard-fail-on-bad-server-string
ghost43 5 years ago
committed by GitHub
parent
commit
28572197fb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 50
      electrum/tests/test_verifier.py
  2. 5
      electrum/verifier.py

50
electrum/tests/test_verifier.py

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
from electrum.bitcoin import hash_encode
from electrum.transaction import Transaction
from electrum.util import bfh
from electrum.verifier import SPV, InnerNodeOfSpvProofIsValidTx
from . import TestCaseForTestnet
MERKLE_BRANCH = [
'f2994fd4546086b21b4916b76cf901afb5c4db1c3ecbfc91d6f4cae1186dfe12',
'6b65935528311901c7acda7db817bd6e3ce2f05d1c62c385b7caadb65fac7520']
MERKLE_ROOT = '11dbac015b6969ea75509dd1250f33c04ec4d562c2d895de139a65f62f808254'
VALID_64_BYTE_TX = ('0200000001cb659c5528311901a7aada7db817bd6e3ce2f05d1c62c385b7caad'
'b65fac75201234000000fabcdefa01abcd1234010000000405060708fabcdefa')
assert len(VALID_64_BYTE_TX) == 128
class VerifierTestCase(TestCaseForTestnet):
# these tests are regarding the attack described in
# https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-June/016105.html
def test_verify_ok_t_tx(self):
"""Actually mined 64 byte tx should not raise."""
t_tx = Transaction(VALID_64_BYTE_TX)
t_tx_hash = t_tx.txid()
self.assertEqual(MERKLE_ROOT, SPV.hash_merkle_root(MERKLE_BRANCH, t_tx_hash, 3))
def test_verify_fail_f_tx_odd(self):
"""Raise if inner node of merkle branch is valid tx. ('odd' fake leaf position)"""
# first 32 bytes of T encoded as hash
fake_branch_node = hash_encode(bfh(VALID_64_BYTE_TX[:64]))
fake_mbranch = [fake_branch_node] + MERKLE_BRANCH
# last 32 bytes of T encoded as hash
f_tx_hash = hash_encode(bfh(VALID_64_BYTE_TX[64:]))
with self.assertRaises(InnerNodeOfSpvProofIsValidTx):
SPV.hash_merkle_root(fake_mbranch, f_tx_hash, 7)
def test_verify_fail_f_tx_even(self):
"""Raise if inner node of merkle branch is valid tx. ('even' fake leaf position)"""
# last 32 bytes of T encoded as hash
fake_branch_node = hash_encode(bfh(VALID_64_BYTE_TX[64:]))
fake_mbranch = [fake_branch_node] + MERKLE_BRANCH
# first 32 bytes of T encoded as hash
f_tx_hash = hash_encode(bfh(VALID_64_BYTE_TX[:64]))
with self.assertRaises(InnerNodeOfSpvProofIsValidTx):
SPV.hash_merkle_root(fake_mbranch, f_tx_hash, 6)

5
electrum/verifier.py

@ -149,9 +149,10 @@ class SPV(NetworkJobOnDefaultServer):
for item in merkle_branch_bytes: for item in merkle_branch_bytes:
if len(item) != 32: if len(item) != 32:
raise MerkleVerificationFailure('all merkle branch items have to 32 bytes long') raise MerkleVerificationFailure('all merkle branch items have to 32 bytes long')
h = sha256d(item + h) if (index & 1) else sha256d(h + item) inner_node = (item + h) if (index & 1) else (h + item)
cls._raise_if_valid_tx(bh2u(inner_node))
h = sha256d(inner_node)
index >>= 1 index >>= 1
cls._raise_if_valid_tx(bh2u(h))
if index != 0: if index != 0:
raise MerkleVerificationFailure(f'leaf_pos_in_tree too large for branch') raise MerkleVerificationFailure(f'leaf_pos_in_tree too large for branch')
return hash_encode(h) return hash_encode(h)

Loading…
Cancel
Save