[インデックス 18387] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto/rand
パッケージにおける Int
および Prime
関数のテストを追加するものです。具体的には、src/pkg/crypto/rand/util_test.go
ファイルに新しいテストケースが追加されています。
コミット
commit 99d23dfdfd19204d76877a7322c298726aba6d9a
Author: Shawn Smith <shawn.p.smith@gmail.com>
Date: Fri Jan 31 11:43:48 2014 +1100
crypto/rand: add tests for Int, Prime
LGTM=rsc, dave
R=golang-codereviews, dave, josharian, rsc
CC=golang-codereviews
https://golang.org/cl/46490043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/99d23dfdfd19204d76877a7322c298726aba6d9a
元コミット内容
crypto/rand
: Int
, Prime
のテストを追加
変更の背景
このコミットの背景には、crypto/rand
パッケージの Int
および Prime
関数に対するテストカバレッジを向上させる目的があります。特に、これらの関数が不正な入力(例えば、Prime
に2未満のビット数を渡す、Int
に0以下の最大値を渡す)を受け取った際の挙動を検証することが重要です。暗号学的に安全な乱数を生成するこれらの関数は、セキュリティ上極めて重要であり、あらゆるエッジケースでの堅牢性を保証するための厳密なテストが不可欠です。
Go言語の標準ライブラリは、その品質と信頼性を維持するために、徹底したテストが求められます。このコミットは、その品質保証プロセスの一環として、特定の関数のコーナーケースにおける挙動を明示的にテストすることで、ライブラリ全体の信頼性を高めることを目的としています。
前提知識の解説
crypto/rand
パッケージ
crypto/rand
パッケージは、暗号学的に安全な乱数ジェネレータ(CSPRNG: Cryptographically Secure PseudoRandom Number Generator)へのアクセスを提供します。これは、鍵生成、セッションID、ノンス(nonce)など、予測不可能性が不可欠なセキュリティ関連の用途で利用されます。このパッケージの乱数は、オペレーティングシステムが提供する乱数源(例: Linuxの/dev/urandom
)から取得されるため、高品質で予測不困難な乱数を提供します。
rand.Int(rand.Reader, max *big.Int) (*big.Int, error)
この関数は、[0, max)
の範囲で暗号学的に安全なランダムな整数を生成します。rand.Reader
は、乱数源として使用される io.Reader
インターフェースを満たすオブジェクトです。max
は生成される乱数の上限(排他的)を指定する *big.Int
型のポインタです。max
が0以下の場合、この関数はパニック(panic)を引き起こします。
rand.Prime(rand.Reader, bits int) (*big.Int, error)
この関数は、指定されたビット数 bits
を持つ暗号学的に安全なランダムな素数を生成します。bits
は生成される素数のビット長を指定します。この関数は、主にRSAなどの公開鍵暗号システムにおける鍵生成に使用されます。bits
が2未満の場合、この関数はエラーを返します。
math/big
パッケージ
Go言語の math/big
パッケージは、任意精度の算術演算をサポートします。これは、標準のGoの整数型(int
, int64
など)では表現できない非常に大きな整数を扱う必要がある場合に不可欠です。crypto/rand
パッケージの Int
および Prime
関数は、大きな数値を扱うため、この math/big
パッケージの *big.Int
型を使用します。
Go言語のテスト
Go言語では、テストは _test.go
で終わるファイルに記述され、testing
パッケージを使用します。テスト関数は Test
で始まり、*testing.T
型の引数を取ります。t.Errorf
や t.Fatalf
などのメソッドを使用して、テストの失敗を報告します。panic
のテストには defer
と recover
を組み合わせて使用することが一般的です。
技術的詳細
このコミットで追加されたテストは、crypto/rand
パッケージの Int
および Prime
関数の特定の挙動、特にエラーハンドリングとパニックの発生条件を検証することに焦点を当てています。
TestPrimeBitsLt2
このテストは、rand.Prime
関数に2未満のビット数(具体的には1ビット)を渡した場合の挙動を検証します。Prime
関数は、2未満のビット数では有効な素数を生成できないため、nil
とエラーを返すことが期待されます。このテストは、その期待されるエラーハンドリングが正しく実装されていることを確認します。
TestInt
このテストは、rand.Int
関数が様々な max
値(128から139まで)に対して正しく動作することを確認します。特に、max.BitLen() % 8 == 0
のケース(つまり、max
がちょうどバイト境界に収まる場合)がカバーされるように、128からテストを開始しています。これは、Int
関数の内部実装がバイト単位で処理を行う可能性があるため、境界条件での正確性を保証するために重要です。テストは、エラーが発生しないことを確認するだけで、生成された乱数の値自体は検証していません。これは、乱数の予測不可能性をテストすることが困難であるため、通常は乱数生成器の出力範囲とエラー条件のみをテストします。
testIntPanics
このヘルパー関数は、rand.Int
がパニックを引き起こすことを期待するテストケースで使用されます。defer
と recover
を利用して、関数呼び出しがパニックを引き起こしたかどうかを捕捉し、パニックが発生しなかった場合にテストを失敗させます。これは、Go言語で意図的なパニックの発生をテストするための標準的なパターンです。
TestIntEmptyMaxPanics
このテストは、rand.Int
関数に空の big.Int
(値が0)を max
として渡した場合にパニックが発生することを確認します。rand.Int
のドキュメントでは、max
が0以下の場合にパニックすると明記されており、このテストはその仕様が正しく実装されていることを検証します。
TestIntNegativeMaxPanics
このテストは、rand.Int
関数に負の値(-1)を max
として渡した場合にパニックが発生することを確認します。これも rand.Int
の仕様に基づいたテストであり、不正な入力に対する関数の堅牢性を保証します。
これらのテストは、関数の入力検証とエラー/パニックハンドリングの正確性を保証することで、crypto/rand
パッケージの信頼性と安全性を高めることに貢献しています。
コアとなるコードの変更箇所
変更は src/pkg/crypto/rand/util_test.go
ファイルに集中しており、以下のコードが追加されています。
--- a/src/pkg/crypto/rand/util_test.go
+++ b/src/pkg/crypto/rand/util_test.go
@@ -6,6 +6,7 @@ package rand_test
import (
"crypto/rand"
+ "math/big"
"testing"
)
@@ -24,3 +25,41 @@ func TestPrimeSmall(t *testing.T) {
}
}
}
++
+// Test that passing bits < 2 causes Prime to return nil, error
+func TestPrimeBitsLt2(t *testing.T) {
++ if p, err := rand.Prime(rand.Reader, 1); p != nil || err == nil {
++ t.Errorf("Prime should return nil, error when called with bits < 2")
++ }
++}
++
+func TestInt(t *testing.T) {
++ // start at 128 so the case of (max.BitLen() % 8) == 0 is covered
++ for n := 128; n < 140; n++ {
++ b := new(big.Int).SetInt64(int64(n))
++ if i, err := rand.Int(rand.Reader, b); err != nil {
++ t.Fatalf("Can't generate random value: %v, %v", i, err)
++ }
++ }
++}
++
+func testIntPanics(t *testing.T, b *big.Int) {
++ defer func() {
++ if err := recover(); err == nil {
++ t.Errorf("Int should panic when called with max <= 0: %v", b)
++ }
++ }()
++ rand.Int(rand.Reader, b)
++}
++
+// Test that passing a new big.Int as max causes Int to panic
+func TestIntEmptyMaxPanics(t *testing.T) {
++ b := new(big.Int)
++ testIntPanics(t, b)
++}
++
+// Test that passing a negative value as max causes Int to panic
+func TestIntNegativeMaxPanics(t *testing.T) {
++ b := new(big.Int).SetInt64(int64(-1))
++ testIntPanics(t, b)
++}
コアとなるコードの解説
import "math/big"
の追加
rand.Int
関数が *big.Int
型を引数に取るため、そのテストコード内で big.Int
オブジェクトを生成するために math/big
パッケージのインポートが必要になります。
TestPrimeBitsLt2
関数
func TestPrimeBitsLt2(t *testing.T) {
if p, err := rand.Prime(rand.Reader, 1); p != nil || err == nil {
t.Errorf("Prime should return nil, error when called with bits < 2")
}
}
このテストは、rand.Prime
に bits
として 1
を渡しています。Prime
関数は2未満のビット数では素数を生成できないため、戻り値 p
が nil
であり、かつ err
が nil
でない(つまりエラーが発生している)ことを期待します。もし p
が nil
でないか、err
が nil
であれば、テストは失敗します。
TestInt
関数
func TestInt(t *testing.T) {
// start at 128 so the case of (max.BitLen() % 8) == 0 is covered
for n := 128; n < 140; n++ {
b := new(big.Int).SetInt64(int64(n))
if i, err := rand.Int(rand.Reader, b); err != nil {
t.Fatalf("Can't generate random value: %v, %v", i, err)
}
}
}
このテストは、max
の値が128から139までの範囲で rand.Int
を呼び出しています。ループの目的は、max
のビット長が8の倍数になるケース(n=128
の場合)を含む、様々な max
値で関数がエラーなく動作することを確認することです。rand.Int
がエラーを返した場合、t.Fatalf
を呼び出してテストを即座に終了させます。
testIntPanics
関数
func testIntPanics(t *testing.T, b *big.Int) {
defer func() {
if err := recover(); err == nil {
t.Errorf("Int should panic when called with max <= 0: %v", b)
}
}()
rand.Int(rand.Reader, b)
}
これはヘルパー関数で、rand.Int
がパニックを引き起こすことを期待するテストケースで使用されます。defer
ステートメント内の匿名関数は、rand.Int(rand.Reader, b)
の呼び出しがパニックした場合に実行されます。recover()
はパニックの値を捕捉し、パニックが発生しなかった場合(err
が nil
の場合)に t.Errorf
を呼び出してテストを失敗させます。これにより、関数が期待通りにパニックしたことを検証できます。
TestIntEmptyMaxPanics
関数
func TestIntEmptyMaxPanics(t *testing.T) {
b := new(big.Int) // b is 0
testIntPanics(t, b)
}
このテストは、max
として値が0の big.Int
を rand.Int
に渡した場合に、testIntPanics
ヘルパー関数を使ってパニックが発生することを確認します。
TestIntNegativeMaxPanics
関数
func TestIntNegativeMaxPanics(t *testing.T) {
b := new(big.Int).SetInt64(int64(-1)) // b is -1
testIntPanics(t, b)
}
このテストは、max
として負の値(-1)を持つ big.Int
を rand.Int
に渡した場合に、testIntPanics
ヘルパー関数を使ってパニックが発生することを確認します。
これらのテストは、crypto/rand
パッケージの Int
および Prime
関数が、不正な入力に対して期待されるエラーまたはパニックの挙動を示すことを保証し、ライブラリの堅牢性と信頼性を向上させます。
関連リンク
- Go言語
crypto/rand
パッケージのドキュメント: https://pkg.go.dev/crypto/rand - Go言語
math/big
パッケージのドキュメント: https://pkg.go.dev/math/big - Go言語
testing
パッケージのドキュメント: https://pkg.go.dev/testing
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のテストに関する一般的なプラクティス
crypto/rand
パッケージのソースコード