[インデックス 13601] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto/rand
パッケージに Read
関数の使用例を追加するものです。具体的には、rand.Reader
から暗号学的に安全な擬似乱数を読み込み、バイトスライスに格納する方法を示すテストコード example_test.go
が新規作成されました。これにより、開発者が crypto/rand
パッケージの主要な機能である乱数生成をより容易に理解し、適切に利用できるようになります。
コミット
commit 4230dd4c6c4c08f1559d85bc135991627fd89d92
Author: Yves Junqueira <yves.junqueira@gmail.com>
Date: Wed Aug 8 12:04:54 2012 +1000
crypto/rand: Example for Read.
R=adg, remyoudompheng, rsc, r
CC=golang-dev
https://golang.org/cl/6457085
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4230dd4c6c4c08f1559d85bc135991627fd89d92
元コミット内容
crypto/rand: Example for Read.
R=adg, remyoudompheng, rsc, r
CC=golang-dev
https://golang.org/cl/6457085
変更の背景
Go言語の標準ライブラリは、その堅牢性と使いやすさで知られていますが、各機能の適切な使用方法を示す例は、ライブラリの普及と開発者の生産性向上に不可欠です。crypto/rand
パッケージは、セキュリティが要求されるアプリケーションにおいて、予測不可能な乱数を生成するために非常に重要です。しかし、その利用方法が明確でない場合、開発者が誤った方法で乱数を生成し、結果としてセキュリティ上の脆弱性を生み出す可能性があります。
このコミットの背景には、crypto/rand.Read
関数の基本的な使い方を明確に示し、開発者が安全かつ正確に暗号学的に安全な乱数を取得できるようにするという意図があります。Goの_test.go
ファイルにExample
関数を追加する慣習は、ドキュメント生成ツール(go doc
やgodoc.org
)によって自動的に実行可能なコード例として抽出され、表示されるため、非常に効果的なドキュメンテーション手法です。これにより、ユーザーはコード例を実際に実行して動作を確認できるため、理解が深まります。
前提知識の解説
1. crypto/rand
パッケージ
crypto/rand
パッケージは、Go言語において暗号学的に安全な乱数を生成するための機能を提供します。これは、パスワードのソルト、セッションID、鍵生成など、予測不可能性が極めて重要となる場面で利用されます。通常の乱数生成器(例: math/rand
)は、シード値が既知であればその出力が予測可能であるため、セキュリティ用途には適していません。crypto/rand
は、オペレーティングシステムが提供するエントロピー源(例: /dev/urandom
や Windows の CryptGenRandom
)を利用して、真に予測不困難な乱数を生成します。
2. rand.Reader
rand.Reader
は、crypto/rand
パッケージが提供するグローバルな変数で、io.Reader
インターフェースを実装しています。これは、暗号学的に安全な乱数のソースとして機能します。Read
メソッドを呼び出すことで、指定されたバイトスライスに乱数を書き込むことができます。
3. io.Reader
インターフェース
Go言語の io
パッケージは、I/Oプリミティブを定義する基本的なインターフェースを提供します。io.Reader
インターフェースは、Read(p []byte) (n int, err error)
メソッドを一つだけ持ちます。このメソッドは、データを読み込み、読み込んだバイト数とエラーを返します。rand.Reader
がこのインターフェースを実装しているため、io
パッケージの他の関数(例: io.ReadFull
)と組み合わせて使用することができます。
4. io.ReadFull
関数
io.ReadFull(r Reader, buf []byte) (n int, err error)
は、io
パッケージが提供するヘルパー関数です。これは、指定された io.Reader
から、buf
スライスの長さと等しいバイト数を読み込むまで繰り返し Read
メソッドを呼び出します。途中でエラーが発生した場合や、EOF(End Of File)に達して要求されたバイト数を読み込めなかった場合は、エラーを返します。これにより、確実に指定された量のデータを読み込むことができます。
5. 暗号学的に安全な乱数 (CSPRNG: Cryptographically Secure Pseudorandom Number Generator)
CSPRNGは、その出力が統計的にランダムであるだけでなく、将来の出力を予測することが計算上不可能であるという特性を持つ乱数生成器です。これは、攻撃者が過去の出力や内部状態に関する情報を持っていたとしても、次の出力を推測できないことを意味します。セキュリティ関連のアプリケーションでは、この特性が不可欠です。
技術的詳細
このコミットで追加された ExampleRead
関数は、crypto/rand
パッケージの Read
メソッドの典型的な使用パターンを示しています。
- バイトスライスの準備: 乱数を格納するためのバイトスライス
b
がmake([]byte, c)
によって作成されます。ここでc
は読み込む乱数のバイト数(この例では10バイト)です。初期状態では、このスライスはゼロで埋められています。 - 乱数の読み込み:
io.ReadFull(rand.Reader, b)
を呼び出すことで、rand.Reader
からb
の長さ分の乱数が読み込まれます。io.ReadFull
を使用することで、b
スライスが完全に乱数で埋められることが保証されます。 - エラーハンドリング:
io.ReadFull
は読み込んだバイト数n
とエラーerr
を返します。n != len(b)
またはerr != nil
の場合、乱数の読み込みに失敗したことを意味するため、エラーメッセージを出力して関数を終了します。これは、暗号学的な乱数生成が失敗した場合(例: システムのエントロピー源が枯渇した場合など)に備えた重要なエラーハンドリングです。 - 結果の検証: 最後に、
bytes.Equal(b, make([]byte, c))
を使用して、読み込んだバイトスライスb
がまだゼロで埋められているかどうかをチェックします。暗号学的に安全な乱数が正常に読み込まれていれば、b
はゼロ以外のランダムな値で埋められているはずなので、この比較はfalse
を返します。この出力は、Example
関数の特別なコメント// Output:
によってテストシステムによって検証されます。
この例は、crypto/rand
を使用する際のベストプラクティスを示しています。特に、io.ReadFull
を使用して確実に必要なバイト数を読み込むことと、エラーハンドリングの重要性を強調しています。
コアとなるコードの変更箇所
このコミットでは、src/pkg/crypto/rand/example_test.go
という新しいファイルが追加されました。
diff --git a/src/pkg/crypto/rand/example_test.go b/src/pkg/crypto/rand/example_test.go
new file mode 100644
index 0000000000..5af8e46f5d
--- /dev/null
+++ b/src/pkg/crypto/rand/example_test.go
@@ -0,0 +1,29 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand_test
+
+import (
+ "bytes"
+ "crypto/rand"
+ "fmt"
+ "io"
+)
+
+// This example reads 10 cryptographically secure pseudorandom numbers from
+// rand.Reader and writes them to a byte slice.
+func ExampleRead() {
+ c := 10
+ b := make([]byte, c)
+ n, err := io.ReadFull(rand.Reader, b)
+ if n != len(b) || err != nil {
+ fmt.Println("error:", err)
+ return
+ }
+ // The slice should now contain random bytes instead of only zeroes.
+ fmt.Println(bytes.Equal(b, make([]byte, c)))
+
+ // Output:
+ // false
+}
コアとなるコードの解説
追加された example_test.go
ファイル内の ExampleRead
関数は以下の通りです。
package rand_test
import (
"bytes"
"crypto/rand"
"fmt"
"io"
)
// This example reads 10 cryptographically secure pseudorandom numbers from
// rand.Reader and writes them to a byte slice.
func ExampleRead() {
c := 10 // 読み込むバイト数を定義
b := make([]byte, c) // 10バイトのバイトスライスを生成(初期値はすべて0)
// rand.Reader から b の長さ分の乱数を読み込む
// io.ReadFull は、b が完全に埋まるまで読み込みを試みる
n, err := io.ReadFull(rand.Reader, b)
// 読み込みが成功したか(読み込んだバイト数が期待通りか、エラーがないか)を確認
if n != len(b) || err != nil {
fmt.Println("error:", err) // エラーがあれば出力
return
}
// 読み込んだバイトスライス b が、まだゼロで埋められているかを確認
// 暗号学的に安全な乱数が生成されていれば、b はランダムな値で埋められているはずなので、
// この比較は false を返すはず
fmt.Println(bytes.Equal(b, make([]byte, c)))
// Output:
// false
// このコメントは、go test -run ExampleRead を実行した際に、
// 上記の fmt.Println の出力が "false" であることを期待することを示す
}
このコードは、crypto/rand
パッケージの rand.Reader
を使って暗号学的に安全な乱数を生成する最も基本的な方法を示しています。
package rand_test
: このファイルがcrypto/rand
パッケージのテスト(および例)であることを示します。_test
サフィックスは、このパッケージがテスト専用であり、メインのパッケージとは別の名前空間でコンパパイルされることを意味します。import (...)
: 必要なパッケージをインポートします。bytes
: バイトスライスを比較するためのbytes.Equal
を使用します。crypto/rand
: 暗号学的に安全な乱数生成器を提供します。fmt
: 出力(エラーメッセージや最終結果)のために使用します。io
:io.ReadFull
関数を使用します。
func ExampleRead()
: Goのテストフレームワークにおける特別な関数名です。Example
で始まる関数は、go doc
コマンドやgodoc.org
でドキュメントとして表示され、go test
コマンドで実行可能なテストとして扱われます。// Output:
コメントと組み合わせることで、関数の出力が期待通りであることを検証できます。c := 10
: 読み込む乱数のバイト数を10に設定します。b := make([]byte, c)
: 10バイトの長さを持つバイトスライスb
を作成します。Goでは、make
で作成されたスライスは要素型のゼロ値で初期化されるため、この時点ではすべての要素が0です。n, err := io.ReadFull(rand.Reader, b)
:rand.Reader
からb
に乱数を読み込みます。io.ReadFull
は、b
が完全に埋まるまで読み込みを保証します。if n != len(b) || err != nil
: 読み込みが成功したかを確認します。n
は実際に読み込まれたバイト数、len(b)
は期待されるバイト数です。これらが一致しない、またはエラーが発生した場合は、問題があったことを示します。fmt.Println(bytes.Equal(b, make([]byte, c)))
: 読み込み後のb
が、初期状態(すべてゼロ)のスライスと等しいかどうかをチェックします。暗号学的に安全な乱数が正常に生成されていれば、b
はランダムな値で埋められているため、この比較はfalse
を返します。// Output: // false
: これはGoのテストシステムが認識する特別なコメントで、ExampleRead
関数が実行されたときに標準出力に "false" が出力されることを期待していることを示します。これにより、例が正しく動作していることを自動的に検証できます。
関連リンク
- Go言語
crypto/rand
パッケージのドキュメント: https://pkg.go.dev/crypto/rand - Go言語
io
パッケージのドキュメント: https://pkg.go.dev/io - Go言語
bytes
パッケージのドキュメント: https://pkg.go.dev/bytes - Go言語のExampleテストに関する公式ブログ記事 (Go 1.4): https://go.dev/blog/go1.4-examples (このコミットは2012年のものなので、当時のドキュメント慣習を反映しています)
参考にした情報源リンク
- Go言語の公式ドキュメント (
pkg.go.dev
) - Go言語のソースコード (
github.com/golang/go
) - Go言語のテストとExampleに関する一般的な知識
- 暗号学的に安全な乱数生成器 (CSPRNG) に関する一般的な情報
- Goのコードレビューシステム (Gerrit) の変更リスト: https://golang.org/cl/6457085 (コミットメッセージに記載)# [インデックス 13601] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto/rand
パッケージに Read
関数の使用例を追加するものです。具体的には、rand.Reader
から暗号学的に安全な擬似乱数を読み込み、バイトスライスに格納する方法を示すテストコード example_test.go
が新規作成されました。これにより、開発者が crypto/rand
パッケージの主要な機能である乱数生成をより容易に理解し、適切に利用できるようになります。
コミット
commit 4230dd4c6c4c08f1559d85bc135991627fd89d92
Author: Yves Junqueira <yves.junqueira@gmail.com>
Date: Wed Aug 8 12:04:54 2012 +1000
crypto/rand: Example for Read.
R=adg, remyoudompheng, rsc, r
CC=golang-dev
https://golang.org/cl/6457085
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4230dd4c6c4c08f1559d85bc135991627fd89d92
元コミット内容
crypto/rand: Example for Read.
R=adg, remyoudompheng, rsc, r
CC=golang-dev
https://golang.org/cl/6457085
変更の背景
Go言語の標準ライブラリは、その堅牢性と使いやすさで知られていますが、各機能の適切な使用方法を示す例は、ライブラリの普及と開発者の生産性向上に不可欠です。crypto/rand
パッケージは、セキュリティが要求されるアプリケーションにおいて、予測不可能な乱数を生成するために非常に重要です。しかし、その利用方法が明確でない場合、開発者が誤った方法で乱数を生成し、結果としてセキュリティ上の脆弱性を生み出す可能性があります。
このコミットの背景には、crypto/rand.Read
関数の基本的な使い方を明確に示し、開発者が安全かつ正確に暗号学的に安全な乱数を取得できるようにするという意図があります。Goの_test.go
ファイルにExample
関数を追加する慣習は、ドキュメント生成ツール(go doc
やgodoc.org
)によって自動的に実行可能なコード例として抽出され、表示されるため、非常に効果的なドキュメンテーション手法です。これにより、ユーザーはコード例を実際に実行して動作を確認できるため、理解が深まります。
前提知識の解説
1. crypto/rand
パッケージ
crypto/rand
パッケージは、Go言語において暗号学的に安全な乱数を生成するための機能を提供します。これは、パスワードのソルト、セッションID、鍵生成など、予測不可能性が極めて重要となる場面で利用されます。通常の乱数生成器(例: math/rand
)は、シード値が既知であればその出力が予測可能であるため、セキュリティ用途には適していません。crypto/rand
は、オペレーティングシステムが提供するエントロピー源(例: /dev/urandom
や Windows の CryptGenRandom
)を利用して、真に予測困難な乱数を生成します。
2. rand.Reader
rand.Reader
は、crypto/rand
パッケージが提供するグローバルな変数で、io.Reader
インターフェースを実装しています。これは、暗号学的に安全な乱数のソースとして機能します。Read
メソッドを呼び出すことで、指定されたバイトスライスに乱数を書き込むことができます。
3. io.Reader
インターフェース
Go言語の io
パッケージは、I/Oプリミティブを定義する基本的なインターフェースを提供します。io.Reader
インターフェースは、Read(p []byte) (n int, err error)
メソッドを一つだけ持ちます。このメソッドは、データを読み込み、読み込んだバイト数とエラーを返します。rand.Reader
がこのインターフェースを実装しているため、io
パッケージの他の関数(例: io.ReadFull
)と組み合わせて使用することができます。
4. io.ReadFull
関数
io.ReadFull(r Reader, buf []byte) (n int, err error)
は、io
パッケージが提供するヘルパー関数です。これは、指定された io.Reader
から、buf
スライスの長さと等しいバイト数を読み込むまで繰り返し Read
メソッドを呼び出します。途中でエラーが発生した場合や、EOF(End Of File)に達して要求されたバイト数を読み込めなかった場合は、エラーを返します。これにより、確実に指定された量のデータを読み込むことができます。
5. 暗号学的に安全な乱数 (CSPRNG: Cryptographically Secure Pseudorandom Number Generator)
CSPRNGは、その出力が統計的にランダムであるだけでなく、将来の出力を予測することが計算上不可能であるという特性を持つ乱数生成器です。これは、攻撃者が過去の出力や内部状態に関する情報を持っていたとしても、次の出力を推測できないことを意味します。セキュリティ関連のアプリケーションでは、この特性が不可欠です。
技術的詳細
このコミットで追加された ExampleRead
関数は、crypto/rand
パッケージの Read
メソッドの典型的な使用パターンを示しています。
- バイトスライスの準備: 乱数を格納するためのバイトスライス
b
がmake([]byte, c)
によって作成されます。ここでc
は読み込む乱数のバイト数(この例では10バイト)です。初期状態では、このスライスはゼロで埋められています。 - 乱数の読み込み:
io.ReadFull(rand.Reader, b)
を呼び出すことで、rand.Reader
からb
の長さ分の乱数が読み込まれます。io.ReadFull
を使用することで、b
スライスが完全に乱数で埋められることが保証されます。 - エラーハンドリング:
io.ReadFull
は読み込んだバイト数n
とエラーerr
を返します。n != len(b)
またはerr != nil
の場合、乱数の読み込みに失敗したことを意味するため、エラーメッセージを出力して関数を終了します。これは、暗号学的な乱数生成が失敗した場合(例: システムのエントロピー源が枯渇した場合など)に備えた重要なエラーハンドリングです。 - 結果の検証: 最後に、
bytes.Equal(b, make([]byte, c))
を使用して、読み込んだバイトスライスb
がまだゼロで埋められているかどうかをチェックします。暗号学的に安全な乱数が正常に読み込まれていれば、b
はゼロ以外のランダムな値で埋められているはずなので、この比較はfalse
を返します。この出力は、Example
関数の特別なコメント// Output:
によってテストシステムによって検証されます。
この例は、crypto/rand
を使用する際のベストプラクティスを示しています。特に、io.ReadFull
を使用して確実に必要なバイト数を読み込むことと、エラーハンドリングの重要性を強調しています。
コアとなるコードの変更箇所
このコミットでは、src/pkg/crypto/rand/example_test.go
という新しいファイルが追加されました。
diff --git a/src/pkg/crypto/rand/example_test.go b/src/pkg/crypto/rand/example_test.go
new file mode 100644
index 0000000000..5af8e46f5d
--- /dev/null
+++ b/src/pkg/crypto/rand/example_test.go
@@ -0,0 +1,29 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand_test
+
+import (
+ "bytes"
+ "crypto/rand"
+ "fmt"
+ "io"
+)
+
+// This example reads 10 cryptographically secure pseudorandom numbers from
+// rand.Reader and writes them to a byte slice.
+func ExampleRead() {
+ c := 10
+ b := make([]byte, c)
+ n, err := io.ReadFull(rand.Reader, b)
+ if n != len(b) || err != nil {
+ fmt.Println("error:", err)
+ return
+ }
+ // The slice should now contain random bytes instead of only zeroes.
+ fmt.Println(bytes.Equal(b, make([]byte, c)))
+
+ // Output:
+ // false
+}
コアとなるコードの解説
追加された example_test.go
ファイル内の ExampleRead
関数は以下の通りです。
package rand_test
import (
"bytes"
"crypto/rand"
"fmt"
"io"
)
// This example reads 10 cryptographically secure pseudorandom numbers from
// rand.Reader and writes them to a byte slice.
func ExampleRead() {
c := 10 // 読み込むバイト数を定義
b := make([]byte, c) // 10バイトのバイトスライスを生成(初期値はすべて0)
// rand.Reader から b の長さ分の乱数を読み込む
// io.ReadFull は、b が完全に埋まるまで読み込みを試みる
n, err := io.ReadFull(rand.Reader, b)
// 読み込みが成功したか(読み込んだバイト数が期待通りか、エラーがないか)を確認
if n != len(b) || err != nil {
fmt.Println("error:", err) // エラーがあれば出力
return
}
// 読み込んだバイトスライス b が、まだゼロで埋められているかを確認
// 暗号学的に安全な乱数が生成されていれば、b はランダムな値で埋められているはずなので、
// この比較は false を返すはず
fmt.Println(bytes.Equal(b, make([]byte, c)))
// Output:
// false
// このコメントは、go test -run ExampleRead を実行した際に、
// 上記の fmt.Println の出力が "false" であることを期待することを示す
}
このコードは、crypto/rand
パッケージの rand.Reader
を使って暗号学的に安全な乱数を生成する最も基本的な方法を示しています。
package rand_test
: このファイルがcrypto/rand
パッケージのテスト(および例)であることを示します。_test
サフィックスは、このパッケージがテスト専用であり、メインのパッケージとは別の名前空間でコンパパイルされることを意味します。import (...)
: 必要なパッケージをインポートします。bytes
: バイトスライスを比較するためのbytes.Equal
を使用します。crypto/rand
: 暗号学的に安全な乱数生成器を提供します。fmt
: 出力(エラーメッセージや最終結果)のために使用します。io
:io.ReadFull
関数を使用します。
func ExampleRead()
: Goのテストフレームワークにおける特別な関数名です。Example
で始まる関数は、go doc
コマンドやgodoc.org
でドキュメントとして表示され、go test
コマンドで実行可能なテストとして扱われます。// Output:
コメントと組み合わせることで、関数の出力が期待通りであることを検証できます。c := 10
: 読み込む乱数のバイト数を10に設定します。b := make([]byte, c)
: 10バイトの長さを持つバイトスライスb
を作成します。Goでは、make
で作成されたスライスは要素型のゼロ値で初期化されるため、この時点ではすべての要素が0です。n, err := io.ReadFull(rand.Reader, b)
:rand.Reader
からb
に乱数を読み込みます。io.ReadFull
は、b
が完全に埋まるまで読み込みを保証します。if n != len(b) || err != nil
: 読み込みが成功したかを確認します。n
は実際に読み込まれたバイト数、len(b)
は期待されるバイト数です。これらが一致しない、またはエラーが発生した場合は、問題があったことを示します。fmt.Println(bytes.Equal(b, make([]byte, c)))
: 読み込み後のb
が、初期状態(すべてゼロ)のスライスと等しいかどうかをチェックします。暗号学的に安全な乱数が正常に生成されていれば、b
はランダムな値で埋められているため、この比較はfalse
を返します。// Output: // false
: これはGoのテストシステムが認識する特別なコメントで、ExampleRead
関数が実行されたときに標準出力に "false" が出力されることを期待していることを示します。これにより、例が正しく動作していることを自動的に検証できます。
関連リンク
- Go言語
crypto/rand
パッケージのドキュメント: https://pkg.go.dev/crypto/rand - Go言語
io
パッケージのドキュメント: https://pkg.go.dev/io - Go言語
bytes
パッケージのドキュメント: https://pkg.go.dev/bytes - Go言語のExampleテストに関する公式ブログ記事 (Go 1.4): https://go.dev/blog/go1.4-examples (このコミットは2012年のものなので、当時のドキュメント慣習を反映しています)
参考にした情報源リンク
- Go言語の公式ドキュメント (
pkg.go.dev
) - Go言語のソースコード (
github.com/golang/go
) - Go言語のテストとExampleに関する一般的な知識
- 暗号学的に安全な乱数生成器 (CSPRNG) に関する一般的な情報
- Goのコードレビューシステム (Gerrit) の変更リスト: https://golang.org/cl/6457085 (コミットメッセージに記載)