我正在寻找一个小抽奖活动,但我希望人们能够验证选择的数字是否合理 . 我知道一些网站使用“可证明公平”系统来实现这一点,其中用户输入与秘密字符串组合,然后进行散列以确定中奖号码 . 一旦秘密字符串被释放,参与者可以使用散列来验证选择了正确的获胜者 .
从sha512哈希中,应生成0-n的“随机”数字(n长度不同但最多为255)以确定获胜者 . 这就是我想到的:
创建一个n长度的数组并插入可以出现在sha哈希中的字符对 . 例如,如果n为255,则数组将具有: array('aa','ab','ac'...'fd','fe','ff'...'97','98','99')
. 基本上它使用a-f和0-9的两个字符的每个组合 .
然后它会查看散列的前两个字符并使用array_search来查看该对是否存在于数组中 . 如果是的话,它的索引是拾取的数字,否则它会移动到下一对字符并搜索它们 . 在极少数情况下,它找不到匹配项,它会不断地自我哈希并使用返回的新哈希继续搜索 .
$values = array('a','b','c','d','e','f','0','1','2','3','4','5','6','7','8','9');
$numbers = array();
$ENTRANTS = 50;
$rand = md5(uniqid(rand(), true)); //This would instead be $secret . $user_input
$hash = hash('sha512',$rand);
$values_index = 0;
$current = $values[$values_index];
$options = 0;
while ($options < $ENTRANTS){
$remaining = ($ENTRANTS - $options > 15)? 16: $ENTRANTS-$options;
for ($n=0; $n < $remaining ;$n++){
array_push($numbers, $current . $values[$n]);
$options++;
}
$values_index++;
$current = $values[$values_index];
}
$outcomes = array();
$winning = null;
$i = 0;
while (empty($winning)){
while ($i+1 < 64 && empty($winning)){
$combo = $hash[$i] . $hash[$i+1];
$number = array_search($combo,$numbers);
if ($number !== false){
$winning = $number;
}
$i++;
}
if (!empty($winning)){
echo "<pre>" . print_r($numbers,true) . "</pre>";
echo $hash . "<br>" . $winning;
}
else {
echo "re-hashing" . "<br>";
$hash = hash("sha512",$hash);
$i = 0;
}
}
这在测试时有效,但我不确定它是否有效地生成随机数 . sha512散列中的字符是否大部分均匀且不可预测地分布?如果您对此有任何疑问或对如何改进有任何建议,请告诉我们!
1 回答
最好的方法 - 就像在加密中一样 - 如果可以避免的话,就不会自行安全 . 作为随机数生成器rand() is not cryptographically secure(参见注释部分) . 在其上应用哈希不会使这个随机数生成器安全 . 实际上,从一组(坏)RNG中制作一个好的RNG是不可能的 .
相反,使用openssl_random_pseudo_bytes要好得多 . 有no need to perform any post processing on the bytes you get from that random number generator - 至少不添加加密强度 .