Address

如何產生一個 Hash160 比特幣地址?

  • February 23, 2022

tl; dr 應該如何使用最基本的工具執行 Hash160?

====================================================

你好,

我試圖弄清楚交易如何在比特幣中運作。

當我為新交易選擇輸入時,我想確保它們屬於特定地址。然而,現有的 txs 沒有指定先前輸出的地址,而是包含地址的雜湊值。

例如:

>> bx fetch-tx 11a1b7ac0a65bd50b7094c720aecd77cfd83d84b1707960fd00dd82a888aab5c --config /home/theo/Desktop/bx-testnet.cfg

{
   hash 11a1b7ac0a65bd50b7094c720aecd77cfd83d84b1707960fd00dd82a888aab5c
   inputs
   {
       input
       {
           address_hash f3b7278583827a049d6be894bf7f516178a0c8e6
           previous_output
           {
               hash 4a3532061d43086299ae9b2409a456bb9638dff32e0858c4ccda27203fb2e4f6
               index 1
           }
           script "[30440220146b8b5b014245a9e27e21122d4dded04c3f39c3a49ac2494743d6f6ae8efff602206d417a4be9c7431ea69699132438510ade1cf8d746607f77d114907762ed1eb301] [023dd2e892290e41bb78efce6ea30a97015ef13eaaa9ebb7b0514485fc365cc391]"
           sequence 4294967295
       }
   }
   lock_time 0
   outputs
   {
       output
       {
           address_hash a73706385fffbf18855f2aee2a6168f29dbb597e
           script "dup hash160 [a73706385fffbf18855f2aee2a6168f29dbb597e] equalverify checksig"
           value 130000000
       }
       output
       {
           address_hash ad6e80394af99ece5d7701bf2f457480b93965b7
           script "dup hash160 [ad6e80394af99ece5d7701bf2f457480b93965b7] equalverify checksig"
           value 49525957813
       }
   }
   version 1
}

說,我想檢查哪些輸出可以從地址發送mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa 所以我在 Python 中使用它的 Hash160:

>> hashlib.new('ripemd160', hashlib.sha256("mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa".encode('utf-8')).digest()).hexdigest()
'748598cd9b004aecf8a2d97464fb1f2a90562ffe'

這不是我預期的結果:a73706385fffbf18855f2aee2a6168f29dbb597e

同時,線上服務正確計算雜湊。

我如何 Hash160 比特幣地址,最好是在 Python 中?

該地址已經是一個散列,還有一個 4 字節的校驗和和一個版本字節。從一個地址到一個 hash160,你不需要計算任何東西的 sha256 或ripemd160。您只需將其從 base58 解碼回十六進制,並丟棄不需要的垃圾。

如果你進行mvm74FACaagz94rjWbNmW2EmhJdmEGcxpabase58 解碼,你會得到

6FA73706385FFFBF18855F2AEE2A6168F29DBB597EF59C240B
VVxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxSSSSSSSS

第一個字節(6F)是版本字節;丟棄它。最後 4 個字節是校驗和;丟棄它。剩下的20個字節是地址對應的公鑰的hash160。

我已經在StackOverflow上回答了這個問題,但我想我會在這裡重新發布答案。

最後我成功了。我的回答中的一些啟示對你來說可能看起來很明顯和基本,但我希望它們對比特幣完全陌生的人(比如我)有所幫助。


Wiki說我可以通過反轉地址生成的最後一步來獲得Hash160

在此處輸入圖像描述 (Hash160 高亮顯示)

這一步是用base58字母編碼一個字節串

b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

這個字母缺少 0、I、l、O,因為這些符號很容易混淆。當一個錯誤的符號可能導致損失大量金錢時,這是您最不想做的事情。

因此,我們需要mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa變成一個字節串。字節採用十六進制格式,範圍從0x00(十進制的 0)到0xff(十進制的 255)。請注意,我們有一個特殊的 b58 字母要處理:使用 utf-8 或其他編碼標準解碼地址將產生廢話。

起初我以為我可以用這個函式輕鬆解碼地址:

def decode(addr):
   b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
   decoded = ''
   for i in addr:
       temp = hex(b58.index(i))
       if len(temp) == 3:
           temp = '0' + temp[-1]
       else:
           temp = temp[2:]
       decoded += (temp)
   return (decoded)

decode('mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa')

>> '2c352c06030e090b212127390803312a1d22152c1d010d2c2811242c0d0f23372f21'

但結果與我在事務中查找的雜湊 ( a73706385fffbf18855f2aee2a6168f29dbb597e) 完全不同。通過這種方式,我了解到我不知道解碼是如何完成的。如果 Hash160 有0xff呢?b58 中沒有這樣的符號,因為十六進制的 58 只是0x3a. 在解碼 b58 時,我們不能獨立處理每個符號。整個地址組成一個用base58數字系統編寫的巨型數字(它的第一個數字對應於58**34)。

為了得到字節串,我首先把這個數字變成了十進制,然後才變成字節串。

如果您知道如何避免這種彎路並直接獲取字節 - 請發表評論

def decode(addr):

   b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

   def base58_to_dec(addr):
       dec = 0
       for i in range(len(addr)):
           dec = int(dec * 58 + b58.index(addr[i]))
       print('Decimal representation')
       print(dec)
       return(dec)

   def dec_to_byte(dec):
       out = ''
       while dec != 0:
           print(dec)
           remn = dec % 256
           dec = int((dec - remn) / 256)
           temp = hex(remn)
           if len(temp) == 3:
               temp = '0' + temp[-1]
           else:
               temp = temp[2:]
           out = temp + out
       return(out)

   dec = base58_to_dec(addr)
   out = dec_to_byte(dec)
   return (out)

decode("mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa")
>> Decimal representation
>> 700858390993795610399098743129153130886272689085970101576715
>> '6fa7370638600000000000000000000000000000000000000b'

該輸出看起來有點像我需要的(a7370638...),但有太多的零。不要看第一個字節(6f)不匹配:它與我們需要的 Hash160 無關,只是協議版本。

這很可能是一個精度錯誤。為了處理它,我使用了mpmath它可以讓你精確地操作整數。

import mpmath as mp
mp.dps = 1000

def decode(addr):

   b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'

   def base58_to_dec(addr):
       dec = 0
       for i in range(len(addr)):
           dec = int(dec * 58 + b58.index(addr[i]))
       return(dec)

   def dec_to_byte(dec):
       out = ''
       while dec != 0:
           remn = mp.mpf(dec % 256)
           dec = mp.mpf((dec - remn) / 256)
           temp = hex(int(remn))
           if len(temp) == 3:
               temp = '0' + temp[-1]
           else:
               temp = temp[2:]
           out = temp + out

       return (out)

   dec = base58_to_dec(addr)
   out = dec_to_byte(dec)
   return (out)

應用精確的模運算,我們最終可以得到 Hash160。只需確保將帶有胖手指檢查的第一個和最後 4 個字節跳閘。

x = decode('mvm74FACaagz94rjWbNmW2EmhJdmEGcxpa')
print(x)
>> 6fa73706385fffbf18855f2aee2a6168f29dbb597ef59c240b

print(x[2:-8])
>> a73706385fffbf18855f2aee2a6168f29dbb597e

耶!就像在交易中一樣!

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