Receiving Encrypted Inputs
One key aspects of writing confidential smart contract is receiving encrypted inputs from users:
function transfer(
address to,
InEuint32 memory inAmount // <------ encrypted input here
) public virtual returns (euint32 transferred) {
euint32 amount = FHE.asEuint32(inAmount);
}
Notice in the example above the distinction between InEuint32 and euint32.
Input Types Conversion
The input types InEuintxx (and InEbool, InEaddress) are special encrypted types that represent user input. Input types contain additional information required to authenticate and validate ciphertexts. For more on that, read on the ZK-Verifier.
Before we can use an encrypted input, we need to convert it to a regular encrypted type:
euint32 amount = FHE.asEuint32(inAmount);
Avoid storing encrypted input types in contract state. These types carry extra metadata, which increases gas costs and may cause unexpected behavior. Always convert them using FHE.asE...().
Now that amount is of type euint32, we can store or manipulate it:
toBalance = FHE.sub(toBalance, amount);
Read more on the available FHE types and operations here.
Full Example
function transfer(
address to,
InEuint32 memory inAmount
) public virtual returns (euint32 transferred) {
euint32 amount = FHE.asEuint32(inAmount);
toBalance = _balances[to];
fromBalance = _balances[msg.sender];
_updateBalance(to, FHE.add(toBalance, amount));
_updateBalance(from, FHE.sub(fromBalance, amount));
}
For the example above to logically work, you will also need to manage access to the newly created ciphertexts in the _updateBalance() function. Read further on the ACL component.
Additional Examples
Voting in a Poll
function castEncryptedVote(address poll, InEbool calldata encryptedVote) public {
_submitVote(poll, FHE.asEbool(encryptedVote));
}
Setting Encrypted User Preferences
function updateUserSetting(address user, InEuint8 calldata encryptedSetting) public {
_applyUserSetting(user, FHE.asEuint8(encryptedSetting));
}