diff --git a/electrum/tests/test_verifier.py b/electrum/tests/test_verifier.py index 464f39b19..009de2ab9 100644 --- a/electrum/tests/test_verifier.py +++ b/electrum/tests/test_verifier.py @@ -8,71 +8,43 @@ from electrum.verifier import SPV, InnerNodeOfSpvProofIsValidTx from . import TestCaseForTestnet -TST_MBRANCH = [ +MERKLE_BRANCH = [ 'f2994fd4546086b21b4916b76cf901afb5c4db1c3ecbfc91d6f4cae1186dfe12', '6b65935528311901c7acda7db817bd6e3ce2f05d1c62c385b7caadb65fac7520'] -TST_R = '11dbac015b6969ea75509dd1250f33c04ec4d562c2d895de139a65f62f808254' +MERKLE_ROOT = '11dbac015b6969ea75509dd1250f33c04ec4d562c2d895de139a65f62f808254' -TEST_T_TX_RAW = ('0200000001cb659c5528311901a7aada' - '7db817bd6e3ce2f05d1c62c385b7caad' - 'b65fac75201234000000fabcdefa01ab' - 'cd1234010000000405060708fabcdefa') - -ORIG_RAISE_IF_VALID_TX = SPV._raise_if_valid_tx +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): - '''test vefify ok forged T tx''' - assert len(TEST_T_TX_RAW) == 128 - t_tx = Transaction(TEST_T_TX_RAW) + """Actually mined 64 byte tx should not raise.""" + t_tx = Transaction(VALID_64_BYTE_TX) t_tx_hash = t_tx.txid() - assert SPV.hash_merkle_root(TST_MBRANCH, t_tx_hash, 3) == TST_R - - def test_verify_ok_f_tx(self): - '''test verify ok forged F tx (fake)''' - SPV._raise_if_valid_tx = lambda raw_tx: None - t_tx = Transaction(TEST_T_TX_RAW) - # first 32 bytes of T encoded as hash - fake_branch_node = hash_encode(bfh(TEST_T_TX_RAW[:64])) - fake_mbranch = [fake_branch_node] + TST_MBRANCH - # last 32 bytes of T encoded as hash - f_tx_hash = hash_encode(bfh(TEST_T_TX_RAW[64:])) - assert SPV.hash_merkle_root(fake_mbranch, f_tx_hash, 7) == TST_R - SPV._raise_if_valid_tx = ORIG_RAISE_IF_VALID_TX + self.assertEqual(MERKLE_ROOT, SPV.hash_merkle_root(MERKLE_BRANCH, t_tx_hash, 3)) - def test_verify_fail_f_tx(self): - '''test verify fail forged F tx (fake)''' - t_tx = Transaction(TEST_T_TX_RAW) + 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(TEST_T_TX_RAW[:64])) - fake_mbranch = [fake_branch_node] + TST_MBRANCH + 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(TEST_T_TX_RAW[64:])) + f_tx_hash = hash_encode(bfh(VALID_64_BYTE_TX[64:])) with self.assertRaises(InnerNodeOfSpvProofIsValidTx): - assert SPV.hash_merkle_root(fake_mbranch, f_tx_hash, 7) == TST_R - - def test_verify_ok_f_tx_even(self): - '''test verify ok forged F tx (fake) with even fake txpos''' - SPV._raise_if_valid_tx = lambda raw_tx: None - t_tx = Transaction(TEST_T_TX_RAW) - # last 32 bytes of T encoded as hash - fake_branch_node = hash_encode(bfh(TEST_T_TX_RAW[64:])) - fake_mbranch = [fake_branch_node] + TST_MBRANCH - # first 32 bytes of T encoded as hash - f_tx_hash = hash_encode(bfh(TEST_T_TX_RAW[:64])) - assert SPV.hash_merkle_root(fake_mbranch, f_tx_hash, 6) == TST_R - SPV._raise_if_valid_tx = ORIG_RAISE_IF_VALID_TX + SPV.hash_merkle_root(fake_mbranch, f_tx_hash, 7) def test_verify_fail_f_tx_even(self): - '''test verify fail forged F tx (fake) with even fake txpos''' - t_tx = Transaction(TEST_T_TX_RAW) + """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(TEST_T_TX_RAW[64:])) - fake_mbranch = [fake_branch_node] + TST_MBRANCH + 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(TEST_T_TX_RAW[:64])) + f_tx_hash = hash_encode(bfh(VALID_64_BYTE_TX[:64])) with self.assertRaises(InnerNodeOfSpvProofIsValidTx): - assert SPV.hash_merkle_root(fake_mbranch, f_tx_hash, 6) == TST_R + SPV.hash_merkle_root(fake_mbranch, f_tx_hash, 6) diff --git a/electrum/verifier.py b/electrum/verifier.py index eb00916ae..01a0eb8db 100644 --- a/electrum/verifier.py +++ b/electrum/verifier.py @@ -149,7 +149,7 @@ class SPV(NetworkJobOnDefaultServer): for item in merkle_branch_bytes: if len(item) != 32: raise MerkleVerificationFailure('all merkle branch items have to 32 bytes long') - inner_node = item + h if index & 1 else 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