Das Signieren von tx mit OpenSSL schlägt jedoch fehl, wenn es mit Bitcoin qt gesendet wird. Wie debuggen?

Ich versuche, einen TX mit 4 Eingängen zu erstellen und ihn über cmdline und openssl auf einem Cold-Storage-Computer zu signieren. Dann möchte ich es über Bitcoin qt (oder blockchain.info) senden. Das Signieren mit einer einzigen Eingabe und einer einzigen Ausgabe funktioniert bei mir bereits (über Unix-cmd-Zeile und OpenSSL). Jetzt möchte ich mit mehreren Eingaben arbeiten, mit ein wenig Hilfe von Stackexchange hier: Wie signiere ich eine Transaktion mit mehreren Eingaben?

Ich habe eine Transaktion mit 4 Eingaben erstellt und kann sie nicht zum Laufen bringen. Die Transaktion sieht so aus und wird korrekt in bitcoin qt (decoderawtransaction) oder mit https://blockchain.info/de/decode-tx dekodiert :

0100000004b0772e6ef46c2d3c60418bb7d5c2c015d6b943e5fca07570eb82c26dc7c9d248010000006B483045022100D675D9F98E5B1F01BDB05E5389ACB453EFA14EF399361099736376611D9BF88E02206B8FEF37F2C2316D3629D6C43945AFA23B0EB0CA2C1163E33B28066B01A4E241012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffff74fb6858c31a292d20c9744187032bddb7ddea02a3aa3ef523c8524a21481881010000006A47304402200F921996446FBAD78ECB6C95303ECD13145CA7E13E769B44742FA499325B347402202F8378D7D154F4F8D345525696F8E31DF8A96C05AA58B2F53012E3550CC90AE7012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffffcc21e36eedb509c660681c1e949dd294bd4c11692439221004c2235d565b74bb000000006A47304402206B7C2D73EC787ADD99740DAB78F7252ED49A1BA42BA358A667BF118B8740BB0C0220366EF47DE6339C261946513C939A301ECF940A294036ED72A5FD893C5CAFEED8012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffffea919487e04ed509d6cb9c7297c277b9be3a68f3836c7d86df378714a75949e8000000006A47304402205B595472AA821D96DBFB6E531A663571A9DB14DDFCF8AC0B4330B6264955C15F02203FDF004B19996654490F00FA9BDFC175265CF95BA6DC86943B4B7C50EAF23616012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffff0120830c00000000001976a91418ec49b27624086a2b6f35f263d951d25dbe24b688ac00000000

Das Hochladen mit Bitcoin qt (sendrawtransaction) gibt diesen Fehler:

16: Mandatory-Script-Verify-Flag-Failed (Signatur muss Null sein für fehlgeschlagene CHECK(MULTI)SIG-Operation) (Code -26)

Welche Möglichkeiten habe ich, um die nächsten Schritte herauszufinden, wenn es schief geht?


WAS BISHER GEMACHT WURDE:

Dies hat mir geholfen, es für eine einzelne Eingabetransaktion zum Laufen zu bringen: Verifizieren eines Bitcoin-Trx auf der Unix-cmd-Zeile mit OpenSSL?

Jetzt habe ich vier Eingänge und komprimierte Pubkeys. Ich habe den obigen TX genau wieder in Electrum erstellt (gleiche 4 Eingänge, gleicher Einzelausgang), signiert. Habe es aber nicht verschickt. Dann habe ich Electrum generiert und meinen generierten tx dekodiert und Zeile für Zeile überprüft, dass es keine Unterschiede in den Werten gibt (außer den Signaturzeilen unterscheiden sie sich natürlich). Danach habe ich eine Textdatei mit Befehlen erstellt, die für jede Eingabe den Pubkey, den Hash (double sha256) und die Signatur ausspuckt. Auf diese Weise könnte ich Signaturen mit openssl auf diese Weise überprüfen:

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

Wenn ich jede Signatur in der Transaktion prüfe, bekomme ich immer eine Erfolgsmeldung von OpenSSL (die komplette Datei ist am Ende unten angehängt). Wenn ich es jedoch per Bitcoin qt sende, bekomme ich die oben genannte Fehlermeldung. Die Fehlermeldung kommt von "the bitcoin network"... Wie kann ich es emulieren?

