A few months back, the crypto team at a16z published the Nakamoto Challenge, a list of the most important problems to solve in blockchain. The fourth one in particular caught our attention: “Compliant Programmable Privacy”, as we have been actively thinking about this for some time. Today, we are proposing a first solution using homomorphic encryption and our fhEVM confidential smart contract protocol (if you’re not familiar with the fhEVM, you can read our articles about confidential ERC20 token and blind auctions).
The fhEVM is a regular EVM with some precompiles that enables computing on encrypted states using our TFHE-rs homomorphic encryption library. From the perspective of the developer, there is no cryptography involved: they simply write Solidity code using the encrypted data types we provide (euint32, ebool, etc). One of the big advantages of the fhEVM vs other privacy solutions is that all the data and computation happens onchain. This means you can have the same level of composability and data availability as regular, plaintext contracts.
This property is key to building programmable privacy, as all the access control logic can be defined in the contract itself. There is nothing that needs to be hardcoded into the protocol, and nothing the user has to do offchain to be compliant. The application can enforce compliance directly, with just a few lines of Solidity code!
In this article, we will show how to build a compliant ERC20 token, using onchain DIDs. The source code for this tutorial can be found in the examples folder of the fhEVM repository.
A Decentralized Identifier (DID) is a unique digital identity that is issued by an entity such as a government, a registrar, a company or the user itself. This DID can be tied to a cryptographic key that proves the user owns the DID, such as an EVM wallet. But it can also store a whole host of attributes, such as the user’s age, nationality, social security number etc. These attributes in turn can then be used to prove that you satisfy some condition (called an “attestation”), such as being over 18 or not being a Narnia citizen.
Most DIDs are implemented client side, and use zero-knowledge proofs to generate attestations. While this is fine in many cases, it quickly becomes complicated when you have multiple users involved in a transaction, when you have to apply complex rules to the DID, or when you need to keep a common set of rules for everyone to follow. It’s essentially the same tradeoff as in edge vs cloud applications.
Having a centralized DID registry however would solve these issues, as you could then simply ask the registry to check that everyone is compliant. It would also make it simpler to keep track of regulations, as you would only need to implement it in a single place. A blockchain would be a perfect infrastructure for this, as it would enable composability between DIDs and applications that require compliance, as well as composability between regulations themselves.
Problem: everyone would see the identity of everyone!
Fortunately we have a solution: homomorphic encryption, and more specifically the fhEVM! Thanks to the ability to have composability on encrypted state, we can host the user DIDs directly onchain in encrypted form, and have compliant applications verify attributes using a simple contract call. The ability to manage an identity via a smart contract, which we call “Identity Abstraction”, is akin to how one can manage funds via smart contract with Account Abstraction.
This tutorial has 3 parts:
Architecture of our Onchain Confidential DID Protocol
The IdentityRegistry contract is a registry of user DIDs that are issued by registrars and include a set of encrypted identifiers, such as their nationality, age, social security number etc. These identifiers are stored as encrypted 32 bit values (euint32).
The contract also handles permissions, such as:
As a first step, let’s implement the logic for creating and managing DIDs:
Now the next step is to implement the logic for identifiers and access control.
An identifier is simply a string (e.g. “date of birth”) and an encrypted 32 bit value. It can be created or updated only by the registrar. A user can’t create their own identifiers, as we want them to be certified by the registrar.
Since identifiers are encrypted however, the user needs to give permission to a contract to access specific values, which we will handle through a simple access control mechanism similar to how you can allow a contract to spend your ERC20 tokens.
contract IdentityRegistry is EIP712WithModifier, Ownable
We can now wrap up our identity registry contract by adding the necessary getters, with some conditions and error handling.
contract IdentityRegistry is EIP712WithModifier, Ownable
The next step is to create our regulation contract.
When implementing a set of rules for transfers between two individuals, it’s important to recognize that these rules may evolve over time. Having a single smart contract defining all the regulation for a given context such as money transfer means that ERC20 contracts don’t have to keep track of regulation themselves. Governments can simply update this contract, and it will automatically propagate to all tokens that implemented it.
At the core, the regulation contract is just a set of conditions that are matched against encrypted identity attributes. To avoid misuse, users won’t directly grant access to the regulation contract, but rather grant access to the ERC20 token contract, who then performs a delegate call to the regulation contract. This approach ensures that only the ERC20 contract, which the user trusts, can access their information. Keep in mind that both the sender and the receiver have to have granted permission to the ERC20 contract before a transfer can happen between them.
In this example, we will implement some basic rules:
Rather than failing the transaction, which could reveal sensitive information, we will simply set the transfer amount to 0 if one of the conditions is not met. This uses a homomorphic ternary operator called a cmux: value = TFHE.cmux(encryptedCondition, valueIfTrue, valueIfFalse
Now that we have an identity registry and a regulation contract, we can finally create our compliant, privacy preserving token contract. This contract will be called CompliantERC20 and have the following key features:
The regulation contract is invoked via a simple call. This implies that users must provide access to the ERC20 contract before initiating any transfer; otherwise, the transfer will be reverted.
Finally, we can now create our ERC20 contract:
Similarly to how users grant permissions to DeFi protocols to spend their tokens, they will need to grant permission to the contract to access identifiers needed by the regulation contract. This is done via a call to Identity.grantAccess(contractAddress, identifiers), which can be retrieved by calling the ERC20.identifiers() view method. This list comes directly from ERC20Rules contract to allow update of properties.
Hopefully this tutorial has shown you that compliance isn’t a difficult thing to build if the rights tools are available. While we initially built the fhEVM to enable privacy in blockchain, we quickly realized that this technology could be used for identity management and thus programmable compliance.
The proposed design here is far from perfect, but we believe it can easily be improved and launched as a real world use case, so that compliance no longer has to be synonymous with surveillance!
A few months back, the crypto team at a16z published the Nakamoto Challenge, a list of the most important problems to solve in blockchain. The fourth one in particular caught our attention: “Compliant Programmable Privacy”, as we have been actively thinking about this for some time. Today, we are proposing a first solution using homomorphic encryption and our fhEVM confidential smart contract protocol (if you’re not familiar with the fhEVM, you can read our articles about confidential ERC20 token and blind auctions).
The fhEVM is a regular EVM with some precompiles that enables computing on encrypted states using our TFHE-rs homomorphic encryption library. From the perspective of the developer, there is no cryptography involved: they simply write Solidity code using the encrypted data types we provide (euint32, ebool, etc). One of the big advantages of the fhEVM vs other privacy solutions is that all the data and computation happens onchain. This means you can have the same level of composability and data availability as regular, plaintext contracts.
This property is key to building programmable privacy, as all the access control logic can be defined in the contract itself. There is nothing that needs to be hardcoded into the protocol, and nothing the user has to do offchain to be compliant. The application can enforce compliance directly, with just a few lines of Solidity code!
In this article, we will show how to build a compliant ERC20 token, using onchain DIDs. The source code for this tutorial can be found in the examples folder of the fhEVM repository.
A Decentralized Identifier (DID) is a unique digital identity that is issued by an entity such as a government, a registrar, a company or the user itself. This DID can be tied to a cryptographic key that proves the user owns the DID, such as an EVM wallet. But it can also store a whole host of attributes, such as the user’s age, nationality, social security number etc. These attributes in turn can then be used to prove that you satisfy some condition (called an “attestation”), such as being over 18 or not being a Narnia citizen.
Most DIDs are implemented client side, and use zero-knowledge proofs to generate attestations. While this is fine in many cases, it quickly becomes complicated when you have multiple users involved in a transaction, when you have to apply complex rules to the DID, or when you need to keep a common set of rules for everyone to follow. It’s essentially the same tradeoff as in edge vs cloud applications.
Having a centralized DID registry however would solve these issues, as you could then simply ask the registry to check that everyone is compliant. It would also make it simpler to keep track of regulations, as you would only need to implement it in a single place. A blockchain would be a perfect infrastructure for this, as it would enable composability between DIDs and applications that require compliance, as well as composability between regulations themselves.
Problem: everyone would see the identity of everyone!
Fortunately we have a solution: homomorphic encryption, and more specifically the fhEVM! Thanks to the ability to have composability on encrypted state, we can host the user DIDs directly onchain in encrypted form, and have compliant applications verify attributes using a simple contract call. The ability to manage an identity via a smart contract, which we call “Identity Abstraction”, is akin to how one can manage funds via smart contract with Account Abstraction.
This tutorial has 3 parts:
Architecture of our Onchain Confidential DID Protocol
The IdentityRegistry contract is a registry of user DIDs that are issued by registrars and include a set of encrypted identifiers, such as their nationality, age, social security number etc. These identifiers are stored as encrypted 32 bit values (euint32).
The contract also handles permissions, such as:
As a first step, let’s implement the logic for creating and managing DIDs:
Now the next step is to implement the logic for identifiers and access control.
An identifier is simply a string (e.g. “date of birth”) and an encrypted 32 bit value. It can be created or updated only by the registrar. A user can’t create their own identifiers, as we want them to be certified by the registrar.
Since identifiers are encrypted however, the user needs to give permission to a contract to access specific values, which we will handle through a simple access control mechanism similar to how you can allow a contract to spend your ERC20 tokens.
contract IdentityRegistry is EIP712WithModifier, Ownable
We can now wrap up our identity registry contract by adding the necessary getters, with some conditions and error handling.
contract IdentityRegistry is EIP712WithModifier, Ownable
The next step is to create our regulation contract.
When implementing a set of rules for transfers between two individuals, it’s important to recognize that these rules may evolve over time. Having a single smart contract defining all the regulation for a given context such as money transfer means that ERC20 contracts don’t have to keep track of regulation themselves. Governments can simply update this contract, and it will automatically propagate to all tokens that implemented it.
At the core, the regulation contract is just a set of conditions that are matched against encrypted identity attributes. To avoid misuse, users won’t directly grant access to the regulation contract, but rather grant access to the ERC20 token contract, who then performs a delegate call to the regulation contract. This approach ensures that only the ERC20 contract, which the user trusts, can access their information. Keep in mind that both the sender and the receiver have to have granted permission to the ERC20 contract before a transfer can happen between them.
In this example, we will implement some basic rules:
Rather than failing the transaction, which could reveal sensitive information, we will simply set the transfer amount to 0 if one of the conditions is not met. This uses a homomorphic ternary operator called a cmux: value = TFHE.cmux(encryptedCondition, valueIfTrue, valueIfFalse
Now that we have an identity registry and a regulation contract, we can finally create our compliant, privacy preserving token contract. This contract will be called CompliantERC20 and have the following key features:
The regulation contract is invoked via a simple call. This implies that users must provide access to the ERC20 contract before initiating any transfer; otherwise, the transfer will be reverted.
Finally, we can now create our ERC20 contract:
Similarly to how users grant permissions to DeFi protocols to spend their tokens, they will need to grant permission to the contract to access identifiers needed by the regulation contract. This is done via a call to Identity.grantAccess(contractAddress, identifiers), which can be retrieved by calling the ERC20.identifiers() view method. This list comes directly from ERC20Rules contract to allow update of properties.
Hopefully this tutorial has shown you that compliance isn’t a difficult thing to build if the rights tools are available. While we initially built the fhEVM to enable privacy in blockchain, we quickly realized that this technology could be used for identity management and thus programmable compliance.
The proposed design here is far from perfect, but we believe it can easily be improved and launched as a real world use case, so that compliance no longer has to be synonymous with surveillance!