Noise growth in RLWE is a budget you spend once
Every homomorphic operation draws down the same account. A practical way to reason about depth before you write any code.
The mistake I made for a long time was treating noise as an implementation detail — something the library handles, something you tune at the end. It is not. The noise budget is the resource the entire computation is denominated in, and if you do not plan the spend, you will find out at decryption time that you overdrew.
The account
An RLWE ciphertext is a pair with , where is small. You can decrypt correctly as long as
Everything you do to the ciphertext grows . The budget is the gap between the current noise and that threshold, and it never refills — except by bootstrapping, which is a separate and much larger expense.
The exchange rate for each operation
Rough magnitudes, with the ring dimension and the decomposition base:
| Operation | Effect on noise |
|---|---|
| Add two ciphertexts | — additive, essentially free |
| Multiply by a plaintext scalar | — cheap if is small |
| Multiply by a plaintext polynomial | — much worse |
| Ciphertext × ciphertext | then relinearise |
| Automorphism + key switch | additive, but adds a key-switching term |
The asymmetry between rows two and three is the one people trip over. Multiplying by a constant is nearly free; multiplying by a polynomial with nonzero coefficients costs a factor of , because every coefficient of the result is a sum of products. In a PIR context this is exactly the difference between "the selection vector is a constant" and "the selection vector is encrypted", and it is why query expansion is designed so carefully.
Planning before coding
Write the circuit down as a tree and label each edge with its noise multiplier before you touch a library. For a depth- multiplicative circuit the noise is roughly
so the depth you can afford is logarithmic in the budget. Two consequences follow immediately:
- Rebalance the tree. A left-deep chain of multiplications and a balanced tree of the same leaves have very different depths. Balanced almost always wins.
- Push plaintext multiplications to the leaves. Doing them early means their noise contribution gets multiplied by fewer subsequent operations.
bad good
× ×
/ \ / \
× c4 × ×
/ \ / \ / \
× c3 c1 c2 c3 c4
/ \
c1 c2 depth 3 depth 2
The check I run first
Before implementing anything, I compute the budget by hand for the intended parameter set and compare it to the circuit's predicted growth, with a safety factor of at least . If the margin is not there, no amount of implementation cleverness will save it — the parameters have to change, or the circuit does.
That check takes ten minutes and has saved me weeks.