Celo中的随机数
Posted mutourend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Celo中的随机数相关的知识,希望对你有一定的参考价值。
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)=sn−1。对于该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身份注册中所使用的随机数
以上是关于Celo中的随机数的主要内容,如果未能解决你的问题,请参考以下文章