Celo中的随机数

Celo项目使用commit-reveal方案来实现无需可信第三方的随机数生成。Validator在提议区块时附加一个随机数承诺,并在后续区块中揭示实际的随机数。随机数用于增加熵池,历史随机值通过keccak256拼接。此过程确保了随机性的不可预测性和安全性。此外,还实现了历史随机值的存储和管理,以控制存储开销并保持随机数历史的可追溯性。
摘要由CSDN通过智能技术生成

1. 引言

在无需可信第三方的情况下,实现不可预测的伪随机数的方案有:

  • VRF
  • VDF
  • Commit-reveal

在这里插入图片描述

当前,Celo项目采用的是简单的commit-reveal方案来随机选择Validator.
对于某特定Validator propose的第 n n n个区块,该Validator会在该区块内附加值 ( r n , s n ) (r_n,s_n) (rn,sn),使得 keccak256 ( r n ) = s n − 1 \text{keccak256}(r_n)=s_{n-1} keccak256(rn)=sn1。对于该Validator propose的第一个区块 n = 1 n=1 n=1,则初始随机值 r 1 = 0 r_1=0 r1=0

  /**
   * @notice Implements step of the randomness protocol.
   * @param randomness Bytes that will be added to the entropy pool.
   * @param newCommitment The hash of randomness that will be revealed in the future.
   * @param proposer Address of the block proposer.
   */
  function _revealAndCommit(bytes32 randomness, bytes32 newCommitment, address proposer) internal {
    require(newCommitment != computeCommitment(0), "cannot commit zero randomness");

    // ensure revealed randomness matches previous commitment
    if (commitments[proposer] != 0) {
      require(randomness != 0, "randomness cannot be zero if there is a previous commitment");
      bytes32 expectedCommitment = computeCommitment(randomness);
      require(
        expectedCommitment == commitments[proposer],
        "commitment didn't match the posted randomness"
      );
    } else {
      require(randomness == 0, "randomness should be zero if there is no previous commitment");
    }

    // add entropy
    uint256 blockNumber = block.number == 0 ? 0 : block.number.sub(1);
    addRandomness(block.number, keccak256(abi.encodePacked(history[blockNumber], randomness)));

    commitments[proposer] = newCommitment;
  }
  /**
   * @notice Compute the commitment hash for a given randomness value.
   * @param randomness The value for which the commitment hash is computed.
   * @return Commitment parameter.
   */
  function computeCommitment(bytes32 randomness) public pure returns (bytes32) {
    return keccak256(abi.encodePacked(randomness));
  }

在每一个区块会reveal该Validator之前区块所commit的随机值,reveal的随机值会存入一个entropy pool中。所有已reveal的历史随机值会通过keccak256拼接在一起。

    // add entropy
    uint256 blockNumber = block.number == 0 ? 0 : block.number.sub(1);
    // 所有已reveal的历史随机值会通过`keccak256`拼接在一起。
    addRandomness(block.number, keccak256(abi.encodePacked(history[blockNumber], randomness)));

mapping(uint256 => bytes32) private history;

  /**
   * @notice Add a value to the randomness history.
   * @param blockNumber Current block number.
   * @param randomness The new randomness added to history.
   * @dev The calls to this function should be made so that on the next call, blockNumber will
   * be the previous one, incremented by one.
   */
  function addRandomness(uint256 blockNumber, bytes32 randomness) internal {
    history[blockNumber] = randomness;
    if (blockNumber % getEpochSize() == 0) {
      if (lastEpochBlock < historyFirst) {
        delete history[lastEpochBlock];
      }
      lastEpochBlock = blockNumber;
    } else {
      if (historySize == 0) {
        historyFirst = blockNumber;
        historySize = 1;
      } else if (historySize > randomnessBlockRetentionWindow) { // 控制history map存储的数据量,节约空间。
        deleteHistoryIfNotLastEpochBlock(historyFirst);
        deleteHistoryIfNotLastEpochBlock(historyFirst.add(1));
        historyFirst = historyFirst.add(2);
        historySize = historySize.sub(1);
      } else if (historySize == randomnessBlockRetentionWindow) {
        deleteHistoryIfNotLastEpochBlock(historyFirst);
        historyFirst = historyFirst.add(1);
      } else {
        // historySize < randomnessBlockRetentionWindow
        historySize = historySize.add(1);
      }
    }
  }

获取特定区块对应的随机值:

  /**
   * @notice Get randomness values of previous blocks.
   * @param blockNumber The number of block whose randomness value we want to know.
   * @param cur Number of the current block.
   * @return The associated randomness value.
   */
  function _getBlockRandomness(uint256 blockNumber, uint256 cur) internal view returns (bytes32) {
    require(blockNumber <= cur, "Cannot query randomness of future blocks");
    require(
      blockNumber == lastEpochBlock ||
        (blockNumber > cur.sub(historySize) &&
          (randomnessBlockRetentionWindow >= cur ||
            blockNumber > cur.sub(randomnessBlockRetentionWindow))),
      "Cannot query randomness older than the stored history"
    );
    return history[blockNumber];
  }

参考资料

[1] Celo身份注册中所使用的随机数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值