2016-08-18 4 views
2

私は厳しい規制の精査の対象となるゲームプラットフォームを開発しています。私はMath.NETを選択しました。しかし、私は監査人からこのコメントを受け取りました。Math.NET CryptoRandomSource次へバイアスされています

コメントが正確で、解決方法は? RandomSource()、次に(INT、INT)で


次のように定義される:

public override sealed int Next(int minValue, int maxValue) 
    { 
     if (minValue > maxValue) 
     { 
      throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue); 
     } 

     if (_threadSafe) 
     { 
      lock (_lock) 
      { 
       return (int)(DoSample()*(maxValue - minValue)) + minValue; 
      } 
     } 

     return (int)(DoSample()*(maxValue - minValue)) + minValue; 
    } 

これは前と同じようにバイアスを生成します。 RNGからスケーリングされていない値を使用し、事前にバイアスを除去することなく範囲を掛けます(範囲が2の累乗でない限り、偏りがあります)。

+0

それが返す正確に何知らない? 'DoSample()'は何であるそのハード、ここで何が起こっているのか動作するように。それだけでuniformalyランダム配布されます0と1の間の数字(どのエンドポイントに含まれているか除外されていますか)は実際には偏っていないことを知っていますか? – Chris

+0

また、メソッドの期待戻り値は何ですか? maxValueまたはminValueを返すことができるはずですか?また、 'Next(0,1)'何百万(何十億)というようなものを呼び出すか、それらが大きく異なるかどうかを調べるための基本的なテストを行ったことがあります。 – Chris

+0

DoSample()メソッドは、0と1の間の倍精度値を返します。このコードに問題はありませんが、大きなサンプルサイズでは大きさが異なる場合、何かが間違っていることを確かめることができます。 。私が引用したビットは、審査員が問題を抱えているのは、範囲が2の累乗ではないからです。残念ながら、すべての範囲は0-99,0-999,0-9999,0-99999です。 – IntoNET

答えて

2

更新Next(minInclusive, maxExclusive)の実装は、この説明の後でMath.NET Numerics v3.13で変更されました。 v3.13以来、それはもはや浮動小数点数を伴わず、要求された範囲(2の累乗)をサポートするために必要な数のビットで整数をサンプリングし、実際の範囲外のものを拒否します。範囲[0,1)(倍精度浮動小数点数)に均一に分布したサンプルを返しDoSample():この方法には、(暗号RNGによって、例えば提供されるような)

仮定をバイトサンプリング自体の上に任意のバイアスを加えることが回避されます。

範囲R = max-minで乗算すると、均等に分布するサンプルが[0,R)になります。これを本質的に床である整数にキャストすると、0,1,2,...,R-1の一様分布の離散サンプルが得られます。私は、Rが偶数、奇数、または2のべき乗であるという事実が、この段階でバイアスに影響を与える可能性がある場所を見ていません。

100'000'000サンプルを計算するためのいくつかの実行も明らかにバイアスを示すものではありませんが、もちろん、これは証拠ではありません:

var r = new CryptoRandomSource(); 
long[] h = new long[8]; 
for (int i = 0; i < 100000000; i++) 
{ 
    h[r.Next(2,7)]++; 
} 

0 
0 
19996313 
20001286 
19998092 
19998328 
20005981 
0 

0 
0 
20000288 
20002035 
20006269 
19994927 
19996481 
0 

0 
0 
19998296 
19997777 
20001463 
20002759 
19999705 
0 
+3

Rが奇数、偶数などである理由は、一種のピジョンホール引数です。 [0,1]で返されるdoubleは2^52の可能な別個の値を持ちます(仮数は52ビットです)。 R = 5で乗算すると、まだ2^52の別個の値がありますが、今では[0,5]にまたがっています。あなたはそれの床を取って、現在セット{0,1,2,3,4}にある2^52の値を持っています。だから、それらの2^52値のどれくらいが各数値にマップされていますか?明らかに2^52は5で割り切れないので、その範囲内の各整数を得る可能性は同じではありません。 – Chris

+2

脆弱性が3つの関連ビットしかないはるかに小さな浮動小数点数を見ているところをよりよく理解する。 DoSampleは0,1/8,2/8,3/8,4/8,5/8,6/8,7/8(8値)を返します。これらを5倍した場合、0,5/8,10/8,15/8,20/8,25/8,30/8,35/8になります。これは0,0,1,1,2,3,3,4となります。一様ではありません! – Chris

+0

私の範囲が常に分かっていると仮定すると、exmple 0-99の場合、0〜100の間の数値を生成してから100を返すと再生成すると、2バイアスの問題を解決できないでしょう? – IntoNET

0

私は0の間の値のため、この解決策を作ってみました最大値を含む。私は数学の専門家ではなく、コメント歓迎です。

選択された特定の乱数を再スケーリング値の等しい分布の範囲外である場合、その乱数を破棄して選択することが許容される)

2bと言う私は規制仕様を満たすように思われます再スケーリングのために、シーケンス内の次は。」

private readonly CryptoRandomSource _random = new CryptoRandomSource(); 

    private int GetRandomNumber(int max) 
    { 
     int number; 
     var nextPowerOfTwo = (int)Math.Pow(2, Math.Ceiling(Math.Log(max)/Math.Log(2))); 

     do 
     { 
      // Note: 2nd param of Next is an *exclusive* value. Add 1 to satisfy this 
      number = _random.Next(0, nextPowerOfTwo + 1); 
     } while (number > max); 

     return number; 
    } 
関連する問題