Mathematica使用的默认哈希码是什么?

时间:2010-10-28 03:33:12

标签: hash wolfram-mathematica

在线文档说

Hash[expr] 
  gives an integer hash code for the expression expr.
Hash[expr,"type"]
  gives an integer hash code of the specified type for expr.

它还提供“可能的哈希码类型”:

  • “Adler32”Adler 32位循环冗余校验
  • “CRC32”32位循环冗余校验
  • “MD2”128位MD2代码
  • “MD5”128位MD5代码
  • “SHA”160位SHA-1代码
  • “SHA256”256位SHA代码
  • “SHA384”384位SHA代码
  • “SHA512”512位SHA代码

然而,这些都不符合Hash[expr]返回的默认值。

所以我的问题是:

  • 默认Hash使用什么方法?
  • 是否内置了其他哈希码?

3 个答案:

答案 0 :(得分:9)

默认的哈希算法或多或少是应用于底层表达式表示的基本32位哈希函数,但确切的代码是Mathematica内核的专有组件。它受Mathematica版本之间的(并且已经)更改,并且缺少许多令人满意的加密属性,因此我个人建议您使用MD5或其中一种SHA变体用于任何安全问题的严重应用程序。内置散列用于典型的数据结构使用(例如,在散列表中)。

您从文档中列出的命名哈希算法是目前唯一可用的哈希算法。你特别想找另一个吗?

答案 1 :(得分:5)

我已经在32和64位Windows版本的Mathematica 10.4上做了一些逆向工程,这就是我发现的:

32 BIT

它使用Fowler–Noll–Vo hash function(FNV-1,前面有乘法),16777619作为FNV素数,84696351作为偏移基础。此函数应用于表达式数据地址的Murmur3-32哈希值(MMA使用指针以保留每个数据的一个实例)。地址最终被解析为值 - 对于简单的机器整数,值是立即的,对于其他人来说有点棘手。 Murmur3-32实现函数实际上包含一个附加参数(默认为4,特殊情况下的行为与维基百科一样),它选择从输入中的表达式struct中选择多少位。由于普通表达式在内部表示为指针数组,因此可以通过重复将4(字节= 32位)添加到表达式的基指针来获取第一个,第二个等。因此,将8传递给函数将给出第二个指针,12给第三个指针,依此类推。因为内部结构(大整数,机器整数,机器实数,大实数等)具有不同的成员变量(例如,机器整数只有一个指向int的指针,一个指向数字的复杂2指针......),对于每个表达式结构有一个"包装"将其内部成员合并为一个32位散列(基本上与FNV-1轮次)。散列的最简单表达式是整数。

murmur3_32()函数有1131470165作为种子,n = 0和维基百科中的其他参数。

所以我们有:

  hash_of_number = 16777619 * (84696351‬ ^ murmur3_32( &number ))

与" ^"意思是XOR。 我真的没有尝试过 - 指针是使用WINAPI EncodePointer()编码的,因此它们无法在运行时被利用。 (可能值得在Wine下使用EncodePonter的修改版本在Linux下运行?)

64 BIT

它使用FNV-1 64位散列函数,其中0xAF63BD4C8601B7DF作为偏移基础,0x100000001B3作为FNV素数,以及SIP64-24散列(here&#39}的参考代码)第一个64位的0x0AE3F68FE7126BBF76F98EF7F39DE1521为k0,最后的64位为k1。该函数应用于表达式的基指针并在内部解析。与32位的murmur3一样,还有一个额外的参数(默认为8)来选择从输入表达式struct中选择多少指针。对于每个表达式类型,都有一个包装器,通过FNV-1 64位轮将结构成员压缩成单个哈希。

对于机器整数,我们有:

    hash_number_64bit = 0x100000001B3 * (0xAF63BD4C8601B7DF ^ SIP64_24( &number ))

同样,我没有真正尝试过。有人可以试试吗?

不适合胆小的

如果您查看他们的notes on internal implementation,他们会说"每个表达式都包含一种特殊形式的哈希码,用于模式匹配和评估。"

他们引用的哈希码是由这些函数生成的哈希码 - 在普通表达式包装函数的某个点上,有一个赋值将计算的哈希放在表达式结构本身中。

理解他们如何利用这些哈希进行模式匹配目的肯定会很酷。所以我试着通过bigInteger包装器来看看会发生什么 - 这是最简单的复合表达式。 它开始检查返回1的东西 - 不知道什么。 所以它执行

    var1 = 16777619 * (67918732 ^ hashMachineInteger(1));

使用hashMachineInteger()就是我们之前所说的 - 包括值。

然后它从struct(bignum_length)读取bigInt的字节长度并运行

    result = 16777619 * (v10 ^ murmur3_32(v6, 4 * v4));

请注意,如果murmur3_32()大于8,则会调用4 * bignum_length(可能与机器整数$MaxMachineNumber 2^32^32的最大值有关,并且与bigInt相反应该是)。

所以,最终的代码是

    if (bignum_length > 8){

    result = 16777619 * (16777619 * (67918732 ^ ( 16777619 * (84696351‬ ^ murmur3_32( 1, 4 )))) ^ murmur3_32( &bignum, 4 * bignum_length ));
    }

我对这种结构的属性做了一些假设。许多XOR的存在以及16777619 + 67918732 = 84696351‬可能使人认为某种循环结构被用来检查模式的事实 - 即减去偏移并除以素数或类似的东西。 Cassandra软件使用Murmur哈希算法进行令牌生成 - 请参阅these images我的意思"循环结构"。也许每个表达都使用各种素数 - 必须仍然检查。

希望有所帮助

答案 2 :(得分:2)

似乎Hash调用内部Data`HashCode函数,然后将其除以2,得到N [..]的前20位数,然后是IntegerPart,加上1,即:

    IntegerPart[N[Data`HashCode[expr]/2, 20]] + 1