Level: Beginner | Duration: 3 hoursPrerequisites: Module 03: Encrypted Types
Overview
The power of FHE lies in performing computations directly on encrypted data. FHEVM exposes a comprehensive set of operations through theFHE library. This module covers every operation category: arithmetic, bitwise, and comparison.
Learning Objectives
By completing this module you will be able to:- Perform arithmetic operations (add, sub, mul, div, rem) on encrypted integers
- Use bitwise operations (and, or, xor, not, shl, shr, rotl, rotr) on encrypted data
- Apply comparison operations (eq, ne, gt, ge, lt, le) returning encrypted booleans
- Understand min/max operations on encrypted values
- Recognize type compatibility rules and overflow behavior
1. Arithmetic Operations
Addition: FHE.add()
Subtraction: FHE.sub()
Overflow behavior: If
b > a, the result wraps around (unsigned underflow). There is no revert. You must handle this in your logic using comparisons.Multiplication: FHE.mul()
Warning: Multiplication is the most gas-expensive arithmetic operation. Use sparingly and prefer smaller types.
Division: FHE.div()
Division is only supported with a plaintext divisor:
You cannot divide two encrypted values. The divisor must be plaintext. Division by zero returns 0 (no revert in FHE).
Remainder: FHE.rem()
Like division, remainder requires a plaintext operand:
Negation: FHE.neg()
Returns the two’s complement negation:
2. Arithmetic Operations Summary
| Operation | Function | Operands | Notes |
|---|---|---|---|
| Addition | FHE.add(a, b) | enc + enc, enc + plain | Wraps on overflow |
| Subtraction | FHE.sub(a, b) | enc - enc, enc - plain | Wraps on underflow |
| Multiplication | FHE.mul(a, b) | enc * enc, enc * plain | High gas cost |
| Division | FHE.div(a, b) | enc / plain only | No enc/enc division |
| Remainder | FHE.rem(a, b) | enc % plain only | No enc/enc remainder |
| Negation | FHE.neg(a) | enc | Two’s complement |
3. Bitwise Operations
AND: FHE.and()
OR: FHE.or()
XOR: FHE.xor()
NOT: FHE.not()
4. Shift and Rotate Operations
Shift and rotate operations are available foreuint8 through euint128. The shift amount is always euint8 or uint8, regardless of the value type being shifted.
Important: The shift amount (second parameter) must ALWAYS be
euint8 or uint8, regardless of the first operand’s type.Shift Modulo: The shift amount is taken modulo the bit width of the type. For example, FHE.shl(euint8_val, 10) is equivalent to FHE.shl(euint8_val, 2) because 10 mod 8 = 2.5. Bitwise Operations Summary
| Operation | Function | Operands |
|---|---|---|
| AND | FHE.and(a, b) | enc & enc, enc & plain |
| OR | FHE.or(a, b) | enc | enc, enc | plain |
| XOR | FHE.xor(a, b) | enc ^ enc, enc ^ plain |
| NOT | FHE.not(a) | ~enc |
| Shift Left | FHE.shl(a, b) | enc, shift amount: euint8/uint8 |
| Shift Right | FHE.shr(a, b) | enc, shift amount: euint8/uint8 |
| Rotate Left | FHE.rotl(a, b) | enc, shift amount: euint8/uint8 |
| Rotate Right | FHE.rotr(a, b) | enc, shift amount: euint8/uint8 |
6. Comparison Operations
All comparison operations return anebool (encrypted boolean).
Equal: FHE.eq()
Not Equal: FHE.ne()
Greater Than: FHE.gt()
Greater Than or Equal: FHE.ge()
Less Than: FHE.lt()
Less Than or Equal: FHE.le()
7. Comparison Operations Summary
| Operation | Function | Returns |
|---|---|---|
| Equal | FHE.eq(a, b) | ebool |
| Not Equal | FHE.ne(a, b) | ebool |
| Greater Than | FHE.gt(a, b) | ebool |
| Greater or Equal | FHE.ge(a, b) | ebool |
| Less Than | FHE.lt(a, b) | ebool |
| Less or Equal | FHE.le(a, b) | ebool |
8. Min and Max
9. Cross-Type Operation Support
Automatic Type Upcasting
fhEVM supports operations between different encrypted types! The result is automatically upcast to the larger type:Rule: When mixing types, the result type is always the LARGER of the two operand types.Supported combinations: All pairs of euint8, euint16, euint32, euint64, euint128.
Encrypted + Plaintext
Many operations accept one encrypted and one plaintext operand:10. Operation Support by Type
Not all operations are available for all encrypted types:| Operation | euint8-128 | euint256 | eaddress | ebool |
|---|---|---|---|---|
| add, sub, mul | ✅ | ❌ | ❌ | ❌ |
| div, rem (scalar) | ✅ | ❌ | ❌ | ❌ |
| min, max | ✅ | ❌ | ❌ | ❌ |
| le, lt, ge, gt | ✅ | ❌ | ❌ | ❌ |
| eq, ne | ✅ | ✅ | ✅ | ✅ |
| and, or, xor | ✅ | ✅ | ❌ | ✅ |
| not, neg | ✅ | ✅ | ❌ | ✅ (not) |
| shl, shr, rotl, rotr | ✅ | ✅ | ❌ | ❌ |
| select | ✅ | ✅ | ✅ | ✅ |
euint256 is primarily useful for storing large hashes/IDs with equality checks. For arithmetic, use euint128 or smaller.11. Overflow and Underflow Behavior
FHEVM uses wrapping arithmetic (modular arithmetic):Important: There are NO overflow reverts in FHE. You must check bounds yourself if needed.
Safe Subtraction Pattern
12. Practical Example: Encrypted Calculator
13. Gas Cost Comparison
Operations ordered by approximate gas cost (lowest to highest):- NOT — Cheapest (single operand)
- AND, OR, XOR — Bitwise is efficient
- ADD, SUB — Standard arithmetic
- SHL, SHR, ROTL, ROTR — Medium (shift operations)
- EQ, NE — Equality checks
- GT, GE, LT, LE — Ordering comparisons
- MIN, MAX — Comparison + select
- MUL — Most expensive arithmetic
- DIV, REM — Expensive (plaintext divisor only)
Summary
- Arithmetic:
add,sub,mul(enc+enc),div,rem(enc+plain only),neg - Bitwise:
and,or,xor,not,shl,shr,rotl,rotr(shift amount alwayseuint8/uint8) - Comparison:
eq,ne,gt,ge,lt,le— all returnebool - Min/Max:
FHE.min(),FHE.max()for clamping - Cross-type operations are supported — result is automatically upcast to the larger type
- Arithmetic uses wrapping (no overflow reverts) — handle bounds manually
- Use
FHE.select()for safe conditional patterns (covered in Module 08)
Next Module: Module 05: Access Control (ACL)