Obvioulsy, games sometimes require randomness. How do we get it?
One good building blocks for randomness is cryptographic hashes. h(X)
, the cryptographic hash of a value X
will look random. If you’re given h(X)
and a bunch of other random value, but you don’t know X
, you won’t be able to distinguish the hash from the other random values.
So if you know a secret X
, you can generate random values with hashes. Of course, the person that knows X
can predict the random value.
See we would really like the randomness to be unpredictable, because a party that can predict the randomness can be bribed to reveal it. Or if they pick the secret, to change it.
What if we used “unpredictable” (but maybe highly structured, i.e. not random) data to generate randomness instead?
That’s where the idea of using blockhashes comes in. Blockhashes are hashes of block headers, which themselves contain a bunch of metadata + various Merkle roots (of the transactions in the block, of the state, …). Transactions are not random, but they are mostly unpredictable, therefore the blockhash should, in principle, be random and unpredictable.
Buuut…
Block builders can manipulate the blockhash. This is because they can make small changes to the data that goes into the blockhash that will cause the blockhash to change. For instance, they include a dummy transaction with a number as calldata. If they don’t like the blokchash obtained, they can change the number and obtain a different blockhash.
This process of iterating inputs to change the randomness until it does what we want is called “grinding” and is the more important thing to consider in randomness protocol
Most famoulsy Chainlink VRF, but there are others. If you’re looking for an open-source implementation, here’s a cool one that works with MUD: mudvrf by Succint Labs.
The principle is very simple: the VRF provider has a secret key somewhere, and they use it to sign some “seed” data, and that you’re randomness.
The signature has the same property has a cryptographic hash, it looks random. Unlike the hashing solution, the applied function (replacing h
) is secret (only the holder of the key can generate cryptograhic signatures), but the seed (X
) is public.
The randomness is “verifiable” because we can verify that a cryptographic signature is correct using the corresponding public key.
VRFs are usually request/response models. This is a request/response model. The randomness is not readily available, you need to put in a request and the VRF service needs to answer.
The seed being used is usually the blockhash of the block where the request was made. This is because, as per above, this is unpredictable to the requester. And even if the block builder wants to manipulate the randomness, as long as they don’t know the VRF provider key, they can’t do anything useful.