This is the first post in a series dedicated to our fhEVM protocol, which enables private smart contracts using homomorphic encryption.
Fully Homomorphic Encryption (FHE) is a technology that allows computations to be performed on encrypted data without requiring its decryption. FHE can be used in blockchain to enable confidential smart contracts, where transaction inputs and states remain encrypted at all time, even during computation. You can read more about the fhEVM protocol here.
Before we look at the features of the fhEVM, it is important to keep in mind a few things:
To make it simple for developers to use encrypted values in their contracts, the fhEVM exposes several encrypted integer data types, such as euint8, euint16, euint32. They act as the encrypted equivalent to the regular uint data types, with one major difference: smaller types are much faster to compute in FHE than bigger types, so if you only need an 8 bit encrypted value, you should not use a 256 container for it! Right now, the fhEVM only supports 8, 16 and 32 bit unsigned encrypted integers, but larger precision, signed integers and other data types are coming soon.
The fhEVM supports many of the traditional integer operations, such as add, sub, mul, shift, min, max, etc. We will be adding more over time, as well as provide some cryptographically optimized methods for the most common workflows.
The require operator is an error-handling, global function in Solidity: if the condition within require comes out to be true then the compiler will execute the method, otherwise it will throw an error. In homomorphic encryption, a comparison between two ciphertexts will return an encrypted Boolean, so to evaluate it at runtime we need a specific method, similar to require, but for encrypted Booleans. Behind the scenes, this will send a request to the validators to run a threshold decryption on the control bit, and return a plaintext value for the condition.
When a user sends an encrypted value in a transaction, it arrives in the contract as a byte array. The contract then needs to explicitly cast it to the correct data type, which will both parse the bytes and verify the ZKPoK attached to it. It then returns an euint that can be used in the rest of the contract’s logic.
Now that we understand the basic building blocks of the fhEVM, we can go into a concrete example and build an ERC20 token contract where the user balances and amounts being transferred are kept hidden at all times.
This confidential ERC20 contract is a classic ERC20 contract with a few differences:
Let’s start by writing our contract with its properties:
Transferring tokens involves a series of steps to ensure security and confidentiality. First, the ciphertext of the amount to be transferred is verified and the method returns an euint32. Then, the contract checks that the amount to be transferred is within the sender's balance, ensuring that there is no overspending. Finally, the transfer is executed by deducting the amount from the sender's balance and adding it to the recipient's balance, homomorphically.
In order for a user to view their balance, the contract needs to tell the network to re-encrypt the value from the network's key into the user's key. This is done directly in Solidity via a simple view function. This view function however needs to be authenticated by having the user provide a signature in the contract method call so that the network knows the user is actually the one owning the balance. The signed token respects the EIP-712 standard.
When a user mints an encrypted amount of tokens, the increase in the contract's total supply can reveal the number of tokens that have been minted. To prevent this, a random number of burnable tokens are minted such that someone decrypting the total supply doesn’t know how many real tokens were minted. The tokens in the burnable pool are then regularly burned to maintain equivalence between the total supply and the actual supply. To simplify, we will reset burnable tokens every 10 mints.
In the mint method of our ERC20 contract, a user-generated random number has been used. This isn’t ideal however, which is why we are planning to add an FHE random number generator to the fhEVM itself, which would enable contracts to generate randomness on-demand.
Tokens are a simple use case, but hopefully this tutorial showed how easy it is to build with FHE. Now that we have a confidential token, we can start thinking about all kinds of applications where this would be useful, such as blind auctions, confidential DeFi and more, which we will explore in future posts.
Join the Zama x FHENIX hackathon during EthCC and take the Zama's fhEVM for a spin!
News, research and product releases