用于种子随机数生成的 MD5,更好的方法?
MD5 for seeded-random number generation, better approaches?
我正在制作游戏,它可能会内置于 JavaScript - 但这个问题与平台无关...
该游戏涉及随机战役的生成,但是为了阻止黑客攻击并减少保存游戏所需的存储量 space(可能是基于云的)我希望生成战役作为种子基于.
在想办法实现这一点时,我考虑了一种基于 MD5 的方法。例如,假设在游戏开始时为用户提供了随机种子 "ABC123"。在为每个游戏关卡选择使用哪个关卡模板时,我可以生成 MD5 哈希值...
MD5("ABC123" + "level1"); // = 3f19bf4df62494495a3f23bedeb82cce
MD5("ABC123" + "level2"); // = b499e3184b3c23d3478da9783089cc5b
MD5("ABC123" + "level3"); // = cf240d23885e6bd0228677f1f3e1e857
理想情况下,只有 16 个模板。还会有更多,但为了演示,如果我要从每个哈希中取出第一个字母,我会从 16 个中得到一个随机数,我可以永远用相同的种子重新生成它。
此种子的级别 1 始终为“3”(#3),级别 2 始终为 "b" (#11),级别 3 始终为 "c" (#12)
这种方法有一些缺点我相信很多人会很快指出...
- MD5 生成 CPU 密集,特别是在循环等中使用时...
- JavaScript 没有附带 MD5 加密器 - 您需要自己动手...
- 这只会给您 16 个号码 - 如果您使用其他号码,则为 128 个。你如何'round'把数字调到你要求的范围内?
- 其实我也考虑过这个。将数字除以潜力(16 或 128...),然后将其乘以所需的随机范围。只要范围保持不变,结果也将保持不变...但这也是一个限制...
考虑到这些缺点,有没有更好的方法,既简单又不需要整个框架?在我的例子中,我真正需要的只是一个 MD5 加密函数,我的实现基本完成了。
如有任何建议,我们将不胜感激。我想 "chosen answer" 将是最有用或最实用的建议或方法,考虑到我提到的所有内容。
我认为你把解决方案复杂化了。
1) 您不需要 MD5 哈希。实际上,由于在您的情况下对散列的统计质量没有兴趣,因此几乎任何散列函数都会令人满意。您可以使用任何评估成本更低的字符串哈希算法。如果您只接受 ASCII characters, then the Pearson hash 也是一个选项 - 它快速、简单且易于移植到任何语言。
2) 你真的需要用户的字符串种子,还是一个整数种子也可以接受?如果可以接受,则可以使用 integer hash function,它比字符串哈希算法快得多,而且非常简单且易于移植。
3) 任何体面的 pseudo-random 数字生成器 (PRNG) 都会为您提供具有不同种子值的完全不同的序列。这意味着随着级别的增加,您可以简单地将种子增加 1
作为 ++seed
并由此生成随机数。除了 JavaScript 的 Math.random()
之外,我建议使用自定义的简单且快速的随机数生成器。您可以使用 xorshift.
的一些变体
有了这 3 点,您列出的所有缺点都得到了解决,并且不需要框架。
我不担心黑客攻击。正如@apokryfos 在评论中指出的那样,即使是您使用 MD5 is not secure 的原始解决方案,我认为游戏中的关卡生成并不是您需要加密的最佳示例。想一想,即使是大标题商业游戏也是可以破解的。
我正在制作游戏,它可能会内置于 JavaScript - 但这个问题与平台无关...
该游戏涉及随机战役的生成,但是为了阻止黑客攻击并减少保存游戏所需的存储量 space(可能是基于云的)我希望生成战役作为种子基于.
在想办法实现这一点时,我考虑了一种基于 MD5 的方法。例如,假设在游戏开始时为用户提供了随机种子 "ABC123"。在为每个游戏关卡选择使用哪个关卡模板时,我可以生成 MD5 哈希值...
MD5("ABC123" + "level1"); // = 3f19bf4df62494495a3f23bedeb82cce
MD5("ABC123" + "level2"); // = b499e3184b3c23d3478da9783089cc5b
MD5("ABC123" + "level3"); // = cf240d23885e6bd0228677f1f3e1e857
理想情况下,只有 16 个模板。还会有更多,但为了演示,如果我要从每个哈希中取出第一个字母,我会从 16 个中得到一个随机数,我可以永远用相同的种子重新生成它。
此种子的级别 1 始终为“3”(#3),级别 2 始终为 "b" (#11),级别 3 始终为 "c" (#12)
这种方法有一些缺点我相信很多人会很快指出...
- MD5 生成 CPU 密集,特别是在循环等中使用时...
- JavaScript 没有附带 MD5 加密器 - 您需要自己动手...
- 这只会给您 16 个号码 - 如果您使用其他号码,则为 128 个。你如何'round'把数字调到你要求的范围内?
- 其实我也考虑过这个。将数字除以潜力(16 或 128...),然后将其乘以所需的随机范围。只要范围保持不变,结果也将保持不变...但这也是一个限制...
考虑到这些缺点,有没有更好的方法,既简单又不需要整个框架?在我的例子中,我真正需要的只是一个 MD5 加密函数,我的实现基本完成了。
如有任何建议,我们将不胜感激。我想 "chosen answer" 将是最有用或最实用的建议或方法,考虑到我提到的所有内容。
我认为你把解决方案复杂化了。
1) 您不需要 MD5 哈希。实际上,由于在您的情况下对散列的统计质量没有兴趣,因此几乎任何散列函数都会令人满意。您可以使用任何评估成本更低的字符串哈希算法。如果您只接受 ASCII characters, then the Pearson hash 也是一个选项 - 它快速、简单且易于移植到任何语言。
2) 你真的需要用户的字符串种子,还是一个整数种子也可以接受?如果可以接受,则可以使用 integer hash function,它比字符串哈希算法快得多,而且非常简单且易于移植。
3) 任何体面的 pseudo-random 数字生成器 (PRNG) 都会为您提供具有不同种子值的完全不同的序列。这意味着随着级别的增加,您可以简单地将种子增加 1
作为 ++seed
并由此生成随机数。除了 JavaScript 的 Math.random()
之外,我建议使用自定义的简单且快速的随机数生成器。您可以使用 xorshift.
有了这 3 点,您列出的所有缺点都得到了解决,并且不需要框架。
我不担心黑客攻击。正如@apokryfos 在评论中指出的那样,即使是您使用 MD5 is not secure 的原始解决方案,我认为游戏中的关卡生成并不是您需要加密的最佳示例。想一想,即使是大标题商业游戏也是可以破解的。