Sha-512

這種從 sha512 雜湊生成“隨機”數字的方法是否有效?

  • February 11, 2014

我希望舉辦一次小型抽獎活動,但我希望人們能夠驗證所選擇的號碼是否公平。我知道有些網站使用“可證明公平”的系統來實現這一點,其中使用者輸入與一個秘密字元串相結合,然後對其進行散列以確定獲勝者。一旦秘密字元串被釋放,參與者可以使用雜湊來驗證選擇了正確的獲勝者。

應該從 sha512 雜湊中生成一個從 0 到 n 的“隨機”數字(n 的長度不同,但最多為 255)以確定獲勝者。這是我想到的:

創建一個長度為 n 的數組並插入可以出現在 sha 雜湊中的字元對。例如,如果 n 為 255,則數組將具有:array('aa','ab','ac'...'fd','fe','ff'...'97','98','99'). 基本上它會使用 af 和 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 = 100;
   $rand =  md5(uniqid(rand(), true));
$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 散列中的字元大部分是否均勻且不可預測地分佈?如果您對此有任何問題或對如何改進有任何建議,請告訴我!

通常,您選擇其中一個條目的方式似乎不必要的複雜。正如 fgrieu 指出的那樣,您應該可以通過減少以參與者數量為模的雜湊值(但使用 $ n $ 人,你計算 $ h $ 反對 $ n $ , 並分配從 $ 0 $ 到 $ n-1 $ ).

不過,一個重要的問題是如何確定散列函式的輸入。如果你用隨機的東西播種,人們就不能確定你沒有作弊(通過嘗試不同的種子)。

為了提供信心,您可能需要執行以下操作:

  • 最初,您提供對您選擇的某些秘密價值的承諾。一切完成後,您可以公開承諾並顯示秘密價值。
  • 然後你執行你的抽獎。人們可以簽下他們的名字,而您可以將名單公開。這樣他們就可以確保他們的名字出現在抽獎中。列表索引還為每個參與者提供了“幸運數字”。
  • 之後,您首先通過發布解除承諾來揭示秘密值。然後創建一個長位串:連接列表中的所有名稱和秘密值。將此位串用作雜湊函式的輸入(SHA512 可以解決問題,但最終結果最多為 $ 2^8 $ 可能性,任何加密雜湊函式都應該工作)。以參與者的數量為模計算數量。如果你想從 $ 1 $ 到 $ n $ 代替 $ 0 $ 到 $ n-1 $ ,然後只需加 1 (或解釋 $ 0 $ 作為 $ n $ ).

為什麼在這種情況下沒有人可以作弊?

  • 你不能作弊,因為在抽獎開始之前你對函式的輸入是固定的(至少如果你的承諾方案具有約束力;順便說一句。你也可以使用類似“我用 AES 加密我的名字。承諾是密文並且秘密值是使用的密鑰”)
  • 其他人也不能作弊,因為在不知道您的輸入的情況下,他們不應該能夠故意改變對他們有利的結果。
  • 由於不斷增長的姓名列表會隨著雜湊結果的每個附加條目而變化,因此在最後一個人輸入他的姓名之前,沒有人可以預測結果。
  • 我能想到的最糟糕的攻擊場景是,您與添加到列表中的最後一個人一起工作。這個人可以嘗試他名字的不同變體,並在知道秘密的情況下計算結果。但現在我想不出任何辦法來解決這個問題。

引用自:https://crypto.stackexchange.com/questions/14431