paint-brush
How you can use Quantum random numbers as a public good, on 13 smart contract protocolsby@api3
18,114 reads
18,114 reads

How you can use Quantum random numbers as a public good, on 13 smart contract protocols

by API3October 21st, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

A deterministic virtual machine is incapable of generating ‘true’ randomness. Due to this, RNG needs to be provided as an oracle service. QRNG is the gold standard for random number generation. It is powered by an Airnode hosted by the Australian National University’s QRNG Airnode. QRNG generates randomness via quantum phenomena using unique properties of quantum physics to generate true randomness. It is served as a public good (apart from the gas costs) and is free of charge. Providers optimally counter the Sybil attack risk.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coins Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - How you can use Quantum random numbers as a public good, on 13 smart contract protocols
API3 HackerNoon profile picture


Random number generation (RNG) has always been one of the biggest problems when working with smart contracts. A deterministic virtual machine is incapable of generating ‘true’ randomness. Due to this, RNG needs to be provided as an oracle service.


To fulfill the need for randomness in smart contracts, decentralized pseudorandom RNG has been a common way. One of the most used methods is Chainlink’s VRF or verifiable random function, which provides cryptographically provable random numbers on-chain. It generates a random number off-chain with cryptographic proof that’s used to verify the result.


However, this configuration suffers from the same issues as any other third-party oracle network. Setting up an oracle node that can provide PRNG exposes potential attack vectors like Sybil attacks, but also lacks source transparency and decentralization. For example, one needs to trust the governing entity to select the network participants, which means decentralized PRNG is only as secure and decentralized as the governing entity.

Quantum Random Number Generation

QRNG generates randomness via quantum phenomena. It uses a ‘true’ source of entropy using unique properties of quantum physics to generate true randomness.


There are different methods of implementing QRNG with varying levels of practicality, yet the common point is that the resulting numbers will be truly random because the outcome of a quantum event is theoretically uncertain with well-defined characteristics. Therefore, QRNG is the gold standard for random number generation.

Australian National University’s QRNG Airnode

Dr Aaron Tranter of ANU

As we already discussed, providing RNG through a third-party oracle network opens space for attack vectors. But first-party oracles (Airnodes) that are directly operated by the QRNG API Providers optimally counter the Sybil attack risk.


API3 QRNG is a public utility offered through the Australian National University (ANU). It is powered by an Airnode hosted by ANU Quantum Random Numbers, meaning that it is a first-party service. Australian National University’s Quantum Optics Division is one of the worlds leading research institutions in the field. The division also operates a REST API, Quantum Random Numbers API, to serve QRNG in Web2.


Read more about how ANU Generates random numbers in real time by measuring the quantum fluctuations of the vacuum


It is served as a public good and is free of charge (apart from the gas costs), and it provides ‘true’ quantum randomness via an easy-to-use solution when requiring RNG on-chain.

How Airnode and API3 QRNG works

https://docs.api3.org/qrng/introduction/how-works.html

To begin, we need to deploy and sponsor the QrngRequester with a matching sponsor wallet. The QrngRequester will be the primary contract that retrieves the random number.


The QrngRequester submits a request for a random number to AirnodeRrpV0. Airnode gathers the request from the AirnodeRrpV0 protocol contract, retrieves the random number off-chain, and sends it back to AirnodeRrpV0. Once received, it performs a callback to the requester with the random number.


You can read more about how API3 QRNG uses the request-response protocol here.

Coding QrngRequester.sol

Getting started

Make sure you have the following installed:


  • Node.js

  • yarn/NPM


Also, make sure you’ve already cloned and installed the Airnode Monorepo. If you haven’t, clone the Airnode Monorepo with this command:

$ git clone https://github.com/api3dao/airnode.git .

To install the dependencies, do the following:

$ yarn run bootstrap

To build all the packages, use this command:

$ yarn run build

Compiling the Contract

To compile the QrngRequester contract, we are going to use Remix IDE. It’s an online IDE that allows the developing, deploying, and administering of smart contracts for EVM-compatible blockchains.

//SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "@api3/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol";

