Shaped Rounding: Trading Empty Slots for Precision

Shaped Rounding: Trading Empty Slots for Precision

October 19, 2026 · 10 min read

At ring degree N=215N = 2^{15}, a CKKS ciphertext holds 1638416384 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 2020-bit scaling factor can carry more than 4848 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:

one value · latency thousands of values · throughput batch size bits, integers real, complex data type approximate arithmetic small batches, low latency TFHE CKKS This work

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 R=Z[X]/(XN+1)\mathcal{R} = \mathbb{Z}[X]/(X^N + 1) has two natural sets of coordinates. Its coefficients are what we store and round. Its slots σt(a)=a(ζ5t)\sigma_t(a) = a(\zeta^{5^t}) are what CKKS decodes and computes on (vector of complex numbers). The canonical embedding σ\sigma converts between the two.

Ciphertexts must have integer coefficients, so every rescaling and keyswitching ends by dividing by an integer rr and rounding each coefficient. The remainder lies in a cube [−12,12]N[-\tfrac12, \tfrac12]^N 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, 1,X,…,XN−11, X, \dots, X^{N-1}. But the lattice R\mathcal{R} 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 g,gX,…,gXN−1g, gX, \dots, gX^{N-1} for a unit gg, an element whose inverse also has integer coefficients. Rounding a/ra/r in that basis means:

  1. change coordinates by g−1g^{-1},
  2. round coefficientwise as usual,
  3. change back by gg.

The result is g⋅⌊g−1a/r⌉g \cdot \lfloor g^{-1} a / r \rceil, which the paper calls shaped rounding. Its error is gg times an ordinary rounding error. In slot coordinates, multiplying by gg just scales slot tt by σt(g)\sigma_t(g). You can then choose gg small on the data slots, and the error there becomes small too.

The smallest example fits in the plane. The ring Z[2]\mathbb{Z}[\sqrt 2] (the real part of Z[Y]/(Y4+1)\mathbb{Z}[Y]/(Y^4+1), with 2=Y−Y3\sqrt 2 = Y - Y^3) has two slots, a+b2↦(a+b2, a−b2)a + b\sqrt 2 \mapsto (a + b\sqrt2,\ a - b\sqrt2). It contains the unit U=1+2U = 1 + \sqrt 2, with slot values 2.4142.414 and −0.414-0.414. Call the first slot “data”, the second “guard”, and round with g=U−kg = U^{-k}:

Shaping polynomial
x data slot → ↑ guard slot

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.

Each tile
data width
guard height
area
Rounding error of x
on the data slot
on the guard slot

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 ring seen through its two slots, , with of slot values and . Rounding in the basis cuts the plane into tiles, one around each lattice point, so the rounding error always fits inside one tile.

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, N=64N = 64, one slot in four carries data, and gg is a unit found by the search described in the paper:

Coefficients
Slots (log scale)
data slot guard slot data slot holding a guard's error
One rounding error in , seen in both coordinate systems: plain rounding leaves , shaped rounding leaves (same sample of ).

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 gege. Every phase then reads

μ=Δm+ge⟺g−1μ=(g−1Δ) m+e.\mu = \Delta m + g e \quad\Longleftrightarrow\quad g^{-1}\mu = (g^{-1}\Delta)\, m + e .

In the g−1g^{-1} coordinates this is ordinary CKKS with a polynomial scaling factor g−1Δg^{-1}\Delta, worth Δ/∣σt(g)∣\Delta / |\sigma_t(g)| in slot tt. With the paper’s unit and Δ=220\Delta = 2^{20}, the data slots see an effective scaling factor of about 2662^{66}, while each level still consumes only 2020 bits of modulus. With g=1g = 1 we are back to CKKS.

This decouples precision from the scaling factor. In CKKS, you cannot keep more bits than you scale by. Here, Δ\Delta only needs to keep the guards under control (see below), and gg adds precision on top. At N=215N = 2^{15} and Δ=220\Delta = 2^{20}, sixteen products by fresh operands keep 48.348.3 bits of precision, against 5.25.2 bits for CKKS at the same scaling factor.

Security does not change. The public bijection (a,b)↦(ga,gb)(a, b) \mapsto (ga, gb) turns Ring-LWE samples with error ee into samples with error gege, and back, so the usual CKKS parameters apply as they are.

Volume is conserved

The tiles kept their area because units have norm one:

∏t∣σt(g)∣=1.\prod_{t} |\sigma_t(g)| = 1 .

Every bit of suppression on the data must be paid for by amplification on the guards. With one data slot in every RR, a bit of guard amplification buys at most R−1R - 1 bits of data precision. The best units spread the cost evenly over the guards. The paper’s unit, for R=16R = 16, suppresses the data by 4646 bits, and no guard is amplified by more than 4.64.6 bits.

This unit lies in Z[XN/(2R)]\mathbb{Z}[X^{N/(2R)}], so its slot values repeat every RR slots. Rotations by multiples of RR therefore keep the error profile aligned with the data. Rotating by 11 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 bb becomes bounded by b2+cb^2 + c, where cc is the error injected on the guards:

bound before squaring → ↑ bound after squaring
attracting
escape
after 21 squarings

A squaring maps a guard bound to (blue curve). The red path follows the bound level after level. Below , a start below settles at ; above, the curve leaves the diagonal and the bound grows without limit.

For c≤1/4c \le 1/4, guards that start small enough settle below 1/21/2 and stay there. Since c≈ME/Δc \approx M E / \Delta, where MM is the largest guard magnitude of gg and EE the size of a rounding remainder, the scaling factor only has to satisfy

Δ  ≥  4ME.\Delta \;\ge\; 4 M E .

This replaces the usual rule. In CKKS, Δ\Delta must cover the target precision plus the rounding error. Here it only has to keep the guards stable, which at N=215N = 2^{15} gives 2020-bit levels, and the precision comes from gg. 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 1616 or 6464 values, bootstrapping at N=215N = 2^{15} restores 2121 levels of 2020 bits, with at least 22.622.6 bits of precision after 2121 products. At that ring degree, sparse CKKS restores only four levels. To get 1616, it has to move to N=216N = 2^{16}:

k=16k = 16 values, single threadRing degreeLevelsMin. precisionBootstrapping time
Sparse CKKS2162^{16}161619.919.9 bits3.773.77 s
This work2152^{15}161622.922.9 bits0.750.75 s
This work2152^{15}212122.822.8 bits0.860.86 s

For 1616 and 6464 values, that is about 55 times faster on one thread and 3.63.6 to 3.73.7 times faster on 1818 cores. The gap narrows for large batches. At 10241024 values, sparse CKKS still fits N=215N = 2^{15} for one or two levels and is then about 1.11.1 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 g−1cg^{-1}c in place of cc and multiplies by gg 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 workGCKKSFocused CKKS
Main focusLow latency for small batchesHigh precisionHigh precision
BootstrappingImplementedAnnouncedDescribed
Conversions to and from CKKSYesNoWithin bootstrapping
Guard analysisGeneral circuitsProducts, linear mapsProducts, linear maps
Public codeYesNo link givenNo

The other works also bring ideas this one does not. GCKKS allows non-unit shaping polynomials and reports leveled precision beyond 10001000 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 gg 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.