a, b, and a
carry-in) and produces two output bits (sum and carry-out). It’s the
basic building block for arbitrary-width integer arithmetic.
This example shows how to compose TFHE gates into a real circuit, all on
encrypted bits.
The math
For input bitsa, b, cin:
| a | b | cin | sum | cout |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 0 |
| 0 | 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 1 | 0 | 1 |
| 1 | 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 |
Implementation
Performance
The adder uses 5 gate evaluations:| Gate | Count | Latency (fast_128 CPU) |
|---|---|---|
| XOR | 2 | 56 ms × 2 = 112 ms |
| AND | 2 | 14 ms × 2 = 28 ms |
| OR | 1 | 14 ms |
| Total | 5 | ~154 ms |
Building an N-bit ripple-carry adder
Optimizing with batching
For a serial pipeline like a ripple-carry adder, the gates happen sequentially (each carry depends on the previous one). Batching doesn’t help here. But for independent additions (e.g., adding 100 pairs of numbers in parallel), usekeys.batch_* to amortize bootstrapping-key DRAM reads on a
local GPU:
Why this matters
A 1-bit full adder doesn’t sound like much, but it’s the cryptographic proof point: arbitrary boolean circuits can be evaluated on encrypted data. Once you have a full adder, you have addition, subtraction (two’s complement), multiplication (shifts + adds), comparison, and via Turing completeness, anything else. In practice, large-circuit FHE is slow — but for targeted privacy-preserving operations (a private credit-score formula, a small ML inference, a multi-party comparison), it’s exactly the right primitive.Next Steps
Server Mode
Move the gates to api.wavis.xyz
GPU Batch
Local GPU acceleration walkthrough