contract RemixQrngExample is RrpRequesterV0 {
    event RequestedUint256(bytes32 indexed requestId);
    event ReceivedUint256(bytes32 indexed requestId, uint256 response);

    address public airnode;
    bytes32 public endpointIdUint256;
    address public sponsorWallet;
    mapping(bytes32 => bool) public waitingFulfillment;

    // These are for Remix demonstration purposes, their use is not practical.
    struct LatestRequest { 
      bytes32 requestId;
      uint256 randomNumber;
    }
    LatestRequest public latestRequest;

    constructor(address _airnodeRrp) RrpRequesterV0(_airnodeRrp) {}

    // Normally, this function should be protected, as in:
    // require(msg.sender == owner, "Sender not owner");
    function setRequestParameters(
        address _airnode,
        bytes32 _endpointIdUint256,
        address _sponsorWallet
    ) external {
        airnode = _airnode;
        endpointIdUint256 = _endpointIdUint256;
        sponsorWallet = _sponsorWallet;
    }

    function makeRequestUint256() external {
        bytes32 requestId = airnodeRrp.makeFullRequest(
            airnode,
            endpointIdUint256,
            address(this),
            sponsorWallet,
            address(this),
            this.fulfillUint256.selector,
            ""
        );
        waitingFulfillment[requestId] = true;
        latestRequest.requestId = requestId;
        latestRequest.randomNumber = 0;
        emit RequestedUint256(requestId);
    }

    function fulfillUint256(bytes32 requestId, bytes calldata data)
        external
        onlyAirnodeRrp
    {
        require(
            waitingFulfillment[requestId],
            "Request ID not known"
        );
        waitingFulfillment[requestId] = false;
        uint256 qrngUint256 = abi.decode(data, (uint256));
        // Do what you want with `qrngUint256` here...
        latestRequest.randomNumber = qrngUint256;
        emit ReceivedUint256(requestId, qrngUint256);
    }
}

The QrngRequester will have three main functions: setRequestParameters(), makeRequestUint256(), and fulfillUint256().


  1. The setRequestParameters() takes in airnode, endpointIdUint256, sponsorWallet and sets these parameters.
  2. The makeRequestUint256() function calls the airnodeRrp.makeFullRequest() function of the AirnodeRrpV0.sol protocol contract which adds the request to its storage and returns a requestId.
  3. The targeted off-chain ANU Airnode gathers the request and performs a callback to the requester with the random number.

Request Parameters

The makeRequestUint256() function expects the following parameters to make a valid request.


  • airnode (address) and endpointIdUint256specify the endpoint. Get these from here.
  • sponsorWallet specifies which wallet will be used to fulfill the request.

Response Parameters

The callback to the QrngRequester contains two parameters:


  • requestId: First acquired when making the request and passed here as a reference to identify the request for which the response is intended.

  • data: In case of a successful response, this is the requested data that has been encoded and contains a timestamp in addition to other response data. Decode it using the function decode() from the abi object to get your random number.


Head to Remix IDE, make a contract, and paste it in the QrngRequester code.

Now, hit compile on the right side of the dashboard and compile the smart contract.

Deploying the Contract

We are going to deploy our QrngRequester to Goerli. Make sure you have enough testnet ETH in your wallet to deploy the contract and fund the sponsorWallet later. You can get some testnet Goerli here.


Head to deploy, run Transactions, and select the “Injected Provider — MetaMask” option under Environment. Connect your MetaMask. Make sure you’re on Goerli.

The _rrpAddressis the main airnodeRrpAddress. The RRP contracts have already been deployed on-chain. You can check for your specific chain here.


Once the _rrpAddress is populated, click on “Deploy.” Confirm the transaction on your MetaMask and wait for it to deploy the Requester contract.

Make sure you’re on the Goerli Testnet

Calling the Contract

When your QrngRequester gets deployed, head to Deploy, run transactions, and click on the dropdown for your Requester under Deployed Contracts.


Now select the setRequestParameters dropdown to set all the parameters.

Add the following to the corresponding fields for the function.


  • _airnode: The airnode address of the desired QRNG service provider. See its value from the ANU Airnode.
  • _endpointIdUint256: The Airnode endpoint ID will return a single random number. See its value from the ANU Airnode.
  • _sponsorWallet: A wallet derived from the requester contract address, the Airnode address, and the Airnode xpub. The wallet is used to pay gas costs to acquire a random number. A sponsor wallet must be derived using the command derive-sponsor-wallet-address from the Admin CLI. Use the value of the sponsor wallet address that the command outputs.


After you’ve set up the Airnode CLI, installed and built all the dependencies and packages, run the following command to derive your _sponsorWallet:

Linux

npx @api3/airnode-admin derive-sponsor-wallet-address \
  --airnode-xpub xpub6CUGRUo... \
  --airnode-address 0xe1...dF05s \
  --sponsor-address 0xF4...dDyu9

Windows

npx @api3/airnode-admin derive-sponsor-wallet-address ^
  --airnode-xpub xpub6CUGRUo... ^
  --airnode-address 0xe1...dF05s ^
  --sponsor-address 0xF4...dDyu9

ANU’s airnode-addressand airnode-xpub can be found here.

Fund the sponsorWallet with some test ETH. Click on transact button and confirm the transaction to set the parameters.

To make the request, click on the makeRequestUint256 button to call the function and make a full request.

Now you can head over to https://goerli.etherscan.io/ and check your sponsorWallet for any new transactions.


You might need to wait for a while as the Airnode calls the fulfill() function in AirnodeRrpV0.sol that will in turn call back the requester contract at fulfillAddress using function fulfillFunctionId to deliver data(the random number).

Here, we can see the latest Fulfill transaction.


Now go back to Remix and click on latestRequest button to check the response.

If the callback has been successfully completed, the randomNumber will be present. The value of waitingFulfillment will be false.

If you want to learn more about it, check out the QRNG Example Project.

Read more about API3 QRNG.


Also published here.