Vulnerability: bitcoin-spv - verifyHash256Merkle allows existence proofs for the same leaf in multiple locations in the tree  Won't Fix
Severity: medium

Description:
`BTCUtils.verifyHash256Merkle` is used by `ValidateSPV.prove` to validate a transaction's existence in a Bitcoin block. The function accepts as input a `_proof` and an `_index`. The `_proof` consists of, in order: the transaction hash, a list of intermediate nodes, and the merkle root.\\nThe proof is performed iteratively, and uses the `_index` to determine whether the next proof element represents a “left branch” or a “right branch:”\\n```\\nuint \\_idx = \\_index;\\nbytes32 \\_root = \\_proof.slice(\\_proof.length - 32, 32).toBytes32();\\nbytes32 \\_current = \\_proof.slice(0, 32).toBytes32();\\n\\nfor (uint i = 1; i < (\\_proof.length.div(32)) - 1; i++) {\\n    if (\\_idx % 2 == 1) {\\n        \\_current = \\_hash256MerkleStep(\\_proof.slice(i \\* 32, 32), abi.encodePacked(\\_current));\\n    } else {\\n        \\_current = \\_hash256MerkleStep(abi.encodePacked(\\_current), \\_proof.slice(i \\* 32, 32));\\n    }\\n    \\_idx = \\_idx  1;\\n}\\nreturn \\_current == \\_root;\\n```\\n\\nIf `_idx` is even, the computed hash is placed before the next proof element. If `_idx` is odd, the computed hash is placed after the next proof element. After each iteration, `_idx` is decremented by `_idx /= 2`.\\nBecause `verifyHash256Merkle` makes no requirements on the size of `_proof` relative to `_index`, it is possible to pass in invalid values for `_index` that prove a transaction's existence in multiple locations in the tree.\\nBy modifying existing tests, we showed that any transaction can be proven to exist at least one alternate index. This alternate index is calculated as `(2 ** treeHeight) + prevIndex` - though other alternate indices are possible. The modified test is below:\\n```\\nit('verifies a bitcoin merkle root', async () => {\\n  for (let i = 0; i < verifyHash256Merkle.length; i += 1) {\\n    const res = await instance.verifyHash256Merkle(\\n      verifyHash256Merkle[i].input.proof,\\n      verifyHash256Merkle[i].input.index\\n    ); // 0-indexed\\n    assert.strictEqual(res, verifyHash256Merkle[i].output);\\n\\n    // Now, attempt to use the same proof to verify the same leaf at\\n    // a different index in the tree:\\n    let pLen = verifyHash256Merkle[i].input.proof.length;\\n    let height = ((pLen - 2) / 64) - 2;\\n\\n    // Only attempt to verify roots that are meant to be verified\\n    if (verifyHash256Merkle[i].output && height >= 1) {\\n      let altIdx = (2 ** height) + verifyHash256Merkle[i].input.index;\\n\\n      const resNext = await instance.verifyHash256Merkle(\\n        verifyHash256Merkle[i].input.proof,\\n        altIdx\\n      );\\n\\n      assert.strictEqual(resNext, verifyHash256Merkle[i].output);\\n\\n      console.log('Verified transaction twice!');\\n    }\\n  }\\n});\\n```\\n

Impact:

Recommended mitigation:
Use the length of `_proof` to determine the maximum allowed `_index`. `_index` should satisfy the following criterion: `_index` < 2 ** (_proof.length.div(32) - 2).\\nNote that subtraction by 2 accounts for the transaction hash and merkle root, which are assumed to be encoded in the proof along with the intermediate nodes.