Skip to main content

Overview

FHE operations are 50,000-100,000x more expensive than plaintext operations. Understanding gas costs is critical for building practical FHE smart contracts. This guide provides comprehensive cost data, comparisons, and optimization strategies.

Why FHE Gas Costs Are High

Every FHE operation is processed by a dedicated coprocessor performing homomorphic computation on ciphertexts:
  1. Ciphertext Size: Encrypted values are kilobytes in size vs. 32 bytes for plaintext
  2. Computation Complexity: Homomorphic operations require extensive lattice-based mathematics
  3. Bit Width Scaling: Larger types (euint256) cost 5-10x more than smaller types (euint8)
  4. Noise Management: Some operations require bootstrapping - the most expensive FHE operation

Operation Cost Table

All costs are approximate and measured on local fhEVM mock environment. Actual costs vary by network.

Arithmetic Operations

Operationeuint8euint16euint32euint64euint128euint256
FHE.add~80k~120k~180k~250k~400k~600k
FHE.sub~80k~120k~180k~250k~400k~600k
FHE.mul~150k~250k~400k~700k~1.2M~2M
FHE.div (scalar)~250k~400k~700k~1.2M~2M~3.5M
FHE.rem (scalar)~250k~400k~700k~1.2M~2M~3.5M
FHE.neg~60k~90k~140k~200k~350k~500k
FHE.min~180k~280k~450k~750k~1.3M~2.2M
FHE.max~180k~280k~450k~750k~1.3M~2.2M

Comparison Operations

Operationeuint8euint16euint32euint64euint128euint256
FHE.eq~120k~180k~280k~450k~800k~1.4M
FHE.ne~120k~180k~280k~450k~800k~1.4M
FHE.gt~120k~180k~280k~450k~800k~1.4M
FHE.ge~120k~180k~280k~450k~800k~1.4M
FHE.lt~120k~180k~280k~450k~800k~1.4M
FHE.le~120k~180k~280k~450k~800k~1.4M

Bitwise Operations

Operationeuint8euint16euint32euint64euint128euint256
FHE.and~60k~90k~140k~200k~350k~500k
FHE.or~60k~90k~140k~200k~350k~500k
FHE.xor~60k~90k~140k~200k~350k~500k
FHE.not~50k~75k~120k~170k~300k~450k
FHE.shl~90k~140k~220k~350k~600k~1M
FHE.shr~90k~140k~220k~350k~600k~1M
FHE.rotl~90k~140k~220k~350k~600k~1M
FHE.rotr~90k~140k~220k~350k~600k~1M

Conditional Selection

Operationeuint8euint16euint32euint64euint128euint256
FHE.select~70k~100k~160k~230k~380k~560k

Other Operations

OperationGas Cost (Approx)
FHE.fromExternal()~50-150k (varies by type)
FHE.asEuint32() (plaintext)~50k
FHE.randEuint32()~100-200k
FHE.allow()~40-50k
FHE.allowThis()~40-50k
FHE.allowTransient()~25-35k (30% cheaper)

Cost Comparison: FHE vs Plaintext

OperationPlaintextFHE (euint32)Ratio
Addition~3 gas~180k gas60,000x
Multiplication~5 gas~400k gas80,000x
Comparison~3 gas~280k gas93,000x
Storage write~5-20k gasSame (handle)1x
Key Insight: Gas cost is dominated by computation, not storage.

Type Selection Impact

Gas Savings by Type

TypeAdd CostRelativeUse Case
euint8~80k1.0x (baseline)Flags, counters (0-255)
euint16~120k1.5xSmall amounts, indices
euint32~180k2.25xTimestamps, balances
euint64~250k3.1xToken balances (6-8 decimals)
euint128~400k5xLarge tokens (18 decimals)
euint256~600k7.5xMaximum compatibility
Example Savings:
// ❌ Expensive: euint64 for vote counter (0-1000)
euint64 voteCount;  // FHE.add costs ~250k gas

// ✅ Efficient: euint16 sufficient
euint16 voteCount;  // FHE.add costs ~120k gas (52% savings)

Optimization Strategies

Strategy 1: Use Smallest Type That Fits

// ❌ Wasteful
euint256 voteCount;  // 0-100 votes, FHE.add ~600k gas

