良いハッシュ関数とは何ですか?


130

良いハッシュ関数とは何ですか?私は大学のデータ構造のコースで多くのハッシュ関数とアプリケーションを見ましたが、良いハッシュ関数を作るのはかなり難しいと私はほとんど思いました。衝突を回避するための経験則として、私の教授は次のように述べています。

function Hash(key)
  return key mod PrimeNumber
end

(modはCおよび同様の言語の%演算子です)

素数をハッシュテーブルのサイズにします。これは、衝突を回避するためのやや良い関数であり、高速な関数ですが、どうすればより良い関数を作成できますか?数値キーに対する文字列キーのより良いハッシュ関数はありますか?


34
あなたは以下の汎用ハッシュ関数の一つ以上を使用して考えた:partow.net/programming/hashfunctions/index.html

fnv_funcでは、p [i]のタイプはcharです。最初の反復後にhで何が起こりますか?それは目的で行われたのですか?

5
@martinatimeによると:ウィキペディアen.wikipedia.org/wiki/Hash_functionにはハッシュ関数に関する情報がたくさんあり、この記事の下部partow.net/programming/hashfunctions/index.htmlにはさまざまな言語で実装されたアルゴリズムがあります。
2501

回答:


33

基本的にあらゆる種類のデータに対して「通常の」ハッシュテーブルルックアップを実行する場合-これは、Paul Hsiehによるもので、これまで使用した中で最高のものです。

http://www.azillionmonkeys.com/qed/hash.html

暗号的に安全であるか、より高度なものに関心がある場合は、YMMVを使用してください。ハッシュテーブルのルックアップにキックアスの汎用ハッシュ関数が必要な場合は、これが探しているものです。


有益なリンクをありがとう!私が知っているいくつかのポイントはかなり良い普遍的に許容可能なハッシュ関数へのボブ・ジェンキンスらによる解析を、私はまだこの1に遭遇していません。
Konrad Rudolph、

:私はSFHは、その後最高の1つですが、私はつぶやきがもっと良いかもしれないと思うことジェンキンスサイトから読んでいた、この優れた答えを参照programmers.stackexchange.com/questions/49550/...
nawfal

2
YMMVは何の略ですか?
コバルザン2015

3
@cobarzanマイレージが異なる場合があります
ProgrammerDan

2
Hsiehのハッシュ関数はひどいものであり、私たちが望むよりも桁違いに多くの衝突があります。特に、最後の4バイトのみが異なる文字列は衝突しやすくなります。最後の4バイトが異なる30文字の文字列がある場合、28バイトが処理された後、ハッシュは最後の2バイトのみが異なります。つまり、残りの2バイト値の1つに対する衝突が保証されます。(ええ、それは速いです。だから何です。)
Andrew Lazarus

51

ユニバーサルハッシュには「優れたハッシュ関数」などはありません(「はい、「ユニバーサルハッシュ」などがあることは知っていますが、それは私が意図したものではありません)。コンテキストに応じて、異なる基準がハッシュの品質を決定します。すでに2人がSHAについて言及しています。これは暗号化ハッシュであり、おそらくあなたが意味するハッシュテーブルにはまったく適していません。

ハッシュテーブルには、非常に異なる要件があります。しかし、それでも、データ型が異なるとハッシュ可能な情報が異なるため、優れたハッシュ関数を普遍的に見つけることは困難です。経験則として、型が等しく保持するすべての情報を考慮することは良いことです。これは常に簡単であるとは限りません。統計(および衝突)の理由から、問題の空間、つまりすべての可能なオブジェクトにわたって適切な広がりを生成することも重要です。つまり、100から1050までの数値をハッシュする場合、オブジェクトの90%以下ではこの数字が0になるため、最上位の数字がハッシュで大きな役割を果たすことは良くありません。最後の3つの数字を数字はハッシュを決定します。

同様に、文字列をハッシュするときは、すべての文字を考慮することが重要です。ただし、すべての文字列の最初の3文字が同じであることが事前にわかっている場合は除きます。これらを考えると無駄です。

これは、実際には、Art of Computer Programming、vol。3.別の読み物として、Julienne WalkerのThe Art of Hashingがあります。


1
コンラート、あなたは確かに理論的な観点から正しいですが、私のコメントで述べたPaul Hsiehハッシュ関数を使ってみたことはありますか?さまざまな種類のデータに対して非常に優れています。
Chris Harris、

9

ハッシュ関数には2つの主要な目的があります。

  • データポイントをnビットに均一に分散します。
  • 入力データを安全に識別するため。

ハッシュの用途を知らずにハッシュを推奨することは不可能です。

プログラムでハッシュテーブルを作成するだけであれば、アルゴリズムの可逆性やハッキング可能性について心配する必要はありません。これにはSHA-1またはAESは完全に不要であり、使用する方がよいでしょう。FNVのバリエーション。FNVは、あなたが述べたような単純な素数のmodよりも優れた分散(つまり、衝突が少ない)を実現し、さまざまな入力サイズにより適応します。

ハッシュを使用して公開情報(パスワードやドキュメントのハッシュなど)を非表示にして認証する場合は、公開の精査によって精査された主要なハッシュアルゴリズムの1つを使用する必要があります。ハッシュ関数ラウンジは、開始するのに適した場所です。


ハッシュ関数ラウンジへのリンクを更新:larc.usp.br/~pbarreto/hflounge.html
Tim Partridge

FNVは、たとえば、SHA1の同じビット数と比較して、誕生日の衝突にどの程度耐えますか?
Kevin Hsu

@Kevinハッシュの雪崩特性が良好である限り(入力の小さな変化=出力の大きな変化)、誕生日の衝突は単にハッシュ内のビットの関数です。FNV-1aはこの点で優れており、必要に応じてハッシュのビット数を増減することができます(ただし、2の累乗ではないビットカウントを取得するには少し余分な労力が必要です)。
Myrddin Emrys、2011

5

これは良いものの例であり、なぜあなたが決してそれを書きたくないと思うかの例でもあります。これはFowler / Noll / Vo(FNV)Hashであり、コンピュータサイエンスの天才であり、純粋なブードゥー教です。

unsigned fnv_hash_1a_32 ( void *key, int len ) {
    unsigned char *p = key;
    unsigned h = 0x811c9dc5;
    int i;

    for ( i = 0; i < len; i++ )
      h = ( h ^ p[i] ) * 0x01000193;

   return h;
}

unsigned long long fnv_hash_1a_64 ( void *key, int len ) {
    unsigned char *p = key;
    unsigned long long h = 0xcbf29ce484222325ULL;
    int i;

    for ( i = 0; i < len; i++ )
      h = ( h ^ p[i] ) * 0x100000001b3ULL;

   return h;
}

編集:

  • Landon Curt Nollは彼のサイトで、オリジナルのFVN-1アルゴリズムよりもFVN-1Aアルゴリズムを推奨しています。改良されたアルゴリズムは、ハッシュの最後のバイトをよりよく分散します。それに応じてアルゴリズムを調整しました。

3
これらの値が選択される理由に関するいくつかの情報については、このサイトを参照することをお勧めします。isthe.com
chongo

お大事に。この短くてシンプルで効率的で汎用的で効果的な64ビットのハッシュ関数は、まさに私が必要としていたものです。
mattarod

3

経験則としては、自分で転がすことはないと思います。SHA-1など、十分にテストされたものを使用するようにしてください。


彼は暗号的に安全なものを必要としているようには見えないので、SHA-1はやり過ぎです。
エリック

ちなみに、SHA-1の衝突は発見されていませんが、衝突が発見されるまでには数年から数ヶ月かかると考えられています。SHA-256の使用をお勧めします。
Samuel Allan 14

1

優れたハッシュ関数には次の特性があります。

  1. メッセージのハッシュが与えられると、攻撃者がハッシュが同一であるような別のメッセージを見つけることは計算上実行不可能です。

  2. メッセージのペアm 'とmが与えられた場合、h(m)= h(m')となるような2つのメッセージを見つけることは計算上不可能です。

2つのケースは同じではありません。最初のケースでは、衝突を見つけようとしている既存のハッシュがあります。後者の場合、あなたは見つけるためにしようとしている任意の衝突する2つのメッセージを。2番目のタスクは、誕生日の「パラドックス」により、はるかに簡単です。

パフォーマンスがそれほど問題にならない場合は、常に安全なハッシュ関数を使用する必要があります。ハッシュの衝突を強制することによって実行できる非常に巧妙な攻撃があります。最初から強力なものを使用する場合は、これらから保護されます。

新しいデザインでMD5またはSHA-1を使用しないでください。私を含め、ほとんどの暗号技術者は、暗号を解読したと考えます。これらの設計の両方の弱点の主な原因は、上で概説した2番目の特性がこれらの構造には当てはまらないことです。攻撃者が2つのメッセージmとm 'を生成できる場合、それらは両方とも同じ値にハッシュされ、ユーザーに対してこれらのメッセージを使用できます。SHA-1とMD5もメッセージ拡張攻撃の影響を受けます。注意を怠ると、アプリケーションが致命的に弱くなる可能性があります。

Whirpoolなどのより現代的なハッシュの方が適しています。これらのメッセージ拡張攻撃の影響を受けず、AESがさまざまな攻撃に対するセキュリティを証明するために使用するのと同じ数学を使用します。

お役に立てば幸いです。


1
この場合、暗号化ハッシュ関数の推奨は非常に悪いアドバイスだと思います。
Slava

@スラバ:なぜ?「この場合、暗号化ハッシュ関数は本当に悪いアドバイスです」と言う理由は何ですか?なぜ悪いアドバイスなのですか?そのようにする相対的な欠点は何ですか?
私についてそれを

2
@Mowzerは、ハッシュマップで使用されるハッシュ関数は高速で軽量でなければならないため(適切なハッシュを提供すると想定)、クリプトハッシュはブルートフォース攻撃を防ぐために計算コストが高くなることは明白でした。
スラバ

1

ここであなたが言っているのは、衝突耐性を持つを使用したいということです。SHA-2を使用してみてください。または、Miyaguchi-PreenelモードのAESのように、一方向圧縮関数で(良い)ブロック暗号を使用してみてください(これまでにこれを試したことはありません)。それの問題はあなたがする必要があることです:

1)IVを持っている。ヒンチンの定数の小数部の最初の256ビットなどを使用してみてください。2)パディング方式があります。簡単です。MD5やSHA-3(Keccak ['ket-chak'と発音)]のようなハッシュからそれを絞り込みます。セキュリティを気にしない場合(他の何人かはこれを言っています)、FNVまたはBob Jenkinsによるlookup2を見てください(実際に私はlookup2を推奨する最初の人です)また、MurmurHashを試してください、高速です(これを確認してください:.16 cpb )。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.