Подписание tx с помощью OpenSSL, но сбой при отправке с помощью биткойн qt. Как отлаживать?

Я пытаюсь создать tx с 4 входами и подписать его через cmdline и openssl на машине с холодным хранилищем. Затем я хочу отправить его через биткойн qt (или blockchain.info). У меня уже работает подпись с одним входом и одним выходом (через строку unix cmd и OpenSSL). Теперь я хочу использовать несколько входов, с небольшой помощью от stackexchange здесь: Как подписать транзакцию с несколькими входами?

Я создал транзакцию с 4 входами и не могу заставить ее работать. Транзакция выглядит следующим образом и корректно декодируется в биткойн qt (decoderawtransaction) или с помощью https://blockchain.info/de/decode-tx :

0100000004b0772e6ef46c2d3c60418bb7d5c2c015d6b943e5fca07570eb82c26dc7c9d248010000006B483045022100D675D9F98E5B1F01BDB05E5389ACB453EFA14EF399361099736376611D9BF88E02206B8FEF37F2C2316D3629D6C43945AFA23B0EB0CA2C1163E33B28066B01A4E241012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffff74fb6858c31a292d20c9744187032bddb7ddea02a3aa3ef523c8524a21481881010000006A47304402200F921996446FBAD78ECB6C95303ECD13145CA7E13E769B44742FA499325B347402202F8378D7D154F4F8D345525696F8E31DF8A96C05AA58B2F53012E3550CC90AE7012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffffcc21e36eedb509c660681c1e949dd294bd4c11692439221004c2235d565b74bb000000006A47304402206B7C2D73EC787ADD99740DAB78F7252ED49A1BA42BA358A667BF118B8740BB0C0220366EF47DE6339C261946513C939A301ECF940A294036ED72A5FD893C5CAFEED8012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffffea919487e04ed509d6cb9c7297c277b9be3a68f3836c7d86df378714a75949e8000000006A47304402205B595472AA821D96DBFB6E531A663571A9DB14DDFCF8AC0B4330B6264955C15F02203FDF004B19996654490F00FA9BDFC175265CF95BA6DC86943B4B7C50EAF23616012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffff0120830c00000000001976a91418ec49b27624086a2b6f35f263d951d25dbe24b688ac00000000

Загрузка с помощью биткойн qt (senddrawtransaction) дает эту ошибку:

16: обязательное подтверждение флага сценария (подпись должна быть нулевой для неудачной операции CHECK(MULTI)SIG) (код -26)

Какие у меня есть варианты, чтобы определить следующие шаги, если что-то пойдет не так?


ЧТО БЫЛО СДЕЛАНО:

Это помогло мне запустить его для одной входной транзакции: Проверка биткойн trx в строке cmd Unix с помощью OpenSSL?

Теперь у меня есть четыре входа и сжатые публичные ключи. Я снова создал вышеуказанный tx в Electrum (те же 4 входа, тот же единственный выход), подписал его. Но не отправил. Затем я расшифровал сгенерированный Electrum и сгенерированный мной tx и построчно проверил, что нет различий в значениях (кроме строк подписи, они, конечно, различаются). После этого я создал текстовый файл с командами, который выдает публичный ключ, хэш (двойной sha256) и подпись для каждого ввода. Таким образом, я мог бы проверить подписи с помощью openssl следующим образом:

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

Когда я проверяю каждую подпись в транзакции, я всегда получаю сообщение об успехе от OpenSSL (полный файл прикреплен в конце ниже). Однако, когда я отправляю его через биткойн qt, я получаю вышеупомянутое сообщение об ошибке. Сообщение об ошибке исходит от «сети биткойнов»... Как я могу эмулировать это?

Чтобы подтвердить транзакцию, выполняется проверка входного SigScript для транзакций и предыдущего вывода PKScript для транзакций. Поэтому я дважды проверил сценарий вывода предыдущей транзакции (для каждого входа). Они все одинаковые:

OP_DUP OP_HASH160 c2df275d78e506e17691fd6f0c63c43d15c897fc OP_EQUALVERIFY OP_CHECKSIG 

Мои действия по проверке будут выглядеть следующим образом: я удаляю SIG и PUBKEY из SigScript ввода tx в виртуальный стек, а затем запускаю PKScript для него шаг за шагом для всех входов. Вот пример для первого ввода (более или менее шаги эмуляции стека):

  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 !

Здесь я сгенерировал для всех 4 входов один и тот же PUBKEY_HASH, так что OP_Equalverify должен работать правильно. В стеке осталось:

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

Я не знаю, что происходит здесь, в сети, я хотел бы думать, что она декодирует транзакцию в свои элементы (для каждого входа), создает над ней хэш и делает что-то похожее на то, что я сделал (конечно, с другими библиотеками ): ПРОВЕРЬТЕ ПОДПИСЬ. Я сделал это так:

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

Есть ли способ получить более конкретное сообщение об ошибке при отправке «неправильной» транзакции? "mandatory-script-verify-flag-failed" и "(код -26)" не помогают мне в дальнейшей отладке...

Вот файл, который был сгенерирован в процессе транзакции и помогает проверить подпись для каждого входа:

##############################################
### 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

Весь код для этого примера создания/подписи находится здесь: https://github.com/pebwindkraft/trx_cl_suite Три команды для создания, подписи и декодирования trx:

./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
Проверяли ли вы подписи LOW-S ( github.com/bitcoin/bips/blob/master/bip-0062.mediawiki )?
Привет, Джонас, да, я удалил в документации выше строгую проверку подписи DER, чтобы ее было легче читать. Это включено в файл tcls_strict_sig_verify.sh.
Нашел исходный код этой ошибки в bitcoin-master (13.1), файл main.cpp, строка 2087. Не похоже на нестандартную кодировку DER. Код проходит через ошибку после проверки DER. Моих знаний недостаточно, чтобы расшифровать детали, поэтому ищу ответ на форуме или подобном. Надеюсь, что смогу дать ответ здесь позже...

Ответы (1)

Я нашел одну ошибку в этих сценариях оболочки, хотя я не уверен, что она единственная. После исправления он теперь генерирует те же sha256d неподписанных txs, что и другой инструмент, который я пробовал (до этого его не было).

Если вы посмотрите здесь , вы увидите, что scriptSig txin правильно устанавливается на scriptPubKey UTXO, который должен быть подписан, однако для scriptPubKeys, которые должны быть пустыми, скрипт ничего не испускает - он должен испускать пустой string, как это делает предложение else:

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

Как я уже сказал, я не проверял остальные скрипты, но, надеюсь, это поможет вам на шаг приблизиться.

ага, вот оно! Я не добавлял в строку шестнадцатеричный ноль, как это рекомендуется на веб-странице bitcoin.stackexchange.com/questions/41209/… . Там написано, что значение становится: ** 'script': '', # Ничего**