2

使用加密库,我可以要求该库给我一些随机字节。问题是这个字节是每个从 0 到 255(包括)的数字,因此创建均匀分布的结果并不是那么简单。

我的意思是:

该函数接收一个数字 N,即 10, 100, ... 10^b,其中 b 是一个介于 1 和 8 之间的数字(可以更大,但我不需要更大的数字)并返回一个介于 0 和给定的数字(不包括给定的数字),比如说如果 N 是 100,函数的结果是从 0 到 99,如果 N 是 10,结果是从 0 到 9。

您可以使用 Math.random 创建一个随机数,然后乘以 N,然后使用 floor。但是,Math.random 在密码学上不是安全的,因此必须使用随机生成的 2^8m 的数字来完成,其中 m 是赋予 crypto.randomBytes 的任意字节数。

我创建了一个简单的函数,显然它正在工作。但是,我知道在随机数中引入一些偏差是相当容易的,我只想对其进行验证,因为它对项目有些重要。

genera_aleatorio_residuo_potencia10 : function (n, cb) {
  var digitos = Math.log(n) / Math.LN10;
  var extra_base2 = digitos > 8 ? digitos - 8 : 0;
  if (Math.floor(digitos + .4) - digitos > 0.00000001) {
    return cb("Numero no es potencia de 10 (10, 100, 1000...)", null);
  }
  digitos = Math.round(digitos);
  async.parallel({
    r1 : crypto_helper.generador_random_bytes(1),
    r2 : crypto_helper.generador_random_bytes(1)
  }, function (err, res) {
    if (err) {
      return cb(err, null);
    }
    var r1 = res.r1[0] + 1;
    var r2 = res.r2[0] + 1;
    var aleatorio = (Math.pow(5, digitos) - 1) * Math.pow(2, extra_base2) * r1 + r2;
    cb(null, aleatorio % n);
  });
}

不用说:crypto_helper.generador_random_bytes 是 node.js 的 crypto.randomBytes 的包装器,我经常使用它来使其与异步库更友好。

我使用 Math.pow(5, digitos) 和 Math.pow(2, extra_base2) 的理由是 N 和 256 之间的最小公倍数。实际上,n 永远不会大于 100000000,所以 Math.pow( 2, extra_base2) 不应该在我们的产品中使用,但我仍然想确保它对其他人有意义。

4

2 回答 2

1

通过简单地模仿 Java 的 SecureRandom.nextInt(int) 在这里所做的事情,我找到了一个很好的解决方案:SecureRandom.nextInt(int)将尽快发布代码(我现在很忙)。我计划使用我从中开发的代码,因为我确认提出的解决方案存在偏差(根本不可接受)。

这里是JDK代码的适配。请注意 31 位数字的限制,因为我意识到 JS 对 32 位的二进制补码执行所有按位运算。我没有实现 2 数字幂的特殊情况,因为我不会使用它。解决方案是针对一般数字而不仅仅是 10 的幂...我敢肯定,对于以 10 为底的数字,必须有更好的解决方案,但无论如何。我重写了代码以不使用我的库并用英文编写,以便其他人可以更轻松地使用它。

var crypto_random_number_range = function (n, cb) {
  //result is a number from 0 a n-1
  //Javascript works with 32 bits for bitwise operations but these are signed (2-complement), so it is good to limit the size of n
  if (n <= 0 || n > 2147483647) {
    return cb("n must be larger than 0 and smaller than 2147483647", null);
  }
  var bits, val;
  async.doWhilst(
    function (cb2) {
      crypto.randomBytes(4, function (err, rbytes) {
        if (err) {
          return cb2(err);
        }
        bits = ((rbytes[3] & 0x7f) << 24) + 
          (rbytes[2] << 16) + (rbytes[1] << 8) + rbytes[0];
        val = bits % n;
        cb2();
      });
    }, function () {
      return (bits - val + (n-1)) < 0;
    }, function (err) {
      if (err) {
        return cb(err, null);
      }
      return cb(null, val);
    }
  );
}

做了几次测试,似乎工作正常。

于 2013-08-16T22:52:10.220 回答
-3
var kazutsukuru = function kazutsukuru(kaketeiruno, kotae) {
  crypto.randomBytes(4, function(mondai, baito) {
    if (mondai) {
      return kotae(mondai);
    }

    kotae(null, Math.floor(baito.readUInt32BE(0) / 4294967296 * kaketeiruno));
  });
};

这应该做你想要的。我决定让我的答案难以阅读,因为您的问题很难阅读。

于 2013-08-16T22:20:01.903 回答