Fully Homomorphic Encryption (FHE)
Confidential computing with encrypted on-chain operations
Fully Homomorphic Encryption (FHE)
Complete FHE infrastructure for private on-chain computation. Perform arithmetic, comparisons, and logic on encrypted data without decryption.
Architecture Overview
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ LUX FHE ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ENCRYPTED TYPES │
│ ┌─────────────────────────────────────────────────────────────────────────────────┐ │
│ │ ebool | euint8 | euint16 | euint32 | euint64 | euint128 | euint256 | eaddress │ │
│ └─────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────┼───────────────────────────────────────────┐ │
│ │ ▼ │ │
│ │ ┌─────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │ │
│ │ │ FHE.sol │ │ TaskManager │ │ Gateway │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ add, sub, mul │───>│ 0xeA30...7848D9 │───>│ Decryption requests │ │ │
│ │ │ lt, gt, eq, ne │ │ (Precompile) │ │ │ │ │
│ │ │ and, or, xor │ │ │ │ │ │ │
│ │ │ select, cast │ │ │ │ │ │ │
│ │ └─────────────────┘ └─────────────────────┘ └─────────────────────┘ │ │
│ │ │ │
│ │ ACCESS CONTROL │ │
│ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ FHE.allow(ctHash, account) - Grant read access to encrypted value │ │ │
│ │ │ FHE.allowThis(ctHash) - Grant contract read access │ │ │
│ │ │ FHE.isSenderAllowed(ct) - Check if sender can use encrypted value │ │ │
│ │ └─────────────────────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ PRECOMPILE ADDRESSES │
│ ┌─────────────────────────────────────────────────────────────────────────────────┐ │
│ │ 0x0200...0080 FheOS - Main FHE operations │ │
│ │ 0x0200...0081 ACL - Access control list │ │
│ │ 0x0200...0082 InputVerifier - Verify encrypted inputs │ │
│ │ 0x0200...0083 Gateway - Decryption gateway │ │
│ └─────────────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────────┘Core Contracts
| Contract | Description | Import |
|---|---|---|
| FHE | Core library - encrypted operations | @luxfi/contracts/fhe/FHE.sol |
| TFHE | Low-level TFHE operations | @luxfi/contracts/fhe/TFHE.sol |
| IFHE | Interface definitions & precompile addresses | @luxfi/contracts/fhe/IFHE.sol |
| Gateway | Decryption request handling | @luxfi/contracts/fhe/FHE.sol |
| GatewayCaller | Base contract for decryption callbacks | @luxfi/contracts/fhe/FHE.sol |
| Permissioned | Access control mixin | @luxfi/contracts/fhe/access/Permissioned.sol |
| PermissionedV2 | Enhanced access control with EIP-712 | @luxfi/contracts/fhe/access/PermissionedV2.sol |
| FHEVMConfig | FHEVM configuration | @luxfi/contracts/fhe/config/FHEVMConfig.sol |
| GatewayConfig | Gateway configuration | @luxfi/contracts/fhe/config/GatewayConfig.sol |
Encrypted Types
type ebool is uint256; // Encrypted boolean
type euint8 is uint256; // Encrypted 8-bit unsigned integer
type euint16 is uint256; // Encrypted 16-bit unsigned integer
type euint32 is uint256; // Encrypted 32-bit unsigned integer
type euint64 is uint256; // Encrypted 64-bit unsigned integer
type euint128 is uint256; // Encrypted 128-bit unsigned integer
type euint256 is uint256; // Encrypted 256-bit unsigned integer
type eaddress is uint256; // Encrypted address
type einput is bytes32; // Encrypted input handleBasic Operations
Arithmetic
import "@luxfi/contracts/fhe/FHE.sol";
contract ConfidentialMath {
euint64 public encryptedValue;
function add(euint64 a, euint64 b) public returns (euint64) {
return FHE.add(a, b);
}
function sub(euint64 a, euint64 b) public returns (euint64) {
return FHE.sub(a, b);
}
function mul(euint64 a, euint64 b) public returns (euint64) {
return FHE.mul(a, b);
}
function div(euint64 a, euint64 b) public returns (euint64) {
return FHE.div(a, b);
}
}Comparison
// Less than
ebool isLess = FHE.lt(a, b);
// Less than or equal (both lte and le work)
ebool isLessOrEqual = FHE.lte(a, b);
// Greater than
ebool isGreater = FHE.gt(a, b);
// Greater than or equal (both gte and ge work)
ebool isGreaterOrEqual = FHE.gte(a, b);
// Equal
ebool isEqual = FHE.eq(a, b);
// Not equal
ebool isNotEqual = FHE.ne(a, b);
// Min/Max
euint64 minimum = FHE.min(a, b);
euint64 maximum = FHE.max(a, b);Bitwise Operations
// AND
euint64 andResult = FHE.and(a, b);
// OR
euint64 orResult = FHE.or(a, b);
// XOR
euint64 xorResult = FHE.xor(a, b);
// NOT
euint64 notResult = FHE.not(a);
// Shift left
euint64 shlResult = FHE.shl(a, b);
// Shift right
euint64 shrResult = FHE.shr(a, b);
// Rotate left
euint64 rolResult = FHE.rol(a, b);
// Rotate right
euint64 rorResult = FHE.ror(a, b);Other Operations
// Square (more efficient than mul(a, a))
euint64 squared = FHE.square(a);
// Remainder
euint64 remainder = FHE.rem(a, b);
// Random number generation
euint64 randomValue = FHE.random();Conditional (Select)
// Encrypted if-then-else
// If condition is true, return ifTrue, else return ifFalse
euint64 result = FHE.select(condition, ifTrue, ifFalse);Access Control
FHE values require explicit access permissions:
import "@luxfi/contracts/fhe/FHE.sol";
contract AccessControlExample {
mapping(address => euint64) private balances;
function deposit(einput encryptedAmount, bytes calldata inputProof) external {
euint64 amount = FHE.asEuint64(encryptedAmount, inputProof);
// Grant this contract access to the encrypted value
FHE.allowThis(amount);
// Grant the depositor access to their balance
FHE.allow(amount, msg.sender);
balances[msg.sender] = FHE.add(balances[msg.sender], amount);
}
function checkBalance() external view returns (euint64) {
// Only returns if sender is allowed
require(FHE.isSenderAllowed(balances[msg.sender]), "Not allowed");
return balances[msg.sender];
}
}Input Verification
Convert encrypted inputs to encrypted types:
// From encrypted input with proof
euint64 amount = FHE.asEuint64(encryptedInput, inputProof);
// From plaintext (trivial encryption)
euint64 plainValue = FHE.asEuint64(100);
// Type casting between encrypted types
euint32 smaller = FHE.asEuint32(FHE.asEuint64(value));Confidential LRC20
LRC20 (Lux token standard) with encrypted balances:
import "@luxfi/contracts/fhe/token/LRC20/ConfidentialLRC20.sol";
contract PrivateToken is ConfidentialERC20 {
constructor() ConfidentialERC20("Private Token", "PRIV") {
_unsafeMint(msg.sender, 1000000);
}
// Balances are encrypted - only authorized parties can view
// mapping(address => euint64) internal _balances;
}ConfidentialLRC20 Functions
// Transfer with encrypted amount
function transfer(address to, einput encryptedAmount, bytes calldata inputProof)
public returns (bool);
// Transfer with euint64 directly
function transfer(address to, euint64 amount) public returns (bool);
// Approve with encrypted amount
function approve(address spender, einput encryptedAmount, bytes calldata inputProof)
public returns (bool);
// Get encrypted balance (requires permission)
function balanceOf(address account) public view returns (euint64);Confidential Governance
Private voting with encrypted vote counts:
import "@luxfi/contracts/fhe/governance/ConfidentialGovernor.sol";
import "@luxfi/contracts/fhe/token/LRC20/ConfidentialLRC20.sol";
// Governance token with encrypted voting power
contract GovernanceToken is ConfidentialERC20Votes {
// Vote counts are encrypted until tally
// Prevents vote buying and coercion
}
// Governor with private voting
contract PrivateGovernor is ConfidentialGovernorAlpha {
// Votes are encrypted during voting period
// Only revealed after voting ends
}Proposal Lifecycle
| State | Description |
|---|---|
Pending | Proposal created, awaiting threshold verification |
Active | Voting in progress (encrypted votes) |
Succeeded | Quorum reached, more FOR than AGAINST |
Defeated | Failed to reach quorum or majority |
Queued | Passed, in timelock queue |
Executed | Proposal executed |
Decryption
Request decryption of encrypted values using FHE.decrypt():
import "@luxfi/contracts/fhe/FHE.sol";
import "@luxfi/contracts/fhe/FHE.sol";
contract DecryptionExample is GatewayCaller {
function decrypt(euint64 encryptedValue) external {
// Request decryption via FHE library
FHE.decrypt(encryptedValue);
}
// For callback-based decryption:
function decryptAndCall(euint64 encryptedValue) external {
uint256[] memory cts = new uint256[](1);
cts[0] = euint64.unwrap(encryptedValue);
TFHE.decrypt(
cts,
this.decryptionCallback.selector,
0, // msgValue
block.timestamp + 100, // maxTimestamp
false // passSignaturesToCaller
);
}
function decryptionCallback(
uint256 requestId,
uint64 decryptedValue
) external onlyGateway {
// Handle decrypted value
}
}Confidential Vesting
Vesting with encrypted amounts:
import "@luxfi/contracts/fhe/finance/ConfidentialVestingWallet.sol";
// Vesting wallet with private vesting amounts
contract PrivateVesting is ConfidentialVestingWallet {
// Vesting amounts are encrypted
// Only beneficiary can see their allocation
}Token Contracts
| Contract | Path | Description |
|---|---|---|
| ConfidentialERC20 | token/ERC20/ConfidentialERC20.sol | LRC20 with encrypted balances |
| ConfidentialERC20Wrapped | token/ERC20/ConfidentialERC20Wrapped.sol | Wrap/unwrap standard LRC20 to encrypted |
| ConfidentialWETH | token/ERC20/ConfidentialWETH.sol | Wrapped LUX with encryption |
| ConfidentialERC20Mintable | token/ERC20/extensions/ConfidentialERC20Mintable.sol | Mintable confidential token |
| ConfidentialERC20WithErrors | token/ERC20/extensions/ConfidentialERC20WithErrors.sol | Confidential token with error codes |
| ConfidentialERC20WithErrorsMintable | token/ERC20/extensions/ConfidentialERC20WithErrorsMintable.sol | Mintable token with error codes |
Finance Contracts
| Contract | Path | Description |
|---|---|---|
| ConfidentialVestingWallet | finance/ConfidentialVestingWallet.sol | Vesting with encrypted amounts |
| ConfidentialVestingWalletCliff | finance/ConfidentialVestingWalletCliff.sol | Vesting with cliff period |
Utility Contracts
| Contract | Path | Description |
|---|---|---|
| EncryptedErrors | utils/EncryptedErrors.sol | Error handling for FHE operations |
| TFHEErrors | utils/TFHEErrors.sol | TFHE-specific error definitions |
| EIP712 | access/EIP712.sol | EIP-712 typed data signing for FHE |
EVM Version Requirement
FHE contracts require Cancun EVM for transient storage:
# foundry.toml
evm_version = "cancun"Security Considerations
- Access Control: Always use
FHE.allow()to grant access to encrypted values - Input Verification: Verify encrypted inputs with proofs before use
- Decryption Timing: Decryption requests are async - design accordingly
- Gas Costs: FHE operations are more expensive than plaintext
- Side Channels: Avoid conditional logic that reveals encrypted values
Gas Costs (Approximate)
| Operation | Gas Cost |
|---|---|
| Trivial Encrypt | ~50,000 |
| Add/Sub | ~100,000 |
| Multiply | ~150,000 |
| Division/Remainder | ~200,000 |
| Comparison (lt, gt, eq, etc.) | ~100,000 |
| Bitwise (and, or, xor, not) | ~80,000 |
| Shift/Rotate (shl, shr, rol, ror) | ~100,000 |
| Min/Max | ~120,000 |
| Select | ~120,000 |
| Square | ~140,000 |
| Random | ~150,000 |
| Decrypt Request | ~200,000 |
Contract Directory Structure
contracts/fhe/
├── FHE.sol # Core FHE library
├── TFHE.sol # Low-level TFHE operations
├── IFHE.sol # Interface definitions
├── FheOS.sol # FHE OS integration
├── ICofhe.sol # Coprocessor interface
├── access/
│ ├── EIP712.sol # EIP-712 signing
│ ├── Permissioned.sol # Access control base
│ └── PermissionedV2.sol # Enhanced access control
├── config/
│ ├── FHEVMConfig.sol # FHEVM configuration
│ └── GatewayConfig.sol # Gateway configuration
├── gateway/
│ ├── Gateway.sol # Decryption gateway
│ └── GatewayCaller.sol # Callback base contract
├── governance/
│ ├── ConfidentialGovernorAlpha.sol # Private voting governor
│ ├── ConfidentialERC20Votes.sol # Encrypted voting power
│ └── CompoundTimelock.sol # Timelock controller
├── finance/
│ ├── ConfidentialVestingWallet.sol # Encrypted vesting
│ └── ConfidentialVestingWalletCliff.sol # Vesting with cliff
├── token/ERC20/
│ ├── ConfidentialERC20.sol # Base confidential token
│ ├── ConfidentialERC20Wrapped.sol # Wrap/unwrap support
│ ├── ConfidentialWETH.sol # Wrapped native token
│ └── extensions/
│ ├── ConfidentialERC20Mintable.sol
│ ├── ConfidentialERC20WithErrors.sol
│ └── ConfidentialERC20WithErrorsMintable.sol
└── utils/
├── EncryptedErrors.sol # Error handling
├── TFHEErrors.sol # TFHE errors
└── debug/
├── Console.sol # Debug logging
└── MockFheOps.sol # Testing mock