The Centaur oracle

Tradisys
Tradisys
Published in
7 min readMar 13, 2019

Waves smart contacts were successfully activated in the block number 1190000. This means that from now on we can do all sorts of interesting things with the power of the blockchain. Of course, we are looking towards games. At the Waves Platform meetup in St. Petersburg, we presented the very first game on this blockchain, working entirely on a smart contract. But the thing is that in order to decide who will make the first move we had to throw a coin. So, we have developed a more technical solution for this problem.

During the Waves meetup at St. Petersburg Tradisys presented two oracles at once.

What is an oracle?

The Oracle is a machine that delivers data from the real world to the blockchain. At the same time, it is solving an extremely important task: generation of random numbers. This number should not be known in advance and everyone should be able to verify it. No one, including the oracle, should be able to influence this random number. It should be as unbiased as possible.

How does the Tradisys oracle work?

We presented two oracles at the meetup: Cyclops and Centaur. The Centaur oracle has been successfully launched and is running at this address. How does it work?

The Centaur oracle is a program. The program is configured in such a way that every 30 blocks (configurable parameter) it reads the current height of the Waves blockchain (the last generated and signed block), takes the hash of this block and performs a data-transaction to the oracle address in the blockchain. But since miners can manipulate block hashes, such hashes cannot be trusted. Therefore, before making a date transaction with a random number, the oracle performs one tricky manipulation.

After receiving the hash of the last block, Centaur signs this hash with a previously generated private RSA-key. No one, except the oracle, has access to this private RSA-key, so no one, except for the oracle, will be able to correctly sign the data-transaction that is sent to the oracle address in the blockchain. You can verify that the oracle is not deceiving with the help of the public RSA-key that was previously tied to the Centaur address.

Thus, any random number generated by the oracle can always be checked for authenticity at any time, because the public RSA-key is permanently attached to the oracle account using a smart contract. This means that if Centaur tries to sign a hash of a block with some other key, then the oracle can be instantly convicted of it.

As a result, as long as the oracle works at the address, to which the public RSA-key was tied, you can check all of its records.

Why is all this necessary?

I hope you remember that before playing the Tic-tac-toe game on the meetup, Inal and I threw a coin to determine who would make the first move. And now let’s try to solve this problem with the help of the oracle :)

Suppose that we want to start a Tic-tac-toe game at 5:10 P.M. Moscow time. Tic-tac-toe is a game, but in our case, it is also a smart contract. We can extend the smart contract by an instruction that will give the right to the first move to one of the players, depending on the specific condition. This condition may be a random number generated by the oracle, which neither I nor Inal can know in advance.

At 5:09:55 P.M. the Tradisys oracle reads the height of the blockchain. The height is 1191337. There is no sense to take the signature of the block of the current height, since this block is still being replenished with transactions, and each of them changes the final block signature. Therefore, the oracle takes the signature of the last fully generated block, i.e. the block number 1191336. The signature of this block looks like this:

The oracle takes the signature of this block and, before sending it to the oracle address, signs the block with a private RSA key, which is not known to anyone but the oracle. There is no point for the miner to sort out the signatures of the block that it generates, since the miner does not know what the final random number will be, after the hash of the block is signed by the oracle.

After signing the hash of the block, the oracle sends the data-transaction to the blockchain. It looks like this:

The data-transaction contains the random number, the block number (which signature of was taken as a basis), and the signature itself. This is how the transaction body looks like:

Thus, the oracle’s smart contract contains 4 fields with the following variables:

  1. basedOnBlockHeight. The height of the block, the hash of which was used. The field can be overwritten.
  2. basedOnBlockSignature. The block signature that was used to generate a random number. The field can be overwritten.
  3. oraclePublicKey. A public RSA key that validates the oracle’s signature. It is impossible to overwrite this field: the smart contract is responsible for this.
  4. randomNumber. Random number itself. Rewritable field.

So, we got a random number, in this case it is:

