LogoLogo
  • Introduction
  • Motivation
  • Roadmap
  • FAQ
  • Technical Walkthrough
  • Using Redact
    • Confidential Balances (Wallet)
    • Encrypting
    • Decrypting
    • Confidential Transfer (Sending)
  • Architecture
    • FHERC20 Token Standard
    • FHERC20.sol
    • ConfidentialERC20.sol
      • RedactCore.sol
    • CoFHE Overview
Powered by GitBook
On this page
  • Encrypting your ERC20 balance
  • Reading your Encrypted Balances
  • Encrypted Transfer
  • Decrypting ConfidentialERC20 and Claiming ERC20

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

Name
Description

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.

We have deployed ConfidentialERC20s for some of the most trusted and widely used tokens on Ethereum and Arbitrum, however since any ERC20 can be used to deploy a ConfidentialERC20, the first user to perform a balance encryption for an arbitrary ERC20 may be required to first deploy a new ConfidentialERC20 token.

(This is similar to creating a new Uniswap pool)

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:

euint128 eAmount = FHE.asEuint128(amount)

This euint128 variable is then added to your balance:

eBalance = FHE.add(eAmount, eBalance)

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:

euint128 eBalance:
44737007662638353742293290064938024389209573332104467622358026769121523303424

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:

FHE.add(
 44737007662638353742293290064938024389209573332104467622358026769121523303424, 
 115747559174423067489356306390877806995718991284442275570070818829210672923648
) = 110692103698438822018438792470625059183234012775043055013737988615198382031872

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.

Only the encrypted amount is sent to the TN, the raw amount is only used to perform the encryption, after that it is discarded.

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 euint128this encrypted input is an InEuint128.

This is great, because this is exactly what we need to call this function in the ConfidentialERC20 contract:

function encTransfer(address to, InEuint128 memory inValue)

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.

PreviousFAQNextConfidential Balances (Wallet)

Last updated 16 days ago