Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12847] ファイルの概要

このコミットは、Go言語の標準ライブラリ crypto/aes パッケージにおけるAES暗号化のパフォーマンス測定を強化するものです。具体的には、復号(decryption)と鍵拡張(key expansion)のベンチマークを追加し、既存の暗号化(encryption)ベンチマークの測定方法を改善しています。これにより、AES操作の各段階における性能特性をより正確に把握し、将来的な最適化の基盤を築くことを目的としています。

コミット

commit cf1f044251ea6e6c999566871a9f4b2a3d627d20
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Fri Apr 6 04:19:35 2012 +0800

    crypto/aes: add benchmarks for decryption and key expansion
    
    R=agl, rsc, fullung
    CC=golang-dev
    https://golang.org/cl/5972056

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/cf1f044251ea6e6c999566871a9f4b2a3d627d20

元コミット内容

crypto/aes: add benchmarks for decryption and key expansion

R=agl, rsc, fullung
CC=golang-dev
https://golang.org/cl/5972056

変更の背景

Go言語の crypto/aes パッケージは、AES暗号化アルゴリズムの実装を提供しています。ソフトウェアの性能は、特に暗号化のような計算負荷の高い操作において非常に重要です。既存のベンチマークは暗号化処理に焦点を当てていましたが、暗号化システム全体の性能を評価するためには、復号処理の性能も同様に重要です。また、AESの鍵拡張(キー・スケジューリング)は、暗号化・復号処理の開始時に一度だけ行われるものの、その性能が全体のオーバーヘッドに影響を与える可能性があります。

このコミットの背景には、以下の目的があったと考えられます。

  1. 復号性能の可視化: 暗号化だけでなく、復号処理のパフォーマンスも測定可能にすることで、AES実装の全体的な効率性を評価できるようにする。
  2. 鍵拡張の性能評価: 鍵拡張処理がボトルネックになる可能性を評価し、必要に応じて最適化の対象とするための基盤を構築する。
  3. ベンチマークの精度向上: 既存の暗号化ベンチマークにおいて、セットアップ時間を測定から除外することで、より正確な実行時間とスループットを測定できるようにする。これは、Goのベンチマークにおける一般的なベストプラクティスです。

これらの変更により、crypto/aes パッケージの性能特性がより詳細に分析できるようになり、将来的な性能改善や最適化の意思決定に役立つ情報が提供されます。

前提知識の解説

このコミットを理解するためには、以下の技術的知識が役立ちます。

1. AES (Advanced Encryption Standard)

AESは、現代において最も広く使用されている対称鍵ブロック暗号の一つです。ブロック暗号とは、固定長のデータブロック(AESでは128ビット)を単位として暗号化・復号を行う暗号方式です。AESは、鍵長によってAES-128、AES-192、AES-256の3つのバリアントがあり、それぞれ128ビット、192ビット、256ビットの鍵を使用します。

AESの暗号化・復号プロセスは、複数の「ラウンド」から構成されます。各ラウンドでは、バイト置換(SubBytes)、行シフト(ShiftRows)、列混合(MixColumns)、ラウンド鍵加算(AddRoundKey)といった一連の変換が適用されます。

2. 鍵拡張 (Key Expansion / Key Schedule)

AESの暗号化・復号プロセスでは、各ラウンドで異なる「ラウンド鍵」が使用されます。これらのラウンド鍵は、初期の秘密鍵(マスターキー)から派生的に生成されます。この生成プロセスを「鍵拡張」または「キー・スケジューリング」と呼びます。鍵拡張は、暗号化または復号を開始する前に一度だけ実行されます。鍵拡張の効率は、特に多数の短いメッセージを暗号化・復号する場合など、暗号化セッションのセットアップ時間に影響を与える可能性があります。

3. Go言語のベンチマーク

Go言語には、標準ライブラリの testing パッケージにベンチマーク機能が組み込まれています。

  • ベンチマーク関数の定義: func BenchmarkXxx(b *testing.B) の形式で関数を定義します。
  • go test -bench=.: このコマンドを実行すると、プロジェクト内のすべてのベンチマーク関数が実行されます。
  • b.N: ベンチマーク関数内のループは b.N 回実行されます。b.N の値は、ベンチマーク実行時に testing パッケージによって動的に調整され、信頼性の高い測定結果が得られるようにします。
  • b.ResetTimer(): このメソッドは、タイマーをリセットします。ベンチマークのセットアップコード(例: データの初期化)が実行された後に呼び出すことで、測定対象のコード(通常はループ内)の実行時間のみを正確に測定できます。
  • b.SetBytes(n int64): このメソッドは、各操作で処理されるバイト数を testing パッケージに伝えます。これにより、ベンチマーク結果に「操作あたりのバイト数」や「スループット(例: MB/s)」が表示されるようになり、性能評価がより直感的になります。
  • b.StopTimer() / b.StartTimer(): これらはタイマーの一時停止と再開に使用されます。b.ResetTimer() と同様に、測定から除外したい処理がある場合に使用できますが、b.ResetTimer() の方が一般的で推奨されるパターンです。

技術的詳細

