以太坊的密码学(三)-密码学哈希函数

介绍以太坊中的密码哈希函数

Posted by HonorJoey on March 24, 2020

密码学哈希函数

哈希函数介绍

以太坊中,密码学哈希函数无处不在。

实际上,哈希函数在所有的加密货币中都有着广泛的应用,密码学家Bruce Schneier(http://bit.ly/2Q79qZp)曾说过一句大实话:“相比加密算法,单向哈希函数在现代密码学中才是主力军。”

简单地说,哈希函数(http://bit.ly/2CR26gD)是一个可以将任意长度数据映射成固定长度数据的数学函数。

哈希函数的输入称为预映射、消息,或就叫输入数据,哈希函数的输出数据称为哈希。密码学哈希函数(http://bit.ly/2Jrn3jM)是哈希函数中的一个特殊类别,具有特别的属性,可以很好地保护平台(如以太坊)的安全。

加密哈希函数是一种单向的哈希函数,可以将任意长度的数据映射为固定长度的比特序列。这种“单向性”意味着,如果我们只知道哈希函数的输出值,还原出输入数据在计算上是不可能的。要发现可能的输入值,唯一的方式就是暴力搜寻,检查每一个可能的输入是否能得到同样的输出值;给定无限的搜索空间,显然,求得原输入在实践中是不可能的。即便可以找到一些输入能产生同样的哈希值,也不一定就是我们想求的那个初始输入:因为哈希函数是“多对一”的函数。发现具有同样哈希值的两个输入的问题被称为哈希碰撞问题。粗略来说,哈希函数的性质越好,哈希碰撞的情形就越少。对以太坊来说,这基本上是不可能的。

密码哈希函数的主要的五个特性:

  • 确定性

    同样的输入信息总是会产生相同的输出哈希。

  • 可验证性

    计算任意输入信息量的哈希运算非常高效(线性的计算性能)。

  • 无关联性

    对于输入消息的微小改变(哪怕是只改变一个比特)都会对输出结果的哈希造成巨大的变化,而且这样的变化与之前的消息之间没有任何关联性。

  • 不可逆性

    从哈希反向计算得出输入的原始信息是不现实的,只能通过暴力穷举式的尝试。

  • 碰撞保护性

    几乎不可能找到能够得到同一个哈希输出的两个不同信息。

这里的碰撞保护性对于防止伪造以太坊中的数字签名尤其重要。

这些属性的结合使得密码学哈希函数在安全领域有着广泛的应用:

  • 数据指纹
  • 数据一致性(错误侦测)
  • 工作量证明
  • 身份认证(密码哈希和密钥延伸)
  • 伪随机数生成器
  • 消息承诺(commit-reveal机制)
  • 唯一标识符

随着对以太坊的深入研究,我们会在系统中发现很多上述应用。

以太坊中的密码学哈希函数:Keccak-256

以太坊协议中多处用到了名为Keccak-256的密码学哈希函数。Keccak-256是2007年由NIST在SHA-3密码学哈希函数竞赛中提出的。Keccak胜出并最终在2015年成为FIPS 202标准。

然而,在以太坊的开发过程中,NIST标准并没有完全确定。在标准化过程完成后,NIST调整了Keccak中的一些参数,意在提升它的性能。与此同时,Edward Snowden披露的政府文档中揭示,NIST可能受到美国国家安全部门的影响,有意地弱化了Dual_EC_DRBG随机数生成器标准,在这个随机数生成器中加入了后门。这导致了公众对变更提案的强烈抵制,并极大地延缓了对应的SHA-3标准化进程。因此,以太坊基金会决定实现由发明者提出的最原始的Keccak算法,而不是在以太坊中使用经过NIST修改的SHA-3标准。

 你会在以太坊的代码和文档中看到大量“SHA-3”的字样,这些多数都是指原始版本的Keccak-256,而不是经过SHA-3标准化的FIPS-202。这两者在实现层的差别微乎其微,只是填入参数的区别。但是对于给定的输入内容,Keccak-256所产出的哈希肯定与FIPS-202 SHA-3所产出的哈希完全不同。

我在使用哪一个哈希函数?

如果两个哈希都叫“SHA-3”,我们如何辨别所使用的程序库是FIPS-202 SHA-3还是Keccak-256?

最简单的办法是采用测试矢量,用一个给定输入的已知结果来判断。用于测试哈希函数最通用的方法是使用空的输入。如果使用哈希函数计算输入的空字符串的哈希值,应该得到如下结果:

Keccak256("") =
  c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
SHA3("") =
  a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a

因此别管这个函数叫什么名字,我们都可以通过这一简单测试来确定它到底是原始的Keccak-256实现,还是NIST最终标准化的FIPS-202 SHA-3实现。记住,尽管在代码中有些地方采用了SHA-3的命名,以太坊使用的是Keccak-256实现。