IPFS技术解析之文件HASH值

IPFS的热门就不必说了,太多的人关注基于它的Filecoin挖矿。但是否能获得很大的收益,谁也说不清楚,毕竟主网没有上线,测试网也没有上线。但矿工们的交集等待,并不会降低大家对IPFS相关技术的关注。除了Filecoin,越来越多的项目也会利用IPFS作为底层存储层或者网络数据传输协议。

空话少说。直奔主题。IPFS和传统文件系统的一个重要区别就是——内容寻址。顾名思义,就是文件的内容定了,其地址(访问路径)也就确定了。这和我们平时存放文件不一样。通常,我可以给一张图片随意更换文件名,把它拷贝到不同的路径。这样,一模一样的文件,其访问方式却随时变化,不可能根据文件的内容确定其访问路径。相比较而言,内容寻址的IPFS就具有一个天然的优势——防篡改。数据只要修改了一个bit,其地址就彻底变化。想借助修改文件瞒天过海,难度就陡增。

比如,我创建了一个很简单的文本文件demo.txt,然后把它上传到IPFS网络中:

$echo -n "StorSwift" > demo.txt

$ipfs add demo.txt

added QmSsw6EcnwEiTT9c4rnAGeSENvsJMepNHmbrgi2S9bXNJr demo.txt

于是,我就得到一个HASH值QmSsw6EcnwEiTT9c4rnAGeSENvsJMepNHmbrgi2S9bXNJr,在全球任何地方都可以访问这个文件。也可以通过IPFS的网关在浏览器中查看:https://gateway.ipfs.io/ipfs/QmSsw6EcnwEiTT9c4rnAGeSENvsJMepNHmbrgi2S9bXNJr

下面我们简单探索一下,这个HASH值是如何得来的。

1. HASH算法:SHA2-256

玩区块链的人,不管对技术多熟悉,或多或少都知道这个概念。每个文件存入IPFS网络,都会有一个唯一的哈希(HASH)值,通过该值便可以确定文件,进而访问数据。只要文件内容稍微修改,HASH就会变化。IPFS采用了SHA2-256这个安全级别还算高的算法,对任意长度的内容,生成的HASH值长度固定,都是32个字节。

在Linux下,直接用sha256sum可以计算SHA2-256格式的HASH值:

$sha256sum demo.txt

6739529c5fb0802b60da9827b1a0942e08ab1a63f4bd855c49a74de55774bbef  demo.txt

得到的结果有64字节,其原因是因为用了十六进制的表示方式,每个字符表示4个bit,加在一起就是256bit,也就是32字节。但在IPFS中,并不能利用上面得到的SHA2-256结果,去确定文件地址,因为IPFS还有一些额外的因素需要考虑。

前面我们把demo.txt加入到IPFS中,除了正文里面的StorSwift几个字符之外,IPFS还会添加一些元数据。比如,通过如下命令我们可以看到IPFSF里面到底存放了什么内容:

$ipfs object get QmSsw6EcnwEiTT9c4rnAGeSENvsJMepNHmbrgi2S9bXNJr

{"Links":[],"Data":"\u0008\u0002\u0012\tStorSwift\u0018\t"}

返回的是一个JSON格式的字符串,Data显示了具体的内容。可见在文件的原始内容之外,添加了一些其他的数据。IPFS会把文件数据以unixfs这种格式保存,可以认为,它是IPFS的核心数据结构MerkleDAG的一个表现方式。具体内容,以后再做解释。我们可以通过获取IPFS的原始格式的数据,来计算正确的HASH值。IPFS保存的内容会被分成许多块(block),本例的文件因为比较小,一个块就可以保存。所以,我们可以用如下的命令直接获取IPFS block的内容:

$ipfs block get QmSsw6EcnwEiTT9c4rnAGeSENvsJMepNHmbrgi2S9bXNJr  | sha256sum

437246839fc6ad5e2b74386df944f99e7cb42998dee02f169644d88ce6b00b8f  -

该block的HASH值用十六进制数表示为:437246839fc6ad5e2b74386df944f99e7cb42998dee02f169644d88ce6b00b8f。它也就是IPFS用特定格式保存文件之后的HASH值。

2. 扩展需求:multihash

是否用该HASH值就能得到我们通常看到的IPFS文件的HASH值?好像不是那么回事,因为我们看到的文件HASH值都是以Qm开头的,显然在这里对不上号。这就涉及到另外一个话题——动态选择HASH算法的设计。

虽然现在SHA2-256还比较安全,但随着科技的发展,说不定哪天就突然有人宣布,可以破解它呢?那自然需要采用更先进的算法。但IPFS的协议制定好了,也不能随便改。怎么办呢?虽然现在用的是SHA2-256,但可以宣称我支持多种HASH算法,到时候升级算法即可,但不会有大的架构改动。于是,IPFS采用了multihash这种简单的HASH表示方式,支持多种HASH算法。如果未来修改算法,用的仍然是multihash,保证了表达方式的持续性。

multihash的格式简单,具体文档参见:multiformats/multihash。它其实就是一个字符串,由三部分组成:HASH算法编码、HASH值的长度(字节数)、HASH 值。

SHA2-256的编码为0x12,其HASH摘要长度为32字节(十六进制数为0x20)。把1220加到前面所得HASH值的开头,我们得到本例文件的multihash编码(十六机制):

1220437246839fc6ad5e2b74386df944f99e7cb42998dee02f169644d88ce6b00b8f

3. 易用需求:Base58

但这个HASH值显然也不是我们看到的内容。那是怎么回事呢?它太长了,一堆数字读起来也不容易,所以需要再进行编码,压缩其长度,且容易被传播。为此,IPFS采用了Base58这种编码。Base58最早被比特币采用,如今在区块链项目中非常流行,经常用于表示钱包地址。做过开发的朋友可能比较了解Base64这种编码,能把任意二进制内容转换成方便软件查看的可读字符。但Base64有一些缺点,就是某些字符不和谐,比如,O和0容易混淆,+和/等符号,很容易让人把一个完整的字符串认为是两个不同的字符串,形成阅读上的障碍。有时候我们用鼠标一点,想自动选中整个字符串,却因为这些符号的干扰,导致选择操作没有那么高效。因此,就诞生了Base58这种编码。很简单,就是和Base64类似,能转换二进制内容为可读字符,只是把前面讲的那些有干扰的字符全部剔除。

Base58的代码非常简单,可以从这里获取:keis/base58

我引用了里面的Python源文件,基于前面生成的multihash编码进行计算:

>>> import base58

>>> base58.b58encode_int(int("1220437246839fc6ad5e2b74386df944f99e7cb42998dee02f169644d88ce6b00b8f", 16))

'QmSsw6EcnwEiTT9c4rnAGeSENvsJMepNHmbrgi2S9bXNJr'

得到的结果QmSsw6EcnwEiTT9c4rnAGeSENvsJMepNHmbrgi2S9bXNJr,正是前面我们用ipfs add命令得到的HASH值!

补充一点,IPFS现在的multihash值,都是以1220开头的,按照Base58的算法,算出来的结果就都是以Qm开头。

4. 总结

大功告成!现在对IPFS文件的HASH值有了比较清楚的认识,知道其来龙去脉了。总结一下,就是:

原始数据封装成 -> 计算SHA2-256 -> 封装成multihash -> 转换成Base58

当然,如果上传的是目录,或者分成多块的文件,其过程就要复杂一些。

你可能感兴趣的:(IPFS技术解析之文件HASH值)