CKKS bootstrap internals
This page specifies the mathematical, value-state, and actual-scale invariants of the built-in full-slot composition executed through CkksEngine.
Evaluator stack
fhelium.experimental.bootstrap compiles diagonal linear maps and polynomial approximations, then evaluates those stages through the ordinary CkksEngine, Ciphertext, NTT, and native-operator stack.
fhelium.experimental.bootstrap.presets constructs versioned measured compositions. Compiler and evaluator objects are paired by protocol: a compiler's stage representation must be understood by its matching evaluator, and their required_levels reports must match execution. Compiled diagonals, rotation decompositions, and ModRaise constants are Python/runtime resources; the dense arithmetic reaches fhelium_rns_ops, fhelium_ntt_ops, and fhelium_ckks_ops through the engine.
Notation
Let:
and ; beconfig.default_scale; beengine.public_level_count, so the final public level is ; be the leading scale prime at level ; be the final structural Q prime; be the exact ordered Q basis named byengine.rns_layout.prime_ids(level=ell); and be the unscaled CoeffsToSlots and SlotsToCoeffs maps; bemodular_reduction.input_bound; bemodular_reduction.fused_input_divisor, either or for the built-in reducers.
The radix-2 compiler convention is
A plaintext reference round trip therefore compiles scale=1.0 and scale=1.0 / S.
Entry and structural-base transition
The input is a two-component coefficient-domain, standard-residue Q ciphertext at final public level [component, *batch, limb, coefficient], coefficient extent prime_ids. At that level the Q basis is [q_s, q_b].
The accepted actual scale
If
is near ,_prepare_entry()multiplies by an NTT/Montgomery RNS encoding of at scale . The level and basis do not change, the ciphertext remains coefficient-domain standard RNS, and the pending scale isIf
is already near , the value passes through and ._rescale_to_structural_base()applies nearest-integer division by :It removes the
row, enters private internal level over[q_b], and then deliberately changes only metadata from to . This reinterpretation changes the represented message by the factor ; it is not an exact-scale rescale result.
This private structural level is not a public CKKS computation level.
Centered ModRaise
For every ciphertext component and polynomial coefficient, centered ModRaise chooses the unique source representative
consistent with the residue modulo modulus_raise_target_level. It is a component-wise centered basis extension, not rescale or modulus restriction.
The transition is
level L, prime_ids [q_b], coefficient, standard, Q, two components, scale Delta_0
->
level ell_r, prime_ids Q_ell_r, coefficient, standard, Q, two components,
scale Delta_02
3
4
Data axes and batch shape are preserved; the limb extent changes from one to len(Q_ell_r). Production execution uses mixed-radix native operators. The slow reference_centered_basis_extend() oracle reconstructs with Python integers and returns a tensor shaped [*batch, target_limb, coefficient] in standard residues on the input device.
ModRaisedCiphertext privately records the source level, source prime_ids, source modulus width, and scale. _apply_modraised_linear() requires that provenance for the first linear map and then returns a core Ciphertext. This prevents a centered-raised value from being mistaken for an unrelated public Q ciphertext.
Cyclic-diagonal linear maps
A DiagonalLinearTransform stores one CPU complex128 vector [slot] for each signed rotation offset
where Rot_k matches numpy.roll(x, k). reference(values) accepts exactly one vector of shape [slot], returns the same shape, and performs neither CKKS encoding nor scale or level simulation.
The direct evaluator rotates, plaintext-multiplies, and sums all diagonal terms, then rescales once. BSGS writes
BSGS rescaling of each giant-group accumulator is algebraically equivalent to the direct sum's single rescale because all group terms share the same pending scale. The schedules have the same map and state transition, but different rounding order can prevent bitwise equality.
For either evaluator, diagonal plaintexts are unbatched [limb, ntt_index] tensors in NTT domain with Montgomery residues, Q basis, actual scale prime_ids. An unbatched diagonal broadcasts across homogeneous ciphertext batch axes. If a stage starts at level
The result has axes [component, *batch, limb, coefficient], two components, coefficient domain, standard residues, Q basis, and prime_ids with the leading row removed. Ordinary transform stages do not reinterpret scale metadata.
CoeffsToSlots, branch split, and coordinates
Construction compiles numerical factors
The factors multiply diagonal values; they are distinct from the diagonal plaintext's metadata scale
After the compiled CoeffsToSlots stages, _multiply_scalar(..., 1 / S) consumes one level and explicitly returns scale
Conjugation gives
- if normalization is not fused,
and the reducers receive raw coordinates and ; - if normalization is fused,
and they receive normalized coordinates and .
Conjugation, branch addition/subtraction, and monomial multiplication preserve level, actual scale, two components, Q basis, domain, residue representation, and exact prime_ids.
Periodic reduction
The raw coordinate is
Both built-in reducers target
For
The method inputs deliberately differ:
reference(values)always consumes normalized and applies the fitted polynomial and recurrence directly;- non-fused
evaluate(...)consumes raw and spends one scalar-multiply level computing ; - fused
evaluate(...)assumes the caller already supplied .
Cosine recurrence
For double_angle_iterations, the fitted seed is
followed by
The final value approximates
Exponential recurrence
The power-basis seed truncates
For
The output of each built-in reduction is a functional two-component, coefficient-domain standard-RNS Q ciphertext at input level plus required_levels, actual scale prime_ids.
Polynomial basis and evaluator requirements
PolynomialApproximation.coefficients is always ascending degree:
ChebyshevInterpolator maps a physical coordinate
Its returned coefficients are functions of domain records evaluate_plaintext() and the homomorphic evaluators do not apply this affine normalization. The caller must provide the basis coordinate and account for any level required to compute it.
BalancedPowerEvaluator uses shared balanced powers. BinaryDecompositionChebyshevEvaluator uses
Both consume a two-component coefficient-domain standard-RNS Q ciphertext and return the same state at the declared deeper level. Ciphertext products temporarily enter NTT/Montgomery form, produce three components, relinearize to two coefficient-domain components, rescale, and reinterpret at
Recombination, SlotsToCoeffs, and output
After periodic reduction, multiplication of the imaginary result by
The compiled SlotsToCoeffs factor
There is no final implicit reset to
where modular_reduction.required_levels. The output is a functional two-component coefficient-domain standard-RNS Q ciphertext with unchanged batch axes and exact Q_ell_out prime_ids.
Primitive keys, caches, and factory requirements
required_rotations is the union of direct or BSGS transform offsets. key_steps("exact") returns that inventory. key_steps("power_of_two") returns signed-power components that _rotate_with_key_inventory() composes online. create_rotation_keys() generates only the selected RotationKeySet. The callable accepts that set and a ConjugationKey as required keyword-only arguments, plus an optional RelinearizationKey. Built-in reductions reject a missing relinearization key; a custom slotwise reduction without ciphertext products may omit it. Branch splitting always requires conjugation, and the same primitive is passed to the reduction for algorithms such as exponential sine extraction. The replaceable reduction stage is slotwise and does not receive or add rotation-key requirements.
The callable's optional diagonal cache retains prepared plaintexts. Its rotation cache contains integer decompositions, and its ModRaise cache contains modulus-dependent arithmetic tables. clear_cache() releases all three. None is part of ciphertext identity or serialized arithmetic state.
The versioned logn16 factories document a measured configuration derived from Preset.slots32768_scale50_levels27_int64 with base_prime_bits=50 and bound to an engine using galois_generator=5. Construction enforces only:
- a valid target level;
;- nonempty compiled transforms with the engine's slot count;
- sufficient public Q depth for the declared component costs.
The application must establish the input-range bound, validate numerical accuracy, and define workload benchmark acceptance criteria. Construction does not verify derivation from the documented preset baseline or certify those workload properties.