OpenFHE Lattice Cryptography Library - Arbitrary Lookup Table Evaluation using CKKS-based Functional Bootstrapping
==================================================================================================================

[License Information](License.md)

Document Description
====================
This document describes how to use the CKKS-based functional bootstrapping functionality to evaluate lookup tables (LUT) and
what capabilities are currently supported in OpenFHE. This is an experimental functionality based on
[Alexandru, Kim and Polyakov CRYPTO 2025](https://eprint.iacr.org/2024/1623.pdf).

Example Description
====================

The example file for this functionality is located at [functional-bootstrapping-ckks.cpp](functional-bootstrapping-ckks.cpp). The file gives
examples on how to run:
- `ArbitraryLUT`, which applies a function specified as an LUT over an input ciphertext, for various values of the input and output bit-sizes;
- `MultiValueBootstrapping`, which applies different functions specified as LUTs over the same input ciphertext, reusing intermediate
computations; it also shows how to apply leveled computations after an LUT evaluation;
- `MultiPrecisionSign`, which evaluates the sign of a large value using digit decomposition, for various sizes of the digits.


Functionality
=============

**RLWE schemelet**
We proposed a hybrid scheme that is similar in flavor to a vectorized FHEW scheme. Concretely, we consider the input and output
messages to be integers encoded in the RLWE (Ring LWE) scheme as coefficients, which is equivalent to the coefficient-encoded BFV scheme.
RLWE is additively homomorphic. For more homomomoprhic operations, we convert to CKKS.

We work with an RLWE scheme that assumes the plaintext modulus and the ciphertext modulus to be powers of two (not RNS-friendly). We
implemented this as a "schemelet", i.e., a thin layer of abstraction for multiprecision encryption, decryption, and conversion to the
(RNS) CKKS scheme.

The RLWE and CKKS schemes are compatible in the sense that they can share the same secret key (and implicitly ring dimension). This
makes the conversion between RLWE and CKKS to essentially be modulus switching.

A vector encoded in RLWE can have as many elements as the ring dimension. If this is the case (the number of elements is between half
the ring dimension and the ring dimension), this corresponds to a full complex packing in CKKS, where the complex slots are also
populated. Otherwise, real CKKS packing (full or sparse) is used.

Note that the message is encoded in the coefficients in the RLWE scheme, but when converted to CKKS, the coefficients are held in
the slots of the CKKS ciphertexts. To be able to apply CKKS leveled computations, we need to homomorphically transform from
the coefficient encoding to the slot encoding. When doing this via an FFT-like transform (instead of a linear transform), the
slots will be bit reversed in the CKKS ciphertext. When intermediate computations involving rotations are done in CKKS (see more
below), it is more efficient to apply bit reversal in the encoding and decoding of RLWE. The argument `bitReverse` in
`SchemeletRLWEMP::EncryptCoeff` and `SchemeletRLWEMP::DecryptCoeff` has this role.

**Functional Bootstrapping**
The full functionality is described in [[AKP25]](https://eprint.iacr.org/2024/1623.pdf).

First, the plaintext input and output bit-sizes for the desired function are set, which determine the depth of the computation. The
RLWE ciphertext modulus and CKKS scaling factor are also set in accordance to the desired precsion. Second, the trigonometric Hermite
Interpolation coefficients are computed for the function to be evaluated, based on a desired order of the interpolation (currently
supported orders are 1, 2, and 3). For non-Boolean functions or higher orders, this is done through `GetHermiteTrigCoefficients`, which
returns complex coefficients. For the first order and a Boolean function f, an optimized implementation is used, which requires the
(real and integer) coefficients to be set as [f(1), f(0) - f(1)]. For numeric accuracy in CKKS, the coefficients should be scaled
down such that their maximum magnitude is at most one. This scaling factor `scale` should be chosen to be an integer to incur a
small noise increase.

The desired number of levels that should remain after the function evaluation (for output precision) should be specified. Then, the
setup for the computation is called by `EvalFBTSetup` and the necessary keys are generated by calling `EvalBootstrapKeyGen`.

The RLWE input ciphertext needs to be converted to a CKKS ciphertext in order to commence the functional bootstrapping. This is done
by calling `SchemeletRLWEMP::ConvertRLWEToCKKS`. Then, `EvalFBT` is called to obtain a CKKS encrypting the coefficients of the function
evaluation output. Finally, to return to the exact RLWE scheme, `SchemeletRLWEMP::ConvertCKKSToRLWE` should be called.

Internally, `EvalFBT` performs the following steps: modulus raising, coefficient to slots transform (equivalent to homomorphic
encoding), complex exponential evaluation, computing powers of the complex exponential, power series evaluation of the
Hermite coefficients, slots to coefficients transform (equivalent to homomorphic decoding) and necessary scalings.

If one wants to apply an intermediate leveled computation on the CKKS slots, then the number of levels for this leveled computation
needs to be specified. If this intermediate computation requires rotations, then in order to apply the rotations over the natural
order in CKKS slots, the RLWE input needs to be bit reversed if multiple levels are used for encoding and decoding. Then
`EvalFBTNoDecoding` should be called, the intermediate computation applied and finally, `EvalHomDecoding` should be called.

The features that need to be enabled for CKKS functional bootstrapping are PKE, KEYSWITCH, LEVELEDSHE, ADVANCEDSHE and FHE.

**Multi-Value Bootstrapping**

When multiple functions need to be evaluated over the same input ciphertext, we can reuse the computations for functional
bootstrapping up to (including) the powers of the complex exponential. This can be called by `EvalMVBPrecompute`. Using the
ciphertexts obtained as such, one can then call `EvalMVB` once for every set of coefficients corresponding to a different
function. As before, if intermediate CKKS leveled computations are required before converting back to RLWE, one
should call `EvalMVBNoDecoding` and `EvalHomDecoding`.

**Chain computations and Sign**

For certain computations, such as sign, we can support LUTs over larger inputs than direct functional bootstrapping for arbitrary
functions. In particular, we achieve this by performing homomorphic digit decomposition using functional bootstrapping for the
smaller digits, and process these smaller digits separately.

**Secret key distributions**

Functional bootstrapping is supported for sparse secret keys.

The SPARSE_TERNARY distribution is the distribution used in the original CKKS paper [[CKKS17](https://eprint.iacr.org/2016/421.pdf)],
where the Hamming weight of the secret key is set to 192. For the set number of overflows in bootstrapping, K = 25, this
distribution leads to a larger probability of failure. For LUT input bit-sizes of over 10 bits, choosing this distribution leads
to requiring an extra level in the complex exponential approximation to achieve correctness. This is the distribution used for
the benchmarks in [[AKP25]](https://eprint.iacr.org/2024/1623.pdf).

The SPARSE_ENCAPSULATED distribution (described in [[BTH22]](https://eprint.iacr.org/2022/024.pdf)) uses a Hamming weight of 32
for the key used in (functional) bootstrapping and 192 for other operations. With the set number of overflows K = 16, this
distribution leads to a negligible probability of failure. Moreover, for all supported LUT sizes (up to 14 bits), the number of
levels for the complex exponential approximation is the same. The only caveat for the current implementation is that when the
scaling factor is very close to the first modulus size in CKKS (which happens for LUT of input bit-size 14), the noise introduced
by the extra key switching is larger.

**Current limitations**
- There is no automated selection of parameters and approximation orders. The user needs to choose appropriate RLWE and CKKS
cryptoparameters, trigonometric Hermite interpolation order and the scaling for the Hermite coefficients. These parameters
should guarantee correct decryption in RLWE (the error should not corrupt the message) in order to achieve
$\textsf{IND}-\textsf{CPA}^{D}$ security.
If the output is decrypted under CKKS, noise flooding should be applied in order to achieve $\textsf{IND}-\textsf{CPA}^{D}$
security.
- With a scaling factor fitting on native int size of 64 bits, LUTs up to 14 bits in size are supported.
- The current multiprecision sign evaluation implementation requires that the digit bit size divides the input bit size.
- Only sparse secrets are currently supported, with the secret key distributions SPARSE_TERNARY (larger probability of
failure) and SPARSE_ENCAPSULATED (negligible probability of failure).
- Only the FIXEDMANUAL mode for rescaling is supported.
- MULTIPARTY is not supported.
