17

如何使用VRF(可验证随机函数)在以太坊上生成随机数

 4 years ago
source link: https://learnblockchain.cn/article/1052
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Chainlink 如何解决以太坊“随机数问题”

随机数和区块链一直达到“一致”(译者注:区块链要求确定性,而随机数正相反)。到目前为止,区块链上还没有可验证的随机函数。

原因是:交易被旷工出块后,需要网络上的多个节点来确认才算真实有效。就要求每个节点验证时都必须得出相同的结果。如果函数是随机的(每次运行的结果不一样),则每个节点将得出不同的结果,从而导致交易得不到确认。

有一些解决(变通)方法可以生成一些 伪随机生成 ,但到目前为止,已有的方法都不算是真正的随机,或存在操控的可能。

登链社区之前也有一篇译文:区块链上生成随机数 大家可以读一读。

关于 chainlink

Chainlink网络可以为任何区块链上的复杂智能合约提供可靠的防篡改输入和输出。 —来自 chain.link 官网的介绍

区块链和智能合约针对一组不可变的规则执行计算是个很棒的平台。问题是规则只能应用于系统内部的数据。而如果要从系统外部获取可验证的数据则非常困难。

Chainlink想要通过提供去中心化的预言机来解决这个问题,使区块链能够通过Chainlink访问生态系统之外的数据。预言机(Oracles)实质上是区块链和外部世界之间的桥梁。

真正的随机

在最近的一篇文章中, Chainlink宣布发布了其新的可验证随机函数(VRF) 。开发者现在可以使用该功能将其集成到多个测试网上的DApp中,从而使智能合约能够获得可在链上验证的随机数。

可验证随机函数是怎么实现的?

如果你想在Javascript中生成一个随机数,代码非常简单:

Math.random();

每执行一次,生成一个随机数。然后这不是 VRF的工作方式 。与Javascript不同,VRF是在一些交易实现的。

以下是 VRF 事件发生的顺序:

  1. 你的智能合约 通过交易 向VRF请求一个随机数。

  2. VRF会生成该随机数字并进行验证。

  3. VRF准备响应1 的请求。

  4. VRF通过 另一笔交易 将随机数字发送回你的智能合约。

为了使第4步成功,你的合约需要实现一个确定的函数,以便VRF调用以返回结果。如何在项目中实现呢?

如何实现随机性

让我们创建一个名为 RandomGenerator 的新合约,在合约里我们将调用VRF并接收结果。

第 1 步: 创建消费者合约

我们将引入 Chainlink提供的 VRFConsumerBase 的合约,这是一个抽象合约,它定义了一个获取和消耗VRF的最少实现(后面也会列出 VRFConsumerBase 的代码),我们定义“ RandomGenerator.sol”文件开头像这样:

pragma solidity ^0.6.2;

import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";

contract RandomGenerator is VRFConsumerBase {

    constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
    }

}

VRFConsumerBase 的合约的源码如下:

pragma solidity 0.6.2;

import "./vendor/SafeMath.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./VRFRequestIDBase.sol";

abstract contract VRFConsumerBase is VRFRequestIDBase {

  using SafeMath for uint256;

  function fulfillRandomness(bytes32 requestId, uint256 randomness)
    external virtual;


  function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed)
    public returns (bytes32 requestId)
  {
    LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, _seed));
    // This is the seed actually passed to the VRF in VRFCoordinator
    uint256 vRFSeed  = makeVRFInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]);
    // nonces[_keyHash] must stay in sync with
    // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above
    // successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest)
    nonces[_keyHash] = nonces[_keyHash].add(1); 
    return makeRequestId(_keyHash, vRFSeed);
  }

  LinkTokenInterface internal LINK;
  address internal vrfCoordinator;

  // Nonces for each VRF key from which randomness has been requested.
  //
  // Must stay in sync with VRFCoordinator[_keyHash][this]
  mapping(bytes32 /* keyHash */ => uint256 /* nonce */) public nonces;
  constructor(address _vrfCoordinator, address _link) public {
    vrfCoordinator = _vrfCoordinator;
    LINK = LinkTokenInterface(_link);
  }
}

