Saltar al contenido

Node.js: cómo generar números aleatorios en un rango específico usando crypto.randomBytes

Solución:

Para generar un número aleatorio en un cierto rango, puede usar la siguiente ecuación

Math.random() * (high - low) + low

Pero si desea utilizar crypto.randomBytes en lugar de Math.random (), esta función devuelve un búfer con bytes generados aleatoriamente. A su vez, debe convertir el resultado de esta función de bytes a decimal. esto se puede hacer usando el paquete de formato biguint. Para instalar este paquete simplemente use el siguiente comando:

npm install biguint-format --save

Ahora necesita convertir el resultado de crypto.randomBytes a decimal, puede hacerlo de la siguiente manera:

var x= crypto.randomBytes(1);
return format(x, 'dec');

Ahora puede crear su función aleatoria que será la siguiente:

var crypto = require('crypto'),
    format = require('biguint-format');

function randomC (qty) {
    var x= crypto.randomBytes(qty);
    return format(x, 'dec');
}
function random (low, high) {
    return randomC(4)/Math.pow(2,4*8-1) * (high - low) + low;
}
console.log(random(50,1000));

Gracias a la respuesta de @Mustafamg y la gran ayuda de @CodesInChaos logré resolver este problema. Hice algunos ajustes y aumenté el rango a un máximo de 256 ^ 6-1 o 281,474,976,710,655. El rango se puede aumentar más, pero necesita usar una biblioteca adicional para números enteros grandes, porque 256 ^ 7-1 está fuera de los límites de Number.MAX_SAFE_INTEGER.

Si alguien tiene el mismo problema, no dude en usarlo.

var crypto = require('crypto');

/*
Generating random numbers in specific range using crypto.randomBytes from crypto library
Maximum available range is 281474976710655 or 256^6-1
Maximum number for range must be equal or less than Number.MAX_SAFE_INTEGER (usually 9007199254740991)
Usage examples:
cryptoRandomNumber(0, 350);
cryptoRandomNumber(556, 1250425);
cryptoRandomNumber(0, 281474976710655);
cryptoRandomNumber((Number.MAX_SAFE_INTEGER-281474976710655), Number.MAX_SAFE_INTEGER);

Tested and working on 64bit Windows and Unix operation systems.
*/

function cryptoRandomNumber(minimum, maximum){
	var distance = maximum-minimum;
	
	if(minimum>=maximum){
		console.log('Minimum number should be less than maximum');
		return false;
	} else if(distance>281474976710655){
		console.log('You can not get all possible random numbers if range is greater than 256^6-1');
		return false;
	} else if(maximum>Number.MAX_SAFE_INTEGER){
		console.log('Maximum number should be safe integer limit');
		return false;
	} else {
		var maxBytes = 6;
		var maxDec = 281474976710656;
		
		// To avoid huge mathematical operations and increase function performance for small ranges, you can uncomment following script
		/*
		if(distance<256){
			maxBytes = 1;
			maxDec = 256;
		} else if(distance<65536){
			maxBytes = 2;
			maxDec = 65536;
		} else if(distance<16777216){
			maxBytes = 3;
			maxDec = 16777216;
		} else if(distance<4294967296){
			maxBytes = 4;
			maxDec = 4294967296;
		} else if(distance<1099511627776){
			maxBytes = 4;
			maxDec = 1099511627776;
		}
		*/
		
		var randbytes = parseInt(crypto.randomBytes(maxBytes).toString('hex'), 16);
		var result = Math.floor(randbytes/maxDec*(maximum-minimum+1)+minimum);
		
		if(result>maximum){
			result = maximum;
		}
		return result;
	}
}

Hasta ahora funciona bien y puede usarlo como un generador de números aleatorios realmente bueno, pero no recomiendo estrictamente el uso de esta función para ningún servicio criptográfico. Si lo desea, úselo bajo su propio riesgo.

¡Todos los comentarios, recomendaciones y críticas son bienvenidos!

Para generar números en el rango [55 .. 956], primero genera un número aleatorio en el rango [0 .. 901] donde 901 = 956 – 55. Luego agregue 55 al número que acaba de generar.

Para generar un número en el rango [0 .. 901], seleccione dos bytes aleatorios y enmascare 6 bits. Eso le dará un número aleatorio de 10 bits en el rango [0 .. 1023]. Si ese número es <= 901, entonces ha terminado. Si es mayor que 901, deséchelo y obtenga dos bytes aleatorios más. Hacer no intente usar MOD, para obtener el número en el rango correcto, eso distorsionará la salida haciéndola no aleatoria.

ETA: Para reducir la posibilidad de tener que descartar un número generado.

Como estamos tomando dos bytes del RNG, obtenemos un número en el rango [0 .. 65535]. Ahora 65535 MOD 902 es 591. Por lo tanto, si nuestro número aleatorio de dos bytes es menor que (65535 – 591), es decir, menor que 64944, podemos usar con seguridad el operador MOD, ya que cada número en el rango [0 .. 901] ahora es igualmente probable. Cualquier número de dos bytes> = 64944 tendrá que desecharse, ya que su uso distorsionaría la salida del azar. Antes, las posibilidades de tener que rechazar un número eran (1024 – 901) / 1024 = 12%. Ahora las posibilidades de un rechazo son (65535 – 64944) / 65535 = 1%. Es mucho menos probable que tengamos que rechazar el número generado aleatoriamente.

running <- true
while running
  num <- two byte random
  if (num < 64944)
    result <- num MOD 902
    running <- false
  endif
endwhile
return result + 55
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *