Secure Random Number Generation onEVM Blockchains / Rollups

Secure Random Number Generation on EVM Blockchains / Rollups · 3 Jul 2024 · 38:15

Peter Robinson outlines his research into generating random numbers securely on-chain, with a focus on EVM blockchains and rollups. The talk looks at how smart contracts can obtain randomness that is hard for an attacker to predict or influence. It was given to the Ethereum Engineering Group, with slides shared alongside the recording.

Speakers

Topics

From Secure Random Number Generation on EVM Blockchains / Rollups, hosted by Ethereum Engineering Group.

Transcript

hello and welcome everyone um my name is Peter Robinson this is your ethereum Engineering Group Meetup and today it's me going to give a talk on um random number generation and blockchains um so I'm the head of blockchain research at a mutable uh looking at all sorts of things over the horizon of how we make the platform more secure better and working on what makes a a game great and um part of that research has actually been looking at random numbers because some games do want to do stuff on chain so let me share my slides okay all right so hopefully

everyone can see my slides and I'm going to set up so I can see the um chat as well yep okay so um all right can people see my slides yes all right brilliant yes yes yes okay cool okay random number Generation Um on block on an evm based blockchains and rollups um yeah so quiz question for everyone as we start off pref ands there you know so what could you use this code in you know if

you were have writing a game that has some sort of loot box you know so one of these things where you open it up and you get a randomly selected set of stuff um and you know so assume you you send in one eth and then you open up this random box um what is wrong with this code to you know just do this sort of operation so no takers okay so imagine that code is called here so we've got a a contract called only

win and you've got your Constructor where you you know you've got that game contract and then you go game open the loop box your sensory your one eth and then you check the value that got out of the loot box and if you don't like the um value then you revert and um so yeah it it means that because you've just got this where you're doing it all in one transaction where you're getting a random number and then someone can just be actually calling you from a different contract um then you're blown and um you might be thinking oh but you know maybe you could check that it's an eoa well um wallet contracts are really um quite popular

these days and so wallet contracts invariably allow you to do a multi call so if you're allowing people to use say passport or some other wallet then they could easily call into your open loot box um function and then have a separate thing where they check the um amount that they've got or the the value they've got so yeah you so trying to do um the unra mapping of the random number um and so the request and the Fulfillment Allin one transaction is going to mean you as a game lose out to um players who know what they're doing so today I'm going to talk through

just top level random number usage and then I'm going to talk about how you go about reducing random numbers um then walk through some lower level technicalities talk about offchain sources you can use and um onchain sources and also talk about random sequences as well so when you when we think about random numbers um on chain you know you you've got um two different types of usages in general you've got like say non-financial um non-deterministic events that you want to have happen so in a in a game for instance you might have um NP PC so a non-player character

and they'll walk in a certain direction say and um that direction might change randomly so the random number generator for that probably shouldn't be onchain because it's a really lowcost low value um thing that's occurring whereas maybe you've got a financial transaction or something that has um high value um for instance um that you could have a randomly generated nft with randomly generated attributes or you could have a loot box um or I mean to talk about you know like gaming as in gambling you can imagine you've got a poker game and

you're going to draw the next um card off the deck of cards and so you know again that's something where there's probably going to be money involved and so you might then decide right that's a good time that to do it but you for low value events you don't want to be doing them on chain I think and so if you've got this non-financial non-deterministic event this low value event you should be using like your standard SDK like Java or goang or rust um you know or maybe you've got um using a game um system and so again like you'd use um your re reality engine is that the one anyway

you use some sort of SDK not on chain um and so for these Financial um non-deterministic events so you do you do need secure random numbers and so you could try to do them offchain or you can do them onchain or you can do them onchain but using offchain systems that are secure and so I'm going to talk through the onchain and offchain systems that um surface the numbers onchain so a two-step process is needed when you're generating random numbers so the the action has to happen to request the

random number and that has to happen in one transaction that a get happens in one block and then at some later point in a different block you're going to have a different transaction to fulfill the request from the first um transaction and return the random number and by splitting that out um you you know you're not going to have that that reversion problem so um yeah so you need to separate it out so you don't have um the game players revert or you know the people consuming the random number um and um you need to link the the request with the response so you can imagine you

could have a system where you're putting in multiple requests and and you wouldn't want the game player the consumer of those random numbers to be able to cherry pick which random number they're going to use for what so you need to say have um you know each each type of usage linked and the sequence of usage linked so that one request gets a very specific response um and so if you've got a payment involved in the um overall process that needs to happen with the request because otherwise what will happen is that the game player will

request the random number be generated but then when they come it comes to payment and consumption they'll say ah well that random number is not interesting so they won't do the Fulfillment and so you need to do the do the payment with the request and then do the Fulfillment so let's drill into things a little bit a few of the technicalities or actually before I go f further forward is all of that does all all of that make sense yes yes course all right cool all right

so um so Random seeds seed in random number talk is a value from which you generate other random values and so um the idea is that um you know you normally the sources in blockchain systems can only generate one value per block and so if you've got multiple applications say multiple games and um you've got multiple players and maybe multiple players might do multiple transactions all in the one block then you can't just be using that one number for everything so you've got to have a way of using that number as a seed and

deriving other numbers from it um yeah and so what you can do is you can personalize the random number you've got the seed you've got to give a more personalized seed that um the individual can use and so how you can do that is you maybe could do a a message digest of the address of say the game contract or the application contract and then assuming message sender is a proxy for the game player or the consumer of the random number then you combine that and maybe there's a request ID which is per

user um and then you bring that all together with the seed and you hash that that that'll give you a personalized seed so that for every game for every game player and for each usage you'll get a different number which is obviously what you want sometimes though you will decide that you need say multiple values um and so when you do that you need to be U very careful about how you do it um so you can't be manipulated so you need to use a shootter random function a prf and so what you do is you um have essentially the message digest

of that personalized seed and an integer and doing that will again generate an array of different numbers and um the thing to make sure though is that you need to lock those game players in um when you when they do the request so that they say I'm going to need five numbers or I'm going to need three numbers so if there was some aspect of the game where it could be variable um of the number of the quantity of numbers you're going to need then you need to lock them in at that request because otherwise what you can imagine an attacker an attacking game

player could do is they could run that prf themselves and go oh the value 25 is going to be really good to me so they could somehow rather try and consume value 0 to 24 doing you know something of low consequence and then use that value 25 as something that's important and maybe advantageous to them so if they were locked in at the start they would have to maybe be paying for all of those numbers and um be um you know like locking in what they're going to do with each number um so yeah lock locking them into exactly how many are going to be returned is important when you're going

to return an array of numbers um so another technicality another thing to consider um so in um at the start of this call actually just before we start click to record we were talking about generating random um information and how you can do it and um David pointed out that a great way is shining a laser through a lava lamp and how you know that can give you some good bits and then I I said you know that you've also got the idea that you know you record the Nano time of a computer doing an event on um in a system say even in the cloud and from the eyes of

the attacker that's hard but you might say combine multiple of these low quality events that might only have a few bits of um uncertainty in them to create this higher quality um random number and so that that idea of combining many sources or random number um in the in a normal um cryptographic system um generally yields a much higher um Quality random number and that way if say one of the sources is compromised then you know it's not a problem so unfortunately that concept of combining random sources

doesn't work in blockchain and the reason why it doesn't work is that you're in a deterministic environment where um you know you you you're combining say a random value with a value that might be able to be manipulated and the point at which the manipulation can happen is after the pure random value has entered the system so hence um if you do combine um say some system that is potentially compromisable onchain with some high quality offchain random then you risk um essentially watering down the um

goodness of the offchain random so um yeah you've got to be aware of combining sources um another thing to consider is um the delay between requesting and fulfillment and this is particularly important for onchain sources so there there must be some sort of delay between when a game requests a number um or a seed value and when it's fulfilled and the real question is how long is long enough and so you know you could say all right we're going to wait until the value is final and um so you know you put your request in it's been finalized and then you come up with the response

so in that way like locking in the actual request and being sure it's not going to revert but um you know what about um what about systems that have got single block finality you know can you that very next block grab the random number and so what how I think you can think of this is that um you know typically the current block um is when you've requested the number and then you know the next block typically if you're using row or block hash it's based on the previous block so hence block plus one is going to be referring to the block

that the user is putting their transaction into so that I think would be a bad idea um and so then block plus two then is a block that you're wanting to you know have as the hash and so then really it means that by the time you're at current block plus three that's when you could actually be doing your fulfillment and so having a delay um tries to ensure that um game players who are Savvy can't in some way influence the situation or help to guess the value so um before I go on um does anyone have any

questions um yeah I was just typing one Peter uh so am I correct to understand that if you submit a transaction and the block that contains that transaction is rejected um and you need to resubmit the transaction you'd want to change your random numbers that were used uh in that transaction ah yeah depending on how they're calculated right yeah yeah yeah yeah um so assuming that you're submitting a value um and say you're you're assuming that you get to come up with a random

request ID so typically you could just use sequential request IDs um because I think that um or depending on how you design your system it shouldn't be um influenceable so if it's an offchain system as we're going to see there are two types and um generally if you use vrfs you're not going to be able to influence the value but um no I think gen it's going to to come down to the design of the system but typically I think you aren't going to have to worry about um that but it does mean you are right that as soon as you if you were say putting a random number into a blockchain system as soon as that random

