私はハッシュ関数について少し研究しています。私はそれが1つの方法で簡単に実行できる方程式であるという概念を理解しています(たとえば、00011010を使用し、それを使ってかなり単純な計算を行います)。しかし、使用する関数は他の方法では非常に困難です。しかし、一方向ハッシュ関数がどのように見えるかの例を見つけることはできません。アナロジーとして素数乗法を与えるYouTubeビデオを見て、グーグルで例を検索しましたが、実際の関数がどのように見えるかの例を見つけることができませんでした。
コンピュータプログラミングの基本的な知識はありますが、経験豊富なコーダーではありません。
暗号化ハッシュ関数 について話しているようですが、特定の出力を持つ入力を簡単に構築できないことが重要です。これが「一方向関数」の意味です。一般的なハッシュ関数(たとえば、ハッシュテーブルに使用される)には、この要件はありません。
暗号化ハッシュ関数の最も簡単な例は、モジュール二乗であるラビン関数です。それはこのように動作します:
N = 4181を使用します。
ハッシュは3666だと言います。あなたの仕事は、X ^ 2 mod 4181 = 3666となるようなXを見つけることです。それをどのように解決しますか?
もちろん、4181 + 3666が平方数であるかどうかを確認し、4181 * 2 + 3666、次に4181 * 3 + 3666を試行することで、総当たりにすることができますが、これには時間がかかります。
あなたはいくつかの深刻な計算を行うことができ、Nの素因数がわかっていれば、すぐに解を見つけることができることがわかります。しかし、知らないで、多数の素因数を見つけること(実際のシナリオではNは非常に多いでしょう)大きい)も永遠にかかります。
すべてのハッシュ関数は一方向です。ハッシュ関数は、larg(er)(潜在的に無限)の入力空間をsmall(er)(通常は有限)の出力空間にマッピングします。
Pigeonhole Principleに精通している場合は、ハッシュ関数mustが一方向であることをすぐにわかるはずです。ピジョンホールの原則に詳しくない場合は、次のように非常に簡単に説明します。
ピジョンホール原則では、少なくとも2つの靴下を入れた少なくとも1つの引き出しがないと、2つの引き出しに3つの靴下を入れることはできないと述べています。
したがって、大きい入力スペースを小さい出力スペースにマップする関数がある場合、同じ出力にマップする少なくとも2つの入力ergoがあり、ハッシュ関数を逆にすることはできません。
高度な数学を使用しないハッシュ関数の非常に単純な例は、次の単純なパリティ関数です。
def hash(n: Nat)
if n.even?
0
else
1
end
end
ご覧のとおり、大きな入力空間(自然数)を小さな出力空間(セット{0、1})にマッピングします。そして、それは一方通行です。結果が1
、何が入力されたのかわかりません。
以下に簡単な例を示します。
文字列「Hello world!」のハッシュ「ヘル」です。 「Hel」が指定されている場合、「Hello world!」を再現することはできませんが、他の多くの文字列と衝突することはありません。
確かに、これがパスワードの場合、最初の3文字を知っていると元のパスワードをブルートフォースで簡単に強制できるため、このハッシュはあまり良くありません。
では、各文字の値に3 mod 26を掛けるとどうなるでしょうか。
H (7) * 3 -> V (21)
e (4) * 3 -> m (12)
l (11) * 3 -> f (5)
これで、ハッシュは「Vmf」になります。確かに、これを元に戻すことはできますが、3倍されたことを知らずに、これは既に少しトリッカーになっています。コンピュータの場合、これは取るに足らないことですが、巨大な素数に対して乗算することを想像してください。それはパターンを見つけることを事実上不可能にし、可能な値を計算してそれらを試すために長い計算時間を費やす必要があります。
「Vmf」に変換するのは簡単なことでしたが、「Hel」に復元するのは簡単ではありません。これがまさにハッシュに求めていることです。
ユーザーが文字列「Hello、World!」を提供した場合、元の文字列を保存する必要はなく、ハッシュを「Hello、World!」に適用するだけで済みます。 「Vmf」を取得し、その文字列をファイルにあるものと比較します。
"Vmf" === "Vmf" // Bingo!
簡単に言えば、これがハッシュです。いろいろなテクニックがありますが、コンセプトは結局同じです。入力からデータの不可逆的な文字列を確定的に作成します。