Scale, depth, and RNS execution
A CKKS parameter set determines how encoded magnitude is tracked, how many rescale transitions a circuit can consume, and which prime basis represents a value. The Engine derives its native residue format from those exact primes. This page traces that relationship from a value's scale to the kernel selected at execution.
Scale tracks encoded magnitude
A plaintext or ciphertext with actual scale value.scale stores this positive binary64 number.
Scale bits means
It is a reporting and planning quantity. For example, “scale 50” means config.default_scale supplies the initial value when encoding or encryption does not receive a caller-selected scale.
Multiplication and rescaling update actual scale as follows:
Depth selects the active Q basis
CkksConfig partitions the ciphertext modulus Q into ordered depth groups:
The public depth interval is config.max_depth == D. At depth rescale_to_next_depth call removes the complete group
The number of public transitions still available is
This is a count of available transitions, not an operation history. The caller chooses when to rescale; multiple multiplications can precede one rescale. Actual scale and the active modulus determine whether that schedule preserves the required numerical range and precision.
FHElium exposes these quantities directly:
config.max_depth
config.q_depth_groups
config.rescale_divisor(depth)
engine.depth_remaining(ciphertext)2
3
4
A depth group determines both scale reduction and RNS work
A parameter planner commonly chooses
G_d = [one prime near 2^50]
G_d = [two primes near 2^25 whose product is near 2^50]2
Both groups consume one CKKS depth and divide scale by approximately
This is why q_depth_groups stores nested prime groups rather than a flat prime count. Semantic depth follows the outer group sequence; NTT, key-switch, and RNS work follow the flattened prime rows.
Residue words and the represented integer
For active prime product
RNS dtype therefore controls the word size and modular arithmetic for each row. The prime set controls the total represented modulus, while the actual scale controls the interpretation of the encoded magnitude. These quantities are independent coordinates. Integers, RNS, and CRT defines forward reduction, reconstruction, and centered representatives.
Encoding and RNS materialization
Encoding and residue execution use two consecutive representations:
slots
-> signed int64 integer coefficients
-> residues modulo every active Q prime
-> Engine-selected integral RNS Tensor2
3
4
The encoder uses int64 to hold signed integer coefficients before modular reduction. integer_coefficients_to_rns reduces each coefficient modulo the active primes and writes the result in engine.dtype. Ciphertexts and live keys retain that RNS dtype.
Execution-format selection and kernel dispatch
When an Engine is constructed, RnsExecutionFormat.select examines every exact Q and P modulus in the configuration and chooses the narrowest supported residue Tensor and Montgomery-radix pairing. engine.dtype reports the result. An expert rns_dtype= argument requests a supported Tensor dtype; construction checks that every configured prime fits the corresponding lazy-reduction range. The Engine uses one format for its lifetime. Device-local RnsContext resources own the dense RNS parameters and residue-representation arithmetic in that format. NttContext composes that RNS context and owns the selected NTT policy, transform tables, and transforms; CKKS preparation supplies the basis-conversion and key-switch materials needed by the chosen operations.
The registered CKKS and RNS operations have shared schemas. Native dtype dispatch selects the scalar specialization of the same implementation. The operation graph, Ciphertext type, depth transition, and Backend registration remain unchanged.
Worked transition
Consider a configuration with
default_scale = 2^50
max_depth = 26
G_0 = [q_0a, q_0b]
q_0a, q_0b < 2^30
q_0a * q_0b approximately 2^50
all remaining Q and P primes below 2^302
3
4
5
6
A fresh ciphertext begins with
depth = 0
depth_remaining = 26
scale = 2^502
3
Multiplying two such ciphertexts produces scale
The result has depth_remaining == 25. The rescale implementation executes two prime-row division steps internally, but they implement one CKKS depth transition. Its RNS kernels use the format selected from the complete prime set when the Engine was built.