Homomorphic Encryption in the EVM
ETHCC 6 · July 2023 · 35:27
Morten Dahl demonstrates integrating fully homomorphic encryption into the EVM. The workshop examines writing private Solidity contracts that process encrypted data without exposing it during computation.
Speakers
Topics
From ETHCC 6, hosted by Ethereum France.
Transcript
foreign welcome to this talk on the FH evm or how to build poliomorphic encryption into the evm so everything on the blockchain is good oh it's public sorry which is good for transparency but of course it also has some privacy issues involved with this one of them being that criminals know who to Target you might feel like you're exposing too much information and in other words without some privacy there are certain applications and
certain use cases that we can't really unblock and find full adoption for so our solution is to use volumorphic encryption to get around this problem and without going into too many details about volume of encryption come find me afterwards if you're more interested the general idea is that with fully homophoric encryption you can encrypt data and you can compute on this data without decrypting it okay so for instance in this slide we have two encryptions and encryption of X and encryptions of Y we could then do an homophoric operation on these two ciphertext and obtain a third ciphertext which is now an encryption of X Plus y likewise we can do homorphic encryption where we compare the two and now we obtain another ciphertext which is then the result of this comparison and again without decrypting anything and more
generally we can take encryptions or values and we can apply a function to the ciphertext and then get a new Cipher text where this function has been applied initially on the plain text okay so in the context of blockchains this makes it possible to take input from the user send it to the blockchain encrypt it have the blockchain process this data while it remains encrypted and we can keep it stored on the blockchain at all times so and we can do this without compromising transparency and usability so in other words we can we don't have to hide what computation is being done so users can still inspect the smart contract still see what kind of logic is executing they just can't see the data that is Computing on we can also allow smart contracts to have their own Access
Control logic as we'll see in a bit where if they want to implement uh some fancy way to kind of satisfy the need for the application they can still do that and we also get composibility in the sense that you can make smart contracts and have them share data like you typically do without encryption but also you can easily mix data coming from different users so if you want to build a blind option where you take data for multiple users then this is also another problem with volume of encryption so some of the use cases to go a bit further we can imagine with this is we can take we can build trustless bridges in the sense that we can take the signature key we can encrypt it we can put it on chain and then we can homophorically generate the signature so in other words we can have a smart
contract that will generate the signature we can build the blind auctions where we don't have to leak any information besides the final winner of the auction so no one gets to see the individual bits because they're all encrypted you just get to see the final result and you can do voting where you don't have to to reveal how much you're you're staking or how much you're bidding for a particular vote so some of you also know or think of zero knowledge when we say privacy and it's true that serial knowledge does give some privacy the way we see it is that still knowledge is more technology built for scalability I think in terms of roll-ups and one of the benefits of fhe is that it doesn't get in the way of compressibility one is around contracts but also especially around mixing data
from multiple users so in serial knowledge you need someone to see all the plain Text data when you want to do the computation and then generate the proof that the computation was done correctly we're still with a with fully morphing encryption you just have all the data encrypted and anyone can perform the computation so you don't need some entity or single entity to see all the plain text Data the computation is happening directly on the ciphertext and also it's very easy to keep all the data on chain so again you don't need to have data stored off chain that can go become unavailable and so on okay so our solution to this the FH evm let's have a look at what it does and the first thing to note is that everything is encrypted under the same public fhe key so we generate a global
public key and this is what makes compatibility so easy to do here we have the dots represent validators that now have this kind of global public key that users and so on can can download the way that we get this public key is that we start out having nothing and then we run a threshold key generation protocol that will basically generate shares of this of the corresponding secret key to the global fhe key and what this means is that no no validator on their own can do anything with the private key that's used for decryption purposes because they only have a share of it so they need to come together a certain a certain threshold of the validators need to come together and agree that okay now we want to use the secret key for something but again no validator can decrypt anything on their own
then when the users want to provide input they simply download the global public fhg key they perform a normal encryption and they send this to the ciphertext and now the validators all know this the encryption of of the input when they want to process on the input so here we have an encryption of X equation Y they can use operation in our FH evm to do the the operations to kind of apply the homorphic operations to the ciphertext and then generate the ciphertext of the of the result in this case e e c um and sometimes we want to decrypt values I'll get into it and we'll do a demo here in a bit we'll see where we need to do decryption but if the validators individually decide okay the smart contract dictates that now we have to decrypt the value here then we can
run a threshold protocol to do decryption where each validators will enter the the the threshold protocol with their share of the decryption key and then securely they will generate the decryption of this obtaining the the plain text we can also do something else which we call re-encryption where the validators besides having shares of the global key they also have in this case a blue public key for instance coming from a user and they have a ciphertext x and then without decrypting uh X in this case the encryption of X they can re-encrypt X under this new blue public key okay and we'll see why that's useful on the next slide but again this is done in a secure way so that X is not actually revealed to the validators it's rather re-encrypted under this this
other key and of course the use case for this is that when users is useful to have all the data encrypted on the chain and so on but at some point you also want to decrypt this user or this data and get it back to the user for instance if we're building a token and the user wants to see the balance the balance needs to be decrypted at some point the way we do that is we run re-encryption first where we take the encrypted balance of the user we re-encrypt it under user's public key and then the user can just call A View function to download this ciphertext and decrypt it because he knows the corresponding secret key for the key that he just applied to the to the blockchain okay um we are not launching a blockchain we're rather providing the components that allows anyone to build encryption
into their blockchain in particular the components we have is this FH evm that allows you to do homorphic operations that can trigger these threshold protocols we also provide the threshold protocols for doing this they're highly optimized for the encryption scheme that we're using tfhe we're also providing a solidity library that makes it easy to express smart contracts operating on encrypted data this is done without having any changes to the solidity compiler so you can use your normal developer tools you just import our library and then you compile the smart contract with this and finally we have an SDK for building gaps that allows you to encrypt data in the proper way and interact with an encrypted blockchain okay but let's try and do an actual demo of this
and I tested and it did work so let's see if it still works okay all right so far so good okay so here we have normal remix what I did is I cloned our example repository so you can do this episode bigger yep is that better yeah cool all right yeah please let me know if any of the screens are too small or pepper to make me okay so I just cloned our example repository here created a smart contract and then let's try to build it and show some of the the concepts that goes into it so we'll stand out just building a simple esc-20 contract here we'll have an owner uh let's make it
public oh we'll have a Constructor say that okay only the whoever created the contract is now the owner of the token as well and then we have our typical mapping where we map an address to a un32 as the balances okay nothing fancy so far so the first thing I want to do is for this particular token I want to make the balances encrypted so what I do is I import our library so I got my cheat sheet here next to me which is also available on npm so this is just because I'm using the example
repository we provide and now when I import a solidity Library what I one of the things I get is I now get an encrypted integer type so what I'm now saying is that my I want my balances to be encrypted I'm not touching any of the other data so you can freely mix public and private data but I want my balances to be encrypted and if everything goes well I should be able to compile this yeah okay and I could now deploy this on the on the blockchain if I wanted but let's add a bit more functionality first so the first thing I want to add is a minting function so let's say we want to Mint or be able to Mint and I want to take an encrypted interview so now we have a means function or sorry mint tokens
um I'm not providing the amount they want to maintain plain text they're either providing an encryption of the amount that they want to to Mint and let me just see here this is public okay and then I'm going to require that only the owner can do this and I'm simply saying that okay the owner is and now I'll take whatever he has currently and I'll add this amount to it so one thing we're adding in our next version of solidity library is the ability to use operator overloading instead of calling these things so that stuff is going to be fixed okay um so now yeah we have our main function and this is valid and useful but it's
not exactly what we want so in order to understand that we need to understand what is this Eun 32 actually and in reality a new n32 is a handle to a ciphertext that's stored on chain so concretely it's the hash of that ciphertext and what we want here instead is we want this function to be or this input to be provided from the user in the form of a ciphertext so in order to do that I'm instead going to say okay these are now some bytes uh coming from this and I'm saying this is the ciphertext I get as input and then what is the corresponding correspondence between this amount and the amount ciphertext well I can get an EU in 32
amount by converting it as EU into 32 and then amount ciphertext okay and the reason we have to do this conversion so to go from the kind of the raw ciphertext into an euend um there is one critical reason for this and this is when we do the conversion here when we convert from the from the bytes into an online value uh we're actually performing two checks which are critical for security the first one is we're requiring that the ciphertext is well formed what is called and this is a cryptographic requirement that for this particular particular ciphertext or encryption scheme if these were just random bytes then a user could try to potentially learn something about the secret key so the encryption scheme
inherently requires that there is a proof that this ciphertext is well formed the other thing we're doing here is that we're checking that the user that provided this knew the underlying plain text and the reason for this is that imagine a user that goes on the blockchain grabs a ciphertext and then inputs it to a Smart contract and asks that smart contract to decrypt the value this will break the entire security of the chain because we can't just use the blockchain as a decryption Oracle in this way so intuitively if we can ask the user to prove that he already knew the plain text that was inside the ciphertext then he wouldn't learn anything else or anything new if he was doing this so what's included in the ciphertext is a Serial knowledge proof that one the ciphertext is actually well formed from a cryptographic perspective
required from a cryptographic perspective and then also that the user knew the underlying plain text so we get around this using misusing the blockchain as a decryption Oracle okay and then now that we have an EU n32 we can start using in our system so this an Eun 32 really represents a ciphertext that's stored on chain and is ready for processing that the system can can process whereas the Cyber text that came in here are just the raw bytes that are so far uh kind of untrusted okay so let's see this working is this clear by the way the distinction between these two okay so I compiled it here I cheated a bit I already copied the API so we have that but now let's try to deploy it so I'm
using metamask here let me check I'm on the right account yep I'm a developer I'm going to reply this um so I said we're not launching a blockchain but we do have a devnet for those that want to experiment with this I'll get to that in a second I confirm okay connection is good so far I copy the address and then over here I have a few sample codes where we're using our JavaScript SDK yeah it's the SDK for interacting with with an encrypted blockchain so I'm going to say contract it's the one we just deployed npn run and then mint what we do here if we look in this Min
function is we instantiate the SDK we encrypt a value in this case a default of a thousand because I'm not specifying it as an EU M32 as a 32-bit integer and then we simply send this transaction to to the blockchain all right fingers crossed while that completes we should be able to look in our block Explorer here and should be top of this one if it's a bit small okay so let me just check that it went through uh yeah looks good so what we see here in the payload it's a bit hard to decipher
but this is the ciphertext that's being sent so I know this is not really meaningful but this is to show that we're not actually sending the plain text right you can go in you can grab the Cyber text if you want to this ciphertext is about eight kilobytes we're working on getting that smaller but it's not it's not terrible okay and we also now have the mint so the next thing we might want to do is try and actually see that this does work so to try and get our balance sorry so that's one thing that we tweak with the evm that we say the gas cost for this operation are tweets so with what happens under the hood good question is we're not compiling everything down to evm bytecode because the homorphic
operations would be too expensive to doing that so what we do in the fagvm one of the things we do there is we add pre-compile smart contracts for the homorphic operations and then in those pre-compassed smart contracts we're calling out to our encryption library to do the the actual operations so the heavy lifting so we can we can tweak the gas cores for individual homorphic operations instead of having everything as evm by code okay so let's try and add this balance um now that we know what this Eun 32 is we can also see why this is this is probably not what we want intentionally I didn't make it public here and the reason is this is okay the user if they want to go and get their own balance if we expose it just like this as a public what they wouldn't even they
wouldn't just get a ciphertext that's encrypted under the public Global key that they can't decrypt they will get a hash of a ciphertext that they can't decrypt so what we want to do here is we want to inject some logic so I'm going to make this one internal and then I will Define a balance of balance of function here and as I said before we could ask the blockchain to just decrypt this value and then they can read it as a plain text value but that would also leak this thing to the to the validators so what we really want to do here is we want to do this this re-encryption and to do this we're going to take a public key from the user and oh and then return
I would say bytes memory where we can use a function provided in solidity Library called re-encrypt where we're taking the balance of the caller and asking it to be re-encrypted on the public Keys provided and if this balance happened to be uninitialized we want an encryption of zero instead then I would type European okay so this will work so what this will do is it will ask the user when they call this function to provide a public key and then they will do the run the threshold protocols among the validators to then re-encrypt the balance under the global key and to the user Pi key and send it back to him
now there is one security issue here and the thing is we since this is a view function nothing is signed so we're getting a public key and we're getting someone that pretends to be a specific sender and this of course he could impersonate anyone he wanted to do so one way around this is to add a signature to it we're not dictating how people want to do this so this is free for for you to do but one nice way of doing it is to use EIP 712 which when the user is then signing his public key we can actually give him some intelligent message about what he's signing instead of just saying okay you're signing this random message that doesn't make any sense it's a way of putting structure onto this custom message that we're asking him to to sign and for this I'm going to cheat a bit so
we have here an Erp modifier that I'm just going to grab first we need to import this okay and then I have pre-cooked modifier what this does is yeah it works with this EAP 712 is basically public key or we expect the signature on in this case then it's certified China message we are now taking bytes let me just get
this right signature as well and then we will require that um only signed by sending public key oh oh make this work is I need to say that this one is is eip712 this is just some boilerplate to make
this work oh sorry wrong and then I need to pass this to the Constructor so the key thing here oh oh thank you okay so the key thing here is we now added a signature to the public key and we kind of decided on our own how we wanted to do this all right so let's try to deploy this I'll copy it
and let's see if we can call it sorry typo oh yeah thank you oh oh there's two actually uh so to look at the JavaScript so the SDK side of this so what we do is in our SDK we also provide a way of generating these tokens authentication tokens as we call them conveniently for you so this is we're generating under the hood we're using salt in ACL to generate these public keys and then we're generating the signature as well so here inside the token we're getting our public key and then we can send in a signature so we're
just providing a convenient way of doing this on the on the SDK side as well or the DAP side as well then when we call the balancer function we get the encrypted balance back and now we can since we have we generated the public key here we can then also ask our SDK to decrypt this value for us again just using uh salt under the hood all right let's see if this works okay so files are good we have a balance of zero so let's see if we can what happens if we meant a bit let's have a look so here we created a new contract
and then here's our main function admin transaction okay so when should be done so let's hopefully our balance is now a thousand because we just minted a thousand tokens okay okay um so the last thing I want to show is how we can do a transfer as well that's also useful in a token so function transfer and then we say okay who are we transferring to and then again this is a function we expect the user to call so we're not accepting an EU and 32 we're accepting a ciphertext that can be converted into an e unit so we say here bytes call data amount
ciphertext that's a public function we now convert this amount tfhe as EU and 32 well ciphertext okay no oh good okay and then we can also use the one thing you want to do when you want to make a transfer is you want to make sure that this amount is actually on the on the user's account right so we say okay we now have another encrypted type which is a Boolean in this case we say okay do we have sufficient funding on this so tfhe less than and then balance of message dot sender okay and then we
require that there are sufficient funding now this won't work right because we have an encrypted value here and in order to uh to run and require plain text operation we need to decrypt this um so what we do here instead is we have a require and what this will do is it will instruct the validators to decrypt this Boolean value we're not decrypting the inputs so we're not decrypting amount or the balance we're just decrypting a Boolean value that will tell the validators whether or not to continue with this transaction or not and if this Boolean value turns out to be false then we abort the transaction and if it goes through then balances 2 is now whatever it was before plus this amount
and we need to subtract it on the sender as well okay let's try to compile this I'm gonna deploy it so contracts npn run um well we need to Mint something first now because it's a new contract so let's do a quick mint all good
let's check that we have some tokens oh uh balance off okay all good and then let's try to make it transfer um looking at the transfer script here nothing exciting we're encrypting the amount that we want to transfer and then just calling the transfer transaction so we say npn run transfer now we want to specify who we're transferring to and I set up a different account here let's go and graph the address so in this case we're encrypting a
default value of or transferring a default value of 100. okay and now if we check our balance off should probably be 900 which it is okay um so let's also see this we have a quick demo website here where I can put in my contract there are a few by the way you can you can go and play with um esc20 blind auction private betting for now we're just sticking to the esc20 I put in my contract address and ask the recipient so again so this is what I'm what I was talking about before with the eip712 that we're now getting the balance right
so we need the user to sign his public key so he needs the there's an interaction with the wallet and in order to make this message a bit more useful for him or a bit more meaningful we can use the AP 712 to actually get say okay we're doing a re-encryption here you're sending a public key and so on so we ask him to sign that we get a response back from the blockchain that he has a hundred tokens and just for good measures we can also try and switch to kind of our developer account that we were using that owns the contract get the balance we now need to sign again because we're on a new account and we have 900 here okay uh that concludes the actual demo any questions on the code part of this so binary search uh in as a smart
contract he's running it locally right it's everyone can run can run it locally and if you can just add another function to the smart contract saying find balance and he uses the existing public key of the user in the Hallmark key and so on and she just called it in a loop uh doing binary search across possible balances and then shrinking where the balance stops and then it tracks the balance this way right so um and you can do that as an individual validator but you need to convince all the other validators to run exactly the same code because when you then do the actual otherwise you're just getting a bunch of encrypted booleans and you have no idea if they're true or false so when you
want to branch in your binary search you need to decrypt that value so if you want to do this you need to convince the other validators to do this and that's why as a user it's still important that you look at the Smart contract code to make sure that they're not trying to guess your value by doing a binary search or something like this because a single validator will get a ciphertext but he can't decrypt that ciphertext he needs all the other a fraction of the other validators to run the decryption how is this done in practice I mean do they communicate with each other to obtain this uh yeah okay so we can go back in here so um in this case it would be a decryption but each validator only has a part of the decryption key so he needs to convince the other validators to then do
the the decryption with him because they have the other parts of the key so it's true you have to be careful that the contract itself is not leaking too much with these requires so as a user it's still your responsibility to go and say when I send my data to a Smart contract is that smart contract trying to do a binary search that leaks too much but a validator on his own can't do this he can deviate from a smart contract of course if he wants to but he still needs the other the other validators to actually do the the decryption of the value to learn anything and that means he needs to convince the other validators to run the same smart contract code going on
in the balance of balance of yeah yeah so is that like simulating the validators talking to each other to do the re-encrypt because I guess in the re-encrypt you also need need the threshold right like on the line 22 you're saying like Oh that's oh okay so I was okay that was just the 712 message okay so so what's happening here if you look at the slides is there's two steps happening the first thing is that in our solidity code we had the re-encrypt uh call uh right so this was a balance off here we're asking the blockchain or the validators to re-encrypt under a new
public key that came in from from the user right exactly that's this step so now we assume that they have the public key from the use of the blue key here and now with the smart contract is asking them to re-encrypt this cyber text that was under the global fhke key to the ciphertext that's on the user supplied Key by the the re-encrypt code and then afterwards when we have the ciphertext under users key um he can just download this using a normal view function right a normal this is just data that's now available to him and then since he knows the the corresponding private key to the blue key he can then decrypt on his side so that's what we saw in the here that he's basically he's up here he's generating the blue key
and then we're asking him to generate a signature on this using his wallet and then when he get the encrypted balance back from the blockchain so this is now the blue ciphertext he can of course decrypt this because he knows the corresponding decryption key for the blue key yeah otherwise yeah yeah so exactly so so there's two places where this happens one is if you look at the solidity code when you do the re-encrypt we're triggering the threshold protocol to re-encrypt under the new key and when we're doing the required down here we're triggering a threshold protocol to do a decryption of just the Boolean value to know if they
continue or not yeah oh uh sorry I have two questions so uh do you have any number of performers of this threshold key generation or decryption Paradox and how many participants are involved I think this is crucial to the whole system right yeah and my second question is that if I'm correct there are bad data so we are recompute every you know homorphic operations right so do you guys think of using like other sourcing these computations using snap Stars such as yeah yeah yeah good question so what we're targeting for is again we're not providing our own blockchain so we want to be a bit flexible here so that people can build whatever corresponds to their use case we're targeting two scenarios one where we have a handful of
validators that want to do this and one where we have around 40 validators at a time this can change over time so we also have resharing protocols where you get from or go from one group of validators to another group of validators and then you reshare the shares of the private Keys as you go along but those are the use cases protocol because you have to apply proofs to prove the validity of odd property keys or the distributions I think it's a little bit you know heavy but that depends on the number of our data is right yeah yeah so the protocols that we do because as some okay I didn't say this in the beginning summer as a company we're specializing in homorphic encryption and then we're building this on top of it so what we do is we specialize on one particular encryption
scheme tfhe um and then what we can do with the threshold protocols is we can heavily optimize them for this particular encryption scheme so that's why decryption is actually very efficient uh even when you're running this between like 40 validators um the other question you had about performance for so for the initial key generation that can be a more expensive operation and it is but it's only happening once during Genesis of the blockchain so do try to like uh using snaps to Outsourcing all the homorphic operations so yeah so the yeah good question so can we the thing is when we do the operations all the validators need to perform the homorphic operations and these are more expensive of course than normal plain text operations so the question is can we Outsource this heavy
computation to uh to powerful instances uh yes we could and we're looking into that we have research going on on that the problem is that if you wanted to build these your knowledge proof of correct computation over the particular mathematical objects that the serial knowledge scheme is working in it doesn't fit exactly so we're working on adapting that to that and then being able to do a verifiable computation on fhe thank you guys sorry we are running out of time we have to move for the next conference but if you have any question feel free to ask the speaker after let me just add one quick thing so we're actually doing a hackathon Friday Saturday here in our Paris office we're a paris-based company so if you're interested uh go have a look at our website scan the QR code and we'll be
happy to see you then thank you very much [Applause] [Music]