C#安全随机数生成算法和安全性分析

廉价感情. 提交于 2019-12-05 14:27:15

        如何评价一个随机数算法?个人认为,一个好的随机数算法,能提供足够的安全性和公平性,并拥有优异的性能。

        真随机数发生器由于价格昂贵,并没有得到普遍采用。那么,伪随机数就出来了,比如sha1prng。伪随机数的安全性依赖于种子。怎么实现sha1prng和其他的伪随机数算法,我们现在不做讨论。java和C#都有相应的API,java的SecureRandom和C#的RNGCryptoServiceProvider。我们就不重复再轮子了。

        上面的两个类都可以为我们提供伪随机的字节流。同时java还提供产生安全随机整数的API了,这里就不讨论java的安全随机数了。下面说说,怎么利用伪随机的字节流产生安全的高强度的随机整数。

        有网友是这样实现,暂且命名为FastNextInt。

        public int FastNextInt(int max)
        {
            byte[] bs = new byte[4];
            generator.GetBytes(bs);
            int value = BitConverter.ToInt32(bs, 0);
            value = value % max;
            if (value < 0) value = -value;
            return value;
        }

这种算法可以快速地得到一个“随机”整数,但是这种方法使得在[0,max)范围内,各整数出现的频率是不一样的。很明显,前面k=0x100000000/max*max个整数,先使得0~(max-1)中的整数各出现了0x100000000/max次。然后0~(0x100000000-k)再会出现一次。所以容易计算得,第(0x100000000-k+1)~max-1个数出现的概率为0x100000000/max/0x100000000=1/max;前面第0~(0x100000000-k)个数出现的概率为(0x100000000/max+1)/0x10000000。其概率比1/max大了1/0x10000000.因此,出现次数多的数就比出现次数少的数多出了约(1/0x100000000)/(1/max)=max/0x100000000的可能。比如,假设max=0x7FFFFFFF;2,3,4....出现了两次,其他数只出现了3次。就相对多出了1/2的可能。举个例子,如果面向21亿观众抽奖,明显这样就显得不公平了。

        是不是这样就无解了?首先回过头思考一下,多出来的可能等于max/0x100000000。如果把分母扩大会怎么样?假如将分母扩大到0x10000000000000000,max在32位的范围内,多出来的可能约为几十亿分之一,是不是可以忽略不计?于是就有了FastNextLong

        public long FastNextLong(long max)
        {
            byte[] bs = new byte[8];
            generator.GetBytes(bs);
            long value = BitConverter.ToInt64(bs, 0);
            value = value % max;
            if (value < 0) value = -value;
            return value;
        }

        这样,既保持了良好的运算性能,又获得更公平的随机数。

        有没有更加公平、安全的随机数算法。答案是有的,并且是符合数学理论的。由于我们的计算机式二进制的,所以只能产生1,2,3,……位的随机数,也就是说可以产生0~1,0~3,0~7,0~15,……这种范围随机数。每个数出现的可能只能是1/(2^1),1/(2^2) ,……其实,我们可以这样做,如果我们要产生0~n的随机数,我们先求出K,其中K是满足n<=2^k的k的最小整数值。接着产生一个K位的随机序列。如果这个序列表示的值属于0~n,那么输出这个数值。在获得输出的条件下,容易得到0~n出现的可能性都是相等的。如果这个序列表示的值大于n,那么再产生一个新数列,循环操作,直到这个序列满足输出条件。容易得到,一个序列获得输出的可能性大于1/2.继续下一轮循环的可能性小于1/2.根据数学的N次独立重复试验概率计算公式,N次没有获得输出的可能性小于(1/2)^N。例如,操作10轮后,没有获得输出的可能性为1/1024.又由于这个概率是指数级减小的,同时,只用到了移位,比较就可以实现。所以这个算法并不需要多少计算资源就可以获得输出。由于FastNextInt用到了耗时的模除,所以这个算法并不比FastNextInt更耗多少资源。

        下面是完整的源代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace RNG
{
    public class SecureRandom
    {
        private readonly static double DOUBLE_UNIT = 1.0 / (1L << 53);
        RandomNumberGenerator generator;
        public SecureRandom(RandomNumberGenerator generator)
        {
            this.generator = generator;
        }
        //产生bits位的随机整数
        // bits>=1
        protected uint Next(int bits)
        {
            byte[] bs = new byte[4];
            generator.GetBytes(bs);
            uint x = BitConverter.ToUInt32(bs, 0);
            return x >> (32 - bits);
        }
        //产生bits位的随机整数
        //bits>=1
        protected ulong Next2(int bits)
        {
            byte[] bs = new byte[8];
            generator.GetBytes(bs);
            ulong x = BitConverter.ToUInt64(bs, 0);
            return x >> (64 - bits);
        }


        protected int BitLength(int x)
        {
            int len = 0;
            while (x > 0)
            {
                len++;
                x >>= 1;
            }
            return len;
        }
        protected int BitLength(long x)
        {
            int len = 0;
            while (x > 0)
            {
                len++;
                x >>= 1;
            }
            return len;
        }

        public int NextInt()
        {
            return (int)Next(32);
        }
        //max>=1,不包括max
        public int NextInt(int max)
        {
            if (max <= 0) throw new ArgumentException("max <= 0");
            int len = BitLength(max);
            uint x = Next(len);
            while (x >= max)
            {
                x = Next(len);
            }
            return (int)x;
        }
        //不包括max
        public int NextInt(int min, int max)
        {
            return NextInt(max - min) + min;
        }
        //max>=1,不包括max
        public int FastNextInt(int max)
        {
            byte[] bs = new byte[4];
            generator.GetBytes(bs);
            int value = BitConverter.ToInt32(bs, 0);
            value = value % max;
            if (value < 0) value = -value;
            return value;
        }
        //不包括max
        public int FastNextIntint(int min, int max)
        {
            return FastNextInt(max - min) + min;
        }
        public long NextLong()
        {
            return ((long)(Next(32)) << 32) + Next(32);
        }
        //max>=1,不包括max
        public long NextLong(long max)
        {
            if (max <= 0) throw new ArgumentException("max <= 0");
            int len = BitLength(max);
            ulong x = Next2(len);
            while (x >= (ulong)max)
            {
                x = Next2(len);
            }
            return (long)x;
        }
        //不包括max
        public long NextLong(long min, long max)
        {
            return NextLong(max - min) + min;
        }
        //max>=1,不包括max
        public long FastNextLong(long max)
        {
            byte[] bs = new byte[8];
            generator.GetBytes(bs);
            long value = BitConverter.ToInt64(bs, 0);
            value = value % max;
            if (value < 0) value = -value;
            return value;
        }
        //不包括max
        public long FastNextLong(long min, long max)
        {
            return FastNextLong(max - min) + min;
        }
        public bool NextBoolean()
        {
            return Next(1) != 0;
        }
        //此方法是java源码中拷贝,此算法得到的浮点数的随机性未考究
        public float NextFloat()
        {
            return Next(24) / ((float)(1 << 24));
        }
        //此方法是java源码中拷贝,此算法得到的浮点数的随机性未考究
        public double NextDouble()
        {
            return (((long)(Next(26)) << 27) + Next(27)) * DOUBLE_UNIT;
        }

        //数组长度需要一致
        protected bool GreaterThanOrEqual(byte[] a, byte[] b)
        {
            //if (a.Length > b.Length) return true;
            //if (a.Length < b.Length) return false;
            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] > b[i]) return true;
                if (a[i] < b[i]) return false;
            }
            return true;//全等
        }

        protected byte[] Next3(int bits)
        {
            int len = (bits + 7) >> 3;
            byte[] bs = new byte[len];
            generator.GetBytes(bs);
            bs[0] >>= (8 - bits) & 0x7;
            return bs;
        }
        protected int BitLength(byte[] x)
        {
            int i = 0;
            for (; i < x.Length && x[i] == 0; i++) ;
            return i == 8 ? 0 : BitLength(x[i]) + (x.Length - i - 1) * 8;
        }

        public byte[] NextBigInt(byte[] max)
        {
            int bitLen = BitLength(max);
            if(bitLen==0) throw new ArgumentException("max == 0");
            byte[] max_ = new byte[(bitLen + 7) >>3];
            Array.Copy(max, max.Length - max_.Length, max_, 0, max_.Length);
            byte[] x = Next3(bitLen);
            while (GreaterThanOrEqual(x,max_))
            {
                x = Next3(bitLen);
            }
            return x;
        }
    }
}

