# 機能設計書 153-SecureRandom\string

## 概要

本ドキュメントは、Hack Standard Library (HSL) における `SecureRandom\string` 関数の機能設計を記載する。この関数は暗号学的に安全なランダム文字列を生成する機能を提供する。

### 本機能の処理概要

`SecureRandom\string` は、暗号学的に安全な方法で指定された長さのランダム文字列を生成する関数である。アルファベット（使用可能な文字セット）を指定した場合は、そのアルファベットの文字のみで構成された文字列を生成する。アルファベットを指定しない場合は、`\random_bytes` から取得した生のバイト列を返す。

**業務上の目的・背景**：暗号学的に安全なランダム文字列は、セキュリティが重要なアプリケーションにおいて不可欠である。具体的には、セッションID、CSRF トークン、API キー、パスワードリセットトークン、確認コード、一時的な認証トークンなどの生成に使用される。これらの用途では、文字列が予測不可能であることが重要であり、通常の擬似乱数では安全性が確保できない。

**機能の利用シーン**：
- セッションIDの生成
- API キーやアクセストークンの生成
- パスワードリセット用トークンの生成
- 2要素認証コードの生成
- CSRF トークンの生成
- ファイル名やURLパラメータのランダム化

**主要な処理内容**：
1. 入力パラメータ `$length` の検証（$length >= 0）
2. アルファベットが指定されていない場合は `\random_bytes` で生バイト列を生成
3. アルファベットが指定されている場合は、ビット操作を使用してアルファベットから文字を選択
4. 結果の文字列を返却

**関連システム・外部連携**：Hack ランタイムの `\random_bytes` 関数を使用し、オペレーティングシステムが提供する暗号学的に安全なランダムソースからエントロピーを取得する。

**権限による制御**：本機能は純粋関数として実装されており、特別な権限は必要としない。`[leak_safe]` コンテキストで実行可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはUIを持たないライブラリのため画面なし |

## 機能種別

計算処理（乱数生成）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $length | int | Yes | 生成する文字列の長さ | $length >= 0 でなければならない |
| $alphabet | ?string | No | 使用する文字セット。null の場合は生バイト列を返す | 指定する場合は長さ 2 以上 2^56 以下 |

### 入力データソース

オペレーティングシステムの暗号学的に安全なランダムソース（`\random_bytes` 経由）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | string | 指定された長さの暗号学的に安全なランダム文字列 |

### 出力先

関数の戻り値として呼び出し元に返却

## 処理フロー

### 処理シーケンス

```
1. 共通処理関数 _Private\random_string の呼び出し
   └─ 引数: \random_bytes をラップしたラムダ、$length、$alphabet
2. 長さ検証
   └─ invariant で $length >= 0 をチェック
3. 長さ 0 のチェック
   └─ 0 の場合は空文字列を返却
4. アルファベット未指定のチェック
   └─ null の場合は \random_bytes($length) を返却
5. アルファベット指定時の処理
   └─ ビット操作を使用してアルファベットから文字を選択
   └─ リジェクションサンプリングで一様分布を保証
6. 結果の返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{$length >= 0?}
    B -->|No| C[InvariantException]
    B -->|Yes| D{$length == 0?}
    D -->|Yes| E[空文字列を返却]
    D -->|No| F{$alphabet == null?}
    F -->|Yes| G[random_bytes で生バイト生成]
    F -->|No| H[アルファベットサイズを計算]
    H --> I[必要ビット数を計算]
    I --> J[ランダムバイトを取得]
    J --> K[ビット操作で文字を選択]
    K --> L{十分な文字を生成?}
    L -->|No| J
    L -->|Yes| M[結果を返却]
    G --> M
    E --> N[終了]
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-153-01 | 長さ制約 | 戻り値の長さは $length と一致する | 常時 |
| BR-153-02 | 文字制約 | $alphabet が指定された場合、戻り値は $alphabet の文字のみで構成される | $alphabet != null |
| BR-153-03 | 暗号学的安全性 | 生成される文字列は暗号学的に安全でなければならない | 常時 |
| BR-153-04 | 一様分布 | アルファベット内の全ての文字が等確率で選択される | $alphabet != null |
| BR-153-05 | アルファベット長制約 | アルファベットの長さは 2 以上 2^56 以下 | $alphabet != null |

### 計算ロジック

アルファベット指定時の文字選択アルゴリズム：

```
1. alphabet_size = アルファベットの長さ
2. bits = ceil(log2(alphabet_size))  // 1文字を表現するのに必要なビット数
3. 以下を必要な文字数分繰り返し:
   a. ランダムバイトを取得
   b. bits ビットを取り出して index を計算
   c. index < alphabet_size であれば、alphabet[index] を結果に追加
   d. index >= alphabet_size の場合はリジェクト（次のランダムビットを試行）
