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.
Prerequisites
Have a CKKS configuration, an input-state and magnitude contract, and the resources required by the selected components. Use the experimental example with synthetic data before applying a new coordinate or depth schedule.
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_depth=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
bootstrap.input_depth, with input precision suitable for the circuit; - every batch member uses all
slots and the 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_depth; - the supplied
EvaluationKeySetcontains the reported rotations and the compatible relinearization and conjugation capabilities.
Construction checks structural-base/default-scale proximity, transform slot counts, target depth, 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
BootstrapArithmetic selects config.default_scale.
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 depth cost in the component's declared depth budget.
Polynomial evaluators derive their basis scale recurrence from the input's actual scale. This preserves the polynomial's coefficients and does not require guessing a full-slot stage's target scale. For a high-degree polynomial, inspect arithmetic.for_input(value, depths).target_scales when planning precision. If the resulting scalar plaintexts cannot fit the integer encoding range, prepare the value with arithmetic.advance_depth(value) and include that real transition in the depth budget; evaluation does not add it silently.
Change the complete topology
A complete custom algorithm is a Python callable. BootstrapArithmetic owns one Engine plus the prepared-constant cache used by Bootstrap's depth-dependent multiplication, depth advancement, and scalar operations. Pass that owner to component evaluate() methods so nested reduction and polynomial schedules share the same material lifecycle. Application code may interleave these components with ordinary Engine operations in any order:
class MyBootstrap:
def __init__(self, engine, reduction):
self.engine = engine
self.arithmetic = bs.BootstrapArithmetic(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.arithmetic,
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
38
Document the custom callable's tensor axes, depth/scale/domain/basis transitions, raw range, normalization owner, and output target. Ordinary dictionaries or tensors can hold caches; runtime value serialization and artifact facilities remain available for persistence.
Generate or supply keys
from fhelium.values 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="direct" requests a direct key for every transform rotation. "power_of_two" stores compact signed-power keys and composes missing direct 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. Their documented setup is:
from fhelium.eager import Engine
config = fh.CkksConfig.parse(
fh.Preset.slots32768_scale50_depth27_int64,
galois_generator=5,
)
engine = Engine(config)2
3
4
5
6
7
Factories do not enforce this 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.
Verify the outcome
Inspect the composed plan, compare its clear reference and encrypted evaluation on the supported input range, and account for output depth and actual scale. examples/25_experimental_bootstrap.py provides an end-to-end composition; bootstrap internals describes component contracts.