【问题标题】:Is generating and concatenating 3 Math.random() values more random than 1 Math.random() value?生成和连接 3 个 Math.random() 值是否比 1 个 Math.random() 值更随机?
【发布时间】:2016-11-08 18:02:06
【问题描述】:

我需要为较长的叙述中的多个句子生成唯一的 ID(其中多个用户可以同时在不同的机器上执行相同的操作)。

我考虑过使用new Date().getTime()(并且可能连接username),但由于在循环遍历句子时生成了id,我发现创建了重复项(因为生成可能发生在同一毫秒)。

所以我目前正在玩:

var random1 = Math.floor((Math.random() * 10000) + 1).toString(36);
var random2 = Math.floor((Math.random() * 10000) + 1);
var random3 = Math.floor((Math.random() * 10000) + 1);
var id = random1 + random2 + random3;
// generates things like:  
// 1h754278042
// 58o83798349
// 3ls28055962

我想到了(诚然,作为一个没有过多思考独特/随机/加密问题的人),加入三个随机数可能不再比一个随机数更随机?

生成和连接 3 个 Math.random() 值是否比 1 个 Math.random() 值更随机?

这个答案 (https://security.stackexchange.com/a/124003) 指出:

如果随机生成器真的产生随机数据,那么它不会 问题。

但我不确定这如何适用于 Math.random() 的使用。

编辑:

场景是 web 上的客户端,而不是为了安全,只是为了确保每个句子在数据库中都有一个唯一的 id。

编辑:

我最终实现了:

function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
    s4() + '-' + s4() + s4() + s4();
}

var id = guid();

发件人:https://stackoverflow.com/a/105074/1063287

另见对该答案的评论:

实际上,RFC 允许从随机创建的 UUID 数字。您只需旋转几位即可将其识别为 这样的。请参阅第 4.4 节。从 Truly 创建 UUID 的算法 随机数或伪随机数:rfc-archive.org/getrfc.php?rfc=4122

【问题讨论】:

  • 这是否在 Web 上运行客户端,您是否打算将其用于安全性?
  • @user1063287 Math.random() 目的不是为了提供唯一性
  • 它不是“更随机”,但它增加了 id 空间,因此降低了冲突的风险,但你不能保证不会有这个。
  • JS 4 now supports guid 用于唯一性

标签: javascript random


【解决方案1】:

Math.random() 返回一个带正号的 Number 值,大于或等于 0 但小于 1,随机或伪随机选择,在该范围内近似均匀分布,使用依赖于实现的算法或策略。

这是 V8 的实现:

uint32_t V8::Random() {

// Random number generator using George Marsaglia's MWC algorithm.
static uint32_t hi = 0;
static uint32_t lo = 0;

// Initialize seed using the system random(). If one of the seeds
// should ever become zero again, or if random() returns zero, we
// avoid getting stuck with zero bits in hi or lo by reinitializing
// them on demand.
if (hi == 0) hi = random();
if (lo == 0) lo = random();

// Mix the bits.
hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
lo = 18273 * (lo & 0xFFFF) + (lo >> 16);
return (hi << 16) + (lo & 0xFFFF);
}

来源:http://dl.packetstormsecurity.net/papers/general/Google_Chrome_3.0_Beta_Math.random_vulnerability.pdf

换句话说,3 个随机值不会比 1 更“随机”。

【讨论】:

  • 去年的实现是fixed
  • 如果你必须把它放在引号中,请具体并给出“(更多)随机”的定义。
【解决方案2】:

通过连接 3 个均匀分布的随机字符串,唯一改变的是更大范围的可能值。分布仍然是均匀的,因此不再是“随机”的,但它确实显着降低了碰撞的风险。然后可能值的数量将增加 36^12 或 4.7383813e+18。

您可以通过连接 12 个 base-36 数字(0-9,A-Z)获得相同的效果。

【讨论】:

  • 实际上 OP 选择连接字符串的算法并不统一,因为他没有确保恒定的长度......
【解决方案3】:

这很复杂。

由于使用随机数生成器的特定方式,第一个字符串可能相同,而第二个或第三个字符串不同。这意味着您生成的唯一字符串比仅调用Math.random() 得到的字符串更多。更多独特的字符串意味着更少的冲突,这正是您的目标。

要确认这一点,只需将大量这些字符串转储到一个文件中,然后对它们进行排序,看看第二个和第三个值是否总是随第一个值变化,或者它们是否可以独立变化(您需要在输出来查看)。

这是 PRNG 状态隐藏方式的产物;并且在几个附加之后它将停止工作。它应该(不能保证!)经过如此多的迭代,您将无法轻松对其进行测试,因此不要尝试凭经验解决。

如果你有一个非常原始的生成器算法,那么你可能会发现只要random1 等于 X,那么random2 将始终等于 Y,random3 将始终等于 Z;因此,如果您在 X 处发生碰撞,那么隐含的 Y 和 Z 也会发生碰撞,因此它们无济于事。

但大多数 PRNG(以及代码结构,因为您从每次调用中仅获取 10000 个不同的值)的状态比它们在单个调用中显示的状态大得多。这意味着即使 random1 是 X,random2random3 仍然是完全不可预测的,并且由于它们的存在而不太可能发生冲突。

但是,当您到达 random100 时,您应该开始看到您可以根据所有其他 randomXs 的值来猜测它将是什么,并且它不会生成任何字符串更独特。

然后整个问题就从种子质量和状态大小的兔子洞中消失了。基本上,随机数生成器可能很弱,以至于它只能产生少至 40 亿个唯一字符串,而在现实情况下可能要少得多。 random() 函数并非旨在解决 GUID 问题,因此它有可能会因此失败。

【讨论】:

    猜你喜欢
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 2020-08-01
    • 2021-03-22
    • 1970-01-01
    相关资源
    最近更新 更多