Solidity – Gas Efficient Ways to Generate Multiple Different Random Numbers

solidity

I am constructing some nft metadat on-chain, and need to grab pseudo random number for each of the traits, these numbers need to be different.

So far best I came up with is following

  function getRandomNumbers(string memory seed) private view returns (uint256[8] memory) {
    return [
      randomise(string(abi.encodePacked("property 1", seed)), property1Arr.length),
      randomise(string(abi.encodePacked("property 2", seed)), property2Arr.length),
      randomise(string(abi.encodePacked("property 3", seed)), property3Arr.length),
      randomise(string(abi.encodePacked("property 4", seed)), property4Arr.length)
    ];
  }

  function randomise(string memory seed, uint256 range) private view returns (uint256) {
    return uint256(keccak256(abi.encodePacked(seed, block.difficulty, block.timestamp, block.number))) % range;
  }

So brief explanation, getRandomNumbers takes in "seed" from client and combines it with property string, this is repeated multiple times for each property. Then resulting combined string is used as "seed" for randomise that returns random integer by further randomising it using some block data and returning number that is in range for the array of properties.

This does decent job, but doesn't scale well, so I am wondering if there is a better approach here that I might be missing.

Best Answer

Maybe the following approach will work for you. The basic idea is that instead of "throwing away" most of the random number after doing "% range", you continue using it.

function getRandomNumbers(string memory seed) public view returns (uint256[4] memory) {
    (uint a, uint b, uint c, uint d) = (5,5,10,20);
    uint256 randomKeccak = uint256(keccak256(abi.encodePacked(seed, block.difficulty, block.timestamp, block.number)));
    return [
      randomKeccak % a,
      randomKeccak / a % b,
      randomKeccak / a / b % c,
      randomKeccak / a / b / c % d
    ];
}

Here a,b,c,d are the lengths of the various propertyArrs.

This is just a proof of concept. You can perhaps also use bit operations for this.

Related Topic