Technical Walkthrough
This walkthrough goes through the core functionality of Redact, namely Encrypting your ERC20 balances, performing an Encrypted Transfer, and Decrypting your encrypted balance back into a public balance. During the walkthrough we will also discuss the underlying technology behind an encrypted token balance, including FHE and Fhenix's CoFHE coprocessor.
Terms
ERC20
A standard token contract with a public balance
(WETH / wBTC / PEPE)
ConfidentialERC20
A confidential token contract with an encrypted balance. All ConfidentialERC20s have an underlying ERC20 that they are paired with.
(eETH / ewBTC / ePEPE)
FHE
Fully Homomorphic Encryption. An encryption scheme that allows math operations to be performed on encrypted values without knowing the unencrypted value.
CoFHE
Fhenix's offchain coprocessor which uses an FHE engine to perform FHE operations and decryptions.
cofhejs
A javascript package released along side the CoFHE coprocessor that allows integration with a dApp.
Encrypting your ERC20 balance
To Encrypt your ERC20 balance in Redact, see this usage guide: Encrypting
uses FHE to encrypt any ERC20 token balance. An existing ERC20 cannot be changed because smart contracts are immutable, so in order to encrypt a balance, we must first deploy a corresponding ConfidentialERC20.
your ERC20 balance is easy, first we approve the amount you want to encrypt, and then we call the encryption function on the ConfidentialERC20. Under the hood, the amount you want to encrypt is converted into an FHE encrypted variable. In the ConfidentialERC20 smart contract, this looks like:
This euint128
variable is then added to your balance:
In the end, your encrypted balance is increased by the new amount being encrypted, just as it would with a standard ERC20, however when your balance is queried the result will be a value like this:
This value is called a ctHash
, it represents a hash of the true ciphertext that is created when a value is encrypted or an FHE operation takes place. It is this full ciphertext that holds the encrypted value, the ctHash is a pointer to the full value. As you can see, this encrypted value hash doesn't expose any information about the true amount of tokens you hold. This is the magic of FHE, it means that you can do an operation like this:
And without ever decrypting the values, the addition can be performed (5 + 10 = 15 in this case).
Reading your Encrypted Balances
For more on the embedded wallet and how to use it, see this guide: Confidential Balances (Wallet)
We now have an encrypted balance, but what good is a balance you can't see?
There are two ways to decrypt this balance, the first is on-chain using FHE.decrypt
(this will be discussed in the Decrypt and Claim flow below), and the other is off-chain using cofhejs
. We want to see our encrypted balance in the Redact dApp, so we will use the off-chain decryption.
Your encrypted balance is only viewable by you (what good is an encrypted balance this is publicly available), so we must first prove our identity by creating and signing a Permit
that verifies that you have knowledge of your wallet's privateKey. This Permit is then packaged with the ctHash
pointing to your encrypted balance and sent to a component of CoFHE called the Threshold Network (TN).
The TN validates the provided Permit and seals
(re-encrypts) your encrypted balance so that only you can reveal it (under the hood this uses a generated keypair, the public key of which is sent as part of your Permit).
The sealed
data is then revealed locally inside of Redact, where it is then shown to you as a plain number.
Encrypted Transfer
To send encrypted tokens in Redact, see this usage guide: Confidential Transfer (Sending)
Now that we have some encrypted tokens (and we can see how much we have), we can make an encrypted transfer to another account. This operation involves an extra step, which is to hide the amount that is being transferred by using an encrypted input.
Encrypting an input involves two steps: encryption and verification. The encryption step is handled locally inside of Redact, and the verification step is handled in the Threshold Network (TN) component of CoFHE. We use a FHE public key fetched from CoFHE to encrypt the amount of ConfidentialERC20 to be transferred. This encrypted value is then sent to the Threshold Network, where its encryption is verified to be valid.
The TN then signs a message that this encrypted amount is valid, and returns it along with a ctHash
that represents the encrypted amount. Together, the signature and ctHash form an encrypted input. In Redact, since all the values are represented by encrypted euint128
this encrypted input is an InEuint128
.
This is great, because this is exactly what we need to call this function in the ConfidentialERC20 contract:
The encTransfer
function is very simple, it removes the transferred amount from the sender's encrypted balance using FHE.sub
, and adds it to the receiver's balance using FHE.add
. Both the senders' and receivers' encrypted balances are updated, but it is unknown by what amount since the input amount is encrypted.
Caveat: Invalid Transfer Amount
There is one caveat with FHE operations, which is that we don't know the value of the variables when we're doing an FHE operation, so how would we know if the user tried to send 20 encrypted tokens, but only owned 10? We won't get into the specifics of what this looks like on-chain (it uses FHE.select
and FHE.gte
) but the result is that if an invalid amount is transferred, that amount is replaced with 0. This means that if the user Bob tries to send 20 encrypted tokens while only owning 10 to another user Alice, the transfer amount would be compared to Bob's balance, seen to be invalid, and replaced with 0. Bobs transaction would still succeed, but he would have sent 0 tokens to Alice. Even though the amount transferred was ultimately 0, both Bob's and Alice's encrypted balance variables would have been updated (by an unknown encrypted amount).
In the future as CoFHE adoption grows, it is the encrypted transfer that will be the core of an encrypted defi ecosystem including confidential swaps/lending/borrowing/etc.
Decrypting ConfidentialERC20 and Claiming ERC20
To Decrypt your confidential tokens in Redact, see this usage guide: Decrypting
To unwrap or decrypt your confidential balance, we will go through the Decrypt & Claim flow. Note that you are decrypting your balance by transferring it from an encrypted state in the ConfidentialERC20 contract to a readable, or cleartext, state in the original ERC20 contract. This process requires two separate transactions, the first performs an on-chain decryption using FHE.decrypt
. CoFHE, which is watching the chain for messages that signal that an operation has been requested, will pick up this message, and perform the decryption. The result of this decryption is then updated on-chain by a transaction sent by the coprocessor (this usually takes between 5-10 seconds to fully finalize).
Once the decryption is finalized and the result stored on-chain, the user is then able to Claim those decrypted tokens. This transaction then transfers the decrypted amount of the ERC20 back to the user, completing the process. This flow requires two separate transactions in order for the asynchronous decryption to be performed by the coprocessor.
Last updated