module dcrypt.random.fortuna.sources.systemtick;

import core.time;


import dcrypt.random.fortuna.entropysource;
import dcrypt.random.fortuna.fortuna: addEntropy;

/// Generate entropy data with the system clock.
@safe
public class SystemTickEntropySource: EntropySource
{

	override void collectEntropy() nothrow {
		ubyte[64] buf;

		getTimingEntropy(buf);

		sendEntropyEvent(buf);
	}

	@nogc @property nothrow
	override public string name() {
		return "SystemTickSource";
	}

	@safe @nogc nothrow
	override uint scheduleNext() {
		return 250;
	}

}

/// Fill the buffer with timing measurements.
/// Params:
/// buf = The buffer to fill.
@safe @nogc nothrow
static void getTimingEntropy(ubyte[] buf) {
	foreach(ref b; buf) {
		ulong ticks = MonoTime.currTime.ticks;
		b = cast(ubyte) (ticks^(ticks>>8)^(ticks>>16)); // Combine three bytes for the case if the system clock has low resolution.
	}
}

unittest {
	ubyte[32] buf1, buf2;
	
	getTimingEntropy(buf1);
	getTimingEntropy(buf2);
	
	assert(buf1 != buf2, "Measurements are not at all random!");
}