number hits the me pool then everyone um or all the savvy people are going to be able to see it and so your system then has to be designed such that um even non saavy players um are not um disadvantaged and so yes you you'd have to be um conscious of that um when things hit the men poool that um you'll be able to see what's going on so um and are there any other did that make sense Dera yes thank you all right cool and I don't think there are other

questions so well let's dive into onchain sources so the block hash of a block is the hash of everything in the block except for the extra data field so you can think of this as a fingerprint of the entire transaction history the whole blockchain history um up to that point and so in solidity you can call down into an OP code and essentially you call block hash and then you pass in a block number and that block number can be any block that's been in the past 256 blocks but it can't be that block itself um because it's referring to the block hash of a

previous block so that's one number that you could do and the issue with that system is that you could have a block producer and they could calculate what the block hash was going to be and then they could put a transaction in of their own and they could like have a number like they could have a 32-bit field or 256bit field that they could manipulate and they could calculate many many many candidate blocks with candidate block hashes and thus manipulate the block cash and so that's certainly possible um to do another issue is that you could

imagine that say if you've got a quiet chain so a chain that doesn't have many transactions and you know with ethereum that's never going to happen um and with even many most l2s I don't think it's going to happen but with the rise of app chains l3s I think there is the possibility where you'll have chains where they might have like say 10 minutes in a row where there is no there are no blocks on the Chain no transactions on the chain and um so you know you can imagine if you got a perfectly quiet chain and maybe there's just a single block producer and you know so maybe the no

there's no information going in that's random at all then an attacker could potentially calculate if they put their transaction in at this block what the calculated block hash will be and so um you know that that's could be a thing and so even people using your chain could be able to guess the right value so that that only would work though if you were putting a transaction in and there weren't transactions coming in from other people another methodology is to use preand so this used to be called difficulty and so the um pref Randal is

um the output of the Randal for the previous block and so from the Shanghai HUD Fork onwards um you um like the op code's been renamed and randal's calculated typically using this sort of formula where you do the um hash of the previous Randal figure um value um and then the BLS signature of um randow combined with the chain ID and the block number and so the thing to think about this equation is that so randal's constant the chain ID for a certain chain is going to be constant

and then that block number is going to you know like is not an influenceable value so the block producer isn't going to be able to say insert new transactions or do whatever they like to influence this number um it'll be [Music] uninfluenced exactly how they do this um yeah oh and and note the use of BLS signatures so BLS signatures don't contain a value that um the signer puts

in so um ecdsa uses a random value but obviously that random value could be manipulable by the um signer so hence the use of BLS and not ecdsa so um there is um a potential issue with um the um use of um preand that you need to be thinking about and so you know you do that transaction one where we lock in um the block number that we're going to get prend for um and um and so yeah in fact that that's actually something to actually

emphasize is that so when you do this transaction to request the random number you're going to say I want prev Randal or block hash but I want prandell to be gathered for a very specific block and um the reason why you do that is that if you just say I want prev Randal um then the user is going to do the Fulfillment and they'll be able to have a look at the number and not be happy with the number and then wait in the next block or the block after so um you know so you've got to be able to say I want it for this very specific block um but the problem with PR Randal is that you can't it it will only give you pray Randal for the previous block and

not a range of blocks so it means that if you're um you know you've got to somehow rather get a transaction to go in at just the right block number and if you don't then the preand that you were trying to get value won't be available to you because you'll be on the wrong block and so so the the only way that I can think of that you can sort out this complexity of having to get your fulfillment in on just the right block is to have a transaction that the block producer puts in each block to record the value of preand Dow so essentially

you then create a um an array um from zero block number of the preand Del values that have been created for the blockchain which is not an ideal um way of doing this but um it's the only way I can think of because otherwise you're guaranteed that the system won't be resilient because you'll be trying to get the preval for a certain block number and you'll miss getting the transaction into the correct block um another consideration with preand Dow is that um you know so the block producer is going to know the

value ahead of time and this probably won't be important but it does mean that the block producer will know stuff a little bit ahead of everyone else because what they'll see is at block number n the Randal figure um value for the previous block producer for block and will have been created and so they know um um what their private key is and so they they can calculate what the randow will be for the block that they're producing block number n+ one and so everyone else only gets to find out about the prandell for Block n+2 when block n plus1 is produced so

the block producer for n+1 knows about the value one block earlier and that isn't a big thing but it's still something to at least acknowledge another part of this whole scenario and something to consider is that rollups um sometimes need a completely D terministic environment and for instance arbitrum always sets the block hash and prand to zero so um if you're going to rely on using them then it's just not going to work on um arbitrum um and some of the other rollup systems so um secure random um onchain

