public static BigInteger GetRandBits(this Random generator, int bits) {
ContractUtils.Requires(bits > 0);
// equivalent to (bits + 7) / 8 without possibility of overflow
int count = bits % 8 == 0 ? bits / 8 : bits / 8 + 1;
// Pad the end (most significant) with zeros if we align to the byte
// to ensure that we end up with a positive value
byte[] bytes = new byte[bits % 8 == 0 ? count + 1 : count];
generator.NextBytes(bytes);
if (bits % 8 == 0) {
bytes[bytes.Length - 1] = 0;
} else {
bytes[bytes.Length - 1] = (byte)(bytes[bytes.Length - 1] & ((1 << (bits % 8)) - 1));
}
if (bits <= 32) {
return (BigInteger)GetWord(bytes, 0, bits);
} else if (bits <= 64) {
ulong a = GetWord(bytes, 0, bits);
ulong b = GetWord(bytes, 32, bits);
return (BigInteger)(a | (b << 32));
} else {
count = (count + 3) / 4;
uint[] data = new uint[count];
for (int i = 0; i < count; i++) {
data[i] = GetWord(bytes, i * 32, bits);
}
return new BigInteger(1, data);
}
}