编辑:这不是重复,它不是对如何使用随机数生成器的天真误解的结果.谢谢.
我似乎在System.Random类生成的数字中发现了重复模式.我正在使用"主"Random实例为第二个"主"Random实例生成种子.此主要Random实例生成的值显示重复模式.特别是,产生的第3个数字是非常可预测的.
下面的程序演示了这个问题.请注意,每次循环使用不同的种子值.
using System;
class Program
{
static void Main(string[] args)
{
// repeat experiment with different master RNGs
for (int iMaster = 0; iMaster < 30; ++iMaster)
{
// create master RNG
var rngMaster = new Random(iMaster + OFFSET);
// obtain seed from master RNG
var seed = rngMaster.Next();
// create main RNG from seed
var rngMain = new Random(seed);
// print 3rd number generated by main RNG
var ignore0 = rngMain.Next(LIMIT);
var ignore1 = rngMain.Next(LIMIT);
var randomNumber = rngMain.Next(LIMIT);
Console.WriteLine(randomNumber);
}
}
const int OFFSET = 0;
const int LIMIT = 200;
}
Run Code Online (Sandbox Code Playgroud)
我认为这应该产生随机输出,但我的盒子上的实际输出是:
84
84
84
84
84
84
84
84
84
84
84
...
Run Code Online (Sandbox Code Playgroud)
谁能解释一下这里发生了什么?更改OFFSET和LIMIT常量会更改输出值,但它总是重复.
Sco*_*ain 53
欢迎来到非加密强RNG的世界.显然,内置的.NET RNG如果将输出限制为0到200,则倾向于将第3个数字输出84.看一下该程序的以下版本,它会更多地显示输出中发生的事情.
class Program
{
static void Main(string[] args)
{
Console.WindowWidth = 44;
Console.WindowHeight = 33;
Console.BufferWidth = Console.WindowWidth;
Console.BufferHeight = Console.WindowHeight;
string template = "|{0,-5}|{1,-11}|{2,-5}|{3,-5}|{4,-5}|{5,-5}|";
Console.WriteLine(template, "s1", "s2", "out1", "out2", "out3", "out4");
Console.WriteLine(template, new String('-', 5), new String('-', 11), new String('-', 5), new String('-', 5), new String('-', 5), new String('-', 5));
// repeat experiment with different master RNGs
for (int iMaster = 0; iMaster < 30; ++iMaster)
{
int s1 = iMaster + OFFSET;
// create master RNG
var rngMaster = new Random(s1);
// obtain seed from master RNG
var s2 = rngMaster.Next();
// create main RNG from seed
var rngMain = new Random(s2);
var out1 = rngMain.Next(LIMIT);
var out2 = rngMain.Next(LIMIT);
var out3 = rngMain.Next(LIMIT);
var out4 = rngMain.Next(LIMIT);
Console.WriteLine(template, s1, s2, out1, out2, out3, out4);
}
Console.ReadLine();
}
const int OFFSET = 0;
const int LIMIT = 200;
}
Run Code Online (Sandbox Code Playgroud)
这是输出
|s1 |s2 |out1 |out2 |out3 |out4 | |-----|-----------|-----|-----|-----|-----| |0 |1559595546 |170 |184 |84 |84 | |1 |534011718 |56 |177 |84 |123 | |2 |1655911537 |142 |171 |84 |161 | |3 |630327709 |28 |164 |84 |199 | |4 |1752227528 |114 |157 |84 |37 | |5 |726643700 |0 |150 |84 |75 | |6 |1848543519 |86 |143 |84 |113 | |7 |822959691 |172 |136 |84 |151 | |8 |1944859510 |58 |129 |84 |189 | |9 |919275682 |144 |122 |84 |28 | |10 |2041175501 |30 |115 |84 |66 | |11 |1015591673 |116 |108 |84 |104 | |12 |2137491492 |2 |102 |84 |142 | |13 |1111907664 |88 |95 |84 |180 | |14 |86323836 |174 |88 |84 |18 | |15 |1208223655 |60 |81 |84 |56 | |16 |182639827 |146 |74 |84 |94 | |17 |1304539646 |31 |67 |84 |133 | |18 |278955818 |117 |60 |84 |171 | |19 |1400855637 |3 |53 |84 |9 | |20 |375271809 |89 |46 |84 |47 | |21 |1497171628 |175 |40 |84 |85 | |22 |471587800 |61 |33 |84 |123 | |23 |1593487619 |147 |26 |84 |161 | |24 |567903791 |33 |19 |84 |199 | |25 |1689803610 |119 |12 |84 |38 | |26 |664219782 |5 |5 |84 |76 | |27 |1786119601 |91 |198 |84 |114 | |28 |760535773 |177 |191 |84 |152 | |29 |1882435592 |63 |184 |84 |190 |
因此,主RND的第一输出与第一RNG的第一输出之间存在一些强相关性.该RandomRNG的设计并不是为了"安全",它的设计是"快",所以像你在这里看到的是什么是快速和安全之间的平衡.如果您不希望发生类似这样的事情,则需要使用加密安全的随机数生成器.
但是,仅仅切换到加密随机数生成器(CRNG)是不够的,您仍然需要小心如何使用CRNG.WEP无线安全性发生了类似的问题.根据标头中给出的IV,可以预测随机数生成器的种子值(WEP密钥)用于保护连接.虽然他们使用CRNG(他们使用RC4)但他们没有正确使用它(你必须在输出变得不可预测之前吐出几千次迭代).