2

I try to create a tx with 4 inputs, and sign it via cmdline and openssl on a cold storage machine. Then I want to send it via bitcoin qt (or blockchain.info). Signing with a single input and a single output already works for me (via unix cmd line and OpenSSL). Now I want to go with multiple inputs, with a little help from stackexchange here: How to sign a transaction with multiple inputs?

I have created a transaction, with 4 inputs, and I can't get it to work. The transaction looks like this, and decodes properly in bitcoin qt (decoderawtransaction) or with https://blockchain.info/de/decode-tx:

0100000004b0772e6ef46c2d3c60418bb7d5c2c015d6b943e5fca07570eb82c26dc7c9d248010000006B483045022100D675D9F98E5B1F01BDB05E5389ACB453EFA14EF399361099736376611D9BF88E02206B8FEF37F2C2316D3629D6C43945AFA23B0EB0CA2C1163E33B28066B01A4E241012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffff74fb6858c31a292d20c9744187032bddb7ddea02a3aa3ef523c8524a21481881010000006A47304402200F921996446FBAD78ECB6C95303ECD13145CA7E13E769B44742FA499325B347402202F8378D7D154F4F8D345525696F8E31DF8A96C05AA58B2F53012E3550CC90AE7012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffffcc21e36eedb509c660681c1e949dd294bd4c11692439221004c2235d565b74bb000000006A47304402206B7C2D73EC787ADD99740DAB78F7252ED49A1BA42BA358A667BF118B8740BB0C0220366EF47DE6339C261946513C939A301ECF940A294036ED72A5FD893C5CAFEED8012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffffea919487e04ed509d6cb9c7297c277b9be3a68f3836c7d86df378714a75949e8000000006A47304402205B595472AA821D96DBFB6E531A663571A9DB14DDFCF8AC0B4330B6264955C15F02203FDF004B19996654490F00FA9BDFC175265CF95BA6DC86943B4B7C50EAF23616012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffff0120830c00000000001976a91418ec49b27624086a2b6f35f263d951d25dbe24b688ac00000000

Uploading with bitcoin qt (sendrawtransaction) gives this error:

16: mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation) (code -26)

What options do I have, to figure out next steps, were it goes wrong?


WHAT WAS DONE SO FAR:

This helped me to get it running for a single input transaction: Verifying a bitcoin trx on the Unix cmd line with OpenSSL?

Now I have four inputs, and compressed pubkeys. I created the above tx exactly again in Electrum (same 4 inputs, same single output), signed it. But didn't send it. Then I decoded Electrum generated and my generated tx, and verified line by line, that there are no differences in values (besides the signature lines, they differ of course). After this I created a text file with commands, which spits out the pubkey, the hash (double sha256) and the signature for each input. This way I could check signatures with openssl this way:

openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex

When I check each signature in the transaction, I always get a success message from OpenSSL (the complete file is attached at the end below). However, when I send it via bitcoin qt, I get the above mentioned error message. The error message comes from "the bitcoin network"... How can I emulate it?

To confirm a tx, a check is run from the tx input SigScript and the previous tx output PKScript. So I double checked the output script of the previous transaction (for each input). They are all the same:

OP_DUP OP_HASH160 c2df275d78e506e17691fd6f0c63c43d15c897fc OP_EQUALVERIFY OP_CHECKSIG 

My check activities would look like this: I drop SIG and PUBKEY from the tx input SigScript on a virtual stack, and then run the PKScript against it, step by step, for all inputs. Here an example for first input (more or less the stack emulation steps):

  step       action      result  
1 SIGSCRIPT  SIGNATURE   3045022100D675D9F98E5B1F . . . B28066B01A4E241  
2 SIGSCRIPT  PUBKEY      03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0  
3 OP_DUP     PUBKEY      03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0  
4 OP_HASH160 xxd -r -p <PUBKEY.txt >pubkey.hex
             openssl dgst -binary -sha256 <pubkey.hex >pk_sha256.hex
             openssl dgst -binary -ripemd160 <pk_sha256.hex >pkhash.hex
             xxd -ps pkhash.hex
                         c2df275d78e506e17691fd6f0c63c43d15c897fc
5 PKSCRIPT   PKH         c2df275d78e506e17691fd6f0c63c43d15c897fc
6 OP_EQUALVERIFY         YES !

Here I have generated for all 4 inputs the same PUBKEY_HASH, so that OP_Equalverify should run correctly. Remaining on the stack is:

1 Input       SIGNATURE  3045022100D675D9F98E5B1F . . . B28066B01A4E241
2 Input       PUBKEY     03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0
3 OP_CHECKSIG

I don't know what happens here in the network, I would like to think it does decode the transaction into it's elements (per input), creates a hash over it, and does something similiar to what I did (of course with other libraries): VERIFY SIGNATURE. I did it like this:

openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex 

Is there a way to get a more specific erro message from sending a "wrong" transaction? "mandatory-script-verify-flag-failed" and "(code -26)" doesn't help me to debug further...

Here is the file that was generated from the transaction process, and helps to verify signature for each input:

##############################################
### Bitcoin prep file to verify signatures ###
##############################################
# Bitcoin (and here with openssl) works only on binary files. For each input, convert to binary.
# the pubkey for above example:
echo 3036301006072a8648ce3d020106052b8104000a032200 > pubkey.txt
echo 03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0 >> pubkey.txt
xxd -r -p <pubkey.txt | openssl pkey -pubin -inform der >pubkey.pem

# TX_IN[0], double sha256 and signature:
echo afc7f91ceb9754ebb644d058334817babf8414d1ce75fd0683ad172e950348c9 > tx_hash.txt
echo 3045022100d675d9f98e5b1f01bdb05e5389acb453efa14ef399361099736376611d9bf88e02206b8fef37f2c2316d3629d6c43945afa23b0eb0ca2c1163e33b28066b01a4e241 > tx_sig.txt
xxd -r -p <tx_hash.txt >tx_hash.hex
xxd -r -p <tx_sig.txt >tx_sig.hex
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex

# TX_IN[1], double sha256 and signature:
echo 11ded58d693d72a23b6191c20222b20ee4947bac63c34d1ccdac07461486a3b0 > tx_hash.txt
echo 304402200f921996446fbad78ecb6c95303ecd13145ca7e13e769b44742fa499325b347402202f8378d7d154f4f8d345525696f8e31df8a96c05aa58b2f53012e3550cc90ae7 > tx_sig.txt
xxd -r -p <tx_hash.txt >tx_hash.hex
xxd -r -p <tx_sig.txt >tx_sig.hex
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex

# TX_IN[2], double sha256 and signature:
echo 12f904b9d0b37c368d24d132aaff2d2fe47fd9a5e3083a501e63410c6d4671ea > tx_hash.txt
echo 304402206b7c2d73ec787add99740dab78f7252ed49a1ba42ba358a667bf118b8740bb0c0220366ef47de6339c261946513c939a301ecf940a294036ed72a5fd893c5cafeed8 > tx_sig.txt
xxd -r -p <tx_hash.txt >tx_hash.hex
xxd -r -p <tx_sig.txt >tx_sig.hex
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex

# TX_IN[3], double sha256 and signature:
echo 183b7652c2785d57483c5f70575e027f513743aad01100828d9eb4aeb48ea4ed > tx_hash.txt
echo 304402205b595472aa821d96dbfb6e531a663571a9db14ddfcf8ac0b4330b6264955c15f02203fdf004b19996654490f00fa9bdfc175265cf95ba6dc86943b4b7c50eaf23616 > tx_sig.txt
xxd -r -p <tx_hash.txt >tx_hash.hex
xxd -r -p <tx_sig.txt >tx_sig.hex
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex

The whole code for this create/sign example is here: https://github.com/pebwindkraft/trx_cl_suite The three commands to create, sign and decode a trx are:

./tcls_create.sh -v -f svn_4inputs.txt 820000 13GnHB51piDBf1avocPL7tSKLugK4F7U2B 33
./tcls_sign.sh -v -f tmp_c_urtx.txt  -w Kxyz...your_priv_key_in_WIF_format...abc -p 03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0
./tcls_tx2txt.sh -vv -r 0100000004b0772e6ef46c2d3c60...b6f35f263d951d25dbe24b688ac00000000
  • Have you checked for LOW-S signatures (github.com/bitcoin/bips/blob/master/bip-0062.mediawiki)? – Jonas Schnelli Nov 16 '16 at 7:47
  • Hi Jonas, yes, I have removed in the documentation above the strict DER sig verification, to make it read easy. This is included in the file tcls_strict_sig_verify.sh. – pebwindkraft Nov 16 '16 at 9:22
  • Found the original code for this error in bitcoin-master (13.1), file main.cpp, line 2087. Doesn't look like non-std DER encoding. Code throughs the error after DER checks. My knowledge isn't sufficient to decode the details, so looking to find an answer in a forum or similiar. Hopefully can provide a reply here later on... – pebwindkraft Nov 20 '16 at 19:52
1

I've found one bug in those shell scripts, though I'm not sure it's the only one. Once fixed, it's now generating the same sha256d's of the unsigned txs as another tool I've tried (before it was not).

If you look here, you'll see that the txin's scriptSig is getting properly set to the to-be-signed UTXO's scriptPubKey, however for the scriptPubKeys that should be blanked out the script isn't emitting anything—it should be emitting an empty string as this else clause does:

if [ $i -eq $j ] ; then
  printf ${TX_IN_ScriptBytes_hex[$i]} >> $utxhex_tmp_fn
  printf ${TX_IN_Sig_Script[$i]} >> $utxhex_tmp_fn
else
  printf 00 >> $utxhex_tmp_fn
fi

As I said, I didn't check the rest of the scripts, but hopefully this gets you one step closer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.