ハッシュ関数のわかりやすい解説――『Web3とは何か』by岡嶋裕史 第1章 ブロックチェーン⑤
過去の連載はこちら。
岡嶋さんの新書最新刊。6刷になりました!
岡嶋さんのオンラインセミナーを開催します。
第1章 ブロックチェーン⑤
ハッシュ関数のわかりやすい解説
関数は中学生のときに習ったが、何かを入れると何かを出してくるハコである。
入力 5,2 → 関数 → 出力 7
5と2を入力して、7が出力されるのなら、その関数はおそらく「足し算関数」である。
入力 よごれたくつした → 関数 → 出力 きれいな靴下
よごれたくつしたを入力して、きれいな靴下が出力されるのであれば、その関数はきっと「洗濯機関数」だろう。
あらゆるデータ → ハッシュ関数 → ハッシュ値
ハッシュ関数はあらゆるデータを受け付ける。文字でも数値でも画像でも音楽でもいい。それをハッシュ関数にかけると、一定サイズの要約データ(ダイジェストデータ)を作ってくれる。これをハッシュ値と呼ぶ。
Windowsマシンにはハッシュ関数を簡単に使える機能があるので、ちょっと試してみよう。
まずハッシュ関数に入れるデータをメモ帳で作った。ファイルの名前は「ハッシュ.txt」で、なかみはアルファベットの「a」一文字だけである。
これをハッシュ関数にかける。コマンドプロンプトから命令文を入れてハッシュ関数を実行する。
すると、「a」のハッシュ値「0cc175b9c0f1b6a831c399e269772661」が出てきた。certutilはこの機能を動かす命令で、色々なことができるので -hashfile でハッシュ値を作って欲しいんだと伝えている。
d:¥ハッシュ.txtは ハッシュ関数にかける文書(aが入ってるやつ)を指定しており、最後のMD5はハッシュ関数を指定している。ハッシュ関数にはたくさんの種類があるので、その中から1つを選ぶわけだ。
もう一度やってみよう。今度はハッシュ関数に投入するデータを変える。
太宰治である。これをハッシュ関数にかけよう。
今度は違うハッシュ値が得られた。「ea91dacc6fe669e5b0bd2281ae46e68c」である。
この結果から、いくつかわかることがある。
まだまだ特性がある。もう1回だけ実験してみよう。データを変える。
どの部分をいじったかすぐにわかっただろうか? 一箇所読点を抜いてある。改ざんだと考えて欲しい。人間だと目が滑って見つけにくいかもしれない。このデータをハッシュ関数にかけてみる。
ea91dacc6fe669e5b0bd2281ae46e68c
f022286160cf5f41becbdd939bd39399
上下を見比べて欲しい。一箇所読点を抜いただけなのに、何から何まで違うハッシュ値になっている。暗号学的ハッシュ関数には次のような特徴があるのだ。
3.もとのデータがちょっとでも変わると、似ても似つかないようなハッシュ値になる
3はいま見たばかりである。人間には見つけるのが難しい針の先ほどの違いでも、ハッシュ関数にかけると似ても似つかない大幅にずれたハッシュ値が出てくるので簡単に改ざんを発見することができる。
また、元データをちょっと変更した結果、ハッシュ値もちょっとしか変わらないと、どこにどんな変更を加えたかハッシュ値から推測されてしまう可能性が高まる。そうした事態をも防止しているのである。
アプリを配布するときに、そのアプリのハッシュ値も一緒に公開するケースなどは、この特性を利用している。配布される側は、たとえばハッキングによってアプリにマルウェア(ウイルス)が混入していてもわからない。でも、メーカーによってちゃんとした状態のアプリのハッシュ値が公開されていれば、ダウンロードしてきたアプリをハッシュ関数にかけてハッシュ値を出し、それをメーカーのハッシュ値と比較することでマルウェアに汚染されているかどうかがわかる。
4.ハッシュ値からもとのデータを復元することができない
4も極めて有用だ。よくハッシュ値と暗号が混同された報道がある。もとのデータを加工してよくわからんデータを出力する意味で両者は似ているが、暗号はもとに戻せる、ハッシュ値はもとに戻せないという決定的な違いがある。ハッシュ関数は逆方向への計算ができない一方向関数なのである。
もとに戻せないことで色々な使い道がある。たとえばパスワードの保存である。パスワードを暗号化して保存するのはまずい。暗号化鍵が漏れれば、パスワードを復元されてしまうからだ。
そこでハッシュ値を使う。パスワードをハッシュ関数にかけ、ハッシュ値を得てそれを保存しておくのだ。仮に漏洩事故でも起こしたとして、漏れるのはハッシュ値だけである。ハッシュ値からパスワードは復元できないので、安全だ。
もとに戻せないなら、パスワードの認証もできないのでは? と思われるかもしれない。でも大丈夫だ。利用者がパスワードを入力したら、それをハッシュ関数にかければよい。ハッシュ関数は同じデータからは、必ず同じハッシュ値を作る。だから、パスワードが合致しているかどうかはハッシュ値を比較すればわかる。
もちろん、不正などいくらでもやりようはある。たとえば、みんながよく使うパスワードのハッシュ値をあらかじめ計算しておくのだ。「123456」のMD5ハッシュ値は「e10adc3949ba59abbe56e057f20f883e」である。パスワードをハッキングした誰かが、そのリストの中に「e10adc3949ba59abbe56e057f20f883e」を見つけたら、「ははぁ、123456だな」とすぐわかってしまう。だから、いくら「パスワードがハッシュ化されている」などと言われても、簡単なパスワードを使ってはいけない。
5.違うデータから同じハッシュ値になることが稀
5はちょっとわかりにくいかもしれない。ハッシュ関数はあらゆるデータを一定サイズのハッシュ値にする。たとえば、1000桁の英数字を10桁のハッシュ値にするハッシュ関数があったとすると、長いものを短くまとめているので、どこかで必ず重複が出てしまう。違うデータから同じハッシュ値が作られてしまう衝突(コリジョン)現象である。同じハッシュ値になる異なるデータのことをシノニムと呼ぶ。
シノニムがあると不正に結びつけやすい。違うデータから同じハッシュ値を導けるなら、悪用できるのは道理である。「1000万円借りました」と「10円貸してください」がシノニムだったら、詐欺の方法などいくらでも思いつく。
安全に関する用途に使うのであれば、シノニムが偶然生じたり、無理くり発見できたりする確率が無視できる水準でなくてはならない。多くのハッシュ関数のうち、3,4,5の特性を満たしたものを暗号学的ハッシュ関数というのである。
この特性を利用して、ハッシュ値は「データに消えない刻印」を記すために使われる。たとえば、文書を作り、公的な時刻サーバから取得した時刻を記入して、ハッシュ値を得る。後から文書の作成時刻を改ざんしたくなっても、元文書を変更しただけではハッシュ値と矛盾が生じるのでバレる。元文書とハッシュ値を別に保存しておけば、改ざんを試みる難易度は上がる。
ブロックチェーンも、この「消えない刻印」としてのハッシュ値を使うのだ。ビットコインなど、ブロックの中身はハッシュ値だらけと言ってもよい。トランザクション(取引)のハッシュ値を計算し、そのハッシュ値を別のトランザクションのハッシュ値とくっつけて、そこからまたハッシュ値を作る・・・・・・といったことを延々と繰り返している。
1つのブロックにトランザクションは1000~2000個入るから、スパゲッティみたいに絡まり合ったハッシュ値ができあがる。極めつけはブロックがいっぱいになってそのブロックを閉じるときに、ブロック全体のハッシュ値をとって次のブロックに埋め込むのである。
地獄のようなハッシュの連鎖ができあがる。こんなに絡まり合っていては、「偶然シノニムを見つけて、そこから元のデータを都合よく改ざんして何か不正を・・・・・・」といった試みは事実上不可能だ。単独のハッシュ値だって不可能に近いのだから。そんなヒマと根性があるなら、ちゃんと仕事した方がずっと高い報酬を得られる。
これが、ブロックチェーンが改ざん困難といわれるゆえんである。書き込み専用であることも、自然に理解できると思う。最初のブロックに書き込んだデータが間違いだったので、違うデータで上書きしようと思いついても、それはチェーン全体の再計算を意味する。システムを何年も止める覚悟がないと、そんな再計算はできない。(続く)