このコミットは、src/pkg/crypto/aes/aes_test.go ファイルに変更を加えています。

  1. BenchmarkEncrypt の改善:

    • 既存の BenchmarkEncrypt 関数から b.StopTimer()b.StartTimer() の呼び出しが削除されました。
    • 代わりに、b.SetBytes(int64(len(out)))b.ResetTimer() が追加されました。
      • b.SetBytes(int64(len(out))) は、暗号化操作で処理されるバイト数(出力データの長さ)をベンチマークシステムに通知します。これにより、ベンチマーク結果にスループット(例: MB/s)が表示されるようになります。
      • b.ResetTimer() は、ベンチマークのセットアップコード(NewCipher の呼び出しなど)が完了した後にタイマーをリセットします。これにより、暗号化ループ (c.Encrypt) の実行時間のみが正確に測定されます。これはGoのベンチマークにおける標準的なプラクティスであり、測定の精度を向上させます。
  2. BenchmarkDecrypt の追加:

    • 新しいベンチマーク関数 BenchmarkDecrypt が追加されました。
    • この関数は、NewCipher でAES暗号器を初期化した後、c.Decrypt(out, tt.out)b.N 回ループで実行し、復号処理のパフォーマンスを測定します。
    • BenchmarkEncrypt と同様に、b.SetBytes(int64(len(out)))b.ResetTimer() を使用して、正確なスループット測定とセットアップ時間の除外を行っています。
  3. BenchmarkExpand の追加:

    • 新しいベンチマーク関数 BenchmarkExpand が追加されました。
    • この関数は、AESの鍵拡張処理 (expandKey) のパフォーマンスを測定します。
    • expandKey 関数は、AES暗号器の内部構造である aesCipherencdec スケジュールを生成するために使用されます。
    • b.ResetTimer() を使用して、鍵拡張ループの実行時間のみを測定しています。b.SetBytes は使用されていませんが、鍵拡張は通常、データ量ではなく鍵長に依存するため、これは適切です。

これらの変更により、crypto/aes パッケージの性能評価がより包括的かつ正確になり、暗号化、復号、鍵拡張という主要な操作のそれぞれについて独立した性能データを得ることが可能になりました。

コアとなるコードの変更箇所

src/pkg/crypto/aes/aes_test.go ファイルの変更点です。

--- a/src/pkg/crypto/aes/aes_test.go
+++ b/src/pkg/crypto/aes/aes_test.go
@@ -352,15 +352,39 @@ func TestCipherDecrypt(t *testing.T) {
 }
 
 func BenchmarkEncrypt(b *testing.B) {
-	b.StopTimer()
 	tt := encryptTests[0]
 	c, err := NewCipher(tt.key)
 	if err != nil {
 		b.Fatal("NewCipher:", err)
 	}
 	out := make([]byte, len(tt.in))
-	b.StartTimer()
+	b.SetBytes(int64(len(out)))
+	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		c.Encrypt(out, tt.in)
 	}
 }
+
+func BenchmarkDecrypt(b *testing.B) {
+	tt := encryptTests[0]
+	c, err := NewCipher(tt.key)
+	if err != nil {
+		b.Fatal("NewCipher:", err)
+	}
+	out := make([]byte, len(tt.out))
+	b.SetBytes(int64(len(out)))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		c.Decrypt(out, tt.out)
+	}
+}
+
+func BenchmarkExpand(b *testing.B) {
+	tt := encryptTests[0]
+	n := len(tt.key) + 28
+	c := &aesCipher{make([]uint32, n), make([]uint32, n)}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		expandKey(tt.key, c.enc, c.dec)
+	}
+}

コアとなるコードの解説

BenchmarkEncrypt の変更

  • b.StopTimer()b.StartTimer() が削除され、より現代的で推奨される b.SetBytes()b.ResetTimer() の組み合わせに置き換えられました。
  • b.SetBytes(int64(len(out))): この行は、ベンチマークの各イテレーションで処理されるバイト数(ここでは暗号化されたデータの長さ)をGoのベンチマークフレームワークに伝えます。これにより、go test -bench の出力に「MB/s」のようなスループットの指標が表示されるようになります。
  • b.ResetTimer(): この行は、ベンチマークのタイマーをリセットします。NewCipher の呼び出しなど、ベンチマーク対象のループの前に実行されるセットアップコードの時間を測定から除外するために使用されます。これにより、c.Encrypt のループのみの純粋な実行時間が測定され、より正確なパフォーマンスデータが得られます。

BenchmarkDecrypt の追加

  • この新しい関数は、AESの復号処理のパフォーマンスを測定します。
  • c.Decrypt(out, tt.out): aes.Cipher オブジェクトの Decrypt メソッドを呼び出し、暗号化されたデータ tt.out を復号して out に書き込みます。
  • BenchmarkEncrypt と同様に、b.SetBytes()b.ResetTimer() を使用して、復号のスループットと正確な実行時間を測定しています。

BenchmarkExpand の追加

  • この新しい関数は、AESの鍵拡張処理のパフォーマンスを測定します。
  • n := len(tt.key) + 28: 鍵拡張に必要な内部バッファのサイズを計算しています。AESの鍵拡張は、鍵長に応じて特定のサイズのスケジュールを生成します。
  • c := &aesCipher{make([]uint32, n), make([]uint32, n)}: aesCipher 構造体のインスタンスを作成しています。この構造体は、暗号化 (enc) と復号 (dec) のための鍵スケジュールを保持します。
  • expandKey(tt.key, c.enc, c.dec): この関数は、与えられた鍵 tt.key から、暗号化と復号の両方に使用される鍵スケジュール (c.encc.dec) を生成します。このベンチマークは、この鍵拡張処理の計算コストを測定します。
  • b.ResetTimer(): 鍵拡張処理のループのみの時間を測定するためにタイマーをリセットしています。鍵拡張は通常、データ量に依存しないため、b.SetBytes() は使用されていません。

これらの追加と変更により、Goの crypto/aes パッケージの性能特性がより詳細に分析できるようになり、暗号化、復号、鍵拡張という主要な操作のそれぞれについて独立した性能データを得ることが可能になりました。

関連リンク

参考にした情報源リンク