I'm using the litecoin testnet network for testing. I have a UTXO at 053baee857adfdc16959e9dbc9618e0e935f0a1e51e226e651fcd67242f1f462
with a vout
of 0.
I make a raw transaction sending the coins to myself (at a different address):
$ ./litecoind createrawtransaction '[{"txid":"053baee857adfdc16959e9dbc9618e0e935f0a1e51e226e651fcd67242f1f462", "vout":0}]' '{"mroLyo22ptLfq5LKMijnCyD35mEsAWTkF9":0.039}'
010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b050000000000ffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000
Then I sign the raw transaction using signrawtransaction
:
$ ./litecoind signrawtransaction 010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b050000000000ffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000
signrawtransaction hash: eed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0
{
"hex" : "010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b05000000006a4730440220258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e0220406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd012103ec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccfffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000",
"complete" : true
}
Note that the hash being signed here is eed3...
. I added a print line t the code so that I could see the uint256
that is being signed. Specifically, in script.cpp
, where the signing for signrawtransaction
takes place, I added an extra boolean parameter to log the hash and the lines below.
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;
}
Next, I decoderawtransaction
and take the first element on the asm
stack, which is the signature.
30 44 02 20
258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e
02 20
406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd
01
Here, with some help from Pieter Wuille (Why the signature is always 65 (1+32+32) bytes long?), we can see the R and the S elements.
Next I put them in to my pycoin test file. Pycoin is an easy to use python library for bitcoin ((https://github.com/richardkiss/pycoin)).
from pycoin.ecdsa import * import string def verify_sig(sig, prefix, xpub, signed_val): is_even = (prefix % 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("is valid: " + str(verify(generator_secp256k1, pub_pair, signed_val, sig))) sigR = 0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e sigS = 0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd sig = (sigR, sigS) x = 0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf hash = 0xeed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0 compressed_char = 0x03 verify_sig(sig, compressed_char, x, hash)
And the result that is printed:
sig: (0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e, 0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd) pub: (0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf, 0x227874efbedb02b88568b55106634b9b4e3eca128ab46fa98abe7066aece0a51) hex: 0xeed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0 is valid: False
I am really not sure what could be going wrong here, since this is just straight ECDSA verification. Are there any values there that seem strange, or any other reason that this would not validate?