天天看點

Solidity随機數代碼

在這個教程中,我們介紹随機數的基本概念以及實作原理,學習如何在以太坊智能合約中實作自己的Solidity随機數發生器,并提供完整的solidity随機數發生器實作源碼。

不同開發語言的以太坊教程: Java | Php Python .Net / C# Golang Node.JS Flutter / Dart

1、什麼是随機數

想象一下你身邊的随機噪音或者任何随機發生的事情,可以說檢測到這些随機模式的機率為0。這就是随機數的意思 —— 一個可以生成指定範圍内的任意不确定數字的模式。

當我這麼說的時候,考慮一下1~100之間的某個數。由于不确定性,我猜不出來你的腦子裡現在想的是哪個數。

随機數是從某個特定分布中選中的數,通常也會要求這些數之間彼此獨立,這樣在前後兩個數之間就不會存在相關性。計算機生成的随機數有時會稱為__僞随機數__,這一術語中保留了__随機__,表示其不可預測性。當沒有額外的約定時,通常随機數采樣自均勻分布。當然也可以使用其他的機率分布,例如,Box-Muller變換可以将一對滿足均勻分布的随機數轉換為一個二維正态分布。

2、什麼是僞随機數

__僞随機數__也被稱為确定性随機位。這些數是使用被稱為__僞随機數發生器/PRNG__的計算機算法生成的,它們是确定性的,是以并不是真的随機,這些僞随機數在經過一定的序列之後可能會重複。

為了生成随機數,我們需要使用一個數來初始化算法,這個數被稱為__種子/SEED__。通常使用補齊的系統時間作為種子,為了確定這些僞随機數有足夠的随機性,我們會加一些__鹽/SALT__或__糖/SUGAR__—— 可以将它視為你的僞随機數的密碼 —— 以避免哈希碰撞,也就意味着會生成重複的數。

3、區塊鍊上如何實作僞随機數發生器

從前面的描述中,我們知道計算機裡的随機數并不是真的随機,并且至少需要一個系統時間來初始化算法,如果你要用它來開發某些有很強的随機要求的應用,例如博彩遊戲、計算機仿真、密碼學等,這就有可能發生哈希碰撞。

這就是為什麼在區塊鍊上基本上不可能生成随機數的原因,我們需要擷取區塊時間或區塊哈希之類的作為種子,由于早期第一代和第二代區塊鍊的出塊速度很慢,那麼發生哈希碰撞的機會非常大。

但是,第三代的區塊鍊已經可以達到很快的出塊速度了,比如0.5~1秒,這樣我們就可以利用區塊時間戳或區塊哈希來初始化僞随機數發生器。

3、Solidity随機數發生器

下面的Solidity合約代碼展示了如何在以太坊區塊鍊上實作一個Solidity随機數發生器。

你可以說這是一個__真随機數發生器/TRNG__,因為我們沒有使用算法來生成随機數,而隻是将區塊時間與種子、鹽、糖組合後計算哈希。我們選擇的這三個值可以是相同的并且是确定性的,但是區塊哈希是不确定性的下面的代碼支援以太坊、波場或其他任何支援Solidity的第三代區塊鍊:

pragma solidity ^0.5.8;

/**
 * @title True random number generator
 * @notice This is a contract to generate a true random number on blockchai.
 * Though true random number generators doesn't require seed. But, to simplify
 * the functions i used seed and other terms used in PRNGs,
 * seed should be enough to generate a random number, but to randomize the pattern
 * even more i added two more functions with salt and sugar.
 */
contract PRNG {
    /**
        * @notice Generates a random number between 0 - 100
        * @param seed The seed to generate different number if block.timestamp is same
        * for two or more numbers.
        */
    function importSeedFromThird(uint256 seed) public view returns (uint8) {
        uint8 randomNumber = uint8(
            uint256(keccak256(abi.encodePacked(block.timestamp, seed))) % 100
        );
        return randomNumber;
    }

    /**
     * @notice Generates a random number between 0 - 100
     * @param seed The seed to generate different number if block.timestamp is same
     * for two or more numbers.
     * @param salt The salt to randomize the pattern
     */
    function importSeedFromThirdSalt(uint256 seed, uint256 salt)
        public
        view
        returns (uint8)
    {
        uint8 randomNumber = uint8(uint256(keccak256(abi.encodePacked(block.timestamp, seed, salt))) % 100);
        return randomNumber;
    }

    /**
     * @notice Generates a random number between 0 - 100
     * @param seed The seed to generate different number if block.timestamp is same
     * for two or more numbers.
     * @param salt The salt to randomize the pattern
     * @param sugar The sugar same as salt but for more randomization
     */
    function importSeedFromThirdSaltSugar(
        uint256 seed,
        uint256 salt,
        uint256 sugar
    ) public view returns (uint8) {
        uint8 randomNumber = uint8(uint256(keccak256(abi.encodePacked(block.timestamp, seed, salt, sugar))) % 100);
        return randomNumber;
    }
}           

在上面的合約中,我們實作了三個函數,分别使用不同的參數生成Solidity随機數:

  • importSeedFromThird:隻需要種子的Solidity随機數發生器
  • importSeedFromThirdSalt:需要種子、鹽的Solidity随機數發生器
  • importSeedFromThirdSaltSugar:需要種子、鹽、糖的Solidity随機數發生器

abi.encodePacked

以不對齊的方式将資料打包。

eccak256

哈希函數和

sha3

類似,隻是采用不同的補齊模式,具體可以參考

這裡

是以,在上面的函數中,我們實際上将包含時間、種子、鹽、糖的資料進行了編碼進而獲得更強的随機性,并盡可能讓随機數不可預測。當然我們可以從上面函數實作中删除時間戳,但是這樣的話,我們就完全控制了随機數的發生,進而破壞了區塊鍊的透明特性。

原文連結:

Solidity随機數發生器原理與實作 — 彙智網