// ✅ Efficient
euint8 voteCount;    // 0-255 range, FHE.add ~80k gas (87% savings)
Decision Tree:
Value range 0-255?           -> euint8
Value range 0-65,535?        -> euint16
Value range 0-4.3B?          -> euint32
Value range 0-18 quintillion? -> euint64
Larger?                      -> euint128 or euint256

Strategy 2: Use Plaintext Second Operands

Operations with plaintext second operands are 30-40% cheaper:
// ❌ Expensive: Both encrypted
euint32 result = FHE.add(value, FHE.asEuint32(10));  // ~180k gas

// ✅ Cheaper: Plaintext second operand
euint32 result = FHE.add(value, 10);  // ~120k gas (33% savings)
Applicable Operations:
  • Arithmetic: add, sub, mul, div, rem
  • Comparison: eq, ne, gt, ge, lt, le
  • Bitwise: and, or, xor, shl, shr

Strategy 3: Minimize FHE Operation Count

// ❌ Multiple operations (4 FHE ops = ~720k gas)
euint32 a = FHE.add(x, y);
euint32 b = FHE.add(a, z);
euint32 c = FHE.mul(b, 2);

// ✅ Combine operations (2 FHE ops = ~360k gas)
euint32 sum = FHE.add(FHE.add(x, y), z);  // Chain additions
euint32 result = FHE.mul(sum, 2);

Strategy 4: Cache Comparison Results

// ❌ Recomputes comparison twice (~560k gas)
euint64 r1 = FHE.select(FHE.gt(a, b), x, y);
euint64 r2 = FHE.select(FHE.gt(a, b), m, n);

// ✅ Compute once, reuse (~440k gas)
ebool isGreater = FHE.gt(a, b);  // ~280k gas (once)
euint64 r1 = FHE.select(isGreater, x, y);  // ~160k gas
euint64 r2 = FHE.select(isGreater, m, n);  // ~160k gas

Strategy 5: Use Shift Instead of Mul/Div for Powers of 2

// ❌ Expensive: Multiply by 8
euint32 result = FHE.mul(value, 8);  // ~400k gas

// ✅ Cheaper: Shift left by 3 (2^3 = 8)
euint32 result = FHE.shl(value, 3);  // ~220k gas (45% savings)

// ❌ Expensive: Divide by 4
euint32 result = FHE.div(value, 4);  // ~700k gas

// ✅ Cheaper: Shift right by 2 (2^2 = 4)
euint32 result = FHE.shr(value, 2);  // ~220k gas (69% savings)

Strategy 6: Use FHE.min/max Instead of Compare + Select

// ❌ Verbose: Compare + Select (~440k gas)
ebool isLess = FHE.lt(a, b);         // ~280k gas
euint32 minimum = FHE.select(isLess, a, b);  // ~160k gas

// ✅ Built-in: FHE.min (~450k gas, similar but cleaner)
euint32 minimum = FHE.min(a, b);

Strategy 7: Pre-compute Off-Chain

If computation involves only plaintext, do it client-side:
// ❌ On-chain computation (3 FHE ops ~760k gas)
function submitOrder(
    externalEuint64 encPrice,
    externalEuint64 encQty,
    externalEuint64 encFee,
    bytes calldata proof
) external {
    euint64 price = FHE.fromExternal(encPrice, proof);
    euint64 qty = FHE.fromExternal(encQty, proof);
    euint64 fee = FHE.fromExternal(encFee, proof);
    euint64 total = FHE.add(FHE.mul(price, qty), fee);  // 2 FHE ops
}

// ✅ Client computes: total = price * qty + fee, sends result
function submitOrder(
    externalEuint64 encTotal,
    bytes calldata proof
) external {
    euint64 total = FHE.fromExternal(encTotal, proof);  // 0 FHE ops
    FHE.allowThis(total);
}

Strategy 8: Use Transient Permissions

// ❌ Persistent permission (~50k gas)
FHE.allow(tempValue, callback);
ICallback(callback).process(tempValue);

// ✅ Transient permission (~30k gas, 40% savings)
FHE.allowTransient(tempValue, callback);
ICallback(callback).process(tempValue);

Strategy 9: Batch ACL Calls

While ACL operations must be called individually, organize them logically:
// ✅ Organized: All ACL at end
balances[from] = newFromBal;
balances[to] = newToBal;

