.NET Framework:随机数生成器生成重复模式

bri*_*rns 46 .net c# random

编辑:这不是重复,它不是对如何使用随机数生成器的天真误解的结果.谢谢.

我似乎在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)但他们没有正确使用它(你必须在输出变得不可预测之前吐出几千次迭代).

  • 最后,我学会了如何打印出那些漂亮的桌子 (16认同)
  • 密码与否,第三个输出是不变的听起来像一个非常糟糕的缺陷.让人惊讶. (15认同)
  • 只有当你以这种非常具体的方式链接`System.Random`时,84(mod 200)的趋势才会出现.不是任何种子在第三个值上产生84(mod 200). (14认同)
  • @oleksii不是很花哨,[这很花哨](https://gist.github.com/leftler/3b4e9b76c869c34f7f52) (3认同)
  • @brianberns .NET有多个RNG.这个是为了快速,可预测的结果.在`System.Security.Cryptography`中的那些比较慢但是没有表现出这么多的特征(但它们仍然可以像RC4那样,它更难看到它) (2认同)