No290 意外に難しい乱数の話
乱数というのをご存知でしょうか?
いわば適当に選んだ値のことなのですが、この「適当に」というのはコンピュータが苦手とする領域なのです。
乱数なんて情報セキュリティとは無縁そうなですが、暗号理論などでは頻繁に登場するテーマなのです。
悪意の第三者にバレないためには、ランダムな鍵情報を用いる必要があります。
これを実現するのが乱数なのです。
今回は、意外に奥の深い乱数について解説をします。
乱数とは何のこと?
日常で「乱数」という言葉を使う機会は少ないでしょう。
何となく適当に選んだ数のことかな?くらいのイメージを持つ方は多いでしょう。
実際その通りなのですが、質の良い乱数となると、出現頻度にかたよりがない、次に表出する値が予測できない、といった条件を満たした数値となります。
そんなの簡単そうですが、意外なことにコンピュータにとっては「適当に選ぶ」というのは実に難しいのです。
ご存知の通り、コンピュータはロジックの塊であり、全ては計算の結果です。
同じ値を使った計算の結果は同じになってくれないと困ります。
そりゃそうですよ。
1+1の答えが場合によって、2になったり、3になったりするようでは使いものになりません。
ですが、適当な値が欲しい時にはこれは困るわけです。同じように「乱数をちょうだい」と言って常に1を帰してくれるようではこれまた逆に使いものになりません。
片や同じ結果を返してほしい、片や違う結果を返してほしい、わけです。
この両者は明らかに矛盾があります。
一体どうやってこれをクリアしているのでしょうか?
擬似乱数という工夫
ですが、コンピュータで乱数を必要とする場面は意外に多いのです。
わかりやすいのがゲームやシミュレーションです。
ゲームではキャラクターの属性や敵の出現場所など常に固定だと単調なゲームになりますし、天気などの自然界のシミュレーションでは、自然と同様なランダムさが求められます。
また、後述しますが、暗号理論の世界でも質の良い乱数が常に求められています。
ですが、前述のように数学で(真の)乱数を得ることはできません。
そこで、いかにもランダムっぽい数を得るための手法がいろいろと開発されました。
これを擬似乱数と呼びます。
この擬似乱数はあくまで「擬似」であり、本当の乱数ではありません。
擬似乱数の計算方法にはいろいろありますが、ごく単純な例として7の倍数を利用した擬似乱数を考えてみましょう。
ここでは、直前に返した値を元として、それに7を掛け、下1ケタを答えとするものです。例えば、最初は単純に7を返し、2回目はそれに7を掛け、得た答え49の下1ケタを返す。3回目はその9に7を掛けて...という具合です。
こんな感じですね。
1回目 7 → 答えは7
2回目 7x7=49 → 答えは9
3回目 9x7=63 → 答えは3
4回目 3x7=21 → 答えは1
5回目 1x7=7 → 答えは7
この計算で、得られる値は
7,9,3,1,7
と(一見ランダムっぽい)数字列が得られます。
上記はあくまで例ですので、擬似乱数と呼ぶにしても質が低すぎますが、このように計算によって答えを返す方式を擬似乱数と呼びます。
このように、擬似乱数の計算には「前回の値」が必要です。
上記の例なら、前回の値が9なら、その9を覚えておかないと次の擬似乱数を計算できません。言いかえれば、前回の値によって、次の値が何になるかは決まっているのです。
つまり、擬似乱数というのは、一見ランダムっぽく見えているだけで、コンピュータは予定した通りの計算しているだけで、ランダムに値をチョイスしているわけではないのです。
実際的な擬似乱数
実用的な擬似乱数となると、線形合同法といった数学的な方式があります。
計算式は、次のようなものになります。
(式中のA,B,Mはいずれも特定の値で、modは余りを求める計算を示します。)
今回の乱数値 = (前回の乱数値 × A + B) mod M
ちょっと複雑な式ですので、実例でいきましょう。
例:(A=13 、B=5、M=24とした例)
1回目: ( 1 x 13 + 5)mod 24 = 18
2回目: (18 x 13 + 5)mod 24 = 23
3回目: (23 x 13 + 5)mod 24 = 16
4回目: (16 x 13 + 5)mod 24 = 21
5回目: (21 x 13 + 5)mod 24 = 14
6回目: (14 x 13 + 5)mod 24 = 19
7回目: (19 x 13 + 5)mod 24 = 12
8回目: (12 x 13 + 5)mod 24 = 17
9回目: (17 x 13 + 5)mod 24 = 10
10回目: (10 x 13 + 5)mod 24 = 15
11回目: (15 x 13 + 5)mod 24 = 8
12回目: ( 8 x 13 + 5)mod 24 = 13
13回目: (13 x 13 + 5)mod 24 = 6
14回目: ( 6 x 13 + 5)mod 24 = 11
15回目: (11 x 13 + 5)mod 24 = 4
16回目: ( 4 x 13 + 5)mod 24 = 9
17回目: ( 9 x 13 + 5)mod 24 = 2
18回目: ( 2 x 13 + 5)mod 24 = 7
19回目: ( 7 x 13 + 5)mod 24 = 0
20回目: ( 0 x 13 + 5)mod 24 = 5
21回目: ( 5 x 13 + 5)mod 24 = 22
22回目: (22 x 13 + 5)mod 24 = 3
23回目: ( 3 x 13 + 5)mod 24 = 20
24回目: (20 x 13 + 5)mod 24 = 1
25回目: ( 1 x 13 + 5)mod 24 = 18
今回は計算式の解説が目的ではありませんので省略します。
ここでは、1)結果がいかにもランダムに見える点、2)0~23の値が全て登場している点、の二つに注目してください。
ここでは、A,B,Mの値が小さな値ですが、実際に使う場合は、もっと大きな値を用いています。
擬似乱数は繰り返される
擬似乱数にはもう一つ問題というか特徴があります。
上述の通り、擬似乱数といってもちょっと変わった計算に過ぎません。計算というのはパラメタが同じなら、結果は必ず同じになります。
何をあたりまえのことを言ってるのか?と思われますか?
ですが、これは乱数としては結構致命的な話なのです。
プログラムというのは、あらかじめ決めておいたパラメタ値で動き始めます。この値は基本的に固定です。ということは、擬似乱数が返す値も常に同じ値から始まることになります。
ということは、ランダムな値を得たいにも関わらず、昨日動かした時と今日動かした時では同じ乱数値(上記の例では18)が返されてしまいます。
もちろん、明日以降も永遠に同じ乱数値(やはり18)が返ってきます。
じゃあ、プログラム起動時にランダムにパラメタ値を変えればエエやん...。
いえいえ、そもそもそれができるなら、擬似乱数なんていらないんですってば。
何だか大変そうな課題に見えますが、意外と単純な方法で回避できます。
もう一度、線形合同法の1回目の式を引用します。
1回目: ( 1 x 13 + 5)mod 24 = 18
よく見ると、最初に1という値が出てきています。
これは「種」(ランダムシード)と呼ばれる値なのですが、プログラム起動時には固定の値となっています。これが固定(上記の例では1)だから、毎回同じ答えになってしまうのです。
ということは、この種をわざと別の値にしてしまえば良いのです。
例えば、この種を2にすればどうなるでしょうか?
再度、引用しますが、種が2となっている計算は18回目となっています。
18回目: ( 2 x 13 + 5)mod 24 = 7
つまり、種を2にすれば、いきなり18回目の計算から始めることになり、最初の乱数値も7とできるわけです。
「おいおい。その種をランダムに設定できないから困るんだ、って言ったばかりじゃないか!」と思われる方、実は方法があるのです。
プログラム起動直後に現在時刻を取り、その値を種に使えば良いのです。
もちろん、秒でも良いですし、ミリ秒やマイクロ秒を使っても構いません。
このひと工夫を加えることで、毎回、違った乱数値を得られるようになるのです。
質の良い擬似乱数
上記の線形合同法に限らず、擬似乱数の求め方にはいろんな種類があります。
特に質の良い乱数が求められているのが暗号理論の世界です。
十分に強い暗号結果を得るためには、高品質な乱数が欠かせないそうです。
出現頻度にかたよりがあると、暗号化した結果そのものにかたよりが生じてしまいます。かたよりがあると、それを糸口として解読されてしまう可能性が高くなります。
つまり、強い暗号を維持するには質の高い擬似乱数が必要となるわけです。
まとめ
コンピュータという機器は同じことや決まったことの繰り返しは大の得意ですが、ランダムに値を取り出すといったことは極端に苦手です。
ですが、ランダムな値を必要とするシーンはたくさんあります。
そこで、本当は計算で求めているからちっともランダムではないのに、いかにもランダムっぽい値を返してくれる擬似乱数というものが考案され、多くのシーンで使われています。
もちろん、ゲームやシミュレーションなどでも乱数は使われていますが、暗号理論でも質の高い擬似乱数の作り方については、今も研究が行われています。
現在でも暗号化の鍵を生み出すには擬似乱数が活躍しています。
さて、コンピュータでは真の乱数(計算では求められない乱数)を得ることができません。
それでも、どうしても真の乱数が欲しいシーンもあります。
そういった特殊な用途に向け、真の乱数を得るための機器というのが存在します。
例えば、商用電源(100Vのコンセントに来ている電気)は微妙に電圧にゆらぎが生じます。そのわずかなゆらぎは様々な要因で発生するものですので、真のランダム値と言えます。
それを利用してランダム値を返してくれる装置というものがあるそうです。
(筆者も実物は見たことがありません)
ランダムに値をピックアップする、という一見簡単そうな乱数というものですが、非常に奥の深い分野のようで、今も擬似乱数の研究は続けられていて、より良い擬似乱数は次々と発表されています。
今回は乱数について解説をしました。
次回もお楽しみに。
さて、本メルマガも6回目の新年を迎えることができました。
これもひとえに読者の皆様からの支援があればこそと感謝しています。
本年も昨年同様のご愛読をいただきますようによろしくお願いいたします。
(本稿は 2023年1月に作成しました)
本Noteはメルマガ「がんばりすぎないセキュリティ」からの転載です。
当所はセミナーなどを通して皆さんが楽しく笑顔でITを利用いただくために、 難しいセキュリティ技術をやさしく語ります。
公式サイトは https://www.egao-it.com/ です。