Hash 寻找UTF16中文件路径的良好64位哈希

Hash 寻找UTF16中文件路径的良好64位哈希,hash,path,collision,utf-16,hash-collision,Hash,Path,Collision,Utf 16,Hash Collision,我有一个Unicode/UTF-16编码路径。路径分隔符为U+005C'\'。 路径是以null结尾的根相对windows文件系统路径,例如“\windows\system32\drivers\myDriver32.sys” 我想将此路径散列为64位无符号整数。 它不需要是“加密声音”。 散列应该不区分大小写,但能够处理非ascii字母。 显然,散列也应该分散得很好 我有一些想法: A) 将windows文件标识符用作“哈希”。在我的例子中,如果文件被移动,我确实希望哈希值改变,所以这不是一个选

我有一个Unicode/UTF-16编码路径。路径分隔符为U+005C'\'。 路径是以null结尾的根相对windows文件系统路径,例如“\windows\system32\drivers\myDriver32.sys”

我想将此路径散列为64位无符号整数。 它不需要是“加密声音”
。 散列应该不区分大小写,但能够处理非ascii字母。 显然,散列也应该分散得很好

我有一些想法:

A) 将windows文件标识符用作“哈希”。在我的例子中,如果文件被移动,我确实希望哈希值改变,所以这不是一个选项

B) 只需对整个字符串使用一个常规的sting散列:hash+=prime*散列+代码点

我确实觉得路径由“分段”(文件夹名和最终文件名)组成这一事实是可以利用的

总结一下需要:

1) 64位哈希值
2) 良好的分发/文件系统路径冲突较少。
3) 高效的
4) 不需要是安全的

5) 不区分大小写的

加密安全哈希在速度方面可能不是很有效,但实际上任何编程语言都有可用的实现。
对于您的应用程序来说,使用它们是否可行取决于您对速度的依赖程度——基准测试将为您提供适当的答案

您可以使用此类散列的子字符串,例如路径上的MD5,该字符串以前已转换为小写,因此散列实际上不区分大小写(要求您使用小写方法,该方法知道如何转换文件系统中可能出现的所有UTF-16非标准字符)


加密安全散列的好处是,无论您使用哪个子字符串部分,其分布都相当均匀,因为它们被设计为不可预测的,即散列的每个部分理想地取决于整个散列数据,就像散列的任何其他部分一样。

即使您不需要加密散列,也可以使用一个,既然你的问题不是关于安全性,那么一个“坏的”加密散列就可以了。我建议,这很快。在我的PC(2.4 GHz CORE2系统,使用一个核心),M4哈希超过700 Mb/s,甚至对于小的输入(小于50字节),它可以处理大约8万条消息秒。您可能会发现更快的非加密散列,但它已经需要一个相当具体的情况下,它作出了可衡量的差异

对于您所追求的特定属性,您需要:

  • “规范化”字符,以便将大写字母转换为小写字母(不区分大小写)。注意,一般来说,Unicode世界中的大小写不敏感不是一件容易的任务。根据您的解释,我推断您只是在追求Windows用于文件访问的那种大小写不敏感(我认为它只是ASCII,所以转换大写->小写很简单)

  • 截断MD4的输出。MD4产生128位;只需使用前64位。这将是分散的,因为你可以希望


  • 5月份有MD4实现,包括上面的RFC1320 I链接。您还可以在中找到C和Java中的开源MD4实现。

    我只想使用一些简单明了的东西。我不知道您使用的是什么语言,因此以下是伪代码:

    ui64 res = 10000019;
    for(i = 0; i < len; i += 2)
    {
      ui64 merge = ucase(path[i]) * 65536 + ucase(path[i + 1]);
      res = res * 8191 + merge; // unchecked arithmetic
    }
    return res;
    
    ui64 res=10000019;
    对于(i=0;i
    我假设
    path[I+1]
    是安全的,因为如果
    len
    是奇数,那么在最后一种情况下,它将安全地读取U+0000


    我不会利用UTF-16中的空白、小写和标题字符以及路径无效字符造成的空白这一事实,因为这些并没有以一种可以快速使用的方式分布。减少32(U+0032以下的所有字符在路径名中都是无效的)不会太贵,但也不会太多地改进哈希。

    您可以在C#中创建一个共享库,并使用FileInfo类获取目录或文件的完整路径。然后在路径中使用.GetHashCode(),如下所示:

    Hash = fullPath.GetHashCode();
    


    虽然这只是一个32位的代码,但您可以复制它或根据文件的某些其他特征附加另一个哈希代码。

    谢谢-但MD5和我所知道的任何其他“加密哈希”都大于64位。我得把钥匙空间折叠起来。我确实有一个方法,它是基于Unicode 5.1的小写字符串,速度非常快。是的,就像我说的,你必须使用MD5的64位子字符串。或者,看看这个问题:是的,这会起作用-我被“sub-sting”弄糊涂了-我认为它指的是文件路径,而不是结果哈希。选择这个是因为这似乎是我的最佳解决方案,并且在通信中有很好的后续效果!谢谢是的,加密散列本身不一定是坏的,因此我建议在必要时做一些基准测试进行评估。一些加密库可能会逐步取消MD4支持,因为它被认为是不安全的,因此广泛实现的MD5在可移植性和兼容性方面可能是未来的证明。据我所知,Windows支持NTFS和VFAT的Unicode文件系统名称(UTF-16;根据Wikipedia,NTFS使用16位字符,这些字符可能(但不一定)是UTF-16)。实际上,每个NTFS卷都有一个大写映射,文件系统驱动程序使用它进行不区分大小写的比较。关于速度,Java在我链接到的相关问题中使用的哈希代码对于编译语言(包括C/C++和Java)-对于dyna来说可能也是一个足够好的哈希代码
    int getHashCode(string uri) 
    {
       if (uri == null) throw new ArgumentNullException(nameof(uri));
    
       FileInfo fileInfo = new FileInfo(uri);
       return fileInfo.FullName.GetHashCode();
    }