8

2^25 のランダムな文字列の SHA256 ハッシュを見つける必要があります。そして、衝突を探します (たとえば、最後の 50 ビットのハッシュのみに誕生日のパラドックスを使用します)。

string:hash ペアを dict 変数に格納しています。次に、変数を値 (キーではなく) でソートし、O(n) ループを使用して衝突を探します。

問題は、2^25 文字列とその 2^25 ハッシュがあるため、dict 変数には 2^50 値が含まれることです。これは非常にリソースを消費します。では、たとえば 1GB 程度の限られた RAM でこれを行うにはどうすればよいでしょうか。

私がすでに試したこと:
1.これを6GBのスワップスペースで実行します。プログラムは一晩実行され、まだ完了していませんでした。これは基本的に、O(n_square) 検索よりもさらに遅くなります! ハッシュは、約 3.2 GB の RAM 使用量で計算されます。しかし、その後 sort コマンドになると、使用される RAM が再び急増し始めます。Python の並べ替えは In-Place-Quicksort を使用します
:(

データベースなどを使用することは想定されていません。せいぜいテキストファイルですが、それは役に立ちません。また、私はPythonにはかなり慣れていませんが、それがあなたの答えのレベルを制限することはありません.

PS: これは課題です。300MB RAM で 1 分以内に衝突を発見したと主張する人もいます。それが本当かどうかはわかりません。私は問題を解決しましたが、答えは到達できません! 仕事中なので、今はコードにアクセスできません。すぐに追加します。

コード:

from Crypto.Hash import SHA256
import os
import random
import string
from operator import itemgetter

def shaa():

    trun=[]
    clist={}
    for i in range(0,33554432):

        sha=SHA256.new(str(i)).hexdigest()
        sha=int(bin(int(sha,16))[-50:],2)
        clist[i]=sha

    print 'Hashes done.'

    clist=sorted(clist.items(), key=itemgetter(1))  
    for i in range(0,33554432):

        if(clist[i]==clist[i+1]):
            #print string[i],string[i+1]
            print clist[i]
            return 1
    return 2

result=2
while(result==2):
    result=shaa()
4

5 に答える 5

3

私は次のようなものに行きます:

16 個のファイルを開きます (バイナリ モードで開いても問題ありません。これは、すべての文字列が同じ長さの場合に最も簡単です)。文字列とハッシュを生成し、ハッシュの最初の 4 ビットに応じてファイルに書き込みます。次に、各ファイルを個別にロードして処理します。これにより、メモリ使用量が 16 分の 1 に減少します。

文字列とハッシュの生成が比較的安価な場合、ファイルは必要ありません。単純に 16 パスを実行し、各パスで上位ニブルがパス番号と一致するハッシュのみを保持します。

于 2012-04-10T13:15:39.640 に答える
2

この問題を解決する 1 つの方法は、非常に長いビットフィールドを使用して、すべてのハッシュが2^25 ビット長のメモリ ブロック内の特定の位置にマップされるようにすることです。

この種の問題を解決するための 100% 保証ではない、より優れた方法は、ブルーム フィルターまたはその他の確率的データ構造を介して行われます。

ブルーム フィルターは、要素がセットのメンバーであるかどうかをテストするために使用される、スペース効率の高い確率的データ構造です。偽陽性の可能性はありますが、偽陰性はありません。つまり、クエリは「セット内 (間違っている可能性があります)」または「間違いなくセット内にありません」のいずれかを返します。

ブルーム フィルターは、自己均衡二分探索木、トライ、ハッシュ テーブル、エントリの単純な配列やリンク リストなど、セットを表す他のデータ構造よりもスペースの面で大きな利点があります。

エラーが 1% のブルーム フィルターは、要素のサイズに関係なく、要素あたり約 9.6 ビットしか必要としません。

したがって、2^25 要素あたり 9.6 ビットの場合、必要なメモリはわずか 38.4 MiB です。

于 2012-04-10T13:28:08.870 に答える
1

ここでの重要な洞察は、数時間後にこれに戻るまで、しばらくの間私を回避したことを認めていると思いますが、sha256ハッシュダイジェストはそれ自体のハッシュであるということです。つまり、追加のハッシュやセットの作成を行う必要はありません。sha256ダイジェストをハッシュとして使用して、カスタム ハッシュ テーブルを作成するだけです。スペースを節約するために、文字列を保存しないでください。ビット配列を作成し ( で作成された int の配列内の整数に対してシフト操作を使用table = numpy.zeros(table_size / bits_per_int + 1, dtype='i'))、衝突を検出し、衝突する文字列を dict マッピング ハッシュを文字列に保存して、2 番目のパスでルックアップします。

table_size大きな素数にする必要があります-2 ** 31より少し大きいものを選びました.268MBのテーブルになりました.これは、新しい衝突/誤検知がほとんど発生しないためです(ハッシュのモジュロ演算によって導入されます)。文字列自体をテキスト ファイルに保存して、繰り返し処理することができます。

したがって、任意の文字列の場合、設定する対応するビットのインデックスは になりますindex = int(hashlib.sha256('foo').hexdigest(), base=16) % table_size。次に and を計算し、major_index = index / bits_in_intシフトminor_index = index % bits_in_int演算とビット演算を on に使用しminor_indexて、正しいビットをチェックして int at に格納しますtable[major_index]

次に、文字列を通過します。文字列が、すでに設定されているビットにマップするハッシュを生成するときはいつでも、hash:stringペアを辞書に保存します。または、ペアを保存し、hash:[string_list]複数の衝突が発生した場合に新しい文字列をリストに追加します。これで、衝突する文字列のペア (a、b) の場合、辞書には b のハッシュと値が含まれます。次に、文字列に対して 2 回目のパスを実行し、それぞれを順番にハッシュし、各ハッシュの辞書をチェックします。ハッシュが辞書にあり、文字列が対応するリストにない場合は、文字列をリストに追加します。ディクショナリ内の一部の文字列は、真の衝突に対応しません。これらの[string_list]ハッシュのほとんどは、1 項目だけの長さになります。hash:[string_list]ペアは破棄される場合があります。他のものは、モジュロ演算ではなく、ハッシュ関数自体に起因する真の衝突である可能性があります。ただし、真陽性と偽陽性の両方があった場合は、除外する偽陽性がまだいくつかある可能性があります。誤検知がないか、結果のリストを再確認する必要があります。

ブルーム フィルターを使用するというBasicWolfの提案は適切なものであり、テーブルが小さくなる可能性があります。しかし、これには多くの複雑さが伴います。気にしませんでした。'0\n'toから改行で終わる文字列に対して上記の方法を試したところ'33554431\n'、54 ビットのオーバーラップを持つ 2 つのハッシュが見つかりました。所要時間は 11 分で、最大メモリ使用量は約 350MB でした (ただし、これはおそらく削減される可能性があります)。プロファイリングを行ったところ、ほとんどの時間がビット テーブルのオフセットの計算に費やされていることがわかりました。これを c でコーディングすると、おそらく大幅な高速化が実現し、ハッシュと文字列を事前にハッシュして保存することも役立ちます。

実際、文字列の事前ハッシュ化を試み、かなりアドホックなnumpyベースの bitarray を、同じ名前bitarrayの C ベースの拡張モジュールからの に置き換えました。これにより、メモリ プロファイルを約 350MB に維持しながら、実行時間を 2 分強に短縮しました。

政府の仕事には十分近いと思います。これは課題であるため、コードは投稿しませんが、追加のポインターを提供できれば幸いです。

于 2012-04-10T19:47:14.663 に答える
0

ハッシュの最後の 50 ビットから文字列までの辞書を使用しないのはなぜですか?

于 2012-04-10T13:11:36.697 に答える
0

たとえば、ハッシュを 10 文字のグループに分割します。このように値をネストすると、再帰検索が行われますが、より高速になるはずです

于 2012-04-10T13:12:06.253 に答える