这一章,我们试图解决一个问题:在对方没有保留初始哈希值的情况下,如何让对方相信一条数据没有被篡改?
我们的最终产品的目标,是存证海量的数据,服务全球人。我们需要存储大量的数据,有巨大的网络吞吐量,所以,我们应该是一个比较专业的机构,一家数字档案馆。
https://commons.wikimedia.org/wiki/File:A_view_of_the_server_room_at_The_National_Archives.jpg
我们该如何存储这些数据呢?我们创造这样一种数据结构,如下图所示。首先要求每个原始数据里必须包含时间戳,正常情况下,我们的档案馆会按照时间顺序一条一条接收数据。然后,我们将原始数据和一个哈希值合并在一起,打包成一个稍大一点的数据包。这里的哈希值是上一个数据包的哈希值。
这样,所有的数据包就构成了一条链。这条链的特性就是,如果其中任何一个数据被篡改,那么下一个数据包里的哈希值就不对了,如果要纠正,那么下下个哈希值又不对了。为了保持哈希值正确,就需要把之后的所有哈希值全部纠正。那么,如果有人保存过链条上的某几个哈希值,ta 就可以发现链条被篡改过了。我们不妨把它称为哈希链条。数字档案馆的职责就是存储和延长这根哈希链条。
那么,回到“A 希望 B 相信一个数据没有被篡改过”这个需求上来。
要满足这个需求,首先,A 需要在数据诞生时,将数据上传给我们的数字档案馆,这样,这条数据就会被永久嵌入在哈希链条里,而链条会持续不断地延长。
B 需要每隔一段时间从数字档案馆下载最新的哈希值(即最后一个数据包里的哈希值),并自己保存起来,这个数据量并不大,万一哪天哈希链条被篡改了,自己能发现。
等到某一天,A 需要让 B 相信这条数据没有被篡改,A 可以将数据发给 B。B 从数字档案馆下载从这条数据到最新一个数据的这一段链条,然后依次验证哈希值是否正确,同时检查之前保存过的几个时间点的哈希值是否都能匹配得上,如下图所示。
从数据诞生,到向 B 申请验证的整个流程如下图所示。
为了帮助你理解,你可以思考一下,如果 A 想要欺骗 B,也就是既给 B 一个临时伪造的数据,又让 B 相信是真实的,难度有多大?
你会发现,只要 B 在哈希链条上做了“采样”,A 根本不可能瞒着 B 把一个临时伪造的数据插入到哈希链条中。
这一章,我们往“不可篡改”又迈进了一大步。但又有一些新的问题:
-
哈希链条的数据量极其巨大,每次验证都要下载一遍的话,非常不便利;
-
一数字档案馆倒闭了,整个哈希链条将遗失,人们就再也无法验证过去的数据;
-
如果案例中的 B 没有持续对哈希链条采样,ta 该如何信任哈希链条?
这些问题,我们将在后面的几章,用非常开创性的方法来解决。
至于我们采用哪一种哈希函数算法,是一个很细分的问题。我们暂定采用上一章提到的 SHA256 算法。