我知道将 Math.random() 用于加密目的是不安全的。我需要一个重构 javascript 中使用的 Math.random() 函数的示例代码来生成随机数。例如,如果我有一个由 Math.random() 生成的随机数,我怎样才能知道种子是什么?
问问题
678 次
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;
}
所以,
- 称呼
Math.random()
- 乘以 2 53得到一个整数
n
(您需要明确使用 uint64_t) - 将其拆分为 RNG 输出的(高位): top 26 bits
n>>27
和 bottom 27 bitsn&((1<<27)-1)
。 - 27 位可以来自第一个或第二个 RNG 输出(如 C,我不认为 C++ 对此处的评估顺序有任何保证)。所以...
- 迭代 2 21 个可能的低位。
- 看看你是否可以通过向前或向后运行 RNG 到达那里。
- 如果是这样,则将该数字作为候选输出。
由于 RNG 的性质,可能有多个候选人。
向后运行 RNG 对读者来说是一个练习(您只需计算 0x5DEECE66D 模 2 48的乘法逆)。或者,您可以取 26 位数字并猜测所有 2 22 个可能的输入。
于 2013-02-22T23:31:15.970 回答