加密哈希函数
加密函数的三个特性:
- 可以输入任意长度的字符串。
- 产生固定长度的输出。
- 可以高效的进行计算。一般来说,复杂度是 O(n) O ( n ) ,其中 n n <script type="math/tex" id="MathJax-Element-2">n</script>是输入的字符串长度
加密哈希函数的三个属性:
- Collision-resistance 碰撞存在性。哈希碰撞确实是存在的,但是我们无法刻意的找到特定的碰撞。
- Hiding 隐藏属性。给定一个输出的哈希值,我们无法计算出产生该输出值的输入值。
- Puzzling-friendly。对于每个n位的输出值y和对应的输入值x,如果想要找到一个一样的输出值对应的输入值,可以寻找满足条件的概率和随机寻找满足条件的概率一样。
哈希指针和对应的数据结构
这里的哈希指针,类似于我们C/C++的指针,但是该指针仅仅指明了物理存储的确切地址,而且还存储了前一个区块某个特定时间下的哈希值。如下图所示的表示方式:
多个数据块通过相同的方式串联到一起,就形成了我们所说的区块链:
上图中,每一个数据块的头部都存储了前一个数据块的地址和特定时间下的哈希值。
区块链的防篡改特性在于:如果一个区块链的某个结点k的数据被篡改,那么k+1区块头部的哈希值与篡改后k的哈希值不同;为了保持前后哈希的一致性,必须篡改后续所有块的哈希值。
但是,即使改到了最后,如果我们仍然保留了篡改前的哈希值,那么篡改后的哈希值与篡改前的哈希值仍然不同,那么我们可以断定数据被更改了。在上面的概述中,我么假设篡改后的所有数据发生哈希碰撞的可能性在统计概率上为0.
在实际的操作中,我们使用Merkle树这一数据结构来表示区块链,而不是使用单一的链式结构:
Merkle树的叶子结点用于存储带有时间戳的数据块,而中间结点存储哈希值,根结点存储最终的状态的哈希值。如果某个数据块的数据被篡改,那么根结点的哈希值肯定会发生变化。关于Merkle更加详细的介绍,可以看这篇博客。
数字签名
数字签名的作用主要有两个:
- 只有你自己才能生成自己的签名,但是其他看到签名的人会证实你的签名是有效的。
- 签名与一个特定的文档绑定,那么这个文档的中所有的记录都证明是你同意的
数字签名的工作模式如下:
- 生成秘钥
(pk,sk) = generateKeys(keySize)
。sk
是私钥,用于给我们的交易信息加密;pk
是公钥,每个人都可以看见,用于验证是我们的签名 - 生成签名
sig = sign(sk, message)
。 私钥sk和我们的消息共同经过加密算法sign,生成签名sig - 验证信息和签名
isValid = verify(pk, message, sig)
。把消息、签名和公钥作为输入,如果是我们发送的消息,则返回true;否则返回false。
公钥作为身份标识
我们可以这么理解:假设我们发现了一个message和一个签名,如果现在有了一个pk,可以让验证算法通过,那么就可以认为是pk做的这笔交易。在去中心化的状态下,我们可以认为一个pk就是一个合法的身份,而且不需要传统的中心服务器来注册身份信息。只要我们想,我们可以随时生成一个pk作为我们的身份,而且这完全是匿名的。