使用加密库我可以要求库给我一些随机字节。问题是这个字节是每个(包括)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,所以数学.pow(2,extra_base2)不应该在我们的产品中使用,但我仍然希望确保它对其他人有意义。
答案 0 :(得分: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);
}
);
}
做了几次测试,似乎工作得很好。
答案 1 :(得分:-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));
});
};
这应该做你想要的。我决定难以阅读我的答案,因为你的问题很难阅读。