安全随机数
Sapphire.randomBytes 是 OXN 的链上随机数源。它从 enclave 自身的熵中取值——不是从区块哈希、时间戳或验证人可控值中——对观察者不可预测,验证人也无法操纵。
签名
function randomBytes(uint256 numBytes, bytes memory personalization)
internal view returns (bytes memory);
numBytes——要多少字节。uint256通常 32,更小范围可以更少。personalization——可选上下文。不同 personalization 字符串在同一区块内产生不同随机流,需要多次独立抽取时有用。
返回长度为 numBytes 的 bytes。
基本用法
import "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol";
contract Raffle {
address[] public participants;
function pickWinner() external view returns (address) {
require(participants.length > 0, "no participants");
bytes memory r = Sapphire.randomBytes(32, "");
uint256 idx = uint256(bytes32(r)) % participants.length;
return participants[idx];
}
}
一次调用内两次抽取
一个函数里需要多个独立随机值时,用不同的 personalization:
bytes memory r1 = Sapphire.randomBytes(32, "draw-1");
bytes memory r2 = Sapphire.randomBytes(32, "draw-2");
不用不同 personalization 时,同一区块内两次调用得到相同结果。这是故意的——熵按区块派生;personalization 字符串让你从同一底层源产生独立流。
安全性质
对观察者不可预测。 随机输出在 enclave 内生成,熵从不离开 enclave。任何 RPC 观察者、区块浏览器、节点运营方都无法在使用前预测这个值。
验证人无法操纵。 因为熵源在 enclave 内而不是从区块元数据派生,验证人无法通过重新排序交易或选择哪个区块包含调用来偏斜结果。
未来不可预测。 现在产出的随机值无法通过模拟未来区块预测——熵流依赖只往前推进的运行时状态。
不要用作随机数的东西
block.timestamp、block.number、block.hash、PREVRANDAO——全都公开可预测。任何观察者都能读;验证人能操纵。任何基于随机性发放价值的场景都不要用。
keccak256(abi.encodePacked(block.timestamp, msg.sender))——常见的以太坊模式,零真实随机性。每一个输入都是公开的。
链下预言机——引入对预言机的信任。公开数据可以,但对机密合约毫无意义。
OXN 上只有 Sapphire.randomBytes 提供真正的密码学随机数。