Ich verwende das Litecoin-Testnet-Netzwerk zum Testen. Ich habe ein UTXO bei 053baee857adfdc16959e9dbc9618e0e935f0a1e51e226e651fcd67242f1f462
mit a vout
von 0.
Ich mache eine Rohtransaktion, indem ich die Coins an mich selbst (an eine andere Adresse) sende:
$ ./litecoind createrawtransaction '[{"txid":"053baee857adfdc16959e9dbc9618e0e935f0a1e51e226e651fcd67242f1f462", "vout":0}]' '{"mroLyo22ptLfq5LKMijnCyD35mEsAWTkF9":0.039}'
010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b050000000000ffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000
Dann signiere ich die Rohtransaktion mit signrawtransaction
:
$ ./litecoind signrawtransaction 010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b050000000000ffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000
signrawtransaction hash: eed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0
{
"hex" : "010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b05000000006a4730440220258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e0220406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd012103ec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccfffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000",
"complete" : true
}
Beachten Sie, dass der hier signierte Hash eed3...
. Ich habe dem Code eine Druckzeile hinzugefügt, damit ich sehen kann, was uint256
signiert wird. Insbesondere in script.cpp
, wo die Signierung für signrawtransaction
stattfindet, habe ich einen zusätzlichen booleschen Parameter hinzugefügt, um den Hash und die Zeilen darunter zu protokollieren.
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType, bool printHash)
{
...
// Leave out the signature from the hash, since a signature can't sign itself.
// The checksig op will also drop the signatures from its hash.
uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
if (printHash)
{
std::cout << "signrawtransaction hash: " << hash.ToString() << std::endl;
}
decoderawtransaction
Als nächstes nehme ich das erste Element auf dem asm
Stapel, das die Signatur ist.
30 44 02 20
258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e
02 20
406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd
01
Hier können wir mit etwas Hilfe von Pieter Wuille ( Warum die Signatur immer 65 (1+32+32) Bytes lang ist? ) die R- und die S-Elemente sehen.
Als nächstes füge ich sie in meine Pycoin-Testdatei ein. Pycoin ist eine einfach zu verwendende Python-Bibliothek für Bitcoin (( https://github.com/richardkiss/pycoin )).
aus pycoin.ecdsa importieren * Zeichenkette importieren def verify_sig(Sig, Präfix, xpub, signed_val): is_even = (Präfix % 2 == 0) pub_pair = public_pair_for_x(generator_secp256k1, xpub, is_even) print("sig: (" + hex(sig[0]) + ", " + hex(sig[1]) + ")") print("pub: (" + hex(pub_pair[0]) + ", " + hex(pub_pair[1]) + ")") print("hex: " + hex(signed_val)) print("ist gültig: " + str(verify(generator_secp256k1, pub_pair, signed_val, sig))) sigR = 0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e sigS = 0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd sig = (sigR, sigS) x = 0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf Hash = 0xeed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0 komprimiertes Zeichen = 0x03 verifiziere_sig(sig, komprimiertes_zeichen, x, hash)
Und das Ergebnis, das gedruckt wird:
sig: (0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e, 0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd) pub: (0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf, 0x227874efbedb02b88568b55106634b9b4e3eca128ab46fa98abe7066aece0a51) hex: 0xeed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0 gilt: Falsch
Ich bin mir wirklich nicht sicher, was hier schief laufen könnte, da dies nur eine direkte ECDSA-Verifizierung ist. Gibt es dort Werte, die seltsam erscheinen, oder gibt es andere Gründe, die dies nicht validieren würde?
Problem gefunden! Bitcoin ist sehr uneinheitlich in Bezug auf Big/Little-Endian-Ganzzahlen. Ich habe den Hash umgekehrt und die Signatur wurde verifiziert!
Abschlussprogramm:
aus pycoin.ecdsa importieren * Zeichenkette importieren Array importieren binascii importieren def verify_sig(Sig, Präfix, xpub, signed_val): is_even = (Präfix % 2 == 0) pub_pair = public_pair_for_x(generator_secp256k1, xpub, is_even) print("sig: (" + hex(sig[0]) + ", " + hex(sig[1]) + ")") print("pub: (" + hex(pub_pair[0]) + ", " + hex(pub_pair[1]) + ")") print("hex: " + hex(signed_val)) print("ist gültig: " + str(verify(generator_secp256k1, pub_pair, signed_val, sig))) sigR = 0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e sigS = 0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd sig = (sigR, sigS) x = 0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf Zeichen = 0x03 revhash = "eed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0" hash = "" für i in range(0, len(revhash), 2): hash = revhash[i:i+2] + hash verify_sig(sig, char, x, int(hash, 16))
Und das Ergebnis:
sig: (0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e, 0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd) pub: (0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf, 0x227874efbedb02b88568b55106634b9b4e3eca128ab46fa98abe7066aece0a51) hex: 0xb035a57aa7c6cceec10e334b6f55c68e37de6f74af66af68b673a963fc00d3ee gilt: True