测试用的源代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace RNG
{
    class Program
    {
        private static void testRandomInt()
        {
            RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
            SecureRandom random = new SecureRandom(rngCsp);
            Console.WriteLine("===========testRandomInt============");
            int max = 300;
            int[] counter = new int[max];
            int total = 10000000;
            for (int i = 1; i < total; i++)
            {
                counter[random.NextInt(max)]++;
            }
            foreach (int x in counter)
            {
                double diff = (x * max - total) * 100.0 / total;
                Console.WriteLine(string.Format("{0,10}\t{1}%", x, diff));
            }
            Console.WriteLine("=======================");
        }
        private static void testFastRandomInt()
        {
            RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
            SecureRandom random = new SecureRandom(rngCsp);
            Console.WriteLine("===========testFastRandomInt============");
            int max = 300;
            int[] counter = new int[max];
            int total = 10000000;
            for (int i = 1; i < total; i++)
            {
                counter[random.FastNextInt(max)]++;
            }
            foreach (int x in counter)
            {
                double diff = (x * max - total) * 100.0 / total;
                Console.WriteLine(string.Format("{0,10}\t{1}%", x, diff));
            }
            Console.WriteLine("=======================");
        }
        private static void testRandomLong()
        {
            RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
            SecureRandom random = new SecureRandom(rngCsp);

            Console.WriteLine("===========testRandomLong============");
            Console.WriteLine(random.NextLong(123456789012345678));
            Console.WriteLine("=======================");
        }
        private static void testRandomBool()
        {
            RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
            SecureRandom random = new SecureRandom(rngCsp);

            Console.WriteLine("==========testRandomBool=============");
            Console.WriteLine(random.NextBoolean());
            Console.WriteLine("--------------");
            int[] counter = new int[2];
            int total = 10000000;
            for (int i = 1; i < total; i++)
            {
                counter[random.NextBoolean() ? 1 : 0]++;
            }
            foreach (int x in counter)
            {
                double diff = (x * 2 - total) * 100.0 / total;
                Console.WriteLine(string.Format("{0,10}\t{1}%", x, diff));
            }
        }
        public static void Print(byte[] bs)
        {
            foreach (byte b in bs)
            {
                Console.Write(string.Format("{0:x2}", b));
            }
            Console.WriteLine("");
        }

        static void Main(string[] args)
        {
            
            testRandomInt();
            testFastRandomInt();
            testRandomLong();
            testRandomBool();
            
            RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
            SecureRandom random = new SecureRandom(rngCsp);
            Console.WriteLine("random float:" + random.NextFloat());
            Console.WriteLine("random double:" + random.NextDouble());

            Console.WriteLine("==========testRandomBigInt 1=============");
            byte[] max = { 0x00, 0x00,0x11, 0x22, 0x33, 0x44, 0x55};
            for (int i = 0; i < 20; i++)
            {
                byte[] r = random.NextBigInt(max);
                Print(r);
            }
            Console.WriteLine("==========testRandomBigInt 2=============");
            byte[] max2 = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
            for (int i = 0; i < 20; i++)
            {
                byte[] r = random.NextBigInt(max2);
                Print(r);
            }
            Console.Read();
        }
    }
}

