俺「ハッシュってなんやねん」

# ハッシュドポテトやで

ぐちゃぐちゃにしちゃうよ～ん。

まるで朝マックのハッシュドポテトやな。

# 小さく切り刻むこと

英英辞書には「hash」の意味はこうやって書かれているで。

> to chop into small pieces
> [引用元](https://www.merriam-webster.com/dictionary/hash)

つまり「細かな破片に刻むこと」って感じやね。

# 文字列をぐちゃぐちゃにしちゃうZE☆

Web開発においての「ハッシュ」はこれの派生の意味を持つよ。

具体的には、**入力された値に対して、決まった長さの(一見するとランダムな)文字列を返す**ことって意味だよ。

紙をシュレッダーにかけると、バラバラになって返ってくる。その中で数枚だけを見せられて「元の紙にはどんな内容が書いてあったと思う？」って聞かれてるイメージ。

ハッシュ化する関数（＝ハッシュ関数）に文字列に渡してあげると、ランダム（そう）な文字列になって返ってくる。

じゃあ実際にハッシュ化をみてみよう！

# PHPで文字列をハッシュ化する

PHPで文字列をハッシュ化する方法の1つに`md5`関数がある（他の言語にも似たような関数があるはず）。

この`md5`関数に「fresh potato」という文字列を入れると、ハッシュ化された文字列が返ってくる。

```PHP
<?php
$fresh_potato = "fresh potato";
$hashed_potato = md5($fresh_potato);
echo $hashed_potato; // aa40fe927f4fe2666c35b660fd903c60 と出力される
```

生の文字列を`md5`関数に入れると、戻り値として長いランダム（そう）な文字列`aa40fe927f4fe2666c35b660fd903c60`が返ってきた。

まさに`aa40fe927f4fe2666c35b660fd903c60`がプログラミングにおける`ハッシュドポテト`です、なんつってな。

# ハッシュの特徴3選

ここからはハッシュの面白い特徴を3つ紹介するZE⭐️

## 同じランダムな文字列になる

ハッシュの面白い特徴の1つに**毎回同じ文字列になる**というのがある。

> 俺「それじゃランダムな文字列じゃないじゃないか！」

という声が聞こえてきそうだ。

そうだ、ハッシュは毎回必ずしもランダムな文字列を生成している訳ではない。

先ほど`md5`関数を使って「fresh potato」という文字列をハッシュ化した（そのときの値は`aa40fe927f4fe2666c35b660fd903c60`であった）。

一見デタラメに見えそうな戻り値であるが、これはあるルール(=アルゴリズム)によって生成されている。

つまり「fresh potato」を再度`md5`関数に入れてハッシュ化しても再び同じ文字列が返ってくる。

何回やっても一緒だ。

そう、ハッシュ値は**毎回同じ文字列になる**のである。

## 少しでも元データが違うと、戻り値もめちゃ変わる

ハッシュは入力される文字列が少しでも変わると、出力される文字列が大きく変わるという特徴も持っている。

先ほどは「fresh potato」という文字列を入力したら`aa40fe927f4fe2666c35b660fd903c60`とというハッシュ値が返ってきた。

今度は「fresh potatu（最後の文字が「o」から「u」に変わってる）」を`md5`関数に入れて試してみよう。

```PHP
<?php
$fresh_potatu = "fresh potatu";
$hashed_potatu = md5($fresh_potatu);
echo $hashed_potatu; // bc3dbd157b9a675fee5a61712cb3f9ed と出力される
```

今度の「fresh potatu」は`bc3dbd157b9a675fee5a61712cb3f9ed`という文字列が返ってきた。

このように最後の文字を「a」から「u」に変えただけで、結果がこんなにも変わってしまった。

```diff_PHP
<?php
- // aa40fe927f4fe2666c35b660fd903c60 と出力される
+ // bc3dbd157b9a675fee5a61712cb3f9ed と出力される
```

ハッシュ化のアルゴリズムはとても複雑なので、この様に**少しでも元データが違うと、戻り値もめちゃ変わる**よ！。

## ハッシュ値から元の文字列を特定できない

ハッシュの面白いもう1つの特徴に**ハッシュ値から元の文字列を特定できない**というのがある。

こちらの特徴に驚く人も少なくないかも知れない。

簡単にいうと、ハッシュ化するときのルール(=アルゴリズム)の中にデータをわざと落とす処理が入っている。

これのせいで、ハッシュ値から元のデータを復元することは不可能になっている。

# 分かりやすい(と思っている)例

冒頭に登場した例えなんだけど、

「シュレッダーでバラバラにした紙屑の一部だけを見せられて、元の紙の内容を当てる」ようなもの。

決まった手順で紙をバラバラにするシュレッダーがあるとして、同じ紙を入れると同じ紙くずが出てくるとする（毎回紙を切る場所や長さや太さが同じみたいなイメージ）。

加えて、毎回紙屑の同じ部分だけを持ってきて、それをハッシュ値として僕たちに見せられているとする。

同じ紙を入れると同じ紙くずが生成され、紙くずの同じ部分を持ってくるから、紙から紙くずを生成するのはできる。

だけど一部しか紙くずを見せられてない上にバラバラになっているから、元の紙の内容はほぼ復元することはできない。

これが「ハッシュ」やでっ！

# じゃあ何に使うの？

一旦ハッシュのいいところを整理してみよう。

- 同じ値を入力すると同じ結果が返ってくる
- 少しでも入力値が変わると、出力が大きく変わる
- 戻り値から元の値を復元することができない

これらのメリットを活かして主に**パスワードの照合**に使われることが多いぞ！

1. 「aaa」という生のパスワードがあって、それをハッシュ化したら「xxx」になったとする。
1. 「aaa」と入力すると、毎回「xxx」が出力される。
1. 仮に「aab(似てるパスワード)」というパスワードをハッシュ化したら「kfv(xxxと全然違う)」になるとする。
1. このハッシュ値から元には戻せないから「xxx」から「aaa」を推測することはできない。

「xxx」は本当のパスワードじゃないけど、「aaa」は毎回「xxx」になるから、パスワードが「xxx」と一致するかを調べたらよさそうじゃない？

しかも「aab」は「xxx」に擦りもしない文字列になるから、本当のパスワードと万が一近い値を入力してもバレる心配が少ない。

加えてDBには「aaa」じゃなくて「xxx」を保存するから、DBの中身が流出しても「aaa」がバレる心配がない。


こんな感じでハッシュ化はパスワードの認証に使われることが多いよ！

# 参考文献

- [hashの英英辞典](https://www.merriam-webster.com/dictionary/hash)
- [PHPのmd5関数](https://www.php.net/manual/ja/function.md5.php)