VRFConsumerBase 仍在后期测试中,因此还没有产品软件包对外提供。这就是为什么使用Github的HTTP URL进行导入的原因。

VRFConsumerBase 抽象合约有两个参数,分别代表协调器(coordinator)和LINK ERC20 代币合约的地址。这些在每个网络上合约地址是固定的(稍后会详细介绍)。

第 2 步: 重载函数

VRFConsumerBase 中有两个对VRF流程至关重要的函数。

第一个是 requestRandomness ,这个函数已经实现了,我们不需要重载。这个函数是用来对VRF进行 初始请求调用

另一个是 fulfillRandomness , 这是VRF在生成数字后,用来回调的函数。我们需要重载它,以便在获取随机数后执行相应的操作。

在我们合约的实现里,仅仅是把随机数存储在一个名为 randomNumber 的状态变量中,以便我们可以在结束时查询它。代码像这样:

pragma solidity ^0.6.2;

import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";

contract RandomGenerator is VRFConsumerBase {
    
    bytes32 public reqId;
    uint256 public randomNumber;

    constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
    }
    
    function fulfillRandomness(bytes32 requestId, uint256 randomness) external override {
        reqId = requestId;
        randomNumber = randomness;
    }
}

我们在 fulfillRandomness 函数上添加了override 修饰符以实现重载,在实现中,使用 reqIdrandomNumber 来保存接收变量的值。

第 3 步: 生成随机数

正如在前面 第1步提到的,函数调用需要传递一些地址和其他值作为参数。在部署智能合约并调用构造函数时,它需要VRF协调器(coordinator)合约地址和网络上LINK 代币合约地址。在Ropsten测试网上,合约地址如下:

  • VRF coordinator: 0xf720CF1B963e0e7bE9F58fd471EFa67e7bF00cfb

  • LINK 代币: 0x20fE562d797A42Dcb3399062AE9546cd06f63280

当调用 requestRandomness 函数时,我们需要传递几个参数:生成随机数的key hash,生成随机数的费用fee(使用LINK代币)和生成随机性的种子seed(最后一个由我们提供)。requestRandomness函数签名如下:

function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed) public returns (bytes32 requestId)

在 Ropsten 网络上,参数值如下:

0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205
1000000000000000000

因此我们的调用代码如下:

// 设置ropsten key hash
bytes32 keyHash = "0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205";// // 设置 ropsten LINK 费用
fee = 1000000000000000000;
// 设置种子
seed = 123456789;
// 请求随机数
bytes32 reqId = rand.requestRandomness(keyHash, fee, seed);

当结果返回时,随机值将存储并且可以通过以下方法获取:

rand.randomNumber;

自己尝试一下

现在我们将逐步实践如何使用 Remix IDE 和Metamask插件从VRF获取随机数。在继续之前,请确保已在浏览器上安装了Metamask 插件。

  • 打开 Remix IDE

  • 如果还没用过 Remix,需要向下图一样选择 Solidity 语言。

    ZV3ER3m.png!web

  • 创建一个文件: RandomGenerator ,把第 2 步中的代码复制过来。

  • 使用左侧菜单,单击Solidity图标,然后选择0.6.2编译器版本,如下图所示。

    RFN3ArM.png!web

然后单击下面的按钮,并在下拉列表中选择“Injected web3”,如下图所示。

QfuUna7.png!web

  • 这时Metamask会提示一个连接请求,我们点击接受请求。
  • 确保MetaMask 连接的是 Ropsten网络,如下图所示:

UZVrAvz.png!web

  • 确保Metamask帐户中有一些Ropsten 网络的 以太币,如果没有,可以从 这里 获取。
  • 回到Remix,在同一选项卡上,应该看到橙色的“ Deploy”按钮,单击“ Deploy”按钮进行部署,注意要接受Metamask弹出的合约部署请求。
  • 在部署后,我们需要确保合约中存有一些LINK 代币,以便它可以为请求随机数支付费用。打开 Ropsten LINK的“水龙头”,粘贴Metamask地址,就可以在Metamask中收到100 LINK。
  • Metamask不知道LINK 代币在Ropsten网络上的地址,因此我们需要添加它。在“ Metamask”中,在帐户名称左侧,单击“菜单”符号,然后单击底部的 “Add Token”。
  • 在 “Custom Token(自定义代币)”下, 添加地址: 0x20fE562d797A42Dcb3399062AE9546cd06f63280 . 剩下的信息将自动填充,提交之后可以看到账号下有 100 个 LINK,下图是 70 个 LINK 的账号截图:

3q6fiyr.png!web

  • 回到 Remix, 复制部署合约地址,如下图:

    rQnQBnJ.png!web

  • 现在我们将向合约发送一些 LINK。回到Metamask,然后单击100 LINK旁边的3个点。粘贴合约地址并发送10 LINK。确认交易后,再继续下一步。

  • 在Remix中,我们现在可以请求随机数了。在同一选项卡中,向下滚动会发现更多代表合约公有(public)函数的橙色按钮,如下图所示。单击 requestRandomness 右侧的箭头以展开参数。

UfmARfQ.png!web

  • 按顺序复制这 3 个数: 0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205 , 1000000000000000000 , 123456789 (或者其他你想要的值)作为参数提交交易。

rauaiyI.png!web

交易可能需要一些时间才能确定,因此需要关注一下终端输出在Etherscan中的交易信息。

2mEnuu7.png!web

交易完成后,我们需要等待VRF生成随机数并将其发送回我们的合约。几分钟后,单击我们在Remix中发送交易的橙色按钮下方的蓝色“ randomNumber”按钮,检查合约是否收到了随机数,如下图所示。

Ez2iUbJ.png!web

如果一切顺利,应该有一个像我这样的随机数,它是 30207470459964961279215818016791723193587102244018403859363363849439350753829 .

现在就大功告成了。

结论

使用 Chainlink 可以在智能合约中可以使用可验证的随机数。在文章中阐述了该机制的工作原理,以及演示了如何将代码集成到智能合约中获取随机数

作者:Alex Roan

原文:https://medium.com/coinmonks/how-to-generate-random-numbers-on-ethereum-using-vrf-8250839dd9e2

欢迎大家在 知乎 ,微博, GitHub 关注我

登链社区赞助翻译。

随机数和区块链一直达到“一致”(译者注:区块链要求确定性,而随机数正相反)。到目前为止,区块链上还没有可验证的随机函数。

原因是:交易被旷工出块后,需要网络上的多个节点来确认才算真实有效。就要求每个节点验证时都必须得出相同的结果。如果函数是随机的(每次运行的结果不一样),则每个节点将得出不同的结果,从而导致交易得不到确认。

有一些解决(变通)方法可以生成一些 伪随机生成 ,但到目前为止,已有的方法都不算是真正的随机,或存在操控的可能。

登链社区之前也有一篇译文:区块链上生成随机数 大家可以读一读。

关于 chainlink

Chainlink网络可以为任何区块链上的复杂智能合约提供可靠的防篡改输入和输出。 —来自 chain.link 官网的介绍

区块链和智能合约针对一组不可变的规则执行计算是个很棒的平台。问题是规则只能应用于系统内部的数据。而如果要从系统外部获取可验证的数据则非常困难。

Chainlink想要通过提供去中心化的预言机来解决这个问题,使区块链能够通过Chainlink访问生态系统之外的数据。预言机(Oracles)实质上是区块链和外部世界之间的桥梁。

真正的随机

