← Back to blog

Private Smart Contracts using Homomorphic Encryption

Rand Hindi
Published on:
July 20, 2022

Homomorphic encryption (FHE) is a technology that enables processing data without decrypting it. This can be used to create private smart contracts on top of public, permissionless blockchains, where only specific users would be able to see the transaction data and contract states. While FHE used to be too slow to be practical, recent breakthroughs are now making this possible in the next couple of years.

Video recording

Slide 1/27

Everything on a blockchain is public

How else would nodes agree on state?

Slide 2/27

This makes web3 unsafe


Criminals know what you own, so they can easily target you and steal your crypto.


Governments can surveil you, even if you use multiple addresses.


Bots can front-run you, creating a hidden tax on every transaction.

Slide 3/27

Zero-knowledge proofs do not enable privacy when multiple users are involved

ZKs offers privacy by computing off-chain, which only works for single users. This doesn’t enable private AMMs and other multi-user dapps.

Slide 4/27

Homomorphic Encryption (FHE) enables encrypted data processing

e.g. $ Enc(a) + Enc(b) = Enc(a+b) $ or more generally $ f(Enc(x)) = Enc(f(x)) $.

Slide 5/27

FHE enables on-chain privacy

- Encrypted Transaction Data

Data included in transactions is encrypted and never visible to anyone.

- Encrypted State Updates

States are updated while remaining encrypted at all times. Not even block producers can see the data.

- Encrypted On-chain Data

Data stored on-chain remains encrypted end-to-end, even when used by smart contacts.

Slide 6/27

FHE makes web3 safe

No targeting

Criminals can’t target you since they cannot see how much crypto you own.

No surveillance

Governments cannot surveil you since they cannot decrypt your on-chain state.


Bots cannot front-run you since they cannot see transaction data.

Slide 7/27

FHE enables new categories of dapps

Slide 8/27

Slide 9/27

Ciphertext = encrypted data + noise

We need to add random noise to the encrypted data to guarantee security.

Slide 10/27

Noise grows with every operation

If the noise grows too big, it will overwrite bits of data with random ones.

Slide 11/27

Bootstrapping reduces noise

Bootstrapping is a special operation that resets the noise to its nominal level.

Slide 12/27

Levelled schemes

e.g. BGV, BFV, CKKS Avoid bootstrapping by provisioning enough room for noise to grow. Very fast but...

Slide 13/27

On-chain states can be updated indefinitely

This means noise will eventually grow too big and lead to incorrect states.

Slide 14/27

That’s not the only problem though ...

Levelled schemes only allow additions and multiplications. Comparisons and non-linear functions are approximated using polynomial approximation.

Slide 15/27

TFHE to the rescue

TFHE is a scheme that enables fast bootstrapping and exact arbitrary computations.

Slide 16/27

TFHE is the only scheme that can support arbitrary smart contracts

Slide 17/27

Concrete is an open source framework for TFHE

User-friendly APIs

Concrete enables using FHE without knowing cryptography.

Hardware accelerated

Concrete can leverage accelerators such as GPUs, FPGAs, and ASICs.

Written in Rust

For better performance and security.

Slide 18/27

FHE will be fast enough for most applications by 2025

And probably before that for smart contracts, but it might not be cheap to run until ASICs are here.

Slide 19/27

Slide 20/27

FHE token contract pseudo-code

contract Token {
    mapping(address => uint256) public balanceOf;
	// Transfer tokens privately, amount is encrypted under the network's key 
	function transfer(address _to, FHECiphertext _value) external returns (bool) {    
		require(_to != address(0), 'ERC20: to address is not valid');
		require(_value <= _balances[msg.sender], 'ERC20: insufficient balance');

		_balances[msg.sender] -= _value;
		_balances[_to] += _value;

		emit Transfer(msg.sender, _to, _value);
		return true;
	// to enable a user to view their balance, we need to re-encrypt 
	// the balance from the network's key to the user's key 
	function view_balance(FHEPublicKey userKey, address Address) external view returns (bytes) {
		require(address == msg.sender, 'ERC20: invalid user');
    	return reencrypt(balanceOf[address], userKey);

Slide 21/27

High level protocol

To enable multiple users to interact with each other, we need the data to be encrypted under the same FHE public key.

Slide 22/27

Dealing with encrypted inputs is tricky


Who holds the network’s private key and how can we prevent them from misusing it?


How do we handle requires on encrypted data without breaking privacy?


How to we prevent malicious users from decrypting other users’ encrypted states?

Slide 23/27

Secure the private key with Threshold FHE

Split the secret key amongst validators such that at least 2/3 are needed for decryption.

1. Secret Sharing

Generate and distribute pieces of the secret key to each validator.

2. Partial Decryption

Each validator then does a partial decryption (or keyswitch).

3. Aggregation

The partial decryptions are aggregated to yield the full decrypted value.

Note: Needs a fixed number of validators such as in DPoS, NPoS, etc..

Slide 24/27

Dealing with encrypted requires

Requires need to be decrypted at execution time to validate transactions.

1. Block production

Validator 1 optimistically executes and proposes a block, but does not participate in threshold decryption.

2. Threshold validation

Other validators optimistically execute and validate the block, then do a threshold decryption of the requires, keyswitches, etc.

3. Block commitment

If there is threshold consensus, the failed transactions are removed and the finalized block appended to the blockchain.

Slide 25/27

Zero-knowledge proof of input awareness

Users need to submit a proof that they know the value of the encrypted inputs.

1. Encrypt data

Users encrypt the transaction inputs they want to keep secret.

2. Generate proof

They then generate a zero-knowledge proof to show they know the inputs.

3. Validate proof

Validators then check the input proofs before executing transactions.

Slide 26/27

Full protocol

Slide 27/27

Future improvements

Provable FHE

Generate a proof of correctness for an FHE execution to avoid redundant execution.


With provable FHE correctness, we can create FHE L2s for Ethereum and others.


Make FHE fast to execute for block producers and cheap to verify for validators.

Written by Rand Hindi

Dr Rand Hindi is the CEO at Zama and an investor in 30+ companies across privacy, AI, blockchain, medtech and psychedelics.

Follow Rand on Twitter.

Don't miss Zama's next big news
Related articles

TFHE Deep Dive - Part I - Ciphertext types

This blog post is part of a series of posts dedicated to the Fully Homomorphic Encryption scheme called TFHE by Ilaria Chillotti.

Read Article

Homomorphic Encryption 101

What is homomorphic encryption?

Read Article

Introducing the Concrete Framework

We are proud to announce the first official release of the Concrete Framework.

Read Article