/dev/randomと/dev/urandom(これで最後)は、乱数を発生させるデバイスで、エントロピ生成機と称する入力デバイス(/proc/input下のデバイス)割り込みタイミングをベースに、乱数を発生させるようです。なお/dev/randomは完全にエントロピ生成機をベースにしており、従ってマウス/キーボードの入力割り込みがない場合、その割り込みが発生するまで、ブロックされます。 /dev/randomをcatで読み出すと、キーボード/マウスを動作させないと停まってしまうのはそのためです。(キーボード/マウスの操作はリモート端末ではダメです。)
なお、割り込みハンドらのstruct irqaction* action->flagsにIRQF_SAMPLE_RANDOMを設定することで、入力デバイス以外の割り込みデバイスでも、乱数のベースにすることができるようです。
/dev/urandomもエントロピ生成機をベースにしていますが、割り込みが発生していない場合、前回の情報をベースにハッシュにて乱数を生成しているようです。従ってブロックされることがありません。
入力割り込み毎に前回の割り込みとの時間差をベースにして、エントロピープールに蓄えて、実際の乱数発生時は、このプールからセコンドプールに転送して、そこから乱数を生成しているようです。たぶんメインプールに蓄え時は、プリエンプと禁止する必要があり、パフォーマンスの兼ね合いじゃないでしょうか?この辺りのこととか、数学的(?)な事もあってか、実装はわかりません。
とりあえず、エントロピーのベースとなる、割り込みからの処理です。入力デバイスからの割り込み毎に、add_input_randomness()がコールされ、そこからadd_timer_randomness()してエントロピーの計算をしているようです。
void add_input_randomness(unsigned int type, unsigned int code,
unsigned int value)
{
static unsigned char last_value;
/* ignore autorepeat and the like */
if (value == last_value)
return;
DEBUG_ENT("input event\n");
last_value = value;
add_timer_randomness(&input_timer_state,
(type << 4) ^ code ^ (code >> 4) ^ value);
}
なんか良くわかりませんが、雰囲気、前回の割り込みと今回の割り込みの時間差(jiffies値)をdelta、前回のdeltaと今回のdeltaの差をdelta2、前回のdelta2と今回のdelta2の差をdelta3とし、その絶対値の小さい物を、credit_entropy_bit()の引数として、エントロピーの処理としているようですが・・・。
static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
{
struct {
long jiffies;
unsigned cycles;
unsigned num;
} sample;
long delta, delta2, delta3;
preempt_disable();
/* if over the trickle threshold, use only 1 in 4096 samples */
if (input_pool.entropy_count > trickle_thresh &&
((__this_cpu_inc_return(trickle_count) - 1) & 0xfff))
goto out;
sample.jiffies = jiffies;
if (!arch_get_random_int(&sample.cycles))
sample.cycles = get_cycles();
sample.num = num;
mix_pool_bytes(&input_pool, &sample, sizeof(sample));
if (!state->dont_count_entropy) {
delta = sample.jiffies - state->last_time;
state->last_time = sample.jiffies;
delta2 = delta - state->last_delta;
state->last_delta = delta;
delta3 = delta2 - state->last_delta2;
state->last_delta2 = delta2;
if (delta < 0)
delta = -delta;
if (delta2 < 0)
delta2 = -delta2;
if (delta3 < 0)
delta3 = -delta3;
if (delta > delta2)
delta = delta2;
if (delta > delta3)
delta = delta3;
credit_entropy_bits(&input_pool,
min_t(int, fls(delta>>1), 11));
}
out:
preempt_enable();
}