E2EE Backend part 1: Homomorphic Encryption
This is the first post in a series exploring a truly privacy-preserving, end-to-end encrypted backend and client.
The goal of this part: a demo that can calculate totals on encrypted user data without ever seeing the plaintext.
Why This Matters
Traditional E2EE protects data at rest and in transit, but the moment the server needs to do anything useful (e.g., compute total revenue, average score, or aggregate telemetry), it must decrypt. That defeats the purpose of zero-trust architecture.
Homomorphic encryption changes the game:
Encrypt(a) + Encrypt(b) = Encrypt(a + b)
The server adds (or multiplies) ciphertexts directly. The result decrypts to the correct plaintext on the client.
The Demo: Homomorphic Sum of 72 Encrypted Numbers
Here’s a complete, runnable Swift example using Apple’s excellent open-source HomomorphicEncryption framework (BFV scheme with UInt64).
// Key parts
let params = try EncryptionParameters<Bfv<UInt64>>(from: .n_8192_logq_40_60_60_logt_26)
let context = try Context(encryptionParameters: params)
let secretKey = try context.generateSecretKey()
// Encrypt each value separately (coefficient encoding, one value per ciphertext)
let (ciphertexts, plaintexts) = try encryptRandomNumbers(numberOfValues: 72, context: context, secretKey: secretKey)
let encryptedSum = try calculateEncryptedSum(ciphertexts: ciphertexts)
// Decrypt & verify
let decrypted = try encryptedSum.decrypt(using: secretKey)
let result = try decrypted.decode(format: .coefficient)[0]
print("Expected: \(plaintexts.reduce(0, +)) | Actual: \(result)")
Output
Expected sum: 41869
Result from homomorphic operation: 41869
Match: ✓ Success!
Repo: github.com/peterspath/HomomorphicSum
Why These Parameters?
- Polynomial degree N = 8192 → supports up to ~8192 operations before noise becomes critical
- Plaintext modulus t ≈ 2²⁶ → plenty of room for the sum of 72 numbers (each ≤999) without modular wrap-around
logq_40_60_60gives sufficient ciphertext modulus bits to keep noise growth manageable during addition
Addition of ciphertexts is extremely cheap compared to multiplication (no relinearization needed).
How Addition Works Under the Hood (BFV)
In BFV, a ciphertext encrypts a plaintext polynomial in the ring R_t = Z_t[X]/(X^N + 1). When you add two ciphertexts:
ct₁ + ct₂ = (c0₁ + c0₂, c1₁ + c1₂) mod q
Decrypting this recovers exactly m₁ + m₂ mod t.
Because we used coefficient encoding with one value per ciphertext, each ciphertext holds a single scalar. This is the simplest way to demonstrate correctness before moving to packed/SIMD encoding.
Enjoyed this post?
Well, you could share the post with others, follow me with RSS Feeds, send me a comment via email, and/or leave a donation in the Tip Jar.
Tags
Category:
Tags:
Year: