乱数生成器とゲームと諜報活動の話

ゲームなどを作っているとランダムさが必要になることがあるけど、コンピュータは基本的に毎回全く同じように動くので、乱数を作り出すのはそう簡単なことではない。Wi-FiやHTTPSなどの暗号は乱数のランダムさに本質的に依存しているので、高品質な乱数生成は世の中的にも重要な話題である。ここでは乱数生成について話をしてみよう。

ゲームではイベントがプレイヤーに予測不可能であればよいだけなので、真の乱数列ではなく擬似乱数列というものを使うことが多い。擬似乱数列は人間にはランダムにみえるけど、実際は何らかの数式によって順番に生成されているだけの数の列で、初期値を毎回違うものにしておくと、人間には毎回違う数列が生成されるようにみえる。初期値には現在時刻を使うことが多い。現在時刻は普通の用途では毎回違うからだ。

昔のゲーム機は現在時刻の設定がなかったので、ファミコンなどでは、起動してからの経過時間を疑似乱数のソースに利用するゲームが多かった。つまりそのようなゲームでは、電源オンしてから正確に同じタイミングで同じボタン操作をしていけば、原理的には以前と同じ乱数により同一のイベントが発生し、過去のプレイを再現することができた。これには1/30秒単位での正確な操作が必要なのだが、ゲームによっては、ボタンを押しっぱなしにすることにより、ゲームがボタン操作を受け付けた瞬間に1フレームのズレもなく入力できるので、これはまったく人間に不可能な技というわけではなかった。

実際この「状況再現」テクニックを使って、スーパーファミコン版のドラクエ1を実機でわずか45分でクリアするということが行われている。ゲーム動画をみてみると驚異的にラッキーで、メタルスライムばかりに出会ってそれをすべて会心の一撃で倒すというような調子なのだが、これはラッキーなゲーム進行を正確な操作でリプレイしているのだ。

一方で暗号ではその強度が乱数の予測不可能さに依存しているので、現在時刻などを乱数の元に使うことはできない。決定論的に動くコンピュータには不可能な真の乱数を作り出すために、Linuxなどは、キーボードのタイピングの間隔やマウスの速度など、予測の難しい外部イベントの正確なタイミングを測って、そのランダムさをカーネル内に溜め込んでいる。その変数は/dev/randomから読むことができる。

ランダムなイベントはそれほど多くないので、ずっと/dev/randomを読んでいるとランダムさが枯渇してそれ以上読めなくなってしまう。例えばsshの暗号鍵を生成しているときに「マウスを動かすと鍵生成が早く終わります」というメッセージが表示されるのはこのためだ。

ソフトウェアだけで高品質な乱数を大量生成するのが難しいのなら、ハードウェアの助けを借りようという発想がある。実際、最近のIntelやAMDのプロセッサには熱雑音を利用したハードウェア乱数生成器が積まれていて、RDRANDという命令で乱数をレジスタにコピーすることができる。RDRANDは数100クロックしかかからないので、これを使うと、物理的にランダムな事象が元になった真の乱数列を、今までとは比べ物にならないほど高いスループットで作り出すことができる。

しかしハードウェア乱数生成器は乱数生成問題の最終的な解決策にはならなかった。たとえばLinuxはRDRAND命令に全面的に切り替えることはせず、今でもイベントのタイミングなどを利用した従来の乱数生成器とRDRAND命令を併用している。

これはなぜかというと、ハードウェア乱数生成器はブラックボックスで、本当に真の乱数を生成しているのかどうか判別するのは難しくて、結局のところ全面的に信用するのはリスクが高すぎるからだ。実際にアメリカ政府の諜報機関NSAがハードウェアセキュリティチップにバックドアをしかけていたことが発覚したことがある。このように、NSAやその他の国の組織が、秘密裏に乱数を予測可能にすることでそれを元に作成される暗号を弱めようとしているという懸念も、あながち杞憂とは言えない。乱数生成というのは他愛もない話のようだが、実はスパイ活動と陰謀が渦巻く熱い世界の話題でもあるのだ。

この記事が気に入ったらサポートをしてみませんか?