```

リジェクションサンプリングを使用する理由：
- アルファベットサイズが 2 の冪乗でない場合、単純なモジュロ演算では一様分布にならない
- リジェクションにより、確率的に完全な一様分布を実現

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | 本機能はデータベース操作を行わない |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvariantException | $length < 0 の場合 | 呼び出し側で非負の $length を指定する |
| - | InvariantException | $alphabet の長さが範囲外の場合 | 適切な長さのアルファベットを指定する |

### リトライ仕様

リトライ処理は不要。内部でリジェクションサンプリングを使用しているが、呼び出し元には透過的。

## トランザクション仕様

本機能はトランザクションを使用しない純粋関数である。

## パフォーマンス要件

- 単一呼び出しのレイテンシ：マイクロ秒〜ミリ秒オーダー（長さに依存）
- アルファベット未指定時は O(n) でランダムバイトを取得
- アルファベット指定時は平均 O(n) だがリジェクションにより多少のオーバーヘッドあり
- 最悪ケースでも 2n 倍程度のランダムバイトで完了が期待される

## セキュリティ考慮事項

- 生成される文字列は暗号学的に安全なランダムソースから導出される
- 予測不可能性が保証されている
- `[leak_safe]` コンテキストで実行可能であり、副作用がない
- トークンやキー生成などのセキュリティクリティカルな用途に使用可能
- アルファベット内の文字は一様分布で選択されるため、統計的な偏りがない

## 備考

- 非暗号用途では `PseudoRandom\string` の使用を検討すること（ただし現在は SecureRandom\string へのエイリアス）
- 定義済みアルファベット定数（`_Private\ALPHABET_BASE64`、`_Private\ALPHABET_BASE64_URL`、`_Private\ALPHABET_ALPHANUMERIC`）が利用可能
- URL セーフな文字列が必要な場合は `ALPHABET_BASE64_URL` を使用すること

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

アルファベット定数を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | private.php | `src/private.php` | ALPHABET_ALPHANUMERIC 定数の定義（53-54行目） |
| 1-2 | private.php | `src/random/private.php` | ALPHABET_BASE64、ALPHABET_BASE64_URL 定数の定義（70-73行目） |

**読解のコツ**: 定義済みアルファベットは URL セーフ性やエンコーディング互換性を考慮して設計されている。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | secure.php | `src/random/secure.php` | SecureRandom\string 関数の実装（50-59行目） |

**主要処理フロー**:
1. **50-53行目**: 関数宣言。$length と $alphabet を引数として取る
2. **54-58行目**: `_Private\random_string` を呼び出し、`\random_bytes` をラップしたラムダを渡す

```hack
function string(
  int $length,
  ?string $alphabet = null,
)[leak_safe]: string {
  return _Private\random_string(
    ($length) ==> \random_bytes($length),
    $length,
    $alphabet,
  );
}
```

#### Step 3: 共通実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | private.php | `src/random/private.php` | random_string 関数の実装（15-68行目） |

**主要処理フロー**:
- **20行目**: invariant で $length >= 0 を検証
- **21-22行目**: $length === 0 なら空文字列を返却
- **24-26行目**: $alphabet === null なら $random_bytes($length) を返却
- **27-28行目**: アルファベットサイズと必要ビット数を計算
- **29-34行目**: invariant でアルファベット長を検証（2^1 〜 2^56）
- **36-64行目**: ビット操作によるリジェクションサンプリングのループ
- **46-48行目**: ランダムバイトを 8 ビットずつアンパック
- **53-62行目**: bits ビットを取り出して文字を選択、index < alphabet_size ならば採用

### プログラム呼び出し階層図

```
SecureRandom\string($length, $alphabet)
    │
    └─ _Private\random_string(lambda, $length, $alphabet)
           │
           ├─ invariant() [入力検証]
           │
           ├─ [alphabet == null]
           │      └─ \random_bytes($length) ──▶ 生バイト列を返却
           │
           └─ [alphabet != null]
                  │
                  ├─ Math\ceil(Math\log(alphabet_size, 2)) [ビット数計算]
                  │
                  └─ ループ処理
                         │
                         ├─ \random_bytes(urandom_length)
                         │
                         └─ ビット操作で文字選択（リジェクションサンプリング）
```

### データフロー図

```
[入力]                         [処理]                              [出力]

$length (int) ──────▶┐
                     ├──▶ invariant() ──▶ 検証OK
$alphabet (?string) ─┘
                              │
                     ┌────────┴────────┐
                     ▼                 ▼
              [alphabet=null]    [alphabet指定]
                     │                 │
                     ▼                 ▼
             random_bytes($len)   ビット操作ループ
                     │                 │
                     ▼                 ▼
              生バイト列        alphabet からの文字列
                     │                 │
                     └────────┬────────┘
                              ▼
                          string 返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| secure.php | `src/random/secure.php` | ソース | SecureRandom 名前空間の公開関数を定義 |
| private.php | `src/random/private.php` | ソース | random_string 共通実装とアルファベット定数を定義 |
| private.php | `src/private.php` | ソース | ALPHABET_ALPHANUMERIC 定数を定義 |
| SecureRandomTest.php | `tests/random/SecureRandomTest.php` | テスト | SecureRandom 関数群のユニットテスト |
| RandomTestTrait.php | `tests/random/RandomTestTrait.php` | テスト | 文字列長・文字・位置のテストを含む |
