Intel Secure Key (RDRAND) possibly strange behaviour

226 views Asked by At

I've been using the Intel-provided RNG feature for some time, to provide myself with some randomness by means of a C++/CLI program I wrote myself.

However, after some time, something struck me as particularly suspicious. Among other uses, I ask for a random number between 1 and 4 and wrote the result down on paper each time. Here are the results :

2, 3, 3, 2, 1, 3, 4, 2, 3, 2, 3, 1, 3, 2, 3, 1, 2, 4, 2, 2, 1, 2, 1, 3, 1, 3, 3, 3, 3.

Number of 1s : 6 Number of 2s : 9 Number of 3s : 12 Number of 4s : 2 Total : 29

I'm actually wondering if there's a problem either with Intel's RNG, my algorithm, methodology or something else maybe ? Or do you consider the bias not to be significant enough yet ?

I'm using Windows 10 Pro, my CPU is an Intel Core i7-4710MQ. Compiled with VS2017.

Methodology :

  1. Start a Powershell command prompt
  2. Load my assembly with Add-Type -Path <mydll>
  3. Invoke [rdrw.Random]::Next(4)
  4. Add one to the result

A detail that may be of importance : I don't ask for that number very often, so there's some time between draws and it usually comes when the RNG hasn't been used for some time (one hour at least).

And yes it's a lazy algorithm, I didn't want to bother myself with exceptions.

Algorithm follows :

#include <immintrin.h>

namespace rdrw {

#pragma managed(push,off)
    unsigned long long getRdRand() {
        unsigned long long val = 0;

        while (!_rdrand64_step(&val));
        return val;
    }
#pragma managed(pop)

    public ref class Random abstract sealed
    {
    public:
        // Returns a random 64 bit unsigned integer
        static unsigned long long Next() {
            return getRdRand();
        }

        // Return a random unsigned integer between 0 and max-1 (inclusive)
        static unsigned long long Next(unsigned long long max) {
            unsigned long long nb = max - 1;
            unsigned long long mask = 1;
            unsigned long long draw = 0;

            if (max <= 1)
                return 0;

            // Create a bitmask that's at least as big as the biggest acceptable value
            while ((nb&mask) != nb)
            {
                mask <<= 1;
                mask |= 1;
            }

            do
            {
                // Throw unnecessary bits
                draw = Next() & mask;
            } while (draw>nb);
            return draw;
        }

        // return a random unsigned integer between min and max-1 inclusive
        static unsigned long long Next(unsigned long long min, unsigned long long max) {

            if (max == min)
                return min;
            if (max < min)
                return 0;
            unsigned long long diff = max - min;
            return Next(diff) + min;
        }
    };
}

Thanks for your insights !

0

There are 0 answers