bitcoinjs / bitcoinjs-lib

A javascript Bitcoin library for node.js and browsers.
MIT License
5.67k stars 2.1k forks source link

upgrading to 3.x to 4.x - difference in signature #1241

Closed wallaceturner closed 5 years ago

wallaceturner commented 5 years ago

When using 3.x I was writing

let keypair =  new ECPair(bigi.fromHex(pKey));
let buffer1 = new Buffer(tosign, "hex")
let signature = keypair.sign(buffer1).toDER().toString("hex");

and the version 4 equivalent (as I understand it)

let keypair = ECPair.fromPrivateKey(Buffer.from(pKey, "hex"))
let signature = keypair.sign(Buffer.from(tosign, "hex"));    
let encodedSignature = bjs.script.signature.encode(signature,  bjs.Transaction.SIGHASH_NONE);    
let hexStr = encodedSignature.toString("hex");

They produce identical output except for the last byte; it seems the hashType is appended to the signature when using bjs.script.signature.encode At the moment I am just truncating the last 2 characters of hexStr which 'fixes' this issue but it feels wrong (and probably is) Can someone clarify?

junderw commented 5 years ago

toDER of the old ecsignature object was separated from bitcoin in that the module was meant to only include ECDSA concepts.

Whereas script module in 4 is definitely bitcoin specific, so the encode function includes the 1 byte sighash version at the end.

  1. This is correct, and a byproduct of a refactoring.
  2. You are safe to just remove the last byte (2 hex chars) from the sig if you aren't signing transactions. (I assume tosign is the hash of some arbitrary message?
wallaceturner commented 5 years ago

@junderw I am signing a transaction, however there is a bit more to the story in that i'm doing its via blockcypher whereby they send you a list of tx to sign (see the very end of the json I have pasted below) You then send the signatures back to them and they push it to the network. They reject any signature with the hashType appended so I can only assume they append it themselves after you send it to them ?

{
   "tx":{
      "block_height":-1,
      "block_index":-1,
      "hash":"43420bf7ef53a8e934922723c761f45e0bc30ddd5ff29cd76124cca620d7b01b",
      "addresses":[
         "C4jhPuD3pLqHMwuUwjg3yVCPD4P67TZ56r",
         "By6JsQn9qU1UQ9U6du5f8q6oaFK1nuRhLy"
      ],
      "total":10958000,
      "fees":2000,
      "size":160,
      "preference":"medium",
      "relayed_by":"220.253.234.40",
      "received":"2018-10-08T05:55:50.674909066Z",
      "ver":1,
      "double_spend":false,
      "vin_sz":2,
      "vout_sz":2,
      "confirmations":0,
      "inputs":[
         {
            "prev_hash":"0a0da1f1e73e8410a6127fb792fb59d39c5d2d23566d5e7ee291323ee0c3741f",
            "output_index":0,
            "output_value":980000,
            "sequence":4294967295,
            "addresses":[
               "C4jhPuD3pLqHMwuUwjg3yVCPD4P67TZ56r"
            ],
            "script_type":"pay-to-pubkey-hash",
            "age":1460793
         },
         {
            "prev_hash":"bdcda0aeddb31d35620777a1027b56a4c957fbcb44c986e872b1f2dd1086db9e",
            "output_index":0,
            "output_value":9980000,
            "sequence":4294967295,
            "addresses":[
               "C4jhPuD3pLqHMwuUwjg3yVCPD4P67TZ56r"
            ],
            "script_type":"pay-to-pubkey-hash",
            "age":1463662
         }
      ],
      "outputs":[
         {
            "value":9998000,
            "script":"76a9144170fea46aa089845744c6f9d27229e2c1c8daf188ac",
            "addresses":[
               "By6JsQn9qU1UQ9U6du5f8q6oaFK1nuRhLy"
            ],
            "script_type":"pay-to-pubkey-hash"
         },
         {
            "value":960000,
            "script":"76a9147f5bd154f2f0b10402aa1aa892eb90162a39d80e88ac",
            "addresses":[
               "C4jhPuD3pLqHMwuUwjg3yVCPD4P67TZ56r"
            ],
            "script_type":"pay-to-pubkey-hash"
         }
      ]
   },
   "tosign":[
      "06c93519d72cd1741d5a661ae47d62396bb6c42ddaa2f5fd3c4ec3e473cf121c",
      "c2710305053139070bd17964614de12768632a297af8123a15ca25a6d52d62c4"
   ]
}
junderw commented 5 years ago

Yes. They are doing the sighash appending for you. So what sighash you send to the encode function is irrelevant. (sighash is only to tell bitcoinjs-lib how to create the tosign hash... but it seems they are producing this for you.)

............................

That being said... THIS API THEY HAVE IS INSECURE!

You are 100% trusting them here, and just blindly signing the hashes they provide without verifying that the hashes match what you verified yourself is the same as giving them your private keys....

I would highly recommend against using this API.

wallaceturner commented 5 years ago

@junderw Thanks for the advice. According to that link there is a way to validate the data being signed

For the extra cautious, you can protect yourself from a potential malicious attack on BlockCypher by validating the data we’re asking you to sign. Unfortunately, it’s impossible to do so directly, as pre-signed signature data is hashed twice using SHA256. To get around this, set the includeToSignTx URL flag to true. The optional tosign_tx array will be returned within the TXSkeleton, which you can use in the following way:

Hashing the hex-encoded string twice using SHA256 should give you back the corresponding tosign data. Decoding the hex-encoded string using our /txs/decode endpoint (or an independent, client-side source) should give you the output addresses and amounts that match your work-in-progress transaction.

Ultimately I would prefer to build the tx locally, however blockcypher has a very user-friendly way of creating a tx that I haven't been able to find in any library (please suggest one if you know one that replicates the following feature) 1) Prior to creating a tx you submit your address(es) to a named wallet (for which you hold the keys) 2) to create a tx you specify the wallet name, the receiving address and an amount 3) blockcypher then creates the tx for you, working out which inputs should be used from the specified wallet.

junderw commented 5 years ago

Please validate the data being signed.

  1. What is the amount of each input?
  2. What is the amount of each output?
  3. Where are all the outputs going? (Are they the addresses you specified? Is change going to an address you control?)
  4. Is the fee reasonable? (Input amount total minus output amount total is the fee... make sure you aren't sending tons of money to miners)

Remember, you need to link the evidence for each of those questions to the hash you are signing... Otherwise they could possibly make you sign a transaction sending all your coins to BlockCypher.