bitcoin 地址是如何生成的

來自簡書git

btc address: 1FmWXNJT3jVKaHBQs2gAs6PLGVWx1zPPHfgithub

手動生成Bitcoin地址看似有點兒事倍功半,若是你瞭解了這個過程,就會明白眼花繚亂的Bitcoin分叉幣地址只是私鑰的不一樣顯示方式,對了解Eth EOS地址也頗有幫助,也能夠更清楚的瞭解Bitcoin是如何花費的,一通則百通,妙哉。算法

生成Bitcoin地址,先由私鑰生成公鑰,再有公鑰生成hash160,最後hash160再進行base58運算獲得地址,以下圖所示:ruby

生成私鑰,再獲得公鑰,是由ECDSA實現的。ECDSA是Elliptic Curve Digital Signature Algorithm的縮寫, 即橢圓曲線數字簽名算法測試

橢圓曲線其實不是橢圓,而是下面的模樣:ui

比特幣用到的橢圓曲線是 secp256k1: $y^2=x^3+7$
那咱們言歸正傳,直接進入主題,我把這個過程分紅了8個步驟。編碼

Step1. 生成私鑰

Bitcoin要使用到Secp256k1這條特殊的橢圓曲線獲得公私鑰,
咱們經過OpenSSL命令來生成私鑰。spa

openssl ecparam -name secp256k1 -genkey > priv.pem

# 輸出DER格式
openssl ec -in priv.pem -outform DER | tail -c +8 | head -c 32 | xxd -p -c 32

# 結果
ccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea64

這裏的結果是個16進制數據
0xccea9c5a20e2b78c2e0fbdd8ae2d2b67e6b1894ccb7a55fc1de08bd53994ea643d

Step2. 生成公鑰

經過priv.pem 生成 pub_keycode

openssl ec -in priv.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65

# 輸出
04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d

輸出DER格式, 字符長度是130
pub_key = 04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d
這是未壓縮公鑰,壓縮公鑰是 03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69

詳細內容請看壓縮公鑰與非壓縮公鑰

Step3. 第2步結果進行hash160運算

hash160運算 就是先進行SHA256,再進行RMD160。

bytes = [pub_key].pack("H*") # 轉爲16進制
hash160_val = Digest::RMD160.hexdigest(Digest::SHA256.digest(bytes) )

hash160_val = 2b6f3b9e337cedbb7c40839523fb1100709c12f7

Step4. 第3步結果加上前綴符

普通的主網地址的前綴符是00,Bitcoin 地址前綴符有不少種, 具體看https://en.bitcoin.it/wiki/Li...

'00'+ '2b6f3b9e337cedbb7c40839523fb1100709c12f7'

step_04 = 002b6f3b9e337cedbb7c40839523fb1100709c12f7

Step5. 第4步結果, 執行2次SHA256, 取前8位做爲校驗和

hex_str = [step_04].pack("H*")
checksum = Digest::SHA256.hexdigest(Digest::SHA256.digest(hex_str) )[0...8]

checksum = 86b2e90c

Step6. 第4步結果跟第5步結果合併

'002b6f3b9e337cedbb7c40839523fb1100709c12f7' + '86b2e90c'
# step_04 + checksum

step_06 = 002b6f3b9e337cedbb7c40839523fb1100709c12f786b2e90c

Step7. Base58編碼

Base58是一種獨特的編碼方式,是Base64的變形,主要用於Bitcoin的錢包地址。相比Base64,Base58去掉了數字0,大寫字母O,大寫字母I,小寫字母l+/,避免引發視覺混淆。

來個base58算法

def encode_base58(int_val, leading_zero_bytes=0)
  alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
  base58_val, base = '', alpha.size

  while int_val > 0
    int_val, remainder = int_val.divmod(base)
    base58_val = alpha[remainder] + base58_val
  end

  base58_val
end

Step8. 第6步結果進行base58編碼

step_06 = "002b6f3b9e337cedbb7c40839523fb1100709c12f786b2e90c"
leading_zero_bytes = (step_06.match(/^([0]+)/) ? $1 : '').size / 2
# leading_zero_bytes的做用是字母填充
address = ("1" * leading_zero_bytes) + encode_base58(step_06.to_i(16) )

獲得 14xfJr1DArtYR156XBs28FoYk6sQqirT2s,這是一個標準的bitcoin地址,終於大功告成。

思考:經過Bitcoin 地址能反向獲得hash160_val麼?

彙總代碼: gen_addr.rb

能夠使用 bitcoin-ruby 生成地址

require 'bitcoin'

pri_key, pub_key = Bitcoin.generate_key # 私鑰 公鑰
# 經過ffi調用OpenSSL獲得,不少類庫都是這麼作的
address = Bitcoin::pubkey_to_address(pub_key)

生成測試網地址

require 'bitcoin'

Bitcoin::network = :testnet #使用測試網
pri_key, pub_key = Bitcoin.generate_key
address = Bitcoin::pubkey_to_address(pub_key)

在Bitcoin系統中,私鑰能得公鑰,公鑰能獲得錢包地址,
私鑰=>公鑰=>錢包地址,而反向是不能夠的。
牢記你的私鑰,並且私鑰不能修改地址也不能修改,誰掌握了私鑰誰就擁有了這些幣!!!


參考:

https://en.bitcoin.it/wiki/Te...
https://en.bitcoin.it/wiki/Ad...
https://en.bitcoin.it/wiki/Li...
https://github.com/liushooter...

相關文章
相關標籤/搜索