输出:

===========testRandomInt============
     33217	-0.349%
     33458	0.374%
     33367	0.101%
     33418	0.254%
     33479	0.437%
     33358	0.074%
     33332	-0.004%
     33259	-0.223%
     33204	-0.388%
     33287	-0.139%
     33335	0.005%
     33293	-0.121%
     33546	0.638%
     33104	-0.688%
     33673	1.019%
     33551	0.653%
     33394	0.182%
     33132	-0.604%
     33465	0.395%
     33349	0.047%
     33523	0.569%
     33544	0.632%
     33367	0.101%
     33292	-0.124%
     32927	-1.219%
     33178	-0.466%
     33640	0.92%
     33476	0.428%
     33171	-0.487%
     33171	-0.487%
     33077	-0.769%
     33266	-0.202%
     33321	-0.037%
     33594	0.782%
     33561	0.683%
     33226	-0.322%
     33140	-0.58%
     33426	0.278%
     33333	-0.001%
     33448	0.344%
     33411	0.233%
     33356	0.068%
     32972	-1.084%
     33606	0.818%
     33135	-0.595%
     33349	0.047%
     33087	-0.739%
     33231	-0.307%
     33385	0.155%
     33786	1.358%
     33388	0.164%
     33485	0.455%
     32996	-1.012%
     33473	0.419%
     33301	-0.097%
     33078	-0.766%
     33146	-0.562%
     33480	0.44%
     33205	-0.385%
     33440	0.32%
     33335	0.005%
     33264	-0.208%
     33305	-0.085%
     33400	0.2%
     33227	-0.319%
     33078	-0.766%
     33179	-0.463%
     33205	-0.385%
     33422	0.266%
     33156	-0.532%
     33223	-0.331%
     32930	-1.21%
     33474	0.422%
     33241	-0.277%
     33126	-0.622%
     33117	-0.649%
     33194	-0.418%
     33467	0.401%
     33277	-0.169%
     33384	0.152%
     33341	0.023%
     33667	1.001%
     33333	-0.001%
     33139	-0.583%
     33335	0.005%
     33615	0.845%
     33555	0.665%
     33518	0.554%
     33536	0.608%
     33063	-0.811%
     33592	0.776%
     33602	0.806%
     33368	0.104%
     33645	0.935%
     33289	-0.133%
     33401	0.203%
     33494	0.482%
     33247	-0.259%
     33510	0.53%
     33592	0.776%
     33258	-0.226%
     32824	-1.528%
     32927	-1.219%
     33043	-0.871%
     33420	0.26%
     33005	-0.985%
     33554	0.662%
     33627	0.881%
     32940	-1.18%
     33488	0.464%
     33332	-0.004%
     33300	-0.1%
     33448	0.344%
     33493	0.479%
     33489	0.467%
     32892	-1.324%
     33263	-0.211%
     33310	-0.07%
     33166	-0.502%
     33554	0.662%
     33397	0.191%
     33308	-0.076%
     33227	-0.319%
     33335	0.005%
     33403	0.209%
     33337	0.011%
     33099	-0.703%
     33496	0.488%
     33249	-0.253%
     33263	-0.211%
     33387	0.161%
     33399	0.197%
     33414	0.242%
     33303	-0.091%
     33642	0.926%
     33433	0.299%
     33280	-0.16%
     33474	0.422%
     32977	-1.069%
     33694	1.082%
     33363	0.089%
     33199	-0.403%
     33429	0.287%
     33767	1.301%
     33147	-0.559%
     33634	0.902%
     33493	0.479%
     33310	-0.07%
     33134	-0.598%
     33322	-0.034%
     33322	-0.034%
     33037	-0.889%
     33623	0.869%
     33197	-0.409%
     33403	0.209%
     33259	-0.223%
     33208	-0.376%
     33049	-0.853%
     33141	-0.577%
     33457	0.371%
     33381	0.143%
     33011	-0.967%
     33221	-0.337%
     33097	-0.709%
     33179	-0.463%
     33115	-0.655%
     33412	0.236%
     33348	0.044%
     33251	-0.247%
     33438	0.314%
     33209	-0.373%
     33278	-0.166%
     33498	0.494%
     33189	-0.433%
     33328	-0.016%
     33560	0.68%
     33385	0.155%
     33224	-0.328%
     33594	0.782%
     33567	0.701%
     33309	-0.073%
     33314	-0.058%
     33476	0.428%
     33328	-0.016%
     33410	0.23%
     32904	-1.288%
     33314	-0.058%
     33197	-0.409%
     33295	-0.115%
     33345	0.035%
     33471	0.413%
     33354	0.062%
     33323	-0.031%
     33406	0.218%
     33479	0.437%
     33417	0.251%
     33509	0.527%
     33645	0.935%
     33466	0.398%
     33441	0.323%
     33317	-0.049%
     33201	-0.397%
     33135	-0.595%
     33595	0.785%
     33323	-0.031%
     33037	-0.889%
     33579	0.737%
     33160	-0.52%
     33231	-0.307%
     33718	1.154%
     33556	0.668%
     33452	0.356%
     33228	-0.316%
     33232	-0.304%
     33157	-0.529%
     33216	-0.352%
     33464	0.392%
     33397	0.191%
     33217	-0.349%
     33467	0.401%
     33348	0.044%
     33336	0.008%
     33367	0.101%
     33420	0.26%
     33109	-0.673%
     33590	0.77%
     33350	0.05%
     33415	0.245%
     33568	0.704%
     33330	-0.01%
     33415	0.245%
     33178	-0.466%
     33261	-0.217%
     33105	-0.685%
     33268	-0.196%
     33327	-0.019%
     32926	-1.222%
     33311	-0.067%
     33131	-0.607%
     33169	-0.493%
     33375	0.125%
     33435	0.305%
     33060	-0.82%
     33472	0.416%
     33408	0.224%
     33285	-0.145%
     33223	-0.331%
     33417	0.251%
     33169	-0.493%
     33608	0.824%
     33407	0.221%
     33281	-0.157%
     33013	-0.961%
     33494	0.482%
     33717	1.151%
     33266	-0.202%
     33765	1.295%
     33337	0.011%
     33302	-0.094%
     33603	0.809%
     33235	-0.295%
     33670	1.01%
     33575	0.725%
     33336	0.008%
     33358	0.074%
     33018	-0.946%
     33350	0.05%
     33284	-0.148%
     33275	-0.175%
     33494	0.482%
     33523	0.569%
     33345	0.035%
     32958	-1.126%
     33685	1.055%
     33173	-0.481%
     33580	0.74%
     33011	-0.967%
     33201	-0.397%
     33516	0.548%
     33203	-0.391%
     33108	-0.676%
     33422	0.266%
     33332	-0.004%
     33468	0.404%
     33205	-0.385%
     33515	0.545%
     33154	-0.538%
     33366	0.098%
     33577	0.731%
     33368	0.104%
     33381	0.143%
     33279	-0.163%
     33160	-0.52%
     33455	0.365%
     32875	-1.375%
     33365	0.095%
     33417	0.251%
     33287	-0.139%
     33377	0.131%
     33165	-0.505%
=======================
===========testFastRandomInt============
     33538	0.614%
     33470	0.41%
     33167	-0.499%
     33034	-0.898%
     33329	-0.013%
     33281	-0.157%
     33264	-0.208%
     33286	-0.142%
     33156	-0.532%
     33259	-0.223%
     33169	-0.493%
     33066	-0.802%
     33132	-0.604%
     33283	-0.151%
     33316	-0.052%
     33424	0.272%
     33112	-0.664%
     33509	0.527%
     33149	-0.553%
     33213	-0.361%
     33151	-0.547%
     33218	-0.346%
     33195	-0.415%
     33209	-0.373%
     33038	-0.886%
     33107	-0.679%
     33515	0.545%
     33390	0.17%
     33475	0.425%
     33165	-0.505%
     33273	-0.181%
     33484	0.452%
     33283	-0.151%
     33664	0.992%
     33616	0.848%
     33600	0.8%
     33406	0.218%
     33383	0.149%
     33220	-0.34%
     32926	-1.222%
     33187	-0.439%
     33591	0.773%
     33448	0.344%
     33520	0.56%
     33448	0.344%
     33625	0.875%
     33255	-0.235%
     33346	0.038%
     33282	-0.154%
     33403	0.209%
     33381	0.143%
     33652	0.956%
     33075	-0.775%
     33433	0.299%
     33357	0.071%
     33302	-0.094%
     33628	0.884%
     33357	0.071%
     33460	0.38%
     33125	-0.625%
     33703	1.109%
     32828	-1.516%
     33311	-0.067%
     33626	0.878%
     33288	-0.136%
     33006	-0.982%
     33172	-0.484%
     33392	0.176%
     33244	-0.268%
     33347	0.041%
     33537	0.611%
     33386	0.158%
     33232	-0.304%
     33320	-0.04%
     33461	0.383%
     33064	-0.808%
     32988	-1.036%
     33319	-0.043%
     33574	0.722%
     33055	-0.835%
     33238	-0.286%
     33436	0.308%
     33488	0.464%
     33548	0.644%
     33423	0.269%
     33193	-0.421%
     33348	0.044%
     33147	-0.559%
     33380	0.14%
     33113	-0.661%
     33509	0.527%
     33464	0.392%
     33174	-0.478%
     33030	-0.91%
     33081	-0.757%
     33496	0.488%
     33176	-0.472%
     33427	0.281%
     33304	-0.088%
     33082	-0.754%
     33138	-0.586%
     33477	0.431%
     33267	-0.199%
     33516	0.548%
     33420	0.26%
     33099	-0.703%
     33208	-0.376%
     33456	0.368%
     33087	-0.739%
     33502	0.506%
     33255	-0.235%
     33512	0.536%
     33098	-0.706%
     33095	-0.715%
     33330	-0.01%
     33091	-0.727%
     33480	0.44%
     33281	-0.157%
     33529	0.587%
     33127	-0.619%
     33353	0.059%
     33066	-0.802%
     33503	0.509%
     33472	0.416%
     33530	0.59%
     33482	0.446%
     33035	-0.895%
     33374	0.122%
     33494	0.482%
     33309	-0.073%
     33577	0.731%
     33269	-0.193%
     33210	-0.37%
     33867	1.601%
     33728	1.184%
     33459	0.377%
     33500	0.5%
     33522	0.566%
     33602	0.806%
     33284	-0.148%
     33259	-0.223%
     33314	-0.058%
     33368	0.104%
     33579	0.737%
     33619	0.857%
     33150	-0.55%
     33637	0.911%
     33467	0.401%
     33354	0.062%
     33467	0.401%
     33414	0.242%
     33390	0.17%
     33279	-0.163%
     33263	-0.211%
     33473	0.419%
     33596	0.788%
     33208	-0.376%
     33170	-0.49%
     33539	0.617%
     33550	0.65%
     33466	0.398%
     33326	-0.022%
     33350	0.05%
     33285	-0.145%
     33342	0.026%
     33319	-0.043%
     33445	0.335%
     33533	0.599%
     33184	-0.448%
     33501	0.503%
     33288	-0.136%
     33290	-0.13%
     33333	-0.001%
     33624	0.872%
     33045	-0.865%
     33096	-0.712%
     33269	-0.193%
     33145	-0.565%
     33185	-0.445%
     33408	0.224%
     33526	0.578%
     33349	0.047%
     33178	-0.466%
     33502	0.506%
     33510	0.53%
     33372	0.116%
     33062	-0.814%
     33779	1.337%
     33157	-0.529%
     33397	0.191%
     33026	-0.922%
     33282	-0.154%
     33306	-0.082%
     33146	-0.562%
     33090	-0.73%
     33502	0.506%
     33488	0.464%
     33656	0.968%
     33351	0.053%
     33379	0.137%
     33152	-0.544%
     33468	0.404%
     33174	-0.478%
     33055	-0.835%
     33168	-0.496%
     33462	0.386%
     33172	-0.484%
     33327	-0.019%
     33037	-0.889%
     33233	-0.301%
     33697	1.091%
     33328	-0.016%
     33368	0.104%
     33489	0.467%
     33708	1.124%
     33007	-0.979%
     33276	-0.172%
     33443	0.329%
     33374	0.122%
     33187	-0.439%
     33103	-0.691%
     33489	0.467%
     33280	-0.16%
     33409	0.227%
     32945	-1.165%
     33561	0.683%
     33138	-0.586%
     33640	0.92%
     33466	0.398%
     33459	0.377%
     33366	0.098%
     32991	-1.027%
     33207	-0.379%
     33594	0.782%
     33281	-0.157%
     33130	-0.61%
     33314	-0.058%
     33345	0.035%
     33431	0.293%
     33297	-0.109%
     33590	0.77%
     33193	-0.421%
     33304	-0.088%
     33351	0.053%
     33235	-0.295%
     33142	-0.574%
     33263	-0.211%
     33482	0.446%
     33223	-0.331%
     33289	-0.133%
     33338	0.014%
     33507	0.521%
     33394	0.182%
     33453	0.359%
     33246	-0.262%
     33453	0.359%
     33539	0.617%
     33325	-0.025%
     33253	-0.241%
     33337	0.011%
     33165	-0.505%
     33571	0.713%
     33623	0.869%
     33173	-0.481%
     33471	0.413%
     33086	-0.742%
     33369	0.107%
     33115	-0.655%
     33343	0.029%
     33403	0.209%
     32854	-1.438%
     33189	-0.433%
     33300	-0.1%
     33341	0.023%
     33441	0.323%
     33264	-0.208%
     33180	-0.46%
     33357	0.071%
     33385	0.155%
     33345	0.035%
     33421	0.263%
     33367	0.101%
     33401	0.203%
     33406	0.218%
     33115	-0.655%
     33422	0.266%
     33607	0.821%
     33404	0.212%
     33451	0.353%
     33230	-0.31%
     33178	-0.466%
     33461	0.383%
     33324	-0.028%
     33240	-0.28%
     33490	0.47%
     32960	-1.12%
     33372	0.116%
     33466	0.398%
     33318	-0.046%
     33451	0.353%
=======================
===========testRandomLong============
89007644488221403
=======================
==========testRandomBool=============
True
--------------
   4997827	-0.04346%
   5002172	0.04344%
random float:0.7498122
random double:0.58139231767367
==========testRandomBigInt 1=============
06df2c4218
0f47eca524
015f02f9d5
0f1bbf3f04
079e0c47ec
0f11fc561f
111cff258c
00c714f655
0c13b76a76
08cb5865ed
0d24079f32
077954d85f
02fc20247c
042a1ce9e4
0cb20f09e2
01e0c30157
019759a1cc
04916840ae
01bb6903c4
0b06f70539
==========testRandomBigInt 2=============
05c45b4bfdd10e538a46add39d3d7e
0836f2f2ef3a099f3674570188f41c
07d570c291195e756bea83d57b3fdf
0329ed611034ed5a28bb844d879eba
04fafcd289d51cac801cac4b9d8f14
07f420c929e9bfa4ea2629838b1b6a
0793343227d8dccda7703d15c259f2
039a719df657299bd1110b57e14969
099c6c1a7cc2b026a8727fbc7eb66e
09416bc3497afb3bc55b93aa634bd7
032de0780dc126e5a4d5de90198c7b
017a8bc3ea7d0f43c177e90c7c917b
0c90302f216d055a1ece20654ffe70
024af92f2c29ea4a4c63b27d5d3c07
0f312181d44cc16192632e21b914c2
0f3bd1eae26d73d6a7591b8b73784d
0cc25269624d2fbddd7615424015ee
04ce83e8decaa1b6aa58f3615ae999
02be0a29ded1dd3826ede7100aa138
03798b94c2a391b97325d2d647583a

        从中可以发现,随机性是得到保证的。

        建议,在一般使用的时候,max比较小的时候可以采用FastNextInt或者FastNextLong,最好使用后者,这样max在32位的范围内,随机性公平都能得到保证,其中将long型结果强制转换成int即可。当然,追求更高安全,更加公平的可以选择NextInt和NextLong。

        再最后还做了一些拓展,实现了NextBigInt,其中参数max是大整数转化为大端序的字节数组。例如0x112233可用大端序字节数组表示为{0x11,0x220,0x33}。在很多使用了大整数的程序中,RSA和ECC加密中都用到了随机的大整数,基本思路和这里的一样。他们是这样是做的,计算出随机整数的上限(max),再计算出max的字节数N。然后产生N个字节的随机字节数组。然后判断这个字节数组对应的大整数值是否在max以内。这种实现的随机性(包括在数学理论上)也是可以得到保证的,大家可以参考上面的分析。但是这种实现的效率太低。假如这个max的最高位所在的字节是1,那么相应的随机字节序列的这个字节,出现1或0的概率为2/128.那么操作10次,还未得到合适的随机字节序列的概率为(63/64)^10≈0.8543。100次未得到合适的随机字节序列的概率为0.2070。而NextBigInt操作3次就可以得到这样的效果(1/8=0.125)。

        

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!