區塊鏈100講:16進位制資料的編碼/解碼演算法

區塊鏈社群HiBlock發表於2018-05-24

image

眾所周知,計算機儲存和處理的都是二進位制資料。為了簡潔,實際上使用最多的是二進位制的一個變種--16進位制。比如筆者的名字叫嘉文,中文拼音是jiawen(全小寫),在計算機裡儲存的就是 6A696177656E。

很明顯,人類容易記住jiawen,而其相應的16進位制程式碼6A696177656E就很考驗人的記憶力了。同樣的,人類很難記住16進位制的資料,但是如果是16進位制編碼的文字字串就相對好記好讀一些了。以下是一張ASCII碼錶的一部分。

image

十六進位制的07是一個Bell(響鈴),如果試著用計算機程式去列印,結果是不可見也不可理解的,只能聽到一聲鈴聲。但是文字字串“07”則相對容易理解和記憶。上文提到過,Bitcoin地址都是16進位制的數,不做轉換,列印的話毫無意義,人類無法直觀的辨識。

大家可以想象一下查詢自己的銀行賬戶餘額的場景,假如賬戶裡只有77塊錢了,查詢結果的列印是大寫字元M(10進位制的編碼是77)。我相信大部分的使用者都不知道那是77的意思。相對的,如果把數字77轉換成文字“77”(其16進位制編碼是3737)後再列印,對於顯示在螢幕上的文字77,使用者就會理解了。總結一下:

image

下面的幾節將討論用文字來表示16進位制資料的幾種編碼方式。

1、Base64

這是一種用64個字元來表示任意二進位制資料的方法,通常exe、jpg、pdf等檔案都是二進位制檔案,用文字編輯器開啟都是亂碼,那麼就需要一個方法,可以將二進位制編碼成字串的格式,這樣可以將二進位制檔案用文字開啟檢視。

那麼,既然是BASE64,就是通過64個字元來編碼的,具體是哪64個字元呢?請見下表:

image

Base64編碼主要用在傳輸、儲存、表示二進位制等領域,還可以用來加密,但是這種加密比較簡單,只是一眼看上去不知道什麼內容罷了,當然也可以對Base64的字元序列進行定製來進行加密,我們來看下Base64的編碼過程。

首先,既然是使用上述64個字元的範圍來表示的,那麼,要能夠表示出64個字元的各種組合,得起碼用6個bit才行,根據排列組合,6個bit可以總共表示出2的6次方的組合的字元排列;針對一份需要轉化的二進位制檔案,可以這樣來處理,每3個位元組一組,這樣一共是24bit,然後可以針對這個24bit再來劃分,劃分成每6bit一組,這樣一共可以分成4組,分成4組6bit後,則對照上表去查詢對應的字元就可以了,這樣就可以轉換為base64了,簡單吧。

那麼,如果在3個位元組一組劃分的時候,如果不是3的倍數怎麼辦呢?這樣就需要使用\x00位元組在末尾補足,再在編碼的末尾加上1個或2個=號,表示補了多少位元組。

由於標準的Base64編碼後可能出現字元+和/,在URL中就不能直接作為引數,所以又有一種"url safe"的base64編碼,其實就是把字元+和/分別變成-和_。

根據這個原理,其實還是比較容易理解這種編碼思想的,而且,也可以看出,這種編碼是可以逆向的,以“yes”這個字串為例,它的Base64編碼是eWVz,大家可以自行嘗試幾個例子。

2、Base58

顧名思義,Base58是基於58個字母和數字組成的,有了Base64的基礎,我們就比較容易理解Base58了,實際上就是Base64的一個子集,相對於Base64來說,Base58不包括以下Base64的字元:

  • 數字0

  • 大寫字母O

  • 大寫字母I

  • 小寫字母l

  • +與/

可以看出,小寫o和大寫O很容易和數字0混淆,小寫l和大寫I很容易和數字1混淆,Base58就是Base64去除了幾個看起來容易混淆的字元以及容易導致轉義的/和+。Base58的編碼表如下:

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

必須注意,不同的應用實現使用的編碼表內容是一樣的,但是順序可能不一樣,比如:

1)比特幣地址:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

2)Ripple 地址:rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz

接下來我們來了解一下Base58Check,比特幣使用的是改進版的Base58演算法,為了解決Base58編碼的字串沒有完整性校驗機制。在傳播過程中,如果出現某些字元損壞或者遺漏,就沒法檢測出來了,所以使用了改進版的演算法Base58Check,

3、 Base58Check

在二進位制資料的傳輸過程中,為了防止資料傳輸的錯誤,保護資料安全,通常會加一個校驗碼。通過校驗碼的配合可以發現資料是否被破壞或者是否在傳送時輸入錯誤了。Base58Check就是Base58加上校驗碼,或者可以說是Base58的一種編碼形式,在比特幣系統中生成錢包地址的時候就使用到了這種編碼形式。

我們知道,錢包地址是用來轉賬的,雖然Base58編碼已經可以做到避免一些容易混淆的字元,但是還不能保證使用者的誤輸入或者地址資訊在傳輸過程中由於某種原因被破壞,這會給使用者帶來潛在的損失風險。

Base58Check的編碼方式是這樣的:進行編碼前,在待編碼的內容字串中加入一個位元組的版本資訊,版本資訊可以自行約定,比如比特幣地址採用了0×00作為版本資訊,然後再啊計入編碼內容字串的雜湊值,通常只要取得雜湊值中的4個位元組就可以了,加到一起後,然後再整體進行Base58編碼。

比特幣地址的生成過程中,是將版本位元組放在了頭部,而將4個位元組的雜湊值放在了尾部,然後進行編碼生成。這個原理還是很簡單的,雜湊演算法具有先天的資料完整性檢測能力,在這裡我們又看到了雜湊演算法的又一個應用。

經過整理編碼後的資料在傳輸過程中如果有發生損壞或者篡改,接收方在得到資料後,會對原始資料進行同樣的校驗碼計算,並且和接收到的結果中的校驗碼進行比較。由於雜湊演算法的特點,只要原始資料有任何更改,計算出的雜湊值都會發生變更,因此只要校驗碼不一致就說明資料不是合法的。

內容來源:《白話區塊鏈》第三章第三節“編碼/解碼演算法”

作者:蔣勇

活動推薦:技術沙龍|學會編寫智慧合約後,該學什麼?(西安) 掃描下圖中二維碼或點選“閱讀原文”即可報名參加

image

相關文章