// Batch ACL calls
FHE.allowThis(balances[from]);
FHE.allow(balances[from], from);
FHE.allowThis(balances[to]);
FHE.allow(balances[to], to);

Strategy 10: Avoid Unnecessary Encryption

Not everything needs to be encrypted:
// ❌ Everything encrypted
euint32 public totalVotes;     // Total count - does this need to be secret?
euint32 public votingDeadline; // Deadline - public info

// ✅ Hybrid approach
uint256 public totalVoters;    // Public count
uint256 public votingDeadline; // Public deadline
euint32 private yesVotes;      // Secret tally
euint32 private noVotes;       // Secret tally

Real Gas Benchmark Results

From test suite (328 tests, local fhEVM mock):

Function Call Costs (Selected)

ContractFunctionGas CostNotes
ConfidentialERC20transfer~292kBalance check + 2 updates + ACL
ConfidentialERC20transferFrom~446kMost expensive: allowance + balance checks
ConfidentialVotingvote~292kVote comparison + counter update
SealedBidAuctionbid~396kEncrypted comparison + 2 selects
EncryptedLotterydrawWinner~171kRandom generation + storage
SimpleCounterincrement~208kAdd + ACL
RandomDemogenerateRandom32~126kRandom generation

Deployment Costs

ContractDeployment GasComplexity
SimpleStorage162kMinimal
ConfidentialERC201.24MFull ERC-20
SealedBidAuction1.51MComplex logic

Gas Budgeting

Estimating Transaction Cost

Total Gas = Base (21k)
          + Contract logic
          + Σ(FHE operations)
          + Σ(ACL operations)
          + Σ(Input conversions)

Example: ERC-20 Transfer

Operation                     | Gas
------------------------------|----------
Base transaction              | 21,000
FHE.fromExternal (euint64)    | 100,000
FHE.ge (balance check)        | 450,000
FHE.sub (sender balance)      | 250,000
FHE.add (receiver balance)    | 250,000
FHE.select (sender)           | 230,000
FHE.select (receiver)         | 230,000
FHE.allowThis x2              | 100,000
FHE.allow x2                  | 100,000
Contract overhead             | 50,000
------------------------------|----------
TOTAL ESTIMATED               | ~1,781,000

Gas Limit Configuration

// hardhat.config.js
module.exports = {
  networks: {
    hardhat: {
      gas: 30_000_000,
      blockGasLimit: 30_000_000,
    },
  },
};

Profiling in Tests

const tx = await contract.transfer(recipient, encryptedAmount, proof);
const receipt = await tx.wait();
console.log(`Transfer gas used: ${receipt.gasUsed.toString()}`);

Hardhat Gas Reporter

npm install hardhat-gas-reporter --save-dev
// hardhat.config.js
require("hardhat-gas-reporter");

module.exports = {
  gasReporter: {
    enabled: true,
    currency: "USD",
  },
};

Cost Reduction Checklist

  • Use smallest encrypted type that fits data range
  • Use plaintext for second operands when possible
  • Cache comparison results instead of recomputing
  • Use bit shifts for multiplication/division by powers of 2
  • Pre-compute values off-chain when feasible
  • Use FHE.allowTransient() for cross-contract calls
  • Minimize total FHE operation count
  • Keep public data as plaintext
  • Use FHE.min/max instead of manual compare + select
  • Batch storage updates before ACL calls

Future Cost Reductions

FHE gas costs are expected to decrease due to:
  1. Hardware acceleration: GPU and ASIC-based FHE accelerators
  2. Algorithmic improvements: New FHE schemes and optimizations
  3. Coprocessor optimization: Continuous TFHE-rs library improvements
  4. Batching: Better operation batching at coprocessor level
  5. Custom gas pricing: Network-specific pricing models
Current costs reflect early-stage technology. Costs will follow Moore’s Law-like improvements over time.

Important Notes

FHE operations cost 50,000-100,000x more than plaintext. Design contracts to minimize encrypted computations.
Storage cost is the same as plaintext (encrypted values are stored as 32-byte handles). Computation dominates gas usage.
Using euint8 instead of euint256 reduces gas costs by 7.5x for most operations.

Build docs developers (and LLMs) love