关于 keccak256

看以太坊代码,发现很多地方使用的加密函数是:keccak256,了解了一下做个输出。

Keccak算法(读作为“ket-chak”)是Guido Bertoni, Joan Daemen, Michael Peters, and Giles Van Assche的工作。 SHA-3的候选人在2008年10月提交。
Keccak采用了创新的的“海绵引擎”散列消息文本。它是快速的,在英特尔酷睿2处理器下的平均速度为12.5周期每字节。它设计简单,方便硬件实现。
Keccak已可以抵御最小的复杂度为2n的攻击,其中N为散列的大小。它具有广泛的安全边际。至目前为止,第三方密码分析已经显示出Keccak没有严重的弱点。尽管如此,Keccak的创建者已经启动Crunchy加密比赛,挑起人们发现和报告成功且可核查的攻击Keccak的兴趣。

Keccak-256被设计为于2007年举行的SHA-3密码哈希函数竞赛的候选者。
Keccak是获胜的算法,在2015年被标准化为 FIPS(联邦信息处理标准)。
不过NIST接受原始的Keccak256设计后,更改了Padding的格式,以太坊坚持使用了原始的方案,因为这一更改存在争议,导致了正式的SHA3实现和原始的Keccak不兼容。
NIST一般指美国国家标准与技术研究院。

作用

keccak256算法则可以将任意长度的输入压缩成64位,16进制的数,且哈希碰撞的概率近乎为0.

keccak256 代码结构

sha3加密接口: crypto.go

加密接口在:crypto.go 源码文件中。
KeccakState: 是对 sha3.state 的封装,下面的注释也有说明。还特意提到ReadSum快。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
// Read to get a variable amount of data from the hash state. Read is faster than Sum
// because it doesn't copy the internal state, but also modifies the internal state.
type KeccakState interface {
hash.Hash
Read([]byte) (int, error)
}

// Keccak256 calculates and returns the Keccak256 hash of the input data.
func Keccak256(data ...[]byte) []byte {
b := make([]byte, 32)
d := sha3.NewLegacyKeccak256().(KeccakState)
for _, b := range data {
d.Write(b)
}
d.Read(b)
return b
}

主要方法 Keccak256Hash

作用:Keccak256Hash计算并返回输入数据的Keccak256哈希值,将其转换为一个内部哈希数据结构。

1
2
3
4
5
6
7
8
9
10
// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
// converting it to an internal Hash data structure.
func Keccak256Hash(data ...[]byte) (h common.Hash) {
d := sha3.NewLegacyKeccak256().(KeccakState)
for _, b := range data {
d.Write(b)
}
d.Read(h[:])
return h
}

验证

拿了一下官方测试举例:crypto_test.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// These tests are sanity checks.
// They should ensure that we don't e.g. use Sha3-224 instead of Sha3-256
// and that the sha3 library uses keccak-f permutation.
func TestKeccak256Hash(t *testing.T) {
msg := []byte("abc")
exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
// 校验结果正确性
checkhash(t, "Sha3-256-array", func(in []byte) []byte {
h := Keccak256Hash(in);
return h[:]
}, msg, exp)
}

// debug 看下具体内容
func checkhash(t *testing.T, name string, f func([]byte) []byte, msg, exp []byte) {
sum := f(msg)
if !bytes.Equal(exp, sum) {
t.Fatalf("hash %s mismatch: want: %x have: %x", name, exp, sum)
}
}

以太坊哪些地方使用到了

几乎只要用的数据相关的,都需要进行转换。

将key进行转换

1
2
3
4
5
6
7
8
9
func (t *odrTrie) TryGet(key []byte) ([]byte, error) {
key = crypto.Keccak256(key)
var res []byte
err := t.do(key, func() (err error) {
res, err = t.trie.TryGet(key)
return err
})
return res, err
}

更多调用,所有的也看不完,找到重要的部分阅读。

调用关系

结论

区块链依赖于加密算法,对加密算法的了解是非常有必要的。全看调用是看不完的,至少需要知道怎么用。
以太坊使用 keccak256 的目的:keccak256算法则可以将任意长度的输入压缩成64位,16进制的数,且哈希碰撞的概率近乎为0.

参考文档