Interface

This section walks through the CKKS interface in the order one would use it: choosing parameters, generating keys, encrypting, computing, and decrypting. Throughout, we assume the standard parameter set from Section 2.3.

Parameter selection

The parameters (ring dimension, number of levels, precision, and so on) are fixed once, ahead of time; Section 2.3 covers how to choose them. The rest of this page assumes the standard parameter set.

Key generation

Key generation comes in two forms:

One part of key generation deserves special attention: the rotation keys. Every distinct rotation needs its own rotation key, and these keys must be generated ahead of time: a rotation whose key was never generated simply cannot be performed. The catch is that each key is roughly $126$ MB apiece at the standard parameters, so generating a key for every conceivable rotation is not an option. Users should generate only the rotation keys the computation actually uses.

Encryption

A CKKS plaintext vector is a vector in $\mathbb{C}^{32768}$. Each coordinate is called a slot. Encryption turns such a plaintext vector into a ciphertext. At the standard parameters, the ciphertext stores each slot to about $40$ bits of precision after the binary point, and the entries should have magnitude at most about $2^{12}$.

Most computations don't have exactly $32768$ values to encrypt, so users will have to decide how to lay the data out across the slots. Three common strategies are:

Attached to every ciphertext is a nonnegative integer called its level. A fresh encryption is produced at level $17$. The level is a budget: it starts high and can only go down as the computation proceeds. The only way to raise it again is bootstrapping, an expensive operation that turns a low-level ciphertext back into a high-level one. The next section describes exactly how each operation spends this budget.

Computation

CKKS exposes a small set of homomorphic operations. Each one produces a new ciphertext and has a well-defined effect on the level. The table below summarizes those effects; $\ell$, $\ell_1$, and $\ell_2$ denote the levels of the inputs.

OperationResulting level
Add (levels $\ell_1, \ell_2$)$\min(\ell_1, \ell_2)$
Subtract (levels $\ell_1, \ell_2$)$\min(\ell_1, \ell_2)$
Multiply by plaintext (level $\ell$)$\ell - 1$ in general; $\ell$ if the plaintext is a scalar integer
Multiply by ciphertext (levels $\ell_1, \ell_2$)$\min(\ell_1, \ell_2) - 1$
Rotation (level $\ell$)$\ell$
Conjugation (level $\ell$)$\ell$
Polynomial evaluation, degree $d$ (level $\ell$)$\ell - \lceil \log_2(d + 1) \rceil$
Matrix multiplication (level $\ell$)$\ell - 1$
Bootstrapping (level $0$)$17$

Addition and subtraction

Addition and subtraction are the cheapest operations: they combine two ciphertexts pointwise and leave the result at the minimum of the two input levels.

Multiplication

Multiplication comes in two flavors, both pointwise (Hadamard):

Rotation

Rotation cyclically shifts the slots: rotating by $i$ sends $$(v_0, v_1, \ldots, v_{32767}) \mapsto (v_i, v_{i+1}, \ldots, v_{i-1}),$$ with indices taken modulo $32768$. It is the only way to move data between slots, and it leaves the level unchanged. Each rotation amount needs its own rotation key, generated ahead of time; a rotation whose key was not generated cannot be performed.

Conjugation

Conjugation replaces each slot by its complex conjugate, sending $$(v_0, v_1, \ldots, v_{32767}) \mapsto (\bar v_0, \bar v_1, \ldots, \bar v_{32767}).$$ It is pointwise and leaves the level unchanged.

Polynomial evaluation

Polynomial evaluation can be built out of the operations above, but is exposed directly for convenience. It applies a polynomial slotwise to an encrypted vector, and a different polynomial can be applied to each slot if desired. Evaluation costs $\lceil \log_2(d + 1) \rceil$ levels, where $d$ is the largest degree among the per-slot polynomials. One caveat for high-degree polynomials: they can only be evaluated accurately when the encrypted values lie in the range $[-2, 2]$, so inputs needs to be scaled into that range first.

Matrix multiplication

Matrix multiplication can also be built out of the operations above, but is exposed directly for convenience. It multiplies an encrypted vector by a plaintext matrix and consumes a single level, regardless of the size of the matrix.

Bootstrapping

Bootstrapping takes a level-$0$ ciphertext and returns a level-$17$ ciphertext encrypting the same vector, preserving about $13$ bits of precision after the binary point. It assumes its input lies within the $2^{12}$ magnitude range, so intermediate values must be kept in this range before a bootstrap.

Decryption

Decryption always happens client-side, and comes in two forms:

At this stage, a small amount of noise flooding is added if needed. If noise flooding is not performed, decryption results must be kept private and never shared with the computation server. Otherwise, the server, which has seen the corresponding ciphertexts, can use the leaked information to recover the secret key.