Back to Fhevm

Homomorphic Complexity Units ("HCU") in FHEVM

docs/solidity-guides/hcu.md

0.14.0-012.9 KB
Original Source

Homomorphic Complexity Units ("HCU") in FHEVM

This guide explains how to use Fully Homomorphic Encryption (FHE) operations in your smart contracts on FHEVM. Understanding HCU is critical for designing efficient confidential smart contracts.

Overview

FHE operations in FHEVM are computationally intensive compared to standard Ethereum operations, as they require complex mathematical computations to maintain privacy and security. To manage computational load and prevent potential denial-of-service attacks, FHEVM implements a metering system called Homomorphic Complexity Units ("HCU").

To represent this complexity, we introduced the Homomorphic Complexity Unit ("HCU"). In Solidity, each FHE operation consumes a set amount of HCU based on the operational computational complexity for hardware computation. Since FHE transactions are symbolic, this helps preventing resource exhaustion outside of the blockchain.

To do so, there is a contract named HCULimit, which monitors HCU consumption and enforces three key limits:

  • Sequential homomorphic operations depth limit per transaction: Controls HCU usage for operations that must be processed in order. Exceeding it reverts with HCUTransactionDepthLimitExceeded.
  • Global homomorphic operations complexity per transaction: Controls HCU usage for operations that can be processed in parallel. Exceeding it reverts with HCUTransactionLimitExceeded.
  • Global homomorphic operations complexity per block: Caps the total HCU consumed across all transactions from non-whitelisted callers in the same block. Exceeding it reverts with HCUBlockLimitExceeded.

If any of these limits is exceeded, the transaction will revert.

HCU limit

The current devnet has an HCU limit of 20,000,000 per transaction and an HCU depth limit of 5,000,000 per transaction. The global per-block HCU cap is set on-chain by governance (via HCULimit.setHCUPerBlock) and is always greater than or equal to the per-transaction limit; you can read its current value from the deployed HCULimit contract (getGlobalHCUCapPerBlock()), and the current block's running total via getBlockMeter(). If any HCU limit is exceeded, the transaction will revert.

To resolve a per-transaction revert, you must do one of the following:

  • Refactor your code to reduce the number of FHE operations in your transaction.
  • Split your FHE operations across multiple independent transactions.

Block-level limit and transaction estimation

Unlike the per-transaction limits, the per-block cap depends on the other transactions included in the same block, not just on your own. The contract keeps a counter (usedBlockHCU) that resets every new block and aggregates HCU spent by every transaction from a non-whitelisted caller in that block. Here, the caller is the dApp contract address passed by FHEVMExecutor, not the user's EOA. As a result:

  • A transaction that estimates successfully (e.g. via eth_estimateGas or a static call) can still revert with HCUBlockLimitExceeded at execution time if other FHE-heavy transactions are mined in the same block ahead of it.
  • This revert is non-deterministic from the sender's perspective: it is a function of block-inclusion ordering, not of the transaction's own payload.

If you hit HCUBlockLimitExceeded, options include:

  • Retry the transaction in a later block, optionally with adjusted gas/priority so it is included when block HCU usage is lower.
  • Reduce the HCU footprint of the transaction so it is more likely to fit alongside others (same techniques as for per-transaction reverts).
  • Request a whitelist entry (addToBlockHCUWhitelist) for caller contracts that have a justified need to bypass the block cap; this is governed on-chain and is not available to arbitrary callers.

HCU costs for common operations

Boolean operations (ebool)

Function nameHCU (scalar)HCU (non-scalar)
and22,00025,000
or22,00024,000
xor2,00022,000
not-2
select-55,000
randEbool-19,000

Unsigned integer operations

HCU increase with the bit-width of the encrypted integer type. Below are the detailed costs for various operations on encrypted types.

8-bit Encrypted integers (euint8)

Function nameHCU (scalar)HCU (non-scalar)
add84,00088,000
sub84,00091,000
mul122,000150,000
div210,000-
rem440,000-
and31,00031,000
or30,00030,000
xor31,00031,000
shr32,00091,000
shl32,00092,000
rotr31,00093,000
rotl31,00091,000
eq55,00055,000
ne55,00055,000
ge52,00063,000
gt52,00059,000
le58,00058,000
lt52,00059,000
min84,000119,000
max89,000121,000
neg-79,000
not-9
select-55,000
randEuint8-23,000

16-bit Encrypted integers (euint16)

Function nameHCU (scalar)HCU (non-scalar)
add93,00093,000
sub93,00093,000
mul193,000222,000
div302,000-
rem580,000-
and31,00031,000
or30,00031,000
xor31,00031,000
shr32,000123,000
shl32,000125,000
rotr31,000125,000
rotl31,000125,000
eq55,00083,000
ne55,00083,000
ge55,00084,000
gt55,00084,000
le58,00083,000
lt58,00084,000
min88,000146,000
max89,000145,000
neg-93,000
not-16
select-55,000
randEuint16-23,000

32-bit Encrypted Integers (euint32)

Function nameHCU (scalar)HCU (non-scalar)
add95,000125,000
sub95,000125,000
mul265,000328,000
div438,000-
rem792,000-
and32,00032,000
or32,00032,000
xor32,00032,000
shr32,000163,000
shl32,000162,000
rotr32,000160,000
rotl32,000163,000
eq82,00086,000
ne83,00085,000
ge84,000118,000
gt84,000118,000
le84,000117,000
lt83,000117,000
min117,000182,000
max117,000180,000
neg-131,000
not-32
select-55,000
randEuint32-24,000

64-bit Encrypted integers (euint64)

Function nameHCU (scalar)HCU (non-scalar)
add133,000162,000
sub133,000162,000
mul365,000596,000
div715,000-
rem1,153,000-
and34,00034,000
or34,00034,000
xor34,00034,000
shr34,000209,000
shl34,000208,000
rotr34,000209,000
rotl34,000209,000
eq83,000120,000
ne84,000118,000
ge116,000152,000
gt117,000152,000
le119,000149,000
lt118,000146,000
min150,000219,000
max149,000218,000
neg-131,000
not-63
select-55,000
randEuint64-24,000

128-bit Encrypted integers (euint128)

Function nameHCU (scalar)HCU (non-scalar)
add172,000259,000
sub172,000260,000
mul696,0001,686,000
div1,225,000-
rem1,943,000-
and37,00037,000
or37,00037,000
xor37,00037,000
shr37,000272,000
shl37,000272,000
rotr37,000283,000
rotl37,000278,000
eq117,000122,000
ne117,000122,000
ge149,000210,000
gt150,000218,000
le150,000218,000
lt149,000215,000
min186,000289,000
max180,000290,000
neg-168,000
not-130
select-57,000
randEuint128-25,000

256-bit Encrypted integers (euint256)

Function nameHCU (scalar)HCU (non-scalar)
and38,00038,000
or38,00038,000
xor39,00039,000
shr38,000369,000
shl39,000378,000
rotr40,000375,000
rotl38,000378,000
eq118,000152,000
ne117,000150,000
neg-269,000
not-130
select-108,000
randEuint256-30,000

Encrypted addresses (euint160)

When using eaddress (internally represented as euint160), the HCU costs for equality and inequality checks and select are as follows:

Function nameHCU (scalar)HCU (non-scalar)
eq115,000125,000
ne115,000124,000
select-83,000

Additional Operations

Function nameHCU
cast32
trivialEncrypt32