Shaped Rounding: Trading Empty Slots for Precision
October 19, 2026 · 10 min read
At ring degree , a CKKS ciphertext holds complex numbers. Some computations only need a handful of them, but the ring degree is set by security and by the size of the modulus, so it cannot shrink to match the batch. The empty slots are computed on anyway.
My new paper, Fully Homomorphic Encryption for Small Batches of Complex Numbers, puts those slots to work as a guard band that absorbs rounding error in place of the slots that carry data. The data slots then get much more precision at the same scaling factor: in leveled computation, a -bit scaling factor can carry more than bits of precision. They can also get the same precision at a much smaller scaling factor, which means more levels per bootstrapping.
In FHE, for computing on a few real or complex numbers, the usual choices each miss something. TFHE is built for latency, but on bits and small integers. CKKS has approximate arithmetic, but is built for throughput on thousands of values. This scheme brings the arithmetic of CKKS to small batches, where latency matters more than throughput:
The idea is simple once you see it as a change of basis in the ring, which is what this post is about.
Two coordinate systems
An element of has two natural sets of coordinates. Its coefficients are what we store and round. Its slots are what CKKS decodes and computes on (vector of complex numbers). The canonical embedding converts between the two.
Ciphertexts must have integer coefficients, so every rescaling and keyswitching ends by dividing by an integer and rounding each coefficient. The remainder lies in a cube in coefficient coordinates. Seen in slot coordinates, that cube is rotated and scaled, and the error comes out roughly the same size in every slot. When only a few slots carry data, that even spread is wasteful. We would rather push the error out of the data slots for better precision, while still producing integer ciphertexts.
Rounding in another basis
Rounding each coefficient means rounding to a lattice point in one particular basis, . But the lattice has many other bases. Rounding in any of them still lands on a lattice point, so the result is still a valid ciphertext component. What changes is the shape of the tile of points that round to each lattice point, and so the region the error falls in.
Take the basis for a unit , an element whose inverse also has integer coefficients. Rounding in that basis means:
- change coordinates by ,
- round coefficientwise as usual,
- change back by .
The result is , which the paper calls shaped rounding. Its error is times an ordinary rounding error. In slot coordinates, multiplying by just scales slot by . You can then choose small on the data slots, and the error there becomes small too.
The smallest example fits in the plane. The ring (the real part of , with ) has two slots, . It contains the unit , with slot values and . Call the first slot “data”, the second “guard”, and round with :
Click or drag to move the point x. It rounds to the lattice point at the center of its tile (circled), and the arrow is the rounding error.
The lattice points never move: is a unit, so every basis shown spans the same lattice. Only the tiles change shape, and their area stays fixed.
The lattice points never move. The tiles are squeezed along the data axis and stretched along the guard axis, and their area stays the same.
The same thing happens in a full ring. Below, , one slot in four carries data, and is a unit found by the search described in the paper:
In coefficient coordinates, the shaped error looks worse. In slot coordinates, it is about nine bits smaller on the data and three bits larger on the guards.
A polynomial scaling factor
Use shaped rounding everywhere the scheme rounds (rescaling, keyswitching, encoding), and sample encryption errors as . Every phase then reads
In the coordinates this is ordinary CKKS with a polynomial scaling factor , worth in slot . With the paper’s unit and , the data slots see an effective scaling factor of about , while each level still consumes only bits of modulus. With we are back to CKKS.
This decouples precision from the scaling factor. In CKKS, you cannot keep more bits than you scale by. Here, only needs to keep the guards under control (see below), and adds precision on top. At and , sixteen products by fresh operands keep bits of precision, against bits for CKKS at the same scaling factor.
Security does not change. The public bijection turns Ring-LWE samples with error into samples with error , and back, so the usual CKKS parameters apply as they are.
Volume is conserved
The tiles kept their area because units have norm one:
Every bit of suppression on the data must be paid for by amplification on the guards. With one data slot in every , a bit of guard amplification buys at most bits of data precision. The best units spread the cost evenly over the guards. The paper’s unit, for , suppresses the data by bits, and no guard is amplified by more than bits.
This unit lies in , so its slot values repeat every slots. Rotations by multiples of therefore keep the error profile aligned with the data. Rotating by instead, as in the figure above, moves guard errors onto the data.
Keeping the guards in check
Guards are never decoded, but they are still part of the phase. If they grow too large, the phase wraps around the modulus and the data is lost too. Squaring is the simplest case to analyze. A guard bounded by becomes bounded by , where is the error injected on the guards:
For , guards that start small enough settle below and stay there. Since , where is the largest guard magnitude of and the size of a rounding remainder, the scaling factor only has to satisfy
This replaces the usual rule. In CKKS, must cover the target precision plus the rounding error. Here it only has to keep the guards stable, which at gives -bit levels, and the precision comes from . When other operations would let the guards grow, a multiplication by a mask that zeroes them resets them, and it can often be folded into an existing plaintext-ciphertext product.
Bootstrapping
Bootstrapping follows the CKKS blueprint, with one constraint: bring the data back without importing the guards. The linear transforms are built so that their exact maps never read a guard slot, and they write zeros back on the guards. The constants of the modular reduction are masked so that they do not repopulate the guards. The same transforms also convert to and from CKKS with shared keys, so a CKKS computation can hand a small subcircuit to the new scheme and take the result back.
Results
The implementation is built on poulpy. With parameters targeting 128-bit security and batches of or values, bootstrapping at restores levels of bits, with at least bits of precision after products. At that ring degree, sparse CKKS restores only four levels. To get , it has to move to :
| values, single thread | Ring degree | Levels | Min. precision | Bootstrapping time |
|---|---|---|---|---|
| Sparse CKKS | bits | s | ||
| This work | bits | s | ||
| This work | bits | s |
For and values, that is about times faster on one thread and to times faster on cores. The gap narrows for large batches. At values, sparse CKKS still fits for one or two levels and is then about times faster. From four levels on, this work is about twice as fast.
Concurrent work
Two independently developed works appeared on ePrint after this paper, and both cite it: GCKKS by Ma, Liu, Wang and Wang, and Focused CKKS by Cheon and Lee. Both share the core idea: multiply the errors by a public polynomial that is small on the data slots, chosen in a subring so that it commutes with the rotations acting on the data. Three groups arriving at it independently is a good sign that it is the natural idea.
The change-of-coordinates view makes the relation precise. When the shaping polynomial is a unit, the three leveled schemes are related by a public change of coordinates under which encryption, rescaling and products coincide. The focused rounding of Cheon and Lee is the shaped rounding above, and GCKKS stores in place of and multiplies by at decryption. All three are bounded by the same norm limit.
The differences lie in what is built around the idea, and in their focus:
| This work | GCKKS | Focused CKKS | |
|---|---|---|---|
| Main focus | Low latency for small batches | High precision | High precision |
| Bootstrapping | Implemented | Announced | Described |
| Conversions to and from CKKS | Yes | No | Within bootstrapping |
| Guard analysis | General circuits | Products, linear maps | Products, linear maps |
| Public code | Yes | No link given | No |
The other works also bring ideas this one does not. GCKKS allows non-unit shaping polynomials and reports leveled precision beyond bits. The bootstrapping of Focused CKKS masks the integer lift, which cuts the modulus cost of CoeffsToSlots at high precision for larger batches, and should combine well with the transforms here for larger batches and higher precisions. They also adapt high precision CKKS bootstrapping.
The takeaway
CKKS rounds in the coefficient basis because it is the obvious basis, not because it is the best one for precision. A unit gives another basis of the same lattice, with the same ciphertexts, keys, and security, and it lets you choose where the rounding error goes.
The construction, proofs, error analysis, bootstrapping algorithm, CKKS conversions and benchmarks are fully described in my paper.