Ecdsa

如何使用 pycoin 驗證樣本 litecoin tx 的 ECDSA?

  • October 30, 2014

我正在使用 litecoin testnet 網路進行測試。053baee857adfdc16959e9dbc9618e0e935f0a1e51e226e651fcd67242f1f462我有一個0的 UTXO vout

我進行了原始交易,將硬幣發送給自己(在不同的地址):

$ ./litecoind createrawtransaction '[{"txid":"053baee857adfdc16959e9dbc9618e0e935f0a1e51e226e651fcd67242f1f462", "vout":0}]' '{"mroLyo22ptLfq5LKMijnCyD35mEsAWTkF9":0.039}'
010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b050000000000ffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000

然後我使用以下命令簽署原始交易signrawtransaction

$ ./litecoind signrawtransaction 010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b050000000000ffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000
signrawtransaction hash: eed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0
{
   "hex" : "010000000162f4f14272d6fc51e626e2511e0a5f930e8e61c9dbe95969c1fdad57e8ae3b05000000006a4730440220258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e0220406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd012103ec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccfffffffff0160823b00000000001976a9147bc2f9c3a30a18cc307d74fd014e4ddf7323398488ac00000000",
   "complete" : true
}

請注意,此處簽名的雜湊是eed3.... 我在程式碼中添加了一個列印行,以便我可以看到uint256正在簽名的內容。具體來說,在進行script.cpp簽名的signrawtransaction地方,我添加了一個額外的布爾參數來記錄雜湊和下面的行。

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取棧上的第一個元素asm,也就是簽名。

30 44 02 20 
258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e
02 20 
406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd
01

在這裡,在 Pieter Wuille 的幫助下(Why the signature is always 65 (1+32+32) bytes long?),我們可以看到 R 和 S 元素。

接下來,我將它們放入我的 pycoin 測試文件中。Pycoin 是一個易於使用的比特幣 Python 庫((<https://github.com/richardkiss/pycoin>))。

從 pycoin.ecdsa 導入 *

導入字元串

def verify_sig(sig, prefix, xpub, signed_val):
is_even = (前綴 % 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("有效:" + str(verify(generator_secp256k1, pub_pair, signed_val, sig)))

sigR = 0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e
sigS = 0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd
sig = (sigR, sigS)
x = 0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf
雜湊 = 0xeed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0
壓縮字元 = 0x03

verify_sig(sig,compressed_char,x,hash)

以及列印的結果:

信號:(0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e,0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07
酒館:(0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf,0x227874efbedb02b88568b55106634b9b4e3eca128ab46fa98abe7066aece0a51)
十六進制:0xeed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0
有效:假

我真的不確定這裡可能出了什麼問題,因為這只是直接的 ECDSA 驗證。那裡是否有任何看起來很奇怪的值,或任何其他無法驗證的原因?

發現問題了!比特幣對於大/小端整數非常不一致。我反轉了雜湊並驗證了簽名!

最終程序:

從 pycoin.ecdsa 導入 *

導入字元串
導入數組
導入 binascii

def verify_sig(sig, prefix, xpub, signed_val):
is_even = (前綴 % 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("有效:" + str(verify(generator_secp256k1, pub_pair, signed_val, sig)))

sigR = 0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e
sigS = 0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07f69cd
sig = (sigR, sigS)

x = 0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf
字元 = 0x03

revhash = "eed300fc63a973b668af66af746fde378ec6556f4b330ec1eeccc6a77aa535b0"
雜湊 = ""
對於範圍內的 i (0, len(revhash), 2):
雜湊 = revhash[i:i+2] + 雜湊

verify_sig(sig, char, x, int(hash, 16))

結果:

信號:(0x258ad2725e66da0ae9825bb849a8e73f86e4767cf256c9fae44d18fbc1aacc2e,0x406638a5b3369bb83d8a4f38a17b2f048c1495ebfd6fdff1a8c7b268e07
酒館:(0xec539eb3d882c07575f6143d891c18d580cd9d2726add0d71d262f2f6f2d4ccf,0x227874efbedb02b88568b55106634b9b4e3eca128ab46fa98abe7066aece0a51)
十六進制:0xb035a57aa7c6cceec10e334b6f55c68e37de6f74af66af68b673a963fc00d3ee
有效:真

引用自:https://bitcoin.stackexchange.com/questions/32194