出題とスコープ
呼び出し元がアルゴリズム、公開鍵、メッセージ、署名、コンテキストを提供する ML-DSA 署名検証ラッパーを実装してください。入力の検証、クロスプロトコルリプレイの防止、エラーおよびテストの設計はどのように行いますか?
面接官が評価するポイント
- 格子暗号のプリミティブを再実装するのではなく、検証済みの FIPS 204 実装を再利用しているか。
- アルゴリズム識別子、公開鍵、メッセージ、署名、コンテキストを曖昧さのない入力として保持しているか。
- 機密情報の詳細を漏洩させることなく、無効な署名、不正な入力、非対応のアルゴリズム、内部障害を明確に区別しているか。
- コンテキストバインディング、絞り込まれたインターフェース、テストベクトルを使用して、クロスプロトコルリプレイや実装の乖離(implementation drift)を防いでいるか。
確認のための質問
- どの ML-DSA パラメータセットが使用され、そのライブラリは FIPS 204 ベクトル検証に合格していますか?
- どのプロトコルがコンテキストを定義し、コンテキストは空になり得ますか?また、どのようなエンコーディングと長さ制限が適用されますか?
- 検証失敗は通常の業務処理結果ですか、それともアラートおよび監査イベントですか?
- メッセージはストリーミングされますか?事前ハッシュ(pre-hash)インターフェースは必要ですか?また、鍵のローテーションはどのように行われますか?
30秒回答フレームワーク
検証済みの ML-DSA ライブラリ API 上に薄いラッパーを構築します。明示的なアルゴリズム識別子からパラメータセットを選択し、バイト入力とコンテキストを検証した上で、プロトコルコンテキストをメッセージとともに検証処理へ渡します。返却する結果は「有効(valid)」「無効(invalid)」「非対応(unsupported)」「不正な形式(malformed)」のみとし、例外トレースは一切返しません。公式テストベクトル、改ざん、誤ったパラメータセット、コンテキスト間リプレイ、境界長、並行性、鍵ローテーションをテストします。秘密鍵やメッセージ全文をログに出力することはありません。
ステップごとの詳細解説
1. ラッパーの境界を設定する
FIPS 204 は ML-DSA の署名および検証を定義しています。RFC 9882 では、CMS がヘッジ付き署名(hedged)と決定論的署名(deterministic)の両方に対して同一の検証アルゴリズムを使用することが規定されています。アプリケーションコード内で NTT、サンプリング、棄却サンプリング(rejection sampling)を実装すべきではありません。依存関係、パラメータセット、テスト済みライブラリのインターフェースを固定(pin)します。
2. 入力とコンテキストを検証する
アルゴリズム識別子が許可されていること、公開鍵および署名のバイト長が選択されたパラメータセットと一致していること、メッセージがポリシー内にあることを確認します。プロトコルに従ってコンテキストをエンコードします。コンテキストは単なるログラベルではなく、署名のドメイン分離を提供するものであり、署名者と合意した値と同一でなければなりません。コンテキストが欠落または不正な場合は malformed または invalid を返し、決して空のコンテキストを推測・補完してはなりません。
3. 安全なエラーセマンティクスを設計する
ライブラリの例外、鍵素材、パーサーの詳細をそのまま返すのではなく、valid、invalid、unsupported、malformed などの構造化された結果を返します。メトリクスや監査ログには、アルゴリズム、バージョン、結果クラス、リクエスト ID のみを記録します。内部障害は制御されたエラーチャネルとアラートを経由させ、ライブラリのクラッシュが無効な署名として誤認されないようにします。
4. テストベクトルとプロトコルテストで挙動を固定する
まず NIST ACVP または FIPS 204 互換のテストベクトルを実行し、次にビット反転、切り捨て、異なるコンテキスト、誤ったアルゴリズム識別子、古い鍵をテストします。クロスプロトコルのケースでは、同一のメッセージが異なるコンテキストで受理されないことを確認します。並行呼び出しには不変な(immutable)入力を使用し、ローテーション中は明示的な旧鍵許容ウィンドウを受け入れ、有効期限後は拒否します。
質の高い模範解答
ML-DSA を独自に再実装するのではなく、検証済みライブラリの薄いラッパーとして作成します。呼び出し元は、明示的なアルゴリズム識別子、パラメータセット、公開鍵、メッセージ、署名、プロトコルコンテキストを提供する必要があります。ラッパーはフォーマットとサイズを検証し、検証 API に同一のコンテキストを渡し、失敗後に別のパラメータセットや空のコンテキストで再試行することは決してありません。返却値は valid、invalid、unsupported、malformed のみとし、内部障害は別途アラートを発報し、ログから鍵とメッセージを除外します。FIPS/ACVP ベクトル、改ざん、切り捨て、コンテキスト間リプレイ、鍵ローテーション、並行性テストによって動作を固定し、ライブラリバージョンとパラメータも固定して管理します。
よくある間違い
- ML-DSA の NTT、サンプリング、棄却サンプリングを再実装してしまうこと。
- アルゴリズム識別子を無視し、異なるパラメータセット間で単一の公開鍵を使い回そうとすること。
- 検証失敗後に、空のコンテキストや別のコンテキストで再試行すること。
- ライブラリの障害、無効な署名、不正な形式の入力を、根拠なく単一の結果にひとまとめにすること。
- メッセージ全文、鍵、例外トレースをログに出力してしまうこと。
- テストベクトル、改ざん、リプレイ、ローテーションのケースを検証せず、正常系(happy path)のみをテストすること。
フォローアップの質問と回答
ヘッジ付き署名と決定論的署名で異なる検証コードが必要ですか?
いいえ。RFC 9882 では両者が同じ検証アルゴリズムを使用すると規定されているため、ラッパーは署名モードに基づいて2つの検証パスに分岐させるべきではありません。
なぜコンテキストによってクロスプロトコルリプレイが防げるのですか?
コンテキストによって署名が特定のプロトコル検証ドメインにバインドされるためです。同一のメッセージと鍵であっても異なるコンテキスト下では検証の意味が異なります。コンテキストが存在しない場合、検証側が勝手に推測したりフォールバックしたりしてはなりません。
ライブラリのアップグレードはどのように処理しますか?
パラメータセットとライブラリバージョンを固定し、公式テストベクトルおよび過去の互換性サンプルを実行した後、変更をカナリアリリースします。バージョンと結果クラスを記録し、動作に差異がある場合は移行が完了するまで古い検証ラッパーを保持します。