简体   繁体   English

使用node.js生成10的幂模的cryptographc随机数

[英]Generating cryptographc random number for modulus of powers of 10 with node.js

Using the crypto library I can require the library to give me a number of random bytes. 使用加密库,我可以要求该库给我一些随机字节。 The thing is that this bytes are numbers from 0 to 255 each (inclusive) and thus it is not that simple to create a uniformly distributed results. 关键在于,这些字节分别是0到255之间的数字(包括0和255),因此创建均匀分布的结果并不是那么简单。

What I mean is the following: 我的意思是:

The function receives a number N, which is 10, 100, ... 10^b, where b is a number between 1 and 8 (could be bigger, but I don't need anything larger) and returns a number between 0 and the given number (not inclusive to the given number), so say if N is 100, the results of the function are from 0 to 99, and if N is 10 the results are from 0 to 9. 该函数接收数字N,该数字是10、100,... 10 ^ b,其中b是1到8之间的数字(可以更大,但我不需要更大),并返回0到0之间的数字。给定数字(不包括给定数字),因此,如果N为100,则函数的结果为0到99,如果N为10,则结果为0到9。

You can create a random number by using Math.random and just multiplying by N and then using floor. 您可以使用Math.random创建一个随机数,然后乘以N,然后使用下限。 However, Math.random is not cryptographically safe, so it must be done by using randomly generated number that are of 2^8m, where m is just whatever number of bytes is given to crypto.randomBytes. 但是,Math.random在密码上并不安全,因此必须使用随机生成的2 ^ 8m的数字来完成,其中m就是为crypto.randomBytes提供的字节数。

I created a simple function which is working, apparently. 我创建了一个可以正常工作的简单函数。 However, I am aware that it is fairly easy to induce some bias into random numbers and I would just like to have it validated, since it is somewhat important for the project. 但是,我知道在随机数上引入一些偏差是很容易的,并且我想对其进行验证,因为这对于项目来说有些重要。

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);
  });
}

Needless to say: crypto_helper.generador_random_bytes is a wrapper of node.js' crypto.randomBytes that I frequently use to make it friendlier with the async library. 不用说:crypto_helper.generador_random_bytes是node.js的crypto.randomBytes的包装,我经常使用它来使其与异步库更加友好。

My reasoning for using Math.pow(5, digitos) and the Math.pow(2, extra_base2) is for the least common multiple between N and 256. In practice, n will never be larger than 100000000, so the Math.pow(2, extra_base2) shouldn't be used in our product, but I would still like to be sure it makes sense to other people. 我使用Math.pow(5,digitos)和Math.pow(2,extra_base2)的原因是N和256之间的最小公倍数。实际上,n永远不会大于100000000,因此Math.pow( 2,Extra_base2)不应在我们的产品中使用,但我仍然想确保它对其他人有意义。

I found a great solution by simply mimicking what Java's SecureRandom.nextInt(int) is doing at here: SecureRandom.nextInt(int) Will post code as soon as I can get to code it (I'm busy at the moment). 通过简单地模仿Java的SecureRandom.nextInt(int)在这里所做的事情,我找到了一个很好的解决方案: SecureRandom.nextInt(int)将在我能够对其进行编码后立即发布代码(此刻我很忙)。 I plan to use the code I develop from it, since I confirmed the proposed solution has a bias (it is not acceptable at all). 我计划使用从中开发的代码,因为我确认了所提出的解决方案存在偏差(根本不可接受)。

Here is the adaptation of the JDK code. 这是JDK代码的改编版。 Notice the limitations on 31 bit numbers, since I realized JS does all its bitwise operations on two's complement with 32 bits. 注意31位数字的限制,因为我意识到JS在32位二进制补码上完成了所有按位运算。 I did not implement the special case for power of 2 numbers since I won't be using it. 我没有使用2的幂的特殊情况,因为我不会使用它。 The solution is for numbers in general and not only powers of 10... I'm sure there must be a better solution for numbers with base 10, but whatever. 该解决方案适用于一般数字,而不仅仅是10的幂...我敢肯定对于以10为底的数字,无论是什么,都必须有更好的解决方案。 I rewrote the code to not use my libraries and to make it in English, so that others can use it more easily. 我重写了代码以不使用我的库,而是用英语编写它,以便其他人可以更轻松地使用它。

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);
    }
  );
}

Did several tests, it seems to be working just fine. 做了几次测试,似乎工作正常。

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));
  });
};

This should do what you want. 这应该做您想要的。 I decided to make my answer hard to read because your question is hard to read. 我决定使我的答案难以阅读,因为您的问题很难阅读。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM