Compose a bootstrap callable
Compose CKKS bootstrapping through the experimental public component interfaces. Use FullSlotBootstrap with the standard full-slot topology and configurable mathematical strategies. Direct Python composition supports custom topologies.
Establish the coordinate convention
A periodic reduction has two coordinates:
- raw branch coordinate
, with the application precondition ; - normalized polynomial coordinate
, whereinput_bound.
The built-in target is
reference(values) always takes normalized evaluate(...) takes raw fuse_input_normalization=False; it takes already normalized FullSlotBootstrap honors fusion by folding
Assemble the built-in topology
from fhelium.experimental import bootstrap as bs
compiler = bs.Radix2FourierTransformCompiler(stage_count=2)
linear_evaluator = bs.DiagonalBSGSEvaluator(
baby_step=16,
hoist_baby_rotations=True,
)
modular_reduction = bs.CosineDoubleAngleReduction(
input_bound=1024,
double_angle_iterations=7,
approximator=bs.ChebyshevInterpolator(degree=44),
evaluator=bs.BinaryDecompositionChebyshevEvaluator(skip_near_zero=1e-15),
fuse_input_normalization=True,
)
bootstrap = bs.FullSlotBootstrap(
engine,
coeffs_to_slots_compiler=compiler,
coeffs_to_slots_evaluator=linear_evaluator,
modular_reduction=modular_reduction,
slots_to_coeffs_compiler=compiler,
slots_to_coeffs_evaluator=linear_evaluator,
modulus_raise_target_level=0,
retain_diagonals=False,
)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Before using this object, establish all of the following:
- the input is a two-component coefficient-domain standard-RNS Q ciphertext at the final public level and actual scale near
default_scaleor its square; - every batch member uses all
slots and the exact activeprime_ids; - both raw branch coordinates lie within
[-input_bound, input_bound]; - the selected polynomial degree and evaluator meet the application's error model;
- the modulus chain accommodates
bootstrap.output_level; - the supplied
RotationKeySetcontains the reported rotations, and compatible relinearization and conjugation keys are supplied separately.
Construction checks structural-base/default-scale proximity, transform slot counts, target level, and depth. It cannot inspect the encrypted coordinate range or certify an application error bound.
Replace BSGS with direct evaluation
The compiler synthesizes each transform; the evaluator decides how its stages are executed. Replacing BSGS with direct diagonal evaluation changes only the evaluator argument:
direct = bs.FullSlotBootstrap(
engine,
coeffs_to_slots_compiler=compiler,
coeffs_to_slots_evaluator=bs.DirectDiagonalEvaluator(),
modular_reduction=modular_reduction,
slots_to_coeffs_compiler=compiler,
slots_to_coeffs_evaluator=bs.DirectDiagonalEvaluator(),
)2
3
4
5
6
7
8
For a cyclic-diagonal stage
BSGS splits
They can differ in rotation inventory, operation ordering, memory use, and CKKS rounding, so compare decoded semantics rather than requiring bitwise residues.
Replace periodic reduction (modular_reduction)
exponential = bs.ExponentialSquaringReduction(
input_bound=1024,
degree=16,
evaluator=bs.BalancedPowerEvaluator(skip_near_zero=1e-15),
fuse_input_normalization=True,
)
bootstrap = bs.FullSlotBootstrap(
engine,
coeffs_to_slots_compiler=compiler,
coeffs_to_slots_evaluator=linear_evaluator,
modular_reduction=exponential,
slots_to_coeffs_compiler=compiler,
slots_to_coeffs_evaluator=linear_evaluator,
)2
3
4
5
6
7
8
9
10
11
12
13
14
15
The exponential component stores ascending power coefficients
Respect polynomial basis conventions
PolynomialApproximation uses ascending coefficients:
basis="power": ;basis="chebyshev": .
For an approximation designed on physical evaluate_plaintext() and homomorphic evaluators do not insert this affine map. Apply the input normalization and include the resulting level cost in the component's declared level budget.
Change the complete topology
A complete custom algorithm is a Python callable. It can invoke CkksEngine, component evaluate() methods, and application-specific code in any order:
class MyBootstrap:
def __init__(self, engine, reduction):
self.engine = engine
self.reduction = reduction
def __call__(
self,
ciphertext,
*,
rotation_keys,
relinearization_key,
conjugation_key,
):
prepared = my_centered_raise(self.engine, ciphertext)
slots = my_forward_transform(
self.engine,
prepared,
rotation_keys=rotation_keys,
)
branches = my_split_branches(
self.engine,
slots,
conjugation_key=conjugation_key,
)
reduced = [
self.reduction.evaluate(
self.engine,
my_normalize_raw_coordinate(branch),
relinearization_key=relinearization_key,
)
for branch in branches
]
return my_inverse_transform(
self.engine,
my_recombine_branches(reduced),
rotation_keys=rotation_keys,
)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Document the custom callable's exact tensor axes, level/scale/domain/basis transitions, raw range, normalization owner, and output target. Ordinary dictionaries or tensors can hold caches; core value serialization and artifact facilities remain available for persistence.
Generate or supply keys
from fhelium.core import EvaluationKeySet
rotation_keys = bootstrap.create_rotation_keys(
secret_key,
rotation_strategy="power_of_two",
)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
evaluation_keys = EvaluationKeySet(
rotations=rotation_keys,
relinearization=relinearization_key,
conjugation=conjugation_key,
)
refreshed = bootstrap(
ciphertext,
evaluation_keys=evaluation_keys,
)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rotation_strategy="exact" requests every mathematical transform rotation. "power_of_two" stores compact signed-power keys and composes missing exact steps online. Generate or provision the relinearization and conjugation keys independently because they serve different operations and are not part of the rotation inventory.
Use the versioned factories correctly
The experimental logn16 factory names identify documented bootstrap configurations rather than runtime validators. Their measured end-to-end setup is:
config = fh.CkksConfig.parse(
fh.Preset.slots32768_scale50_levels27_int64,
base_prime_bits=50,
)
engine = fh.CkksEngine(config, galois_generator=5, device="cuda:0")2
3
4
5
Factories do not enforce this exact preset and do not prove the raw branch range or output error. Treat a different engine, range, polynomial profile, or application tolerance as a new validation target.