Um eine tx zu bestätigen, wird eine Prüfung von dem tx-Eingabe-SigScript und dem vorherigen tx-Ausgabe-PKScript ausgeführt. Also habe ich das Ausgabeskript der vorherigen Transaktion (für jede Eingabe) doppelt überprüft. Sie sind alle gleich:

OP_DUP OP_HASH160 c2df275d78e506e17691fd6f0c63c43d15c897fc OP_EQUALVERIFY OP_CHECKSIG 

Meine Prüfaktivitäten würden wie folgt aussehen: Ich lege SIG und PUBKEY aus dem tx-Eingabe-SigScript auf einen virtuellen Stack und lasse dann das PKScript Schritt für Schritt für alle Eingaben dagegen laufen. Hier ein Beispiel für die erste Eingabe (mehr oder weniger die Stack-Emulationsschritte):

  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 !

Hier habe ich für alle 4 Inputs den gleichen PUBKEY_HASH generiert, damit OP_Equalverify korrekt laufen sollte. Auf dem Stack verbleibt:

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

Ich weiß nicht, was hier im Netzwerk passiert, ich würde gerne glauben, dass es die Transaktion in ihre Elemente (pro Eingabe) dekodiert, einen Hash darüber erstellt und etwas Ähnliches tut wie ich (natürlich mit anderen Bibliotheken). ): UNTERSCHRIFT ÜBERPRÜFEN. Ich habe es so gemacht:

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

Gibt es eine Möglichkeit, eine spezifischere Fehlermeldung zu erhalten, wenn eine "falsche" Transaktion gesendet wird? "mandatory-script-verify-flag-failed" und "(code -26)" helfen mir nicht weiter zu debuggen ...

Hier ist die Datei, die aus dem Transaktionsprozess generiert wurde und hilft, die Signatur für jede Eingabe zu überprüfen:

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

Der gesamte Code für dieses Beispiel zum Erstellen/Signieren ist hier: https://github.com/pebwindkraft/trx_cl_suite Die drei Befehle zum Erstellen, Signieren und Decodieren eines Trx sind:

./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
Haben Sie nach LOW-S-Signaturen gesucht ( github.com/bitcoin/bips/blob/master/bip-0062.mediawiki )?
Hallo Jonas, ja, ich habe in der obigen Dokumentation die strenge DER-Sig-Prüfung entfernt, um es leichter lesbar zu machen. Diese ist in der Datei tcls_strict_sig_verify.sh enthalten.
Den Originalcode für diesen Fehler in bitcoin-master (13.1), Datei main.cpp, Zeile 2087 gefunden. Sieht nicht wie eine Nicht-Standard-DER-Codierung aus. Code durchläuft den Fehler nach DER-Prüfungen. Mein Wissen reicht nicht aus, um die Details zu entschlüsseln, also suche nach einer Antwort in einem Forum oder ähnlichem. Hoffentlich kann ich hier später eine Antwort geben ...

Antworten (1)

Ich habe einen Fehler in diesen Shell-Skripten gefunden, obwohl ich nicht sicher bin, ob es der einzige ist. Einmal behoben, generiert es jetzt die gleichen Sha256ds der unsignierten TXs wie ein anderes Tool, das ich ausprobiert habe (vorher nicht).

Wenn Sie hier nachsehen , werden Sie sehen, dass die scriptSig des txin richtig auf den scriptPubKey des zu signierenden UTXO gesetzt wird, aber für die scriptPubKeys, die ausgeblendet werden sollten, gibt das Skript nichts aus – es sollte ein leeres Zeichen ausgeben string wie diese else-Klausel:

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

Wie gesagt, ich habe den Rest der Skripte nicht überprüft, aber hoffentlich bringt Sie das einen Schritt näher.

Jup, das ist es! Ich habe keine Hex-Null in die Zeichenfolge eingefügt, wie von der Webseite bitcoin.stackexchange.com/questions/41209/… empfohlen . Dort steht, dass der Wert wird: ** 'script': '', # Nothing**