如何使用2 ^ 50个元素处理dict变量?

时间:2012-04-10 13:04:00

标签: python hash dictionary ram

我必须找到2 ^ 25个随机字符串的SHA256哈希值。然后寻找碰撞(使用生日悖论的最后一个,比如说只有50位的散列)。

我将字符串:hash对存储在dict变量中。然后用值(而不是键)对变量进行排序,然后使用O(n)循环查找碰撞。

问题在于,由于有2 ^ 25个字符串及其2 ^ 25个哈希值,因此dict变量中包含2 ^ 50个值。这是非常耗费资源的。那么,我如何使用有限的内存,比如大约1GB呢?

我已经尝试过:
1.使用6GB交换空间运行它。该程序一夜之间运行,但仍未完成。这基本上比O(n_square)搜索更慢!哈希计算的RAM使用量约为3.2 GB。但在那之后,当涉及到sort命令时,使用的RAM再次开始拍摄!我虽然python排序使用In-Place-Quicksort :(
我只存储了哈希并发现了碰撞。但找不到相应的字符串,因为没有存储它。

我不应该使用数据库等。最多是一个文本文件,但这没有帮助。另外,我对Python很陌生,但不要限制你的答案水平。

PS:这是一项任务。有人声称在一分钟内发现了300MB RAM的冲突。不知道这是不是真的。我已经解决了问题,但答案无法实现! 在工作中,所以现在无法访问代码。将很快添加。

代码:

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()

5 个答案:

答案 0 :(得分:3)

我会选择这样的事情:

打开16个文件(以二进制模式打开应该没问题;如果所有字符串都具有相同的长度,这将是最简单的)。生成字符串和散列,并根据散列的前4位将它们写入文件。然后单独加载和处理每个文件。这将使内存使用量减少16倍。(当然,只要不用完文件句柄,就可以使用任意数量的文件。每次访问时打开和关闭每个文件都会变得相当慢。)

如果生成字符串和哈希值相对便宜,则甚至不需要这些文件。只需要进行16次传球,并且在每次传球中只保留散列上半球的传球号码。

答案 1 :(得分:2)

解决问题的一种方法是使用很长的位域,以便每个哈希都映射到2^25 长内存块中的某个位置。

通过Bloom filter或其他概率数据结构来解决此类问题的更好但非100%保证的方式。

  

布隆过滤器是一种节省空间的概率数据结构,用于测试元素是否是集合的成员。假阳性是可能的,但假阴性不是;即查询返回“内部设置(可能是错误的)”或“绝对不设置”。

     

Bloom过滤器比其他数据结构具有强大的空间优势,可用于表示集合,例如自平衡二进制搜索树,尝试,哈希表或简单数组或条目的链接列表。

     

1%错误的布隆过滤器每个元素只需要大约9.6位 - 无论元素的大小如何。

因此,每2 ^ 25个元素9.6位,只需要38.4 MiB的内存。

答案 2 :(得分:1)

我认为这里的关键洞察力 - 我承认有一段时间回避我,直到几个小时后才回到这里 - 是sha256哈希摘要是它自己的哈希< / em>的。换句话说,您不必进行任何其他散列或集创建。您所要做的就是使用sha256摘要作为哈希创建自定义哈希表。为了节省空间,请不要存储字符串;只需创建一个位数组(对使用table = numpy.zeros(table_size / bits_per_int + 1, dtype='i')创建的整数数组中的整数使用移位运算)来检测冲突,然后将冲突中的碰撞字符串保存到字符串中,以便在第二次传递中查找字符串。

table_size应该是一个很大的素数 - 我选择了一个稍大于2 ** 31的数据,这就是268MB的表 - 因为这会产生很少的新碰撞/误报(由模运算引入)在哈希)。您可以将字符串本身保存到文本文件中,您可以迭代它。

因此,对于任何字符串,要设置的相应位的索引将为index = int(hashlib.sha256('foo').hexdigest(), base=16) % table_size。然后计算major_index = index / bits_in_intminor_index = index % bits_in_int,在minor_index上使用shift和bitwise操作来检查并在table[major_index]处的int中存储正确的位,依此类推。

现在对字符串进行传递。每当字符串生成映射到已设置的位的散列时,将hash:string对存储在字典中。或者更好的是,存储hash:[string_list]对,在多次碰撞的情况下将新字符串附加到列表中。现在对于任何碰撞的字符串对(a,b),字典将包含b的散列和值。然后执行第二次遍历字符串,依次散列,并检查每个散列的字典。如果散列位于字典中,并且字符串不在相应列表中,请将该字符串添加到列表中。字典中的一些字符串与真正的碰撞不对应;大多数哈希值的[string_list]只有一个项目长,而hash:[string_list]对可能会被丢弃。其他可能是由哈希函数本身产生的真实冲突,而不是模数运算。但是,在那些既有真实也有误报的情况下,你可能仍然会有一些误报。你必须仔细检查结果列表是否有误报。

BasicWolf建议使用布隆过滤器是一个很好的建议,可能会导致一个较小的表。但它增加了许多复杂性;我没打扰。我尝试了从'0\n''33554431\n'的以换行符结尾的字符串的上述方法,并找到了两个具有54位重叠的哈希值。花了11分钟,最大内存使用量大约为350MB(尽管可能会减少。)我做了一些分析,发现大部分时间花在计算位表的偏移量上。在c中编码可能会提供显着的加速,预先散列和存储哈希以及字符串也会有所帮助。

事实上,我尝试对字符串进行预处理,并使用same name的基于c的扩展模块中的numpy替换了我的基于bitarray的基于比特阵列的比特阵列。 。这将运行时间缩短到2分钟以上,同时保持内存配置文件只有350MB左右。

我认为足够接近政府工作。由于这是一项任务,我不会发布代码,但我很乐意提供额外的指示。

答案 3 :(得分:0)

为什么不使用最后50位的字典到字符串?

答案 4 :(得分:0)

例如以10个字符为一组拆分散列。并以这种方式嵌套值,您将进行递归搜索,但它应该更快