Sketching a RNG Oracle Service

An Ethereum Outline for Generating Secure Random Numbers

Tim Cotten
Cotten.IO

--

This article proposes an outline for what an oracle service for generating random numbers would need to look like, covering both cases for same-block and future-block execution.

Building off of the thoughts and work from previous articles I’ve decided build an oracle service dedicated to random number generation on the Ethereum blockchain.

For review: an oracle service is a smart contract that communicates with a trusted external and off-chain data-source. Oracalize, for instance, has a URL oracle service where you can call a given URL with an optional TLS notary.

Based on the Random.org JSON-RPC API, though, I think we can do better by creating a dedicated smart contract that other smart contracts can talk to for fetching the requests.

Since the Random.org site offers this susbcription-based API and also allows for signatures on the data being returned we can assure consumers on the Ethereum blockchain that our oracle service is a trustworthy source of random data.

Use cases include gambling, consensus decisions, lotteries, simulations, and more.

Methods

Since this is an experiment I want to try offering two main methods of retrieving random data: inline and request-based.

What I mean by that is there are two main ways of using the oracle service I’m proposing: either a smart contract is sending a call message to our oracle service and receives a response back in the same block (read-only), or the smart contract wants data directly from Random.org and is willing to wait until at least the next block for a response.

Inline Data

The idea for inline data is that, at regular intervals, the smart contract is updated with a large binary blob of data stored in a uint array.

The invoking contracts can request all the same functions as the Request-style method, however the random number generation will be done during the same block the request was made, spending more gas to combine the raw binary data with a supplied nonce and the msg.sender with some ability to iterate on and recycle the binary blob if all the entropy has already been used.

A concern here is that the resulting operation may be predictable by the invoking contract (since the random data is visible in the contract storage), and thus fail security considerations (the contract might only call the function when it knows the RNG outcome would be favorable).

To avoid this we’d need to include some scheme that permutes the raw binary data based on a dynamic field that won’t be known/predictable before the message call is sent. This is absolutely doable if the work is done in the following block (see the Delayed approach below), but in an inline situation another source of entropy is needed.

The block.timestamp can be forged up to 900 seconds, so that’s not a good option (if a miner is a bad actor).

Because the inline method doesn’t require anything but one-way updates (from data-source to oracle) it’s contemplated this service would be free.

Request Data

On the other hand, if the user wants the assurance of a direct connection to Random.org’s API, the oracle will take the request and the off-chain monitor will pick it up and update the contract with the fulfilled data, along with a signature verifying the authenticity of the result.

The invoking smart contract can either make a blind request and check for a result using a fetch function, or specify the callback the function should use.

This method would require a nominal Ether payment in order to fund the round-trip costs in fulfilling the data request.

Delayed Data (A Hybrid Approach)

The request/fetch model can also be extended to the inline/free style (sans a callback) by caching the request and hashing the raw binary data with the now future block-hash (that was unknown) during the fetch call.

This breaks the request into two pieces, where the actual work to create the random data is being done in the second function fetch.

Proposed Function Scope

For the sake of simplicity I would mirror the JSON-RPC API for the actual random number function calls:

  • generateIntegers
  • generateDecimalFractions
  • generateGaussians
  • generateStrings
  • generateUUIDs
  • generateBlobs

Any other kinds of random number generation (lottery numbers, etc) could be handled using the above functions in a light-weight library.

Function naming would probably follow the convention:

[method][type](..., [callback])Examples:
inlineIntegers(n); // current block
delayedBlobs(size); // current block
fetchBlobs(size); // future block
requestIntegers(n); // current block
fetchIntegers(n); // future block

In this manner we can create fast and secure random numbers on the Ethereum blockchain in a non-deterministic (i.e. non-predictable) manner.

This would mark a useful production oracle service with free/low-costs helping secure any smart contract relying on secure random numbers.

--

--

Founder of Scrypted Inc: Building interactive digital assets for the Metaverse. <tim@cotten.io> @cottenio