如何使用RNGCryptoServiceProvider生成Bridge手?

时间:2014-09-02 05:57:58

标签: c# random cryptography rngcryptoserviceprovider

Bridge游戏由52张不同的扑克牌组成,这些扑克牌随机分布在四个玩家中,每个玩家最终得到13张牌:一个所谓的"交易"。 Roughly a little less than 2^96 Bridge deals are possible。在this document中,生成随机交易的程序的要求描述如下:

  
      
  1. 该软件应该能够生成所有可能的桥接协议,因为这也可以通过手动处理。
  2.   
  3. 软件应该以相同的概率生成每笔交易,而不受董事会编号,之前的手或任何影响   其他情况。
  4.   
  5. 即使在会议中看到所有其他交易之后,也无法预测交易。
  6.   

本文继续说明伪随机生成器不能用于生成交易,因为看到伪随机序列的第一个元素可以计算所使用的种子,从而使黑客能够预测将要跟随的交易

此外,由于大多数伪随机生成器采用32位的种子,因此应该遵循这些生成器最多能够生成2 ^ 32个不同的桥交易而不是所需的2 ^ 96并且遵循所谓的Birthday paradox,在2 ^ 32交易的平方根之后,可能会产生相同的交易。

描述Bridge交易生成应用程序要求的文档的作者编写了一个程序,在世界范围内用于生成随机交易,使用键盘上的人类输入生成96位种子。十四年来,这种方法没有出现任何缺陷。

我想编写一个例程,放弃使用人工输入来生成所需种子的需要。

RNGCryptoServiceProvider。我使用下面的代码生成随机数,首先在1到52的范围内,然后在1到51的范围内,依此类推,直到剩下一张卡为止。

测试产生的交易我非常有信心这段代码能够以相同的概率产生任何交易能够,并且任何卡片最终都有四个玩家之一的机会等于0.25。

但由于我不知道RNGCryptoServiceProvider中使用的种子的强度,我想知道是否:

  1. 此代码将能够或可以适应,产生2 ^ 96个不同的交易。
  2. 此代码的下一笔交易无法预测。
  3. 修改 获得此问题中先前提到的随机数的方法存在缺陷。如果这个代码能够产生2 ^ 96个不同的Bridge交易,这就分散了主要问题。我用the one published by Stephen Taub and Shawn Farkas in the MSDN magazine

    替换了随机数生成器

    用于生成加密安全随机数的代码,范围为1-52,1-51,依此类推,最高为1-2,取自this website

         /// <summary>
    /// Returns a random number within a specified range.
    /// </summary>
    /// <returns>
    /// A 32-bit signed integer greater than or equal to <paramref name="minValue"/> and less than <paramref name="maxValue"/>; that is, the range of return values includes <paramref name="minValue"/> but not <paramref name="maxValue"/>. If <paramref name="minValue"/> equals <paramref name="maxValue"/>, <paramref name="minValue"/> is returned.
    /// </returns>
    /// <param name="minValue">The inclusive lower bound of the random number returned.</param>
    /// <param name="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.</param>
    /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minValue"/> is greater than <paramref name="maxValue"/>.</exception>
    public override Int32 Next(Int32 minValue, Int32 maxValue)
    {
        if (minValue > maxValue) throw new ArgumentOutOfRangeException("minValue");
        if (minValue == maxValue) return minValue;
        Int64 diff = maxValue - minValue;
    
        while (true)
        {
            //The cryptoProvider is of type RNGCryptoServiceProvider.
            cryptoProvider.GetBytes(uint32Buffer); //The uint32Buffer has a size of 4 bytes.
            UInt32 rand = BitConverter.ToUInt32(uint32Buffer, 0);
    
            Int64 max = (1 + (Int64)UInt32.MaxValue);
            Int64 remainder = max % diff;
            if (rand < max - remainder)
            {
                return (Int32)(minValue + (rand % diff));
            }
        }
    }
    

1 个答案:

答案 0 :(得分:5)

一旦你有一个真正统一的随机数发生器(RNG)&#34;,请执行以下操作:

  1. 使用基于外部源的种子初始化RNG。这可以是键盘输入,程序开始时间或许多其他事情。根据我的研究,似乎RNGCryptoServiceProvider已经完成了这一部分。

  2. 最重要的是,在(频繁)间隔时,从RNG中抽取一个数字。把这个号码丢掉,重要的是你已经循环了#34; RNG。如果需要,您可以随机设置间隔以增加不可预测性。更多的周期更好,所以我会选择一个你认为可以去的最大间隔。

    • 随机区间有两种选择:(a)使用较弱的RNG(它们使用的是),以及(b)忽略它。在老虎机中,用户的输入(按下&#34;旋转&#34;)导致实际的RNG抽取。结合足够快的骑行间隔,它被认为是不可预测的。

  3. (有些可选)不要连续绘制所有数字。在绘制下一个数字(或一组数字)之前,等待一段随机的时间(允许RNG循环一个随机的次数)。因为初始绘制很可能是基于用户输入,所以 应该能够一次性绘制它们。但它不会受到伤害。

  4. 这是游戏(赌博)行业中使用的过程,其中不可预测的RNG受到严格监管(当然,也是必需的)。使用此方法完成涉及500张牌(来自100个单独的牌组)的抽签。请注意,所使用的RNG通常采用32位种子,并且完全可以接受。