views:

111

answers:

2

I couldn't find any clock drift RNG code for Windows anywhere so I attempted to implement it myself. I haven't run the numbers through ent or DIEHARD yet, and I'm just wondering if this is even remotely correct...

void QueryRDTSC(__int64* tick) {
 __asm {
  xor eax, eax
  cpuid
  rdtsc
  mov edi, dword ptr tick
  mov dword ptr [edi], eax
  mov dword ptr [edi+4], edx
 }
}

__int64 clockDriftRNG() {
 __int64 CPU_start, CPU_end, OS_start, OS_end;

 // get CPU ticks -- uses RDTSC on the Processor
 QueryRDTSC(&CPU_start);
 Sleep(1);
 QueryRDTSC(&CPU_end);


 // get OS ticks -- uses the Motherboard clock
 QueryPerformanceCounter((LARGE_INTEGER*)&OS_start);
 Sleep(1);
 QueryPerformanceCounter((LARGE_INTEGER*)&OS_end);

 // CPU clock is ~1000x faster than mobo clock    
    // return raw
 return ((CPU_end - CPU_start)/(OS_end - OS_start));

    // or
 // return a random number from 0 to 9
 // return ((CPU_end - CPU_start)/(OS_end - OS_start)%10);
}

If you're wondering why I Sleep(1), it's because if I don't, OS_end - OS_start returns 0 consistently (because of the bad timer resolution, I presume).

Basically, (CPU_end - CPU_start)/(OS_end - OS_start) always returns around 1000 with a slight variation based on the entropy of CPU load, maybe temperature, quartz crystal vibration imperfections, etc.

Anyway, the numbers have a pretty decent distribution, but this could be totally wrong. I have no idea.

Edit: According to Stephen Nutt, Sleep(1) may not be doing what I'm expecting, so instead of Sleep(1), I'm trying to use:

void loop() {
 __asm {
  mov ecx, 1000
  cylcles:
  nop
  loop cylcles
 }
}
+1  A: 

Consider some multiplication to increase the range. Then use the result to seed a PRNG.

Yuliy
+1  A: 

The Sleep function is limited by the resolution of the system clock, so Sleep (1) may not be doing what you want.

Stephen Nutt