Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/pke/examples/CKKS_BOOTSTRAPPING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The bootstrapping procedure follows a modular framework consisting of four main

The original method started with a modulus raising step, as follows:
1. **ModRaise** (Modulus Raising): The ciphertext $(c_0, c_1)\mod q$ is logically viewed as $(c_0, c_1)\mod Q$, for $Q >> q$. This process effectively changes the underlying plaintext from $m(X)$ to $m(X) + q\cdot I(X)$, where $I$ is an integer overflow. Note that the modulus $Q$ needs to be large enough to support the desired number of levels after bootstrapping, as well as the levels required for the bootstrapping procedure. Also note that the overflows are over the coefficients of the ciphertext.
2. **CoeffsToSlots** (Homomorphic Encoding): This step performs a linear transformation to move the coefficients of the ciphertext polynomials into slots, in order to enable the removal of the overflows. In OpenFHE, this is implemented using a matrix-vector multiplication approach (often using a FFT-like butterfly structure) to minimize the number of rotations. Note that this step is expensive since it happens at the largest modulus.
2. **CoeffsToSlots** (Homomorphic Encoding): This step performs a linear transformation to move the coefficients of the ciphertext polynomials into slots, in order to enable the removal of the overflows. In OpenFHE, this is implemented using a matrix-vector multiplication approach (often using a FFT-like butterfly structure) to minimize the number of rotations. The baby-step/giant-step evaluation accumulates the giant steps in Horner form with a single giant-step stride, which also minimizes the number of distinct rotation keys that must be generated and stored. Note that this step is expensive since it happens at the largest modulus.
3. **EvalMod** (Approximate Modular Reduction): This is the core functional evaluation. To recover an encryption of the message $m$ without the overflow, we have to evaluate an approximate modular reduction function homomorphically, using a sine function approximation for small angles. To handle larger ranges of $I$ (determined by the parameter $K$ depending in turn on the secret key distribution), we employ $r$ iterations of the double-angle formula, which reduces the computational complexity at the expense of a higher multiplicative depth. The underlying trigonometric function is computed using Chebyshev series interpolation. See [https://eprint.iacr.org/2019/688](https://eprint.iacr.org/2019/688), [https://eprint.iacr.org/2018/1043](https://eprint.iacr.org/2018/1043), [https://eprint.iacr.org/2020/1203](https://eprint.iacr.org/2020/1203) for details.
4. **SlotsToCoeffs** (Homomorphic Decoding): This step is the inverse of the CoeffsToSlots step and returns the underlying message to the slots encoding, resulting in a refreshed ciphertext $(c_0', c_1')(\bmod Q')$.

Expand Down
36 changes: 36 additions & 0 deletions src/pke/include/scheme/ckksrns/ckksrns-fhe.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,36 @@ class FHECKKSRNS : public FHERNS {
//------------------------------------------------------------------------------
// EVALUATION: CoeffsToSlots and SlotsToCoeffs
//------------------------------------------------------------------------------
// The transforms below use a baby-step/giant-step (BSGS) decomposition in
// which the giant steps are accumulated in Horner form with a single giant-
// step stride. This requires only one giant-step rotation key per level
// (instead of one per giant step), minimizing the number of distinct
// rotation keys that EvalBootstrapKeyGen must generate and store.

/**
* Single-level linear transform, used for CoeffsToSlots/SlotsToCoeffs when the
* level budget is 1. Evaluated with a BSGS decomposition (Horner giant steps).
* @param A precomputed diagonal plaintexts of the linear transform
* @param ct input ciphertext
*/
Ciphertext<DCRTPoly> EvalLinearTransform(const std::vector<ReadOnlyPlaintext>& A,
ConstCiphertext<DCRTPoly>& ct) const;

/**
* Homomorphic encoding (CoeffsToSlots) over multiple BSGS levels, evaluated
* with Horner giant steps to minimize the number of rotation keys.
* @param A precomputed encoding plaintexts, one inner vector per BSGS level
* @param ctxt input ciphertext
*/
Ciphertext<DCRTPoly> EvalCoeffsToSlots(const std::vector<std::vector<ReadOnlyPlaintext>>& A,
ConstCiphertext<DCRTPoly>& ctxt) const;

/**
* Homomorphic decoding (SlotsToCoeffs); the inverse of EvalCoeffsToSlots,
* evaluated with the same Horner giant-step BSGS structure.
* @param A precomputed decoding plaintexts, one inner vector per BSGS level
* @param ctxt input ciphertext
*/
Ciphertext<DCRTPoly> EvalSlotsToCoeffs(const std::vector<std::vector<ReadOnlyPlaintext>>& A,
ConstCiphertext<DCRTPoly>& ctxt) const;

Expand Down Expand Up @@ -329,6 +352,19 @@ class FHECKKSRNS : public FHERNS {
static Ciphertext<DCRTPoly> EvalAddExt(ConstCiphertext<DCRTPoly> ciphertext1,
ConstCiphertext<DCRTPoly> ciphertext2);

// Loads the loop-invariant automorphism key, index and O(N) permutation map for a constant
// Horner giant stride, so they are built once instead of re-derived inside the BSGS
// accumulation loop. Shared by the bootstrapping and scheme-switching linear transforms.
static EvalKey<DCRTPoly> GetGiantStepRotation(ConstCiphertext<DCRTPoly> ct, int32_t stride, uint32_t& autoIndex,
std::vector<uint32_t>& map);

// Inlined giant-step rotation for the Horner accumulation: equivalent to
// EvalFastRotationExt(KeySwitchDown(outer), stride, precompute(.), addFirst=true), reusing the
// caller-supplied loop-invariant (autoIndex, map, giantKey) from GetGiantStepRotation.
static Ciphertext<DCRTPoly> EvalHornerGiantRotate(ConstCiphertext<DCRTPoly> outer, uint32_t autoIndex,
const std::vector<uint32_t>& map,
const EvalKey<DCRTPoly>& giantKey);

static EvalKey<DCRTPoly> ConjugateKeyGen(const PrivateKey<DCRTPoly> privateKey);

static Ciphertext<DCRTPoly> Conjugate(ConstCiphertext<DCRTPoly> ciphertext,
Expand Down
Loading