在最近的一篇文章中, Chainlink宣布发布了其新的可验证随机函数(VRF) 。开发者现在可以使用该功能将其集成到多个测试网上的DApp中,从而使智能合约能够获得可在链上验证的随机数。

可验证随机函数是怎么实现的?

如果你想在Javascript中生成一个随机数,代码非常简单:

Math.random();

每执行一次,生成一个随机数。然后这不是 VRF的工作方式 。与Javascript不同,VRF是在一些交易实现的。

以下是 VRF 事件发生的顺序:

  1. 你的智能合约 通过交易 向VRF请求一个随机数。

  2. VRF会生成该随机数字并进行验证。

  3. VRF准备响应1 的请求。

  4. VRF通过 另一笔交易 将随机数字发送回你的智能合约。

为了使第4步成功,你的合约需要实现一个确定的函数,以便VRF调用以返回结果。如何在项目中实现呢?

如何实现随机性

让我们创建一个名为 RandomGenerator 的新合约,在合约里我们将调用VRF并接收结果。

第 1 步: 创建消费者合约

我们将引入 Chainlink提供的 VRFConsumerBase 的合约,这是一个抽象合约,它定义了一个获取和消耗VRF的最少实现(后面也会列出 VRFConsumerBase 的代码),我们定义“ RandomGenerator.sol”文件开头像这样:

pragma solidity ^0.6.2;

import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";

contract RandomGenerator is VRFConsumerBase {

    constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
    }

}

VRFConsumerBase 的合约的源码如下:

pragma solidity 0.6.2;

import "./vendor/SafeMath.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./VRFRequestIDBase.sol";

abstract contract VRFConsumerBase is VRFRequestIDBase {

  using SafeMath for uint256;

  function fulfillRandomness(bytes32 requestId, uint256 randomness)
    external virtual;

  function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed)
    public returns (bytes32 requestId)
  {
    LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, _seed));
    // This is the seed actually passed to the VRF in VRFCoordinator
    uint256 vRFSeed  = makeVRFInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]);
    // nonces[_keyHash] must stay in sync with
    // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above
    // successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest)
    nonces[_keyHash] = nonces[_keyHash].add(1); 
    return makeRequestId(_keyHash, vRFSeed);
  }

  LinkTokenInterface internal LINK;
  address internal vrfCoordinator;

  // Nonces for each VRF key from which randomness has been requested.
  //
  // Must stay in sync with VRFCoordinator[_keyHash][this]
  mapping(bytes32 /* keyHash */ => uint256 /* nonce */) public nonces;
  constructor(address _vrfCoordinator, address _link) public {
    vrfCoordinator = _vrfCoordinator;
    LINK = LinkTokenInterface(_link);
  }
}

VRFConsumerBase 仍在后期测试中,因此还没有产品软件包对外提供。这就是为什么使用Github的HTTP URL进行导入的原因。

VRFConsumerBase 抽象合约有两个参数,分别代表协调器(coordinator)和LINK ERC20 代币合约的地址。这些在每个网络上合约地址是固定的(稍后会详细介绍)。

第 2 步: 重载函数

VRFConsumerBase 中有两个对VRF流程至关重要的函数。

第一个是 requestRandomness ,这个函数已经实现了,我们不需要重载。这个函数是用来对VRF进行 初始请求调用

另一个是 fulfillRandomness , 这是VRF在生成数字后,用来回调的函数。我们需要重载它,以便在获取随机数后执行相应的操作。

在我们合约的实现里,仅仅是把随机数存储在一个名为 randomNumber 的状态变量中,以便我们可以在结束时查询它。代码像这样:

pragma solidity ^0.6.2;

import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";

contract RandomGenerator is VRFConsumerBase {

    bytes32 public reqId;
    uint256 public randomNumber;

    constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
    }

    function fulfillRandomness(bytes32 requestId, uint256 randomness) external override {
        reqId = requestId;
        randomNumber = randomness;
    }
}

我们在 fulfillRandomness 函数上添加了override 修饰符以实现重载,在实现中,使用 reqIdrandomNumber 来保存接收变量的值。

