哈希函数的随机性,如SHA1

时间:2012-08-01 23:02:26

标签: php random sha

我正在尝试根据用户ID生成随机数的均匀分布。也就是说,我希望每个用户的随机数在用户请求随机数时保持不变(但用户不需要存储该数字)。对于给定的大型userID $arr,我当前用于计算分布的算法(在PHP中)是:

$range = 100;
$results = array_fill(0, $range, 0);

foreach ($arr as $userID) {
    $hash = sha1($userID,TRUE);
    $data = unpack('L*', $hash);
    $seed = 0;
    foreach ($data as $integer) {
        $seed ^= $integer;
    }
    srand($seed);
    ++$results[rand(0, $range-1)];
}

人们希望这会产生近似均匀的分布。但事实并非如此!我已经检查过以确保$arr中的每个值都是唯一的,但列表中的一个条目总是比其他条目获得更多的活动。有没有更好的方法来生成一个字符串的散列,它会产生近似均匀的分布?显然SHA不能胜任这项工作。我也试过MD5和一个简单的crc32,都有相同的结果!?

我疯了吗?事实上,我唯一的解释是,验证$arr中的每个条目都是唯一的吗?

4 个答案:

答案 0 :(得分:4)

sha1哈希数分布非常均匀。执行此操作后:

<?php

$n = '';
$salt = 'this is the salt';

for ($i=0; $i<100000; $i++) {
    $n .= implode('', unpack('L*', sha1($i . $salt)));
}   

$count = count_chars($n, 1);
$sum = array_sum($count);

foreach ($count as $k => $v) {
    echo chr($k)." => ".($v/$sum)."\n";
} 

?>

你得到这个结果。每个数字的概率:

0 => 0.083696057956298
1 => 0.12138983759522
2 => 0.094558704004335
3 => 0.07301783188663
4 => 0.092124978934097
5 => 0.088623772577848
6 => 0.11390989553446
7 => 0.092570936094051
8 => 0.12348330833868
9 => 0.11662467707838

您可以根据用户的ID使用sha1作为简单的随机数生成器。

在十六进制中,分布接近完美:

//  $n .= sha1($i . $salt, false);

0 => 0.06245515
1 => 0.06245665
2 => 0.06258855
3 => 0.0624244
4 => 0.06247255
5 => 0.0625422
6 => 0.0625246
7 => 0.0624716
8 => 0.06257355
9 => 0.0625005
a => 0.0625068
b => 0.0625086
c => 0.0624463
d => 0.06250535
e => 0.06250895
f => 0.06251425

答案 1 :(得分:1)

mt_rand()应在所请求的范围内分布均匀。创建用户后,使用mt_rand()为该用户创建随机种子,然后始终mt_srand()使用该用户的种子。

要获得从0到99的均匀分布,仅作为示例,只需mt_rand(0,$range-1)。使用sha1,md5或其他一些散列算法做一些技巧,实际上不会比直接随机分配更均匀。

答案 2 :(得分:0)

如果您发布的结果会让您得出结论认为您没有获得适当的分发,那会很有帮助,但这可能是以下三种情况之一:

  1. 您只是看着太小的样本,和/或您错过了解释您的数据。正如其他人所评论的那样,均匀分布完全没有完全统一的输出是完全合理的。

  2. 如果您使用mt_rand代替rand,则效果会更好。

  3. (就个人而言,我认为这很有可能)你过度优化种子生成,丢失数据/鸽子/否则会损害你生成随机数的能力。阅读你的代码,我认为你正在做以下事情:

    1. 生成未知值的统一随机哈希
    2. 将哈希分成长片并按位对它们进行异或(
    3. 设置rand的种子,并从该种子生成随机数
    4. 但你为什么要做第2步呢?你认为从中得到了什么好处?尝试采取这一步骤,只需使用从哈希中提取的第一个值作为种子,并查看这是否不会给您带来更好的结果。具有随机性的良好经验法则 - 不要试图超越实施算法的人,不能做到:)

答案 3 :(得分:0)

虽然这里的所有答案都很好,但我会提供对我来说正确的答案,那就是我确实疯了。实际上,uniq命令实际上并不像我预期的那样工作(数据需要先排序)。所以解释的确是$arr中的值不是唯一的。