docs/solidity-guides/functions.md
This document provides an overview of the functions available in the FHE Solidity library. The FHE library provides functionality for working with encrypted types and performing operations on them. It implements fully homomorphic encryption (FHE) operations in Solidity.
The FHE Solidity library provides essential functionality for working with encrypted data types and performing fully homomorphic encryption (FHE) operations in smart contracts. It is designed to streamline the developer experience while maintaining flexibility and performance.
add(uint8 a, euint8 b) is valid, but add(uint32 a, euint16 b) is not.The library ensures that all operations on encrypted data follow the constraints of FHE while abstracting complexity, allowing developers to focus on building privacy-preserving smart contracts.
ebool: Encrypted boolean valueeuint8: Encrypted 8-bit unsigned integereuint16: Encrypted 16-bit unsigned integereuint32: Encrypted 32-bit unsigned integereuint64: Encrypted 64-bit unsigned integereuint128: Encrypted 128-bit unsigned integereuint256: Encrypted 256-bit unsigned integereaddress: Encrypted Ethereum addressexternalEbool: Input type for encrypted boolean valueexternalEuint8: Input type for encrypted 8-bit unsigned integer valueexternalEuint16: Input type for encrypted 16-bit unsigned integer valueexternalEuint32: Input type for encrypted 32-bit unsigned integer valueexternalEuint64: Input type for encrypted 64-bit unsigned integer valueexternalEuint128: Input type for encrypted 128-bit unsigned integer valueexternalEuint256: Input type for encrypted 256-bit unsigned integer valueexternalEaddress: Input type for encrypted Ethereum addressFHE.asEbool converts encrypted integers to encrypted booleansFHE.asEuintX converts plaintext values to encrypted typesFHE.asEaddress converts plaintext addresses to encrypted addressesasEuintThe asEuint functions serve three purposes:
euintX typed ciphertext to a euintY typed ciphertext, where X != Y;The first case is used to process encrypted inputs, e.g. user-provided ciphertexts. Those are generally included in a transaction payload.
The second case is self-explanatory. When X > Y, the most significant bits are dropped. When X < Y, the ciphertext is padded to the left with trivial encryptions of 0.
The third case is used to "encrypt" a public value so that it can be used as a ciphertext. Note that what we call a trivial encryption is not secure in any sense. When trivially encrypting a plaintext value, this value is still visible in the ciphertext bytes. More information about trivial encryption can be found here.
Examples
// first case
function asEuint8(bytes memory ciphertext) internal view returns (euint8)
// second case
function asEuint16(euint8 ciphertext) internal view returns (euint16)
// third case
function asEuint16(uint16 value) internal view returns (euint16)
asEboolThe asEbool functions behave similarly to the asEuint functions, but for encrypted boolean values.
function setFHEVM(FHEVMConfig.FHEVMConfigStruct memory fhevmConfig) internal
Sets the FHEVM configuration for encrypted operations.
function isInitialized(T v) internal pure returns (bool)
Returns true if the encrypted value is initialized, false otherwise. Supported for all encrypted types (T can be ebool, euintX, eaddress, ebytesX).
Available for euint* types:
function add(T a, T b) internal returns (T)
function sub(T a, T b) internal returns (T)
function mul(T a, T b) internal returns (T)
FHE.add, FHE.sub, FHE.mul, FHE.min, FHE.max, FHE.neg, FHE.div, FHE.rem
div and rem operations are supported only with plaintext divisors:warning: Functions with FHE operations cannot be marked as
viewsince FHE operations cost gas to execute since they always involve a state-change. For instance, you cannot compute and return the encrypted sum of two encrypted values in a view function.
add, sub, mul, div, rem)Performs the operation homomorphically.
Note that division/remainder only support plaintext divisors.
Examples
// a + b
function add(euint8 a, euint8 b) internal view returns (euint8)
function add(euint8 a, euint16 b) internal view returns (euint16)
function add(uint32 a, euint32 b) internal view returns (euint32)
// a / b
function div(euint8 a, uint8 b) internal pure returns (euint8)
function div(euint16 a, uint16 b) internal pure returns (euint16)
function div(euint32 a, uint32 b) internal pure returns (euint32)
min, maxAvailable for euint* types:
function min(T a, T b) internal returns (T)
function max(T a, T b) internal returns (T)
Returns the minimum (resp. maximum) of the two given values.
Examples
// min(a, b)
function min(euint32 a, euint16 b) internal view returns (euint32)
// max(a, b)
function max(uint32 a, euint8 b) internal view returns (euint32)
neg, not)There are two unary operators: neg (-) and not (!). Note that since we work with unsigned integers, the result of negation is interpreted as the modular opposite. The not operator returns the value obtained after flipping all the bits of the operand.
{% hint style="info" %} More information about the behaviour of these operators can be found at the TFHE-rs docs. {% endhint %}
FHE.and, FHE.or, FHE.xor, FHE.not, FHE.shl, FHE.shr, FHE.rotl, FHE.rotrAND, OR, XOR)Unlike other binary operations, bitwise operations do not natively accept a mix of ciphertext and plaintext inputs. To ease developer experience, the FHE library adds function overloads for these operations. Such overloads implicitly do a trivial encryption before actually calling the operation function, as shown in the examples below.
Available for euint* types:
function and(T a, T b) internal returns (T)
function or(T a, T b) internal returns (T)
function xor(T a, T b) internal returns (T)
Examples
// a & b
function and(euint8 a, euint8 b) internal view returns (euint8)
// implicit trivial encryption of `b` before calling the operator
function and(euint8 a, uint16 b) internal view returns (euint16)
<<, >>)Shifts the bits of the base two representation of a by b positions.
Examples
// a << b
function shl(euint16 a, euint8 b) internal view returns (euint16)
// a >> b
function shr(euint32 a, euint16 b) internal view returns (euint32)
Rotates the bits of the base two representation of a by b positions.
Examples
function rotl(euint16 a, euint8 b) internal view returns (euint16)
function rotr(euint32 a, euint16 b) internal view returns (euint32)
eq, ne, ge, gt, le, lt){% hint style="info" %} Note that in the case of ciphertext-plaintext operations, since our backend only accepts plaintext right operands, calling the operation with a plaintext left operand will actually invert the operand order and call the opposite comparison. {% endhint %}
The result of comparison operations is an encrypted boolean (ebool). In the backend, the boolean is represented by an encrypted unsigned integer of bit width 8, but this is abstracted away by the Solidity library.
Available for all encrypted types:
function eq(T a, T b) internal returns (ebool)
function ne(T a, T b) internal returns (ebool)
Additional comparisons for euint* types:
function ge(T a, T b) internal returns (ebool)
function gt(T a, T b) internal returns (ebool)
function le(T a, T b) internal returns (ebool)
function lt(T a, T b) internal returns (ebool)
// a == b
function eq(euint32 a, euint16 b) internal view returns (ebool)
// actually returns `lt(b, a)`
function gt(uint32 a, euint16 b) internal view returns (ebool)
// actually returns `gt(a, b)`
function gt(euint16 a, uint32 b) internal view returns (ebool)
select)function select(ebool control, T a, T b) internal returns (T)
If control is true, returns a, otherwise returns b. Available for ebool, eaddress, and ebytes* types.
This operator takes three inputs. The first input b is of type ebool and the two others of type euintX. If b is an encryption of true, the first integer parameter is returned. Otherwise, the second integer parameter is returned.
// if (b == true) return val1 else return val2
function select(ebool b, euint8 val1, euint8 val2) internal view returns (euint8) {
return FHE.select(b, val1, val2);
}
Random encrypted integers can be generated fully on-chain.
That can only be done during transactions and not on an eth_call RPC method, because PRNG state needs to be mutated on-chain during generation.
// Generate a random encrypted unsigned integer `r`.
euint32 r = FHE.randEuint32();
The FHE library provides a robust set of access control functions for managing permissions on encrypted values. These functions ensure that encrypted data can only be accessed or manipulated by authorized accounts or contracts.
function allow(T value, address account) internal
function allowThis(T value) internal
function allowTransient(T value, address account) internal
Descriptions
allow: Grants permanent access to a specific address. Permissions are stored persistently in a dedicated ACL contract.allowThis: Grants the current contract access to an encrypted value.allowTransient: Grants temporary access to a specific address for the duration of the transaction. Permissions are stored in transient storage for reduced gas costs.The allow and allowTransient functions enable fine-grained control over who can access and decrypt encrypted values. Temporary permissions (allowTransient) are ideal for minimizing gas usage in scenarios where access is needed only within a single transaction.
Example: granting access
// Store an encrypted value.
euint32 r = FHE.asEuint32(94);
// Grant permanent access to the current contract.
FHE.allowThis(r);
// Grant permanent access to the caller.
FHE.allow(r, msg.sender);
// Grant temporary access to an external account.
FHE.allowTransient(r, 0x1234567890abcdef1234567890abcdef12345678);
function isAllowed(T value, address account) internal view returns (bool)
function isSenderAllowed(T value) internal view returns (bool)
isAllowed: Checks whether a specific address has permission to access a ciphertext.isSenderAllowed: Similar to isAllowed, but automatically checks permissions for the msg.sender.{% hint style="info" %}
Both functions return true if the ciphertext is authorized for the specified address, regardless of whether the allowance is stored in the ACL contract or in transient storage.
{% endhint %}
These functions help ensure that only authorized accounts or contracts can access encrypted values.
Example: permission verification
// Store an encrypted value.
euint32 r = FHE.asEuint32(94);
// Verify if the current contract is allowed to access the value.
bool isContractAllowed = FHE.isAllowed(r, address(this)); // returns true
// Verify if the caller has access to the value.
bool isCallerAllowed = FHE.isSenderAllowed(r); // depends on msg.sender
function cleanTransientStorage() internal
cleanTransientStorage: Removes all temporary permissions from transient storage. Use this function at the end of a transaction to ensure no residual permissions remain.// Clean up transient storage at the end of a function.
function finalize() public {
// Perform operations...
// Clean up transient storage.
FHE.cleanTransientStorage();
}
Impl library.0 (for integers) or false (for booleans) in computations.