阅读 216

区块链100讲:16进制数据的编码/解码算法

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