本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
免责声明:本文仅从技术角度翻译、分析Solana,不构成任何的投资建议。 原创翻译,转载请注明出处。
4 Proof of History 历史证明
历史证明是通过一个计算生成的序列,来提供⼀种加密验证两个事件之间的时间流逝的⽅法。它使⽤加密函数生成序列,因此⽆法从各个序列的输⼊预测最终输出,必须完全执⾏才能⽣成输出。该函数在单个内核上按顺序运⾏,前者的输出结果作为当前计算的输⼊参数,定期记录当前输出,这些输出的记录可以被外部计算机的计算机重新计算和验证。
通过将数据(或数据的hash)附加到加密函数的state(理解成函数入参)中,数据可以在该序列中打上时间戳。当state、index和数据被附加到序列中时,它的记录提供了一个时间戳,可以保证数据是在序列⽣成下⼀个hash之前的某个时间创建的。这种设计还⽀持⽔平缩放,因为多个⽣成器可以通过将它们的state混合到彼此的序列中来相互同步。⽔平缩放在4.4中有深⼊介绍。
4.1 说明
本系统的工作原理如下。通过使⽤hash加密函数,如果不运⾏该函数就⽆法预测其输出(例如 sha256、ripemd等),从某个随机起始值运⾏该函数并获取其输出并将其作为输⼊再次传递给同⼀个函数。记录函数被调⽤的次数和每次调⽤的输出。选择的起始随机值可以是任何字符串,例如当天纽约时报的标题。
例如:
PoH Sequence | ||
---|---|---|
Index | Operation | Output Hash |
1 | sha256(“any random starting value”) | hash1 |
2 | sha256(hash1) | hash2 |
3 | sha256(hash2) | hash3 |
哈希N 表示实际的哈希输出。
只需要每隔⼀段时间发布hash和index的⼦集。
例如:
PoH Sequence | ||
---|---|---|
Index | Operation | Output Hash |
1 | sha256(“any random starting value”) | hash1 |
200 | sha256(hash199) | hash200 |
300 | sha256(hash299) | hash300 |
只要选择的哈希函数是抗碰撞的,这组哈希就只能由计算机单线程按顺序计算。这是因为如果不从起始值实际运⾏算法 300 次,就⽆法预测index 300 处的哈希值将是什么。因此我们可以从数据结构中推断出在index 0 和index 300 之间存在时间流逝。
见图 2, 哈希值 62f51643c1 在计数 510144806912产生的, 哈希值 c43d862d88 是在计数 510146904064 上产⽣的。根据前⾯讨论的 PoH 算法的特性,我们可以相信在计数 510144806912 和计数 510146904064 之间存在时间流逝。
图 2:历史序列证明
4.2 事件时间戳
此哈希序列还可⽤于记录在⽣成特定hash n之前创建的某些数据。使⽤“combine”函数将数据与当前index处的hash组合起来,组合的数据可以简化为数据的hash值。“combine”函数可以是简单的数据拼接,也可以是任何抗碰撞操作。下⼀个⽣成的哈希值表⽰数据的时间戳,因为它只能在插⼊特定数据后⽣成的。
例如:
PoH Sequence | ||
---|---|---|
Index | Operation | Output Hash |
1 | sha256(“any random starting value”) | hash1 |
200 | sha256(hash199) | hash200 |
300 | sha256(hash299) | hash300 |
发⽣了⼀些外部事件,例如拍摄照⽚或创建了任意数据:
PoH Sequence With Data | ||
---|---|---|
Index | Operation | Output Hash |
1 | sha256(“any random starting value”) | hash1 |
200 | sha256(hash199) | hash200 |
300 | sha256(hash299) | hash300 |
336 | sha256(append(hash335, photograph sha256)) | hash336 |
hash336 通过拼接的 hash335 和 照⽚的sha256 计算而出的。index和 照⽚的sha256 被记录为序列输出的⼀部分。因此,任何验证此序列的⼈都可以复现这个结果,而且验证过程可以并行,此部分在4.3有介绍。
因为初始过程仍然是顺序的,所以我们可以判断输⼊到序列中的事情⼀定是在计算未来hash值之前的某个时间发⽣的。
POH Sequence | ||
---|---|---|
Index | Operation | Output Hash |
1 | sha256(“any random starting value”) | hash1 |
200 | sha256(hash199) | hash200 |
300 | sha256(hash299) | hash300 |
336 | sha256(append(hash335, photograph1 sha256)) | hash336 |
400 | sha256(hash399) | hash400 |
500 | sha256(hash499) | hash500 |
600 | sha256(append(hash599, photograph2 sha256)) | hash600 |
700 | sha256(hash699) | hash700 |
表 1:具有 2 个事件的 PoH 序列
在表1所表⽰的序列中 , 照⽚2 在hash600之前创建,照⽚1 在hash336之前创建。 将数据插⼊hash序列会导致序列中所有后续值发⽣更改。只要所使⽤的hash函数是抗碰撞的,并且数据是附加的,就应该不可能预先计算任何未来的序列。
添加到序列中的数据可以是原始数据本⾝,也可以是原数据的hash值。
见图3, 输⼊ cfd40df8... 被插⼊到历史证明序列中。它被插⼊的count是 510145855488,它被插⼊的状态是3d039eef3。 所有未来⽣成的hash都通过对序列的这种变化进⾏修改,这种变化由图中的颜⾊变化表⽰。
观察这个序列的每个节点都可以确定所有事件插⼊的顺序并估计插⼊之间的真实时间。
图 3:将数据插⼊历史证明