比特幣中的Base58 編碼


base58和base64一樣是一種二進制轉可視字符串的算法,主要用來轉換大整數值。區別是,轉換出來的字符串,去除了幾個看起來會產生歧義的字符,如 0 (零), O (大寫字母O), I (大寫的字母i) and l (小寫的字母L) ,和幾個影響雙擊選擇的字符,如/, +。結果字符集正好58個字符(包括9個數字,24個大寫字母,25個小寫字母)。不同的應用實現中,base58 最后查詢的字母表可能不同,所以沒有具體的標准。下面是幾個應用中的字母表:

比特幣地址:

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

Monero 地址

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

Ripple 地址

rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz

Flickr 的短URL

123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ

Base58 編碼與解碼

Base58 的輸入是一個[0,256)的值的流,輸出結果是一個[0,58) 的值的流。然后將每個值去查字母表,得出一個可視字符串。轉換過程實際上就是一個256進制的值轉換為一個58進制的值。

進制轉換過程如下(下面偽代碼描述256進制轉換為58進制過程, base58編碼需要將58進制流查表得到對應的字符流):

# 將 input 256進制流轉換為 output 58進制流 for carry in input: for (outputPos, outputNum) in output.reverse(): carry += outputNum * 256 output[outputPos] = carry % 58 carry /= 58 # output 流處理完畢, carry依然有值, 則繼續向 output 前部插入 while carry != 0 : output.insertFront(carry%58) carry /= 58 

在實現的時候,開頭的0需要特殊處理下,因為0轉換后依然是0, 所以可以將輸入流開頭的0直接填充到結果前邊。

逆轉換過程(先將輸入字符串轉換為58進制的流, 然后將58進制的流轉換為256進制的流, 下面偽代碼描述58進制轉換為256進制過程):

# 將 input 58進制流轉換為 output 256進制流 for carry in input: for (outputPos, outputNum) in output.reverse(): carry += outputNum * 58 output[outputPos] = carry % 256 carry /= 256 # output 流處理完畢, carry依然有值, 則繼續向 output 前部插入 while carry != 0 : output.insertFront(carry%256) carry /= 256 

同樣,在實現的時候,開頭的0需要特殊處理下,因為0轉換后依然是0, 所以可以將輸入流開頭的0直接填充到結果前邊。

Base58Check

比特幣之所以加入改進版的 Base58 算法,主要為了解決 Base58 導出的字符串沒有校驗機制,這樣,在傳播過程中,如果漏寫了幾個字符,會檢測不出來。所以使用了改進版的算法 Base58Check。

實現是:在encode前,在輸入流尾部加入輸入內容的hash值(4個字節)。然后再對輸入流進行 Base58Encode。

在 decode 時候:先 Base58Decode, 然后拆成兩部分(內容和校驗值),判斷對內容計算的校驗值和校驗值字段是否一致。

Go 的base58庫:
https://github.com/shengdoushi/base58

比特幣Base58相關源碼地址: https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM