0

我知道将 Math.random() 用于加密目的是不安全的。我需要一个重构 javascript 中使用的 Math.random() 函数的示例代码来生成随机数。例如,如果我有一个由 Math.random() 生成的随机数,我怎样才能知道种子是什么?

4

1 回答 1

2

看源头。在这种情况下,它位于mozilla/js/src/jsmath.cpp 中

static const uint64_t RNG_MULTIPLIER = 0x5DEECE66DLL;
static const uint64_t RNG_ADDEND = 0xBLL;
static const uint64_t RNG_MASK = (1LL << 48) - 1;
static const double RNG_DSCALE = double(1LL << 53);

/*
 * Math.random() support, lifted from java.util.Random.java.
 */

...

extern uint64_t random_next(uint64_t *rngState, int bits)
{
    uint64_t nextstate = *rngState * RNG_MULTIPLIER;
    nextstate += RNG_ADDEND;
    nextstate &= RNG_MASK;
    *rngState = nextstate;
    return nextstate >> (48 - bits);
}

static inline double random_nextDouble(JSContext *cx)
{
    uint64_t *rng = &cx->compartment->rngState;
    return double((random_next(rng, 26) << 27) + random_next(rng, 27)) / RNG_DSCALE;
}

所以,

  1. 称呼Math.random()
  2. 乘以 2 53得到一个整数n(您需要明确使用 uint64_t)
  3. 将其拆分为 RNG 输出的(高位): top 26 bitsn>>27和 bottom 27 bits n&((1<<27)-1)
  4. 27 位可以来自一个或第二个 RNG 输出(如 C,我不认为 C++ 对此处的评估顺序有任何保证)。所以...
    • 迭代 2 21 个可能的低位。
    • 看看你是否可以通过向前向后运行 RNG 到达那里。
    • 如果是这样,则将该数字作为候选输出。

由于 RNG 的性质,可能有多个候选人。

向后运行 RNG 对读者来说是一个练习(您只需计算 0x5DEECE66D 模 2 48的乘法逆)。或者,您可以取 26 位数字并猜测所有 2 22 个可能的输入。

于 2013-02-22T23:31:15.970 回答