PBfWlrG2sZhw7axnsBHj6XlKSPparV5LEW3a/b2FBztxgtAeA3iIwsXD1Zji+EX/z9xJuGAlqcWa1JW2cbQVciMZKCTYUDyhEd9rko6yIcFOp9uMvTsk7jz7Pp+Go61Jn/5TzQJ3TiLd0BoQcVSPZujHP6pw/krXbKBNufLAhPZIXJxS1NRLZSiT/E3BUuTglkqWFeEvMEP5/EqLqzZWnkk9iY41L9V5z8mtp0Of7XVjbPxKEpMWQi9XykKPXWQaV+M2jX4cvQTB0An1HfUrNYNaP0CTwNyGV9BYtBSYw1J/BfrWlveer8CGCft9HKFmHjKZPvXCFzx+LZ1ACvzQtA==

As you probably noticed, it is not exactly a number :) Let’s remove everything from it, except numbers, and we get:

27653231912996153061359419580792401091891

As you can see, there are quite a few digits here. Each record of the oracle is a string, where all characters, including digits, are different, and the number of digits are also different.

Now we can add an additional instruction to our Tic-tac-toe smart contract. This instruction will look something like this:

  1. Read string containing a random oracle number.
  2. Delete everything except digits. Now the string contains only digits.
  3. Take the digit, which is fifth from the left.
  4. If the resulting digit is from 0 to 4, then the crosses go first.
  5. If the resulting number is from 5 to 9, then the toes go first.

Now Inal and Ivan do not argue who goes first. Choose Inal crosses, and Ivan toes, or vice versa, the right to perform the first move will be determined by the smart contract. And neither Ivan nor Inal can influence the situation and gain an unfair advantage.

And this is only one of thousands of examples of using random numbers from the oracle.

Trustless system

What if the Tradisys oracle conspires with a node (for example, the Tradisys Node)? :) After all, then the Tradisys Node will be able to negotiate with the Tradisys oracle and get access to the private RSA key of the oracle. And it will mean that the node will be able to manipulate the block signature, checking the result of a random number with the received private RSA key. So, if the Tradisys Node is playing the Tic-tac-toe game with Inal, then it, very likely, will always go first :)

That is why the source code of the Tradisys Centaur oracle will be published in open access. We hope that in the near future there will be several more oracles that have a sufficient level of trust. This will allow us to make an adjustment to the smart contract, so that the smart contract takes random numbers from several different oracles and, for instance, sum them to get the final value.

Since all oracles will have unique RSA private keys, despite the fact that the block signature will be the same for everyone (assuming these oracles make transactions with the same frequency), the oracles’ random numbers will be different.

The miner’s collusion with a particular oracle becomes useless, since now the miner-сheater will need to bribe all oracles at once, random numbers of which are used by the smart contract.

Epilogue

Now the oracle is stable. Centaur records a random number every 30 blocks. In the future, we will increase the frequency of the recording of random numbers. We will open the source code in a few days (just need a little time to clean up the code).

The Centaur oracle address:

http://wavesexplorer.com/address/3P4xYCRQtXKkLV4gKVPEjE8ckwRKRjhdahk

The code of the smart contract:

let contractPK = base58'BYvio3cJctKKydTMQkfZEnPLEvm9nEnPodCbhz8SuZda'

match (tx) {
case t:DataTransaction =>

let sig = sigVerify(t.bodyBytes,t.proofs[0],t.senderPublicKey)

t.data[0].key == "randomNumber" && t.data[1].key == "basedOnBlockHeight" && t.data[2].key == "basedOnBlockSignature"
&& size(t.data) == 3 && sig

case _ => false
}

We were in a bit of a hurry, and so the smart contract is not perfect. The smart contract logic is built flawlessly, however there is one extra detail :) The issue is insignificant, and so it makes no sense to re-deploy the contract to another address. Don’t worry, there is no security threat. However, this once again confirms that in a hurry you can make a mistake. The oracle is fully working and safe. It generates a random number every 30 blocks. You can use it safely.

Happy randoms!

--

--