C# 从UInt32到UInt16的简单、可重复的哈希

C# 从UInt32到UInt16的简单、可重复的哈希,c#,hash,C#,Hash,我有一个小问题,需要把一个大约10位数的数字散列成一个6位数的数字。散列需要是确定性的 更重要的是,散列不是资源密集型的 例如,假设我有一些数字,x,比如123456789 我想写一个散列函数,它给我一个数字y,比如987654 然后我想要一个函数,它将x和y作为参数,在x上重新应用散列,并检查结果是否为y 在给定哈希值的情况下,应该很难计算可能的输入值 我的第一个想法是将成对的数字相乘,结果产生了大量重复的散列值 我觉得这类问题有某种优雅的解决方案,但我自己就是想不出来 有人能帮我吗?提前感谢

我有一个小问题,需要把一个大约10位数的数字散列成一个6位数的数字。散列需要是确定性的

更重要的是,散列不是资源密集型的

例如,假设我有一些数字,x,比如123456789

我想写一个散列函数,它给我一个数字y,比如987654

然后我想要一个函数,它将x和y作为参数,在x上重新应用散列,并检查结果是否为y

在给定哈希值的情况下,应该很难计算可能的输入值

我的第一个想法是将成对的数字相乘,结果产生了大量重复的散列值

我觉得这类问题有某种优雅的解决方案,但我自己就是想不出来


有人能帮我吗?提前感谢:

丢弃较低的16位或最后4位怎么样

1234567890 --> 123456

只需将整数除以10000即可轻松完成。

您需要的是散列

试试CRC16

X>>16^X&0xFFFF


….

您要做的是尝试在整个范围内尽可能均匀地分布散列值。一些内置的散列方法在这方面做得相当好,因此您可以尝试获取字符串表示的散列代码,并简单地丢弃一半位:

ushort code = (ushort)value.ToString().GetHashCode();
但是,这也取决于您将使用哈希代码的目的。内置的哈希代码不打算永久存储。计算哈希代码的算法可能会随着框架的任何新版本而改变,因此,如果将哈希代码存储在数据库中,它们将来可能会变得无用。在这种情况下,您将不得不自己从头开始创建哈希算法,或者使用一些为永久存储设计的哈希算法

用于框架中某些值的哈希代码的一个简单算法是,当哈希代码小于数据时,使用异或使值中的所有位都重要:

byte[] b = BitConverter.GetBytes(value);
ushort code = (ushort)(BitConverter.ToUInt16(b, 0) ^ BitConverter.ToUInt16(b, 2));
或者更有效但不太明显的方法:

ushort code = (ushort)((value >> 16) ^ value);
对于小值,这当然没有模糊属性,因此您可能希望加入一些随机位,以使哈希代码与值显著不同:

ushort code = (ushort)(0x56D4 ^ (value >> 16) ^ value);

你所说的问题是无法解决的

您说您希望系统有点难以破坏,我认为您的意思是,攻击者获取已知摘要并从中生成可能的输入(哈希到给定摘要)有点困难。由于在您建议的系统中只有40亿个可能的输入和65536个可能的散列,因此无论散列算法是什么,查找与给定散列相对应的消息都是非常简单的。平均而言,攻击者将有大约65000条可能的消息可供选择,因此可以选择最适合其邪恶计划的消息

我预计在散列分解空间中会出现一些困难的问题,比如说,投入价值数百万美元的超级计算机时间来分解。你的建议可能会被没有经验的高中生打破,他们编写Javascript程序需要几分钟的时间,最多可能需要一分钟的时间;这甚至还没有模糊地接近于某种程度上的困难


为什么要在算法上选择如此微小的限制,这些限制本质上会使打破散列变得微不足道?就这一点而言,对如此少量的数据(如32位整数)进行哈希运算的价值是什么?

哈希运算的要点是很难轻松构建另一个副本,我认为这就是OP所说的加密。这个方法没有太大的帮助,但是他没有说太多关于他打算用这个值做什么,在这种情况下,我倾向于使用最简单的可能的解决方案来满足口头需求。此外,考虑到对于每个唯一的16位输出,假设输入到输出的映射是均匀分布的,则将有65536个输入值映射到该输出。所以无论如何都会有重复。对不起,我没有很好地描述我的问题。我尝试添加一个示例来澄清。我需要一个比这更难破解的加密/散列。将32位数字拆分为两个16位数字,反转其中一个,然后对两个进行异或,怎么样?在任何情况下,正如其他人所建议的那样,像CRC16这样的东西可能会很好地工作。您还没有完全清除数据输入和输出,您希望得到10个二进制数字吗?十进制数字?等但是,我可以说,如果您希望将0000000000到99999999转换为000000到9999999,那么如果没有一些别名重复值,就无法完成转换。如果您真的想将其转换为uint16,那么使用简单的CRC16几乎与任何其他CRC16一样好。代码古德:试图更好地澄清这个问题——我会去谷歌CRC
16同时,不管怎样,只要将其转换为较小的类型,就可以获得大量的副本,在本例中,最多值2^16。如果你真的想最小化重复,它将非常依赖于你的原始值的范围-基于此,你可以尝试提出一个算法。如果没有这些具体的信息,这里你能期望的最好的是一个通用算法,它可能仍然会为你产生大量的重复。确实,许多重复是不可避免的,但是我的第一次尝试给出了大约1/3的结果,这非常糟糕!我想我现在有了一个可行的解决方案,所以谢谢你的帮助。TBH我仍然不太明白为什么这叫做散列而不是加密,但我要去查字典!加密意味着有一个称为解密的对应操作,因此该操作不能有损。另一方面,散列是有损的;这是关于生成一个具有消息特征的摘要。感谢您的代码和解释!在混合中加入一个秘密号码会给方法增加一个简单的额外的保密元素。我将实施这种方法。另外,有趣的一点是,框架中的内置哈希算法可能会发生变化。