Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: true-asset on August 30, 2014, 05:55:58 AM



Title: Verifying BlockCypher transaction skeletons before signing
Post by: true-asset on August 30, 2014, 05:55:58 AM
Preface:

BlockCypher transaction build and send workflow: http://dev.blockcypher.com/samples/create-tx.html

Code:
POST https://api.blockcypher.com/v1/btc/main/txs/new
> {
>   "inputs": [
>     {"addresses": ["1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD"]}
>   ],
>   "outputs": [
>     {"addresses": ["1FGAsJFNgWvFz2tWQAnRq8S6fVX9Zmuxje"], "value": 500000}
>   ]
> }
{
  "tx": {
    "block_height": -1,
    "hash": "f961dea839fd69653547a0308360de67846a49d3593f7459773e27af8d9f5ec0",
    "addresses": [
      "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD",
      "1FGAsJFNgWvFz2tWQAnRq8S6fVX9Zmuxje",
    ],
    "total": 661116,
    "fees": 10000,
    "received": "2014-04-20T23:52:21.069978821Z",
    "ver": 1,
    "lock_time": 0,
    "vin_sz": 2,
    "vout_sz": 2,
    "confirmed": 0,
    "inputs": [
      {
        "prev_hash": "0c83c8321537a7c79dc6214788944ba6cd5ea76f0594453b6251fcf1856f2e4b",
        "output_index": 0,
        "script": "",
        "output_value": 171116,
        "addresses": [
          "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD"
        ],
        "script_type": "pay-to-pubkey-hash"
      },
      {
        "prev_hash": "995a50e05d197be88d4da74160b4bcd2c363ebb1a49f95e572667d580bc70aba",
        "output_index": 0,
        "script": "",
        "output_value": 500000,
        "addresses": [
          "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD"
        ],
        "script_type": "pay-to-pubkey-hash"
      }
    ],
    "outputs": [
      {
        "value": 500000,
        "script": "76a9149c703cb3e9f1a2a154e548b3acafd0054d4835a788ac",
        "addresses": [
          "1FGAsJFNgWvFz2tWQAnRq8S6fVX9Zmuxje"
        ],
        "script_type": "pay-to-pubkey-hash"
      },
      {
        "value": 161116,
        "script": "76a9148629647bd642a2372d846a7660e210c8414f047c88ac",
        "addresses": [
          "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD"
        ],
        "script_type": "pay-to-pubkey-hash"
      }
    ]
  },
  "tosign": [
    "04779733bba8085dd86c21d86c8f9e786a1124751c42061d4c539229a07c4464",
    "0396ea6f1bf7493e738339bd720267e7281144b222343ffe4167e00792c62ff2"
  ]
}

Question:

What is the easiest way to check that the "tosign" hashes actually correspond to the correct transactions (i.e. is indeed a transaction from the specified "input" to the specified "output")? Solution needs to be pure client side browser JavaScript and be compatible on all modern mobile devices.


Title: Re: Verifying BlockCypher transaction skeletons before signing
Post by: mriou on August 31, 2014, 08:33:39 PM
I really wish I had a better answer to this question but unfortunately it's not possible as-is. The data that gets signed and later checked by the OP_CHECKSIG operation is a hash of the transaction data, and this is how the scripts work, not something we can change. So the details of the transaction can't be extracted and checked anymore after hashed.

What we could do is, provided an option, return you the transaction data. You would have to hash it yourself before signing but at least all the information would still be there. Verification would still be not trivial though as you'd have to Base58 decode the address. Provided all that, I have a function you could get some inspiration from to do the verification (only verifies the output but in practice that's what you really care about):

func Check(txdata []byte, outputAddress string) bool {
  if len(txdata) < 25 { return false }
  decoded := base58Decode(outputAddress)
  // 4 last bytes of tx are the lock time, byte before is OP_CHECKSIG, address is right before that
  // before are the address length, OP_DUP OP_HAS160 and the length of the script
  output := txdata[len(txdata)-34:]
  oneoutput := bytes.Compare([]byte{1, 0, 0, 0}, output[0:4]) == 0
  checksig  := output[4] == 25 && output[5] == 118  && output[6] == 169 && output[7] == 20 &&
                output[28] == 136 && output[29] == 172
  addrmatch := bytes.Compare(output[8:28], decoded[1:21]) == 0
  return oneoutput && addrmatch && checksig
}


Title: Re: Verifying BlockCypher transaction skeletons before signing
Post by: true-asset on September 01, 2014, 02:21:20 AM
mriou that looks like a workable solution. You are correct - I only care about the output address and the amount.
I do not mind if BlockCypher wants to send fund from their another wallet instead as long as the correct amount goes to the recipient :)


Title: Re: Verifying BlockCypher transaction skeletons before signing
Post by: zinger81 on July 25, 2015, 04:06:18 PM
good job 8)