第 3 步: 生成随机数

正如在前面 第1步提到的,函数调用需要传递一些地址和其他值作为参数。在部署智能合约并调用构造函数时,它需要VRF协调器(coordinator)合约地址和网络上LINK 代币合约地址。在Ropsten测试网上,合约地址如下:

  • VRF coordinator: 0xf720CF1B963e0e7bE9F58fd471EFa67e7bF00cfb

  • LINK 代币: 0x20fE562d797A42Dcb3399062AE9546cd06f63280

当调用 requestRandomness 函数时,我们需要传递几个参数:生成随机数的key hash,生成随机数的费用fee(使用LINK代币)和生成随机性的种子seed(最后一个由我们提供)。requestRandomness函数签名如下:

function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed) public returns (bytes32 requestId)

在 Ropsten 网络上,参数值如下:

0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205
1000000000000000000

因此我们的调用代码如下:

// 设置ropsten key hash
bytes32 keyHash = "0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205";// // 设置 ropsten LINK 费用
fee = 1000000000000000000;
// 设置种子
seed = 123456789;
// 请求随机数
bytes32 reqId = rand.requestRandomness(keyHash, fee, seed);

当结果返回时,随机值将存储并且可以通过以下方法获取:

rand.randomNumber;

自己尝试一下

现在我们将逐步实践如何使用 Remix IDE 和Metamask插件从VRF获取随机数。在继续之前,请确保已在浏览器上安装了Metamask 插件。

  • 打开 Remix IDE

  • 如果还没用过 Remix,需要向下图一样选择 Solidity 语言。

    ZV3ER3m.png!web

  • 创建一个文件: RandomGenerator ,把第 2 步中的代码复制过来。

  • 使用左侧菜单,单击Solidity图标,然后选择0.6.2编译器版本,如下图所示。

    RFN3ArM.png!web

然后单击下面的按钮,并在下拉列表中选择“Injected web3”,如下图所示。

QfuUna7.png!web

  • 这时Metamask会提示一个连接请求,我们点击接受请求。

  • 确保MetaMask 连接的是 Ropsten网络,如下图所示:

UZVrAvz.png!web

  • 确保Metamask帐户中有一些Ropsten 网络的 以太币,如果没有,可以从 这里 获取。
  • 回到Remix,在同一选项卡上,应该看到橙色的“ Deploy”按钮,单击“ Deploy”按钮进行部署,注意要接受Metamask弹出的合约部署请求。
  • 在部署后,我们需要确保合约中存有一些LINK 代币,以便它可以为请求随机数支付费用。打开 Ropsten LINK的“水龙头”,粘贴Metamask地址,就可以在Metamask中收到100 LINK。
  • Metamask不知道LINK 代币在Ropsten网络上的地址,因此我们需要添加它。在“ Metamask”中,在帐户名称左侧,单击“菜单”符号,然后单击底部的 “Add Token”。
  • 在 “Custom Token(自定义代币)”下, 添加地址: 0x20fE562d797A42Dcb3399062AE9546cd06f63280 . 剩下的信息将自动填充,提交之后可以看到账号下有 100 个 LINK,下图是 70 个 LINK 的账号截图:

3q6fiyr.png!web

  • 回到 Remix, 复制部署合约地址,如下图:

    rQnQBnJ.png!web

  • 现在我们将向合约发送一些 LINK。回到Metamask,然后单击100 LINK旁边的3个点。粘贴合约地址并发送10 LINK。确认交易后,再继续下一步。

  • 在Remix中,我们现在可以请求随机数了。在同一选项卡中,向下滚动会发现更多代表合约公有(public)函数的橙色按钮,如下图所示。单击 requestRandomness 右侧的箭头以展开参数。

UfmARfQ.png!web

  • 按顺序复制这 3 个数: 0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205 , 1000000000000000000 , 123456789 (或者其他你想要的值)作为参数提交交易。

rauaiyI.png!web

交易可能需要一些时间才能确定,因此需要关注一下终端输出在Etherscan中的交易信息。

2mEnuu7.png!web

交易完成后,我们需要等待VRF生成随机数并将其发送回我们的合约。几分钟后,单击我们在Remix中发送交易的橙色按钮下方的蓝色“ randomNumber”按钮,检查合约是否收到了随机数,如下图所示。

Ez2iUbJ.png!web

如果一切顺利,应该有一个像我这样的随机数,它是 30207470459964961279215818016791723193587102244018403859363363849439350753829 .

现在就大功告成了。

结论

使用 Chainlink 可以在智能合约中可以使用可验证的随机数。在文章中阐述了该机制的工作原理,以及演示了如何将代码集成到智能合约中获取随机数

作者:Alex Roan

原文: https://medium.com/coinmonks/how-to-generate-random-numbers-on-ethereum-using-vrf-8250839dd9e2

欢迎大家在 知乎 ,微博, GitHub 关注我

登链社区赞助翻译。

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 1分钟前
  • 阅读 ( 6 )
  • 学分 ( 0 )
  • 分类:以太坊

Recommend

  • 71
    • www.tuicool.com 5 years ago
    • Cache

    一文搞懂可验证延迟函数 VDF

    自从以太坊将 可验证延迟函数( Verifiable Random Function, VDF ) 列入研究计划 [1] 并打算在以太坊 2.0 使用之后,VDF 得到了广泛的关注。VDF 这个概念最初由斯坦福大学密码学教...

  • 29
    • www.tuicool.com 5 years ago
    • Cache

    LIBRA 中的可验证随机数 VRF

    Libra 中采用的椭圆曲线是 ED25519 ,而不是像以太坊比特币使用的是 secp256k1 . 虽然有不同,但是从本质上来说他们都是椭圆曲线,基本性质都是完全相同的.因此适用于 S256 曲线的...

  • 22
    • learnblockchain.cn 4 years ago
    • Cache

    Chainlink VRF 可验证随机函数详解

    要开发安全的智能合约,并规避合约资金被盗风险,开发者必须在安全方面下大功夫。如果随机数是智能合约依赖的关键数据,那么开发者就自然会期望合约所有相关方都拥有同等的不确定性,并降低因某一方成功预测结果而钻空子的风险。Chainlink...

  • 28

    在与科罗拉多州立彩票公司讨论以太坊(ETH)黑客马拉松合作时,Vitalik Buterin(以下简称“V神“)认为,将来彩票可能会受益于以太坊2.0的可验证...

  • 11

    如何设计以太坊上的高额赌注随机数游戏 | 登链社区 | 深入浅出区块链技术如何设计以太坊上的高额赌注随机数游戏 ...

  • 8

    NFT验证平台Ethernity Chain将集成Chainlink可验证随机函数和喂价  •  3 小时前 ...

  • 8

    Chainlink VRF 已在币安智能链上线,为开发者提供可验证的随机数2021 年,在币安智能链上开发和发布的去中心化应用数量激增,目前总锁仓量达 310 亿美元。币安智能链支撑着数目可观且不断增长的新旧 Defi 项目,但随着在币安智能链上发布的 NFT...

  • 5

    [研究] 可验证延迟函数(VDF)(一)一文搞懂 VDF 2019-05-26 研究 约 7811 字 预计阅读 16 分钟 次阅读 自从以太坊将可验证...

  • 3

    C 语言之随机数函数(rand())的使用方法 在程序设计中,难免会使用到随机值函数,其原理与语法大多类似,接下来以C语言为例介绍其随机值函数 rand() 用法。 引用

  • 8

    Objective-C 随机数及数组随机取元素 这里记录一下Objective-C随机数以及随机数在数组中的使用。 arc4random() 这个貌似是最好用的,听说比较精确,用起来也比较方便,不需要初始化随机种子。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK