【Golang】BLAKE3 for Go の使い方【FNV1 より数倍速いってマ？ッハ？】

> SHA-3 のコンペで最終選考まで残って [Keccak](https://ja.wikipedia.org/wiki/SHA-3) に負けた [BLAKE2](https://ja.wikipedia.org/wiki/BLAKE)。その後継である [BLAKE3](https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE3) が「爆速らしい。しかも FNV1a より数倍」と聞いたので試してみたい。

でも公式は Rust と C 言語での実装なのです。どちらも話せません ... 最近勉強している ​Go 言語（以下 Golang）で試してみたかったのです。

- [BLAKE3](https://github.com/BLAKE3-team/BLAKE3) | BLAKE3-team @ GitHub
    - BLAKE3 の仕様書: [BLAKE3 Specs](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) @ GitHub
- 関連記事:
    - [hashアルゴリズムとハッシュ値の長さ一覧（＋ハッシュ関数の基本と応用）](https://qiita.com/KEINOS/items/c92268386d265042ea16) @ Qiita

## TL; DR <sub><sup><sub><sup>（今北産業）</sup></sub></sup></sub>

1. <ruby>16<rt>・・</rt></ruby> バイト長ハッシュで速い [FNV1](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) より、<ruby>64<rt>・・</rt></ruby> バイト長ハッシュの **BLAKE3 の方が 8 倍以上[速かった](#%E3%83%99%E3%83%B3%E3%83%81%E3%83%9E%E3%83%BC%E3%82%AF)**。😱
2. 試したライブラリ（どちらも BLAKE 非公式）:
    - [BLAKE3 for Go - Luke Champine バージョン](https://github.com/lukechampine/blake3)<br>`go get lukechampine.com/blake3`
    - [BLAKE3 for Go - Zeebo バージョン](https://github.com/zeebo/blake3)<br>`go get github.com/zeebo/blake3`
    - 実測結果: Zeebo の方が Luke より平均して若干速いがほぼ同じ。
    - 使いやすさ: Luke 版の方はシンプルで使いやすいが、Zeebo の方が [hash.Hash](https://pkg.go.dev/hash#Hash) のインターフェースを基準にしていたり、[ドキュメントが充実している](https://pkg.go.dev/github.com/zeebo/blake3#pkg-examples)ため、他のハッシュ関数との入れ替えがしやすい。
3. 本家も強度の検証が終わっていないらしい ＋ Golang 版 BLAKE3 もベータ版なのでプロダクション・レベルではまだ使わない方がいいかもしれない。**改ざん検知目的よりチェックサム目的なら十分実用的で速い**。

## TS; DR

### サンプル・コード

#### Luke Champine バージョンの使い方

```go:シンプル（小さなデータ向け）
/* import "lukechampine.com/blake3" */
input := "This is a string"

valByte := blake3.Sum256([]byte(input))

// Expect value was taken from R implementation: https://github.com/dirkschumacher/blake3
expect := "718b749f12a61257438b2ea6643555fd995001c9d9ff84764f93f82610a780f2"
actual := fmt.Sprintf("%x", valByte)

fmt.Println("expect:", expect)
fmt.Println("actual:", actual)
// Output:
// expect: 718b749f12a61257438b2ea6643555fd995001c9d9ff84764f93f82610a780f2
// actual: 718b749f12a61257438b2ea6643555fd995001c9d9ff84764f93f82610a780f2
```

```go:ファイルまるごとなどメモリ消費しそうな場合
/* import "lukechampine.com/blake3" */
input := "This is a string"

h := blake3.New(256, nil)

// 本来は、ここでファイルからのデータをループで書き込む
if _, err := h.Write([]byte(input)); err != nil {
	log.Fatalf("failed to write data. Err: %v", err)
}

valByte := h.Sum(nil)[:32] // 512bit で返ってくるので必要なぶん32バイト

// Expect value was taken from R implementation: https://github.com/dirkschumacher/blake3
expect := "718b749f12a61257438b2ea6643555fd995001c9d9ff84764f93f82610a780f2"
actual := fmt.Sprintf("%x", valByte)

fmt.Println("expect:", expect)
fmt.Println("actual:", actual)
// Output:
// expect: 718b749f12a61257438b2ea6643555fd995001c9d9ff84764f93f82610a780f2
// actual: 718b749f12a61257438b2ea6643555fd995001c9d9ff84764f93f82610a780f2
```

- [動作確認済みの完全なサンプル](https://github.com/KEINOS/go-blake3-example)

### ベンチマーク

- アルゴリズム:
    - Adler (32bit)
    - BLAKE3 Luke Ver. (256bit, 512bit)
    - BLAKE3 Zeebo Ver. (256bit, 512bit)
    - CRC32 (32bit)
    - FNV-1 (32bit)
    - FNV-1a (32bit)
    - MD5 (128bit)
    - MMH3 (128bit)
    - SHA-2 (256bit, 512bit)
    - SHA-3 (256bit, 512bit)
    - Whirlpool (512bit)
- 10秒間のイテレーション（処理）✖︎2回（iter が大きいほど多く処理 = time/iter が小さいほど処理が短い）
- [ベンチマークのソース](https://github.com/KEINOS/go-blake3-example/blob/main/bench_test.go) @ GitHub
- [最新のベンチ結果](https://github.com/KEINOS/go-blake3-example#bench-results) @ GitHub