is very either very hard or impossible um and you know so having to design your blockchain so your so your block producers always put a transaction in to capture the prev andal is going to be pretty hard and if you're on a system like arbitrum where um the um preval and block has just don't available then it's impossible so at that point you need to turn to offchain sources and um before I dive into that are there any questions about onchain sources

okay so off chain sources there's a uh a concept called verifiable random functions and so um a vrf is an algorithm where you have a um a asymmetric key pair private key and a public key and the idea is that you give it an ID a request number and you um then the system combines the request number and the private key to um produce a blob and you can use that um the um public key to verify that the um output is a result of the input and so um yeah

so private ke is combined with the input value Alpha produce a value beta and then the public key combined with the input value Alpha can be used to verify that beta was generated using the private key according to the algorithm so some very smart bookies came up with this algorithm and I think it's um awesome because um and this um system so this is um a image from chain link um you can imagine you've got your smart contract it comes up with an ID number and then chain links offchain system with its private key it um generates the shooter random number the um vrf then

onchain um has a contract which verifies using the public key that the um value is created correctly and then the random number is passed to that smart contract back at number one and um yeah so it's a great little system and so chain link have got a system where they've got a single private key and it can fail over between geod dispersed servers and so I guess the the big trust assumption there is that chain Link's private key is never released never leaked um Supra um previously super oracles they use an MPC methodology where they've got several servers that

cooperate to generate a random value and um so I guess you're trusting that the multiple private shares aren't somehow other leaked um also the performance of the Supra isn't as good as chain link um so chain link the verification is simpler whereas Supra you're um having to um use um BS and um so it's more complicated so it is more gas to do the verification there are also um systems called Quantum random number generators so QRS and um so the idea is that the server signs a random value and that

then on chain you verify the public key and then you say I I accept this random value and there's a few things that I I have concerns about with this sort of system um so there's no way to prove that a certain random value is fulfilling a certain random request I think um or it's hard so maybe the request could be um signed along with the random value or something like that um and also um how is there a failover situation so if there is um how do you get to understand if you're getting the right trusted value or not um so anyway

that the anu's got a qrng and so it's probably worth investigating further but to me it I I do have concerns I think for me I can understand the vrf uh methodology and the idea of it um creating a number and I think you got to think that in the eyes of the attacker these random numbers are going to be equal even though one's got using Quantum effects the um just having a prng that you cannot observe and you can verify is generated using a a a request ID that you've given is pretty powerful all by

itself are there any questions about the um vrf design or qrng okay so Random sequences so I did say that you'd have to do one request and then do fulfillment in a different transaction but um you can use random sequences to do U one random number per transaction and so you combine the request for the next random with the Fulfillment for the previous random and I guess the question that you've got to scratch your um chin about and have a think about is

well what could go wrong with this and so savy players um you know will know ahead of time what random number was generated so they're going to be able to have a look and uh work out what number was generated and they'd be able to think well when in say an hour's time I consume that random number this is the number it's going to be so that might have um negative consequences so a way of getting around this is that you need to have a a set of sequences so maybe you've got say five usages of random

numbers so each random each usage has to have a separate sequence so that I can't say use um the next random for low value um usage a and then use like the one say in three three random numbers time in the sequence for usage B which is high value um you also can't um use um this sort of um system in a shared activity so if you did then you can imagine that more Savvy players may be able to see the random number ahead of time whereas your less technical players won't and that would be

unfair so random numbers my final thoughts is that um it's actually not too hard to generate a number that looks randomish on chain you know you could do a kick Haack 256 of the block number and it will look random but it's really very difficult to generate numbers that aren't s able to calculational guessing within the constrained environment of the evm um and you know assuming you've got s sufficiently Savvy game players and so if you're going to be you know like dealing with tens of thousands hundreds of thousands millions billions of dollars then people will be motivated to

try and beat the system so um yeah you've got to try and design your system so that it you know can handle that um the merch door is still open and running um future talks so in two weeks time we've got Andreas who's going to talk about L2 transaction fee API standardization we've got Lei is going to talk about Unis swap V4 and the um incubation program that he participated in and then a little bit later we've got David who's going to talk about how AI is going to assist web3 adoption if you're here today you can um

watch um the YouTube videos of the or recordings of the talks um there's a slack workspace you can join um and um yeah if you're watching the YouTube video you can join live and ask tricky questions sometimes there are code examples in which case will end up in that repo and um are there any questions great job Peter thank you yeah looks like no questions which is all all good as well um yeah I think

the answer of random numbers is it's pretty hard isn't it um it would be good if it was straightforward um but yeah anyway have a great day evening night everyone and um I will talk to you all in two weeks time thanks Peter goodbye byebye