fhelium.eager
Construct and execute CKKS operations with runtime-owned resources.
Engine accepts a CKKS configuration and creates device-local arithmetic and random resources when a call first selects each device. Source factories use PyTorch's default device unless the caller supplies device. The Engine owns key lifecycles and does not copy key material across devices unless automatic replication is enabled. Evaluator calls dispatch from operand placement, update public metadata, and invoke registered Tensor operations. Program compilation and execution belong to Backend and its Compile callers.
Engine
class View source
Engine(ckks_config: CkksConfig | Preset | dict[str, object] | None=None, *, ntt_backend: str | None=None, rns_dtype: torch.dtype | None=None, rng_seed: int | None=None, rng_nonce: int | None=None, allow_automatic_key_generation: bool=True, allow_automatic_key_replication: bool=False)Own eager CKKS configuration and per-device execution resources.
Cheon-Kim-Kim-Song (CKKS) ciphertexts encode approximate complex slot values as polynomials. A two-component ciphertext (CT2) has phase
Source factories use PyTorch's default device when the caller omits device. Tensor-consuming operations dispatch from operand placement and do not move operands implicitly. A boundary device= authorizes movement of that boundary's public value. Key material is not copied between devices unless the caller places it there or enables automatic key replication. Each used device owns its arithmetic tables, random stream, direct-dispatch entries, and key bindings.
rotation_key_steps
method
def rotation_key_steps(step: int) -> tuple[int, ...]: ...Describe a rotation's key path without generating or moving keys.
A direct installed key takes precedence. When automatic generation is enabled, a missing direct key is represented by its normalized step. Otherwise the path is decomposed using installed rotation steps only. A zero rotation requires no key.
config
property
config: CkksConfigReturn the Engine's fixed CKKS configuration.
galois_generator
property
galois_generator: intReturn the Engine's Galois generator.
ntt_backend_name
method
def ntt_backend_name(device: torch.device | str) -> str: ...Return the NTT backend selected for one concrete device.
ring_dimension
property
ring_dimension: intReturn the Engine's polynomial ring dimension.
depth0_qp_prime_ids
property
depth0_qp_prime_ids: tuple[int, ...]Return the depth-zero QP prime identifiers.
key_digit_count
property
key_digit_count: intReturn the hybrid key-switch digit count.
dtype
property
dtype: torch.dtypeReturn the Engine's RNS storage dtype.
max_depth
property
max_depth: intReturn the greatest public CKKS depth in this Engine.
depth_remaining
method
def depth_remaining(value: Ciphertext | Plaintext | int) -> int: ...Return how many public rescale transitions remain.
num_slots
property
num_slots: intReturn the number of complex slots in one CKKS polynomial.
create_secret_key
method
def create_secret_key(*, modulus_basis: Literal['Q', 'QP']='QP', device: torch.device | str | None=None) -> SecretKey: ...Sample the secret polynomial and materialize its RNS transforms.
The key generator samples ternary coefficients CkksKeyGenerator.create_secret_key.
create_public_key
method
def create_public_key(secret_key: SecretKey, *, modulus_basis: Literal['Q', 'QP']='Q', device: torch.device | str | None=None) -> PublicKey: ...Generate a public-key pair for a secret polynomial.
For a sampled uniform polynomial CkksKeyGenerator.create_public_key.
create_key_switch_key
method
def create_key_switch_key(source_secret_key: SecretKey, destination_secret_key: SecretKey, *, uniform_component_by_key_digit: torch.Tensor | None=None, device: torch.device | str | None=None) -> KeySwitchKey: ...Generate hybrid-RNS material from one secret relation to another.
For source and destination secrets [digit, component=2, QP row, NTT index] data in NTT/Montgomery form.
create_relinearization_key
method
def create_relinearization_key(secret_key: SecretKey, *, device: torch.device | str | None=None) -> RelinearizationKey: ...Generate key-switch material from
This is the evaluation key used to replace the CkksKeyGenerator.create_relinearization_key in NTT/Montgomery form.
create_rotation_key
method
def create_rotation_key(rotation_step: int, secret_key: SecretKey, *, device: torch.device | str | None=None) -> RotationKey: ...Generate key-switch material from
The signed slot displacement is normalized modulo the slot count and mapped to an odd Galois element
create_conjugation_key
method
def create_conjugation_key(secret_key: SecretKey, *, device: torch.device | str | None=None) -> ConjugationKey: ...Generate key-switch material from
The automorphism CkksKeyGenerator.create_conjugation_key returns the QP NTT/Montgomery key digits needed to restore the original secret relation.
plaintext
method
def plaintext(message: Sequence[object] | torch.Tensor | complex | float | int, *, depth: int=0, scale: float | None=None, device: torch.device | str | None=None) -> Plaintext: ...Wrap ordered public slots with planned CKKS depth and actual scale.
This method stores the message tensor without applying the CKKS embedding. encode later maps the slots to a polynomial. scale defaults to the configuration's planning value but is stored on this plaintext as its own actual scale.
encode
method
def encode(message: Sequence[object] | torch.Tensor | complex | float | int, *, depth: int=0, scale: float | None=None, device: torch.device | str | None=None) -> Plaintext: ...Encode ordered CKKS slots as scaled integer coefficients.
For the configured embedding ckks.EncodeOp to native-ckks-encode and returns coefficient-domain integer_coefficients state at depth; no RNS prime rows exist yet.
prepare_compressed_plaintext
method
def prepare_compressed_plaintext(message: Sequence[object] | torch.Tensor | complex | float | int, *, depth: int=0, scale: float | None=None, modulus_basis: Literal['Q', 'QP']='Q', polynomial_domain: Literal['coefficient', 'ntt']='ntt', device: torch.device | str | None=None) -> CompressedPlaintext: ...Prepare compact Montgomery plaintext from one period of slots.
The last message axis is repeated semantically to fill N/2 slots. For U=2r (at least four with generator 3) and R=N/U, p(X)=a(X^R) is encoded using only U coefficients and U values per prime row. Random rounding uses the full-ring coefficient word positions and advances by N words per batch item. Coefficient output stores U coefficients with zero implicit rows in strided-sparse layout. NTT output stores U values in contiguous layout, each representing R repeated evaluations. Depth, selected Q/QP rows and actual scale are retained. The reduced FFT can differ in floating-point roundoff from encoding a fully expanded message near quantization thresholds.
integer_coefficients_to_rns
method
def integer_coefficients_to_rns(plaintext: Plaintext, *, modulus_basis: Literal['Q', 'QP']='Q') -> Plaintext: ...Reduce an integer plaintext polynomial into active prime rows.
At plaintext depth QP, ckks.IntegerCoefficientsToRnsOp dispatches to native-ckks-integer-coefficients-to-rns. The result is coefficient-domain standard RNS with unchanged depth and actual scale.
prepare_plaintext_for_addition
method
def prepare_plaintext_for_addition(plaintext: Plaintext, *, modulus_basis: Literal['Q', 'QP']='Q', polynomial_domain: PolynomialDomain='coefficient') -> Plaintext: ...Prepare a plaintext for modular addition to component zero.
The method first issues ckks.IntegerCoefficientsToRnsOp as needed, then rns.StandardToMontgomeryOp. polynomial_domain="ntt" also transforms the prepared polynomial for direct addition to an NTT/Montgomery ciphertext. Message, depth, actual scale, and requested Q or QP rows are unchanged.
prepare_plaintext_for_multiplication
method
def prepare_plaintext_for_multiplication(plaintext: Plaintext, *, modulus_basis: Literal['Q', 'QP']='Q') -> Plaintext: ...Prepare a plaintext for pointwise NTT ciphertext multiplication.
After addition preparation, the method dispatches ntt.CoefficientMontgomeryToNttMontgomeryOp. Every active-prime polynomial is transformed while retaining its Montgomery factor. Depth and plaintext actual scale remain unchanged for the eventual rns.MultiplyPlaintextOp.
prepare_public_operand
method
def prepare_public_operand(public: object, ciphertext: Ciphertext, *, operation: Literal['add', 'multiply'], source_role: Literal['message', 'plaintext', 'static'], scale_mode: Literal['runtime_plaintext_scale', 'default_scale', 'ciphertext_scale']) -> Plaintext: ...Prepare a typed public value for encrypted addition or multiplication.
Addition selects the ciphertext actual scale so the prepared plaintext can be added to component zero. Multiplication retains a supplied plaintext scale or uses the configured default for a message/static value; its scale later multiplies the ciphertext scale. This Eager method composes ckks.EncodeOp and registered RNS/NTT transitions.
decode
method
def decode(plaintext: Plaintext, *, is_real: bool=False, device: torch.device | str | None=None) -> torch.Tensor: ...Decode coefficient data into the configured CKKS slot order.
For coefficient polynomial is_real takes the real part after embedding. The method dispatches ckks.DecodeOp to native-ckks-decode; RNS plaintexts must first be reconstructed to bounded coefficient data.
encrypt
method
def encrypt(plaintext: Plaintext, public_key: PublicKey | None=None, *, device: torch.device | str | None=None, output_domain: PolynomialDomain='coefficient') -> Ciphertext: ...Encrypt an integer coefficient plaintext under a public key.
For public key ckks.EncryptOp computes native-ckks-encrypt implementation returns a CT2 Q or QP ciphertext with the plaintext's depth and actual scale. output_domain selects coefficient/standard or NTT/Montgomery output. NTT output transforms the error-and-message terms and adds them directly to the public-key products.
decrypt
method
def decrypt(ciphertext: Ciphertext, secret_key: SecretKey | None=None, *, device: torch.device | str | None=None) -> Plaintext: ...Evaluate the ciphertext phase and reconstruct bounded coefficients.
For CT2 the phase is
encrypt_message
method
def encrypt_message(message: Sequence[object] | torch.Tensor | complex | float | int, public_key: PublicKey | None=None, *, depth: int=0, scale: float | None=None, device: torch.device | str | None=None, output_domain: PolynomialDomain='coefficient') -> Ciphertext: ...Encode slots and encrypt the resulting polynomial.
This composes encode and encrypt: it forms ckks.EncodeOp and ckks.EncryptOp. The output records the selected depth, actual scale, public-key basis, and coefficient/standard representation.
decrypt_message
method
def decrypt_message(ciphertext: Ciphertext, secret_key: SecretKey | None=None, *, is_real: bool=False, device: torch.device | str | None=None) -> torch.Tensor: ...Decrypt a ciphertext phase and decode its CKKS slots.
This composes ckks.DecryptOp with ckks.DecodeOp. It reconstructs an approximate coefficient polynomial is_real projects the decoded slots to their real parts.
zero_plaintext_like
method
def zero_plaintext_like(plaintext: Plaintext) -> Plaintext: ...
def zero_plaintext_like(plaintext: CompressedPlaintext) -> CompressedPlaintext: ...2
Create independent zero storage in the input's represented state.
Compact explicit entries and sparse implicit rows are both zeroed. Depth, scale, layout, prime rows, domain and residue form are retained.
encrypt_zero_like
method
def encrypt_zero_like(ciphertext: Ciphertext, public_key: PublicKey | None=None) -> Ciphertext: ...Return a randomized encryption of zero in a ciphertext's represented state.
The method encodes and encrypts a zero slot vector at the reference depth and actual scale, then applies the same registered NTT transition if the reference is in NTT/Montgomery form. The result decrypts to encryption noise around zero and has matching Q or QP rows and representation.
install_evaluation_key
method
def install_evaluation_key(symbol: str, key: KeySwitchKey) -> None: ...Install one validated evaluation key under an inventory name.
remove_evaluation_key
method
def remove_evaluation_key(symbol: str) -> None: ...Remove one installed evaluation-key binding if present.
secret_key
property
secret_key: SecretKeyReturn the installed secret key, generating one when permitted.
set_secret_key
method
def set_secret_key(key: SecretKey | None) -> None: ...Install or remove the secret key and invalidate dependent keys.
public_key
property
public_key: PublicKeyReturn the installed public key, generating one when absent.
set_public_key
method
def set_public_key(key: PublicKey | None) -> None: ...Install or remove the public encryption key.
relinearization_key
property
relinearization_key: RelinearizationKeyReturn installed relinearization material, generating it when absent.
set_relinearization_key
method
def set_relinearization_key(key: RelinearizationKey | None) -> None: ...Install or remove relinearization material.
rotation_keys
property
rotation_keys: dict[int, RotationKey]Return the normalized rotation-key map.
rotation_key
method
def rotation_key(step: int) -> RotationKey: ...Return rotation material for step, generating it when permitted.
set_rotation_key
method
def set_rotation_key(key: RotationKey) -> None: ...Install a key under its normalized self-described rotation step.
conjugation_key
property
conjugation_key: ConjugationKey | NoneReturn installed conjugation material, if any.
set_conjugation_key
method
def set_conjugation_key(key: ConjugationKey | None) -> None: ...Install or remove conjugation material.
validate_ciphertext
method
def validate_ciphertext(value: Ciphertext) -> None: ...Validate a ciphertext against this runtime's complete RNS layout.
validate_public_key
method
def validate_public_key(key: PublicKey) -> None: ...Validate public encryption material against this runtime.
validate_secret_key
method
def validate_secret_key(key: SecretKey) -> None: ...Validate secret-key storage and context against this runtime.
validate_key_switch_key
method
def validate_key_switch_key(key: KeySwitchKey) -> None: ...Validate key-switch material against this runtime.
reconstruct_q_coefficients
method
def reconstruct_q_coefficients(residues: torch.Tensor, ciphertext: Ciphertext) -> torch.Tensor: ...Reconstruct centered coefficients from all active Q rows.
The active Q basis represents each coefficient modulo its product
add
method
def add(lhs: Ciphertext, rhs: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...Add ciphertext components modulo every active prime.
Inputs have matching component, row, polynomial-domain, residue, and scale state, with residues in each prime's standard storage range. For each component rns.AddStandardOp to native-rns-linear. Component count, depth, prime rows, polynomial domain, residue representation, and actual scale are preserved; inplace=True writes the same result into lhs.
add_
method
def add_(lhs: Ciphertext, rhs: Ciphertext) -> Ciphertext: ...Add
This is the in-place form of add and dispatches rns.AddStandardOp. All represented state is preserved.
add_scalar
method
def add_scalar(ciphertext: Ciphertext, scalar: int | float, *, scalar_scale: float | None=None) -> Ciphertext: ...Add a quantized real scalar to the constant coefficient of
For scalar ckks.AddScalarOp samples
sum_ciphertexts
method
def sum_ciphertexts(ciphertexts: Sequence[Ciphertext]) -> Ciphertext: ...Sum a non-empty sequence by repeated modular ciphertext addition.
The method clones the first value and repeatedly dispatches rns.AddStandardOp. Mathematically each output component is
sum_ciphertext_batch
method
def sum_ciphertext_batch(batch: Ciphertext, *, dim: int=0) -> Ciphertext: ...Reduce one batch axis by modular ciphertext addition.
rns.SumStandardBatchOp computes, for every component
subtract
method
def subtract(lhs: Ciphertext, rhs: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...Subtract ciphertext components modulo every active prime.
Inputs have matching component, row, polynomial-domain, residue, and scale state, with residues in each prime's standard storage range. For each component rns.SubtractStandardOp to native-rns-linear and preserves depth, scale, prime rows, component count, polynomial domain, and residue representation. inplace=True writes into lhs.
subtract_
method
def subtract_(lhs: Ciphertext, rhs: Ciphertext) -> Ciphertext: ...Subtract
This in-place form dispatches rns.SubtractStandardOp and retains the ciphertext's represented state.
negate
method
def negate(value: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...Negate every ciphertext component modulo its active primes.
Residues may describe coefficient polynomials or NTT values but must be in each prime's standard storage range. For each component and prime row, rns.NegateStandardOp computes native-rns-linear. The result decrypts to the additive inverse and preserves depth, actual scale, rows, component count, and representation.
negate_
method
def negate_(value: Ciphertext) -> Ciphertext: ...Negate every component of
This is the in-place rns.NegateStandardOp path; all represented state is unchanged.
coefficient_domain_to_ntt_domain
method
def coefficient_domain_to_ntt_domain(value: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...
def coefficient_domain_to_ntt_domain(value: Plaintext, *, inplace: bool=False) -> Plaintext: ...2
Apply the forward negacyclic NTT to every RNS polynomial.
For ciphertext standard residues, each component dispatches ntt.CoefficientStandardToNttMontgomeryOp and stores ntt.CoefficientMontgomeryToNttMontgomeryOp. Depth, prime rows, basis, component shape, and actual scale are preserved; the result state is NTT/Montgomery.
coefficient_domain_to_ntt_domain_
method
def coefficient_domain_to_ntt_domain_(value: Ciphertext) -> Ciphertext: ...
def coefficient_domain_to_ntt_domain_(value: Plaintext) -> Plaintext: ...2
Transform
This dispatches the same registered NTT operation as coefficient_domain_to_ntt_domain and returns the input object with unchanged depth, prime rows, and actual scale.
ntt_domain_to_coefficient_domain
method
def ntt_domain_to_coefficient_domain(value: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...
def ntt_domain_to_coefficient_domain(value: Plaintext, *, inplace: bool=False) -> Plaintext: ...2
Apply the inverse negacyclic NTT to every RNS polynomial.
Ciphertext components dispatch ntt.NttMontgomeryToCoefficientStandardOp and end in coefficient/standard form. A plaintext dispatches ntt.NttMontgomeryToCoefficientMontgomeryOp and ends in coefficient/Montgomery form. The ring element, depth, Q or QP rows, component shape, and actual scale are preserved.
ntt_domain_to_coefficient_domain_
method
def ntt_domain_to_coefficient_domain_(value: Ciphertext) -> Ciphertext: ...
def ntt_domain_to_coefficient_domain_(value: Plaintext) -> Plaintext: ...2
Transform
The method dispatches the ciphertext or plaintext inverse NTT operation used by ntt_domain_to_coefficient_domain; it does not alter depth, rows, or actual scale.
standard_residues_to_montgomery_residues
method
def standard_residues_to_montgomery_residues(plaintext: Plaintext, *, inplace: bool=False) -> Plaintext: ...
def standard_residues_to_montgomery_residues(plaintext: CompressedPlaintext, *, inplace: bool=False) -> CompressedPlaintext: ...2
Multiply each coefficient residue by its Montgomery radix.
rns.StandardToMontgomeryOp maps native-rns-transition. The plaintext remains in coefficient domain with unchanged polynomial, Q or QP rows, depth, and actual scale.
standard_residues_to_montgomery_residues_
method
def standard_residues_to_montgomery_residues_(plaintext: Plaintext) -> Plaintext: ...
def standard_residues_to_montgomery_residues_(plaintext: CompressedPlaintext) -> CompressedPlaintext: ...2
Convert plaintext rows to Montgomery representation in place.
This dispatches rns.StandardToMontgomeryOp and returns the input plaintext; its polynomial, depth, prime rows, and actual scale do not change.
montgomery_residues_to_standard_residues
method
def montgomery_residues_to_standard_residues(plaintext: Plaintext, *, inplace: bool=False) -> Plaintext: ...
def montgomery_residues_to_standard_residues(plaintext: CompressedPlaintext, *, inplace: bool=False) -> CompressedPlaintext: ...2
Remove the Montgomery factor from each coefficient residue.
rns.MontgomeryToStandardOp maps native-rns-transition. The plaintext polynomial, coefficient domain, Q or QP rows, depth, and actual scale are preserved.
montgomery_residues_to_standard_residues_
method
def montgomery_residues_to_standard_residues_(plaintext: Plaintext) -> Plaintext: ...
def montgomery_residues_to_standard_residues_(plaintext: CompressedPlaintext) -> CompressedPlaintext: ...2
Convert plaintext rows to standard residues in place.
This dispatches rns.MontgomeryToStandardOp and returns the input plaintext without changing its polynomial, depth, rows, or actual scale.
rescale_divisor
method
def rescale_divisor(*, depth: int) -> int: ...Return the active Q divisor removed at depth.
rescale_to_next_depth divides each ciphertext coefficient and its actual scale by the product of the Q rows assigned to this transition.
rescale_output_scale
method
def rescale_output_scale(input_scale: float, *, depth: int) -> float: ...Compute the per-value actual scale after one rescale.
For input scale
rescale_to_next_depth
method
def rescale_to_next_depth(value: Ciphertext, *, rounding: Literal['nearest', 'floor']='nearest', inplace: bool=False) -> Ciphertext: ...Divide by the current Q depth-group modulus and consume one depth.
A depth group may contain multiple RNS primes. The operation removes every row in that group, advances depth once, and divides the value's actual scale by the complete group product.
rescale_to_next_depth_
method
def rescale_to_next_depth_(value: Ciphertext, *, rounding: Literal['nearest', 'floor']='nearest') -> Ciphertext: ...Rescale
The underlying row operations remove every prime in the group; the public value advances one depth and divides scale by the group product.
mod_switch_to_depth
method
def mod_switch_to_depth(value: Ciphertext, target_depth: int, *, inplace: bool=False) -> Ciphertext: ...Discard Q rows until target_depth without quotient scaling.
If the source rows are rns.RestrictDepthOp/ckks.ModSwitchOp.
mod_switch_to_next_depth
method
def mod_switch_to_next_depth(value: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...Discard the next Q depth group and advance one depth.
This calls mod_switch_to_depth for
mod_switch_to_next_depth_
method
def mod_switch_to_next_depth_(value: Ciphertext) -> Ciphertext: ...Discard the next Q depth group in place and return
The actual scale and surviving residues are unchanged; only depth and row metadata advance.
mod_switch_to_depth_
method
def mod_switch_to_depth_(value: Ciphertext, target_depth: int) -> Ciphertext: ...Restrict target_depth and return it.
The method performs direct row selection, preserving actual scale and every surviving residue.
reinterpret_at_scale
method
def reinterpret_at_scale(value: Ciphertext, target_scale: float, *, max_relative_change: float | None=None, inplace: bool=False) -> Ciphertext: ...Replace actual-scale metadata without arithmetic.
The payload, depth, prime rows, polynomial domain, and Montgomery state are copied unchanged while scale target_scaleckks.ReinterpretScaleOp/rns.ReinterpretScaleOp.
reinterpret_at_scale_
method
def reinterpret_at_scale_(value: Ciphertext, target_scale: float, *, max_relative_change: float | None=None) -> Ciphertext: ...Replace
No residues or rows change. max_relative_change limits the permitted ratio between the old and new scale.
multiply
method
def multiply(lhs: Ciphertext, rhs: Ciphertext) -> Ciphertext: ...Multiply two CT2 ciphertexts into one CT3 ciphertext.
Both inputs are two-component NTT/Montgomery ciphertexts with matching depth and active prime rows. For ckks.MultiplyOp computes native-ct2-convolution implementation consumes NTT/Montgomery inputs. Depth and rows are retained, and actual scale becomes
multiply_scalar
method
def multiply_scalar(ciphertext: Ciphertext, scalar: int | float, *, scalar_scale: float | None=None) -> Ciphertext: ...Multiply a ciphertext by a stochastically quantized real scalar.
For scalar ckks.MultiplyScalarOp samples
multiply_integer_scalar
method
def multiply_integer_scalar(ciphertext: Ciphertext, scalar: int) -> Ciphertext: ...Multiply every ciphertext component by an integer
ckks.MultiplyIntegerScalarOp computes native-ckks-scalar-arithmetic. Because
add_plaintext
method
def add_plaintext(ciphertext: Ciphertext, plaintext: Plaintext | CompressedPlaintext, *, inplace: bool=False) -> Ciphertext: ...Add a prepared plaintext polynomial to ciphertext component zero.
For ordinary RNS plaintext rns.AddPlaintextOp computes native-plaintext-arithmetic. Compressed input dispatches ckks.AddCompressedPlaintextOp and expands the same values logically. Matching depth, prime rows, and actual scale are required; output state and later components are preserved.
add_plaintext_
method
def add_plaintext_(ciphertext: Ciphertext, plaintext: Plaintext | CompressedPlaintext) -> Ciphertext: ...Add prepared plaintext
This is the in-place ordinary/compressed plaintext addition path and returns the input ciphertext with unchanged represented state.
multiply_plaintext
method
def multiply_plaintext(ciphertext: Ciphertext, plaintext: Plaintext | CompressedPlaintext, *, inplace: bool=False) -> Ciphertext: ...Multiply each ciphertext component by a prepared plaintext.
For NTT/Montgomery plaintext rns.MultiplyPlaintextOp computes ckks.MultiplyCompressedPlaintextOp for the same expanded polynomial. Depth, rows, and component count remain; actual scale becomes
multiply_plaintext_
method
def multiply_plaintext_(ciphertext: Ciphertext, plaintext: Plaintext | CompressedPlaintext) -> Ciphertext: ...Replace a ciphertext by its prepared-plaintext product.
The method uses the ordinary or compressed registered multiplication path, updates actual scale to
sum_plaintext_products
method
def sum_plaintext_products(ciphertexts: Sequence[Ciphertext], plaintexts: Sequence[Plaintext | CompressedPlaintext]) -> Ciphertext: ...Compute a sum of prepared-plaintext products in one operation.
For equally sized sequences, the result is
Every ciphertext must have the same NTT/Montgomery Q or QP state, depth, active rows, component shape, and actual scale. Every prepared plaintext must match those rows and have a common actual scale. The result preserves the ciphertext state and has scale
sum_plaintext_product_groups
method
def sum_plaintext_product_groups(ciphertexts: Sequence[Ciphertext], plaintext_groups: Sequence[Sequence[Plaintext | CompressedPlaintext]]) -> Ciphertext: ...Apply several prepared-plaintext rows to shared ciphertext terms.
For
Every operand follows sum_plaintext_products' matching NTT/Montgomery state, depth, row, shape, and scale requirements. Each result has scale Ciphertext.unbind_batch recovers separate results. The operation executes the supplied rectangular matrix; it does not choose how a caller partitions a linear transform. A Backend implementation may reuse a ciphertext load across plaintext rows without stacking the inputs or materializing individual products.
sum_rotated_plaintext_product_groups
method
def sum_rotated_plaintext_product_groups(ciphertext: Ciphertext, rotation_keys: Sequence[RotationKey | None], plaintext_groups: Sequence[Sequence[Plaintext | CompressedPlaintext]]) -> Ciphertext: ...Apply prepared-plaintext rows to one direct rotation group.
A None key denotes the unrotated input; each other entry supplies its own signed rotation step. For
The input is coefficient/standard Q CT2. Every direct rotation completes hybrid key switching and ModDown before its NTT/Montgomery plaintext product. The output inserts a first batch axis of length
relinearize
method
def relinearize(value: Ciphertext, key: RelinearizationKey | None=None, *, output_domain: PolynomialDomain='coefficient') -> Ciphertext: ...Map a CT3 product phase back to two components.
The input is a three-component NTT/Montgomery product. For phase ckks.RelinearizeOp dispatches to native-relinearize-streaming and returns output_domain="ntt" retains
switch_key
method
def switch_key(value: Ciphertext, key: KeySwitchKey, *, output_domain: PolynomialDomain='coefficient') -> Ciphertext: ...Switch a CT2 ciphertext from a source secret to a destination secret.
The input is a two-component coefficient/standard Q ciphertext. For ckks.SwitchKeyOp dispatches the whole operation through one streaming hybrid-RNS implementation, which shares its QP accumulator across decomposition digits. output_domain="ntt" combines
rotate_with_key
method
def rotate_with_key(value: Ciphertext, key: RotationKey, *, output_domain: PolynomialDomain='coefficient') -> Ciphertext: ...Apply the slot displacement carried by a direct rotation key.
The input is a two-component coefficient/standard or NTT/Montgomery Q ciphertext. The call dispatches ckks.RotateOp to native-rotate-streaming. Its Galois automorphism output_domain="ntt" requests NTT/Montgomery output. For NTT input and output, the automorphism and unchanged component-zero contribution remain in NTT form while only component one is inverted for key switching.
rotate_by_step
method
def rotate_by_step(value: Ciphertext, rotation_step: int) -> Ciphertext: ...Cyclically rotate CKKS slots by a signed displacement.
The step is normalized modulo the slot count. A zero step clones the input; an installed direct key issues one ckks.RotateOp and a decomposed key path issues successive rotations whose displacements sum modulo the slot count. Each stage preserves CT2 shape, depth, Q rows, and actual scale.
rotate_many_by_steps
method
def rotate_many_by_steps(value: Ciphertext, rotation_steps: Sequence[int], *, use_hoisting: bool=True) -> list[Ciphertext]: ...Return the requested cyclic slot rotations in caller order.
Each normalized step denotes the same mathematical result as rotate_by_step. Direct single-key rotations may be grouped into one ckks.RotateManyOp dispatched to native-rotate-many-hoisted; hoisting shares digit decomposition and Q-to-QP basis extension but does not regroup or alter outputs. Multi-key paths remain successive ckks.RotateOp calls.
rotate_many_with_keys
method
def rotate_many_with_keys(value: Ciphertext, keys: Sequence[RotationKey], *, use_hoisting: bool=True, output_domain: PolynomialDomain='coefficient') -> list[Ciphertext]: ...Apply each supplied rotation key and preserve its output order.
With hoisting, one ckks.RotateManyOp shares key-switch preparation while each result equals the corresponding independent ckks.RotateOp. Without hoisting, keys dispatch separately. Every output keeps CT2 shape, depth, active Q rows and actual scale. output_domain="ntt" returns NTT/Montgomery results, equivalent to transforming each coefficient result. The hoisted implementation retains Q evaluations during ModDown; independent rotations combine c0 with the coefficient correction before its forward NTT.
rotate_by_step_
method
def rotate_by_step_(value: Ciphertext, rotation_step: int) -> Ciphertext: ...Replace
The method uses rotate_by_step and therefore dispatches the required ckks.RotateOp sequence while preserving depth, rows, and actual scale.
conjugate
method
def conjugate(value: Ciphertext, key: ConjugationKey | None=None, *, output_domain: PolynomialDomain='coefficient') -> Ciphertext: ...Apply complex conjugation to every CKKS slot.
The input is a two-component coefficient/standard Q ciphertext. The method dispatches ckks.ConjugateOp to a whole-operation implementation. It applies output_domain selects coefficient/standard or NTT/Montgomery output. CT2 shape, depth, Q rows, and actual scale remain unchanged.