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