C# 32位快速统一哈希函数。使用MD5/SHA1并截断4个字节?
可能重复:C# 32位快速统一哈希函数。使用MD5/SHA1并截断4个字节?,c#,.net,C#,.net,可能重复: 我需要将许多字符串散列到32位(uint) 我可以使用MD5或SHA1并从中获取4个字节吗?还是有更好的选择 不需要安全,也不需要关心是否有裂缝等等。 我只需要快速和统一地散列到32位。MD5和SHA1应一致 但是,我是否可以使用更好(更快)的内置替代方案?如果不是,你会使用哪一种 这里有人问哪一个更好,但没有其他选择,有一个安全问题(我不关心安全): 如果安全性不起作用,则使用加密哈希函数(如MD5或SHA1)生成一个哈希并从中提取4个字节即可。但它们比各种非加密散列函数慢,因为
我需要将许多字符串散列到32位(uint) 我可以使用MD5或SHA1并从中获取4个字节吗?还是有更好的选择 不需要安全,也不需要关心是否有裂缝等等。 我只需要快速和统一地散列到32位。MD5和SHA1应一致 但是,我是否可以使用更好(更快)的内置替代方案?如果不是,你会使用哪一种 这里有人问哪一个更好,但没有其他选择,有一个安全问题(我不关心安全):
如果安全性不起作用,则使用加密哈希函数(如MD5或SHA1)生成一个哈希并从中提取4个字节即可。但它们比各种非加密散列函数慢,因为这些函数主要是为安全而设计的,而不是为了速度 请看一看非加密散列函数,例如或
- 非加密散列函数Zoo
- 性能图
编辑:floodyberry.com域现在由域停车服务注册-删除死链接最简单但很好的字符串算法如下:
int Hash(string s)
{
int res = 0;
for(int i = 0; i < str.Length; i++)
{
res += (i * str[i]) % int.MaxValue;
}
return res;
}
int散列(字符串s)
{
int res=0;
对于(int i=0;i
显然,这绝对不是一个安全的哈希算法,但它很快(真的很快)返回32位,而且据我所知,是统一的(我已经尝试了许多算法挑战,并取得了很好的结果)
不用于散列密码或任何合理数据。是否需要加密强度散列?如果你只需要32位,我打赌不会 试试Fowler-Noll-Vo散列。它速度快,具有良好的分布和雪崩效应,通常可用于哈希表、校验和等:
public static uint To32BitFnv1aHash(this string toHash,
bool separateUpperByte = false)
{
IEnumerable<byte> bytesToHash;
if (separateUpperByte)
bytesToHash = toHash.ToCharArray()
.Select(c => new[] { (byte)((c - (byte)c) >> 8), (byte)c })
.SelectMany(c => c);
else
bytesToHash = toHash.ToCharArray()
.Select(Convert.ToByte);
//this is the actual hash function; very simple
uint hash = FnvConstants.FnvOffset32;
foreach (var chunk in bytesToHash)
{
hash ^= chunk;
hash *= FnvConstants.FnvPrime32;
}
return hash;
}
public static class FnvConstants
{
public static readonly uint FnvPrime32 = 16777619;
public static readonly ulong FnvPrime64 = 1099511628211;
public static readonly uint FnvOffset32 = 2166136261;
public static readonly ulong FnvOffset64 = 14695981039346656037;
}
publicstaticuint到32bitfnv1ahash(这个字符串到hash,
bool separateUpperByte=false)
{
i可由testohash计算;
if(separateUpperByte)
bytesToHash=toHash.ToCharArray()
.选择(c=>new[]{(字节)((c-(字节)c)>>8),(字节)c})
.SelectMany(c=>c);
其他的
bytesToHash=toHash.ToCharArray()
.选择(转换为ToByte);
//这是实际的哈希函数;非常简单
uint hash=FnvConstants.FnvOffset32;
foreach(bytesToHash中的var块)
{
hash^=块;
散列*=FnvConstants.fnprime32;
}
返回散列;
}
公共静态类FnvConstants
{
公共静态只读单元FnvPrime32=16777619;
公共静态只读ulong FnvPrime64=1099511628211;
公共静态只读uint FnvOffset32=2166136261;
公共静态只读ulong FnvOffset64=14695981039346656037;
}
这对于基于每个对象的字符串摘要(自定义ToString()或其他)为GetHashCode创建语义上相等的哈希非常有用。您可以重载此函数以获取任何
IEnumerable
,使其适用于校验和流数据等。如果您需要64位哈希(ulong),只需复制函数并用64位常量替换使用的常量即可。哦,还有一件事;散列(和大多数一样)依赖于未检查的整数溢出;千万不要在“checked”块中运行此散列,否则它几乎肯定会抛出异常。CRC(或相关)是否适合此用途?还有的问题。
?.GetHashCode()可以在.Net版本中更改,但我需要值保持不变。此外,我的大多数字符串都不短。String.GetHashCode()的返回值在.NET Framework的32位和64位版本之间也有所不同,因此实际上,除了进程内相等之外,您不应该依赖它;如果您必须持久化哈希或使用由另一个进程或运行时生成的哈希,您应该使用自己的哈希。因此,您是否要将此哈希持久化到比进程更长的时间?此算法具有极差的雪崩特性。一个简单的算法只需求解最大的C(重复字符十进制值)和N(字符串长度),其中CN(N+1)/2
和minLength
,然后增加字符值,最右边的第一个,保持在目标哈希下和可打印字符代码内,直到哈希完全匹配。正如我所说,速度是关键。安全不是问题。这仅适用于使用哈希表快速检索字符串。