【问题标题】:6 Character Short Hash Algorithm6 字符短散列算法
【发布时间】:2013-08-30 03:30:45
【问题描述】:

我的目标是为长度为 42 个不区分大小写的字母数字字符的字符串生成一个 6 个字符的短哈希字符串(可能包含字符 [A-Z][a-z][0-9])。唯一性是关键要求。安全性或性能并不那么重要。

是否有特定的算法可以给出这个结果,还是我应该坚持截断 MD5 哈希或 SHA-1 哈希 (Like in this question)?如果有,发生碰撞的概率是多少?

【问题讨论】:

  • 我试过了,string sourceString = "SomeTestStringWhichIs42CharactersInLength!"; Console.WriteLine(sourceString.GetHashCode().ToString("X6"));它返回一个 8 字符哈希。
  • 如何为 42 字符长的字符串生成唯一的 6 字符哈希?
  • 根据您的限制,您可以(最多)散列 62^6 个数字而不会发生冲突。尽管在散列了一半之后,您将有 50% 的碰撞机会(充其量)。取决于要散列的数据和散列算法 - 当然。一些算法在不同的数据集下会做得更好

标签: c# hash md5 sha


【解决方案1】:

简单的哈希:)

private string Hash(string str)
{
    var allowedSymbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
    var hash = new char[6];

    for (int i = 0; i < str.Length; i++)
    {
        hash[i % 6] = (char)(hash[i % 6] ^ str[i]);
    }

    for (int i = 0; i < 6; i++)
    {
        hash[i] = allowedSymbols[hash[i] % allowedSymbols.Length];
    }

    return new string(hash);
}

【讨论】:

  • 由于hash[i % 6] ^ str[i]这里的异或,这个算法有很高的冲突率。 OP 声明输入字符串不区分大小写,对于 a-z 和 A-Z,所有字符的最高两位都是相同的。即使您使用了所有正常的可打印 ASCII 字符 (0x20-0x7e),对于 66% 的字符集,前两位仍然相同。
  • 非常适合我。我必须根据名称和嵌套元素的程度生成颜色。 jsfiddle.net/fgg8xx2k 示例是用 Typescript 编写的
  • 我发现这个功能对我的使用非常有用,但它确实存在碰撞率高的问题。我的解决方案是先使用 MD5 对我的 str 进行哈希处理,然后使用此函数获得用户友好的输出。它似乎为我解决了这个问题。
【解决方案2】:

您最好的选择是截断众所周知的散列函数(MD5 或 SHA 系列),因为这些算法具有统计上良好的散列值均匀分布(并且还使用完整的散列,而不仅仅是 6 个字符)。

现在计算碰撞概率

- 英文字母数量:26 - 添加大写字母:26 - 添加数字:10 -------------- 总共你得到 26 + 26 + 10 = 62 个字符。 现在您有 6 个位置,这为您提供了 62^6 种可能的组合。 即 56.800.235.584 ~ 570 亿个组合。 这是一个可能的哈希值空间 - N。 -------------- 要计算碰撞让我们使用公式 Pcollision = K^2 / 2N 这是碰撞概率的一个非常粗略的近似值

现在让我们看看一个表中多个项目的结果表 - K

# 项目 |碰撞概率 -------------------------------------- 10 | 1.7 * 10^-9 100 | 1.7 * 10^-7 1K | 1.7 * 10^-5 10K | 1.7 * 10^-3 100K | 0.17

这个公式只能用于小 K,但它表明给定哈希表中的 100K 个条目,您大约有 17% 的机会发生冲突。

链接

Collision probability

【讨论】:

  • 感谢您的指导性评论。但我认为您在表中计算了Pcollision = K^2 / N 而不是Pcollision = K^2 / 2N
【解决方案3】:

最好的解决方案几乎可以肯定是使用 SHA1,转换为 Base62(尽管 Base64 会更容易,因为它内置在框架 Convert.ToBase64String 中。你必须做一些寻找合适的 Base62 库),并且然后将输出截断为 6 个字节。

我不会使用GetHashCode(),因为它有一个history of collision problems。 (我并不是要声称这个特定的错误会适用于您,只是将此作为GetHashCode 过去没有很好实施的证据。)

我也不会实现自定义散列算法,很容易意外编写具有高冲突率的算法。 SHA1 和其他主要的散列算法已经进行了大量的研究和审查,你很难想出更好的方法。

【讨论】:

    猜你喜欢
    • 2014-03-25
    • 2015-05-02
    • 2020-07-14
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 2012-09-03
    • 1970-01-01
    • 2023-03-23
    相关资源
    最近更新 更多