Deseo generar de forma segura un número aleatorio en el rango [0, N), donde N es un parámetro. Sin embargo, System.Security.Cryptography.RandomNumberGenerator solo proporciona un método GetBytes() para llenar una matriz con valores aleatorios.Generación segura de un BigInteger uniformemente aleatorio
(necesito los números enteros aleatorios de valores de uso único utilizadas en una versión ligeramente modificada de SRP. La parte "ligeramente modificado" está fuera de mi control, y la única razón por la que estoy siquiera tocar cosas cripto.)
He escrito un método para hacer esto, pero estoy buscando una forma mejor o al menos la confirmación de que lo estoy haciendo bien.
using System.Numerics
///<summary>Generates a uniformly random integer in the range [0, bound).</summary>
public static BigInteger RandomIntegerBelow(this System.Security.Cryptography.RandomNumberGenerator source, BigInteger bound) {
Contract.Requires<ArgumentException>(source != null);
Contract.Requires<ArgumentException>(bound > 0);
Contract.Ensures(Contract.Result<BigInteger>() >= 0);
Contract.Ensures(Contract.Result<BigInteger>() < bound);
//Get a byte buffer capable of holding any value below the bound
var buffer = (bound << 16).ToByteArray(); // << 16 adds two bytes, which decrease the chance of a retry later on
//Compute where the last partial fragment starts, in order to retry if we end up in it
var generatedValueBound = BigInteger.One << (buffer.Length * 8 - 1); //-1 accounts for the sign bit
Contract.Assert(generatedValueBound >= bound);
var validityBound = generatedValueBound - generatedValueBound % bound;
Contract.Assert(validityBound >= bound);
while (true) {
//generate a uniformly random value in [0, 2^(buffer.Length * 8 - 1))
source.GetBytes(buffer);
buffer[buffer.Length - 1] &= 0x7F; //force sign bit to positive
var r = new BigInteger(buffer);
//return unless in the partial fragment
if (r >= validityBound) continue;
return r % bound;
}
}
Ese es un código hermoso. – Amy