ModRaise, CoeffToSlot (a homomorphic DFT evaluated with baby-step giant-step rotations), EvalMod (a polynomial approximation of modular reduction) and SlotToCoeff, with exact operation counts per stage, where the levels go, and the data-movement profile that makes bootstrapping a memory problem.
Concepts used here, and where they are explained. Each links to its series glossary entry: a short explanation, then links to the slides that explain it in depth, in this series, the Cryptography decks or LLM Inference Simulators.
Each multiplication consumes a level (deck 01). When a ciphertext reaches level 0 it cannot be multiplied again. Bootstrapping homomorphically evaluates (an approximation of) decryption to produce an equivalent ciphertext at a high level. For CKKS the standard pipeline is that of Cheon, Han, Kim, Kim and Song (EUROCRYPT 2018, ePrint 2018/153), refined by Han & Ki (ePrint 2019/688) and Bossuat et al. (EUROCRYPT 2021, ePrint 2020/1203):
The orange stages are rotation-heavy and key-hungry; EvalMod is multiplication-heavy and reuses one relinearisation key. That difference drives everything in decks 03–05.
SlotToCoeff can run first, on the nearly exhausted input, before ModRaise (OpenFHE's BTSlotsEncoding option). Its rotations then use keys with few limbs, its levels are no longer taken from the top of the chain, and for real-valued data EvalMod runs once instead of twice. In the companion model (option stc_first) the ark-set bootstrap leaves 10 levels instead of 7 and takes 11.51 ms instead of 13.94 ms on the ARK-class design. OpenFHE's own StC-first trace shows the same shape (examples/results.md OpenFHE's own StC-first trace shows the same shape (examples/results.md §19 in the code repo).sect;19 in the code repo).
Encoding uses a DFT-like map (the canonical embedding). To operate on the polynomial's coefficients, which is where q0·I lives, bootstrapping applies the inverse encoding map homomorphically.
ARK (arXiv:2205.00922) quotes the same structure: with k = 5 over 3 levels, "40 HRots and 158 PMults" per homomorphic DFT. The companion model, without ARK's further optimisations, does 43 and 189.
A matrix-vector product with d diagonals needs d rotations if done directly. BSGS splits d = n1 × n2: rotate the input n1−1 times (baby steps), form n2 inner sums with pre-rotated diagonals, and rotate each sum once (giant steps).
After CoeffToSlot the slots hold the coefficients t = m + q0·I (scaled). EvalMod computes t mod q0, which is not a polynomial, so it is approximated: (q0/2π)·sin(2πt/q0) is close to t mod q0 when m is small. In practice this means a scaled cosine evaluated with Chebyshev polynomials, followed by double-angle steps cos(2x) = 2cos2x − 1.
| Step (one copy, ark set) | HMults | Levels |
|---|---|---|
| Scale into the approximation interval (a constant multiply) | 0 | 1 |
| Baby powers T2…T8 (degree 59 → b = 8) | 7 | 3 |
| Giant powers T16, T32 | 2 | (in parallel) |
| 8 baby polynomials (constant multiply-adds), then combine (g = 8) | 7 | 1 + 3 |
| 2 double-angle steps | 2 | 2 |
| Total per copy | 18 | 10 |
| Parameter set | L | CoeffToSlot | EvalMod | SlotToCoeff | Used by bootstrap | Left for the application |
|---|---|---|---|---|---|---|
| ark | 23 | 3 | 10 | 3 | 16 | 7 |
| lattigo | 24 | 3 | 10 | 3 | 16 | 8 |
| gpu100x | 34 | 3 | 10 | 3 | 16 | 18 |
| openfhe-sparse (8 slots) | 18 | 1 | 14 | 1 | 16 | 2 |
| openfhe-full14 (N = 214) | 30 | 3 | 14 | 3 | 20 | 10 |
One full-slot bootstrap of the ark set, baseline algorithm (hoisted BSGS). "Requested" bytes are what the operations need, before any on-chip reuse; deck 03 turns them into actual HBM traffic.
| Stage | HE ops | HMult | HRot | PMult | Distinct keys | NTT + iNTT limbs | Key GB requested | Plaintext GB requested |
|---|---|---|---|---|---|---|---|---|
| ModRaise | 1 | 0 | 0 | 0 | 0 | 50 | 0.00 | 0.00 |
| CoeffToSlot | 75 | 0 | 43 | 189 | 43 | 5,520 | 5.22 | 2.28 |
| EvalMod | 55 | 36 | 0 | 0 | 1 | 5,968 | 2.66 | 0.00 |
| SlotToCoeff | 72 | 0 | 42 | 189 | 42 | 2,172 | 1.41 | 0.99 |
A bootstrap alternates between a bandwidth-bound phase and a compute-bound phase, so no single roofline point describes it. That is the reason to simulate it as a sequence of operations rather than estimate it from totals. The analytic bound in deck 03 is 28% below the simulated time for exactly this reason.
"All three" is Min-KS + seeded keys + on-the-fly plaintexts (slide 11). This runs the simulator's trace generator in the browser (the same JavaScript that powers deck 03) and counts operations and requested bytes per stage. No timing here, only the workload.
Each technique changes the workload, not the hardware. Effects on one ark-set bootstrap, from the companion trace generator:
| Technique | What it does | Effect on the workload |
|---|---|---|
| Hoisting (default) | Baby-step rotations share one ModUp | Fewer NTTs; same keys. Turning it off costs 15% more time on an NTT-starved design (deck 05) |
| Min-KS (ARK) | Apply baby and giant rotations iteratively by one fixed step, so a whole BSGS loop needs only 2 keys | CoeffToSlot keys: 43 → 7. Same rotation count, but hoisting is lost (more NTTs) and the rotations are serial |
| Seeded keys | The uniform half of each evaluation key is regenerated on chip from a seed | Key bytes halved; some PRNG work on the multiply-add lanes |
| On-the-fly plaintexts (in the spirit of ARK's OF-Limb) | Generate DFT diagonals on chip from a compact form instead of loading them | Plaintext bytes drop to one limb each; adds NTTs |
| OpenFHE's BSGS (lazy ModDown) | Keep rotations in the Q·P basis, multiply plaintexts there, ModDown once per DFT level; then baby steps cost no NTTs, so use many more of them | A third fewer transforms (13,710 → 9,234) but 109 rotations instead of 85, and plaintexts stored with the special limbs: right for a CPU, wrong for a memory-bound accelerator (deck 05) |
| SlotToCoeff first | Run SlotToCoeff before ModRaise, on the nearly exhausted input | 18 HMults instead of 36 (one EvalMod), 9,544 transforms instead of 13,710, keys 6.95 instead of 9.29 GB requested, and 10 levels left instead of 7. The only lever here that helps every design (deck 05) |
| Radix / level budget | More DFT levels → fewer rotations | Fewer keys and bytes, fewer useful levels; use the interactive slide |
Min-KS, seeded keys and on-the-fly plaintexts trade arithmetic for bytes; OpenFHE's BSGS trades bytes for arithmetic; SlotToCoeff first saves both. Whether that wins depends on whether the design is memory-bound or compute-bound, which is exactly what the simulator in deck 03 decides.
OpenFHE v1.5.1 was instrumented (an 82-line patch) to log every NTT, base conversion, key switch, automorphism, rescale and plaintext multiply of a bootstrap. Below is N = 214, 8,192 slots, level budget {3, 3}, dnum 3, against the model at the same parameters, run with the default (balanced) BSGS split and with OpenFHE's. Each cell reads OpenFHE / model / model with OpenFHE's BSGS (HMults: OpenFHE / model).
| Stage | Rotations | HMults | NTT + iNTT limbs | Key GB requested |
|---|---|---|---|---|
| CoeffToSlot | 46 / 35 / 51 | — | 2,419 / 5,151 / 2,025 | 1.45 / 1.13 / 1.64 |
| EvalMod | — | 48 / 56 | 20,411 / 11,816 / 11,816 | 1.05 / 1.28 / 1.28 |
| SlotToCoeff | 45 / 34 / 50 | — | 1,025 / 2,494 / 854 | 0.57 / 0.43 / 0.63 |
Deck 03 builds the accelerator model and runs this workload on it, live.