fhelium
Public CKKS configuration, values, keys, engine, and file operations.
DEFAULT_CPU_NTT_BACKEND
constant View source
DEFAULT_CPU_NTT_BACKEND: Final[str] = 'radix2_indexed'COMPRESSED_PLAINTEXT_FORMAT_VERSION
constant View source
COMPRESSED_PLAINTEXT_FORMAT_VERSION = 1DEFAULT_NTT_BACKEND
constant View source
DEFAULT_NTT_BACKEND: Final[str] = 'radix2_compact_group8_smem8'SUPPORTED_NTT_BACKENDS
constant View source
SUPPORTED_NTT_BACKENDS: Final = tuple(NTT_BACKEND_POLICIES)Ciphertext
class View source
Ciphertext(data: torch.Tensor, level: int, scale: float, context_id: str, prime_ids: tuple[int, ...], polynomial_domain: PolynomialDomain = 'coefficient', modulus_basis: ModulusBasis = 'Q', residue_representation: ResidueRepresentation = 'standard')Bases: TensorResident
One homogeneous process-local CKKS ciphertext tensor or dense batch.
data is a dense integral tensor with layout [component, *batch, limb, coefficient_or_ntt_index]. The component extent is two or three for
Limb row prime_ids[i]. The final extent indexes coefficients in polynomial_domain. modulus_basis selects scale is the positive finite actual scale
Every member of batch_shape shares the exact level, scale, component count, domain, basis, residue form, context, and ordered prime_ids. Direct construction retains the input dtype, device, and storage; engine operations additionally require the engine's configured integral dtype, device, ring dimension, and expected row interval. clone owns new storage, while limb slices and batch selections are views. Methods ending in _ mutate this object and are visible through aliases.
Distribution and communication are deliberately not encoded in this value: an SPMD program decides what each rank stores and which collectives it executes.
Attributes
| Name | Type | Default/value |
|---|---|---|
data | torch.Tensor | |
level | int | |
scale | float | |
context_id | str | |
prime_ids | tuple[int, ...] | |
polynomial_domain | PolynomialDomain | 'coefficient' |
modulus_basis | ModulusBasis | 'Q' |
residue_representation | ResidueRepresentation | 'standard' |
component_count
property
component_count: intlimb_count
property
limb_count: intring_dimension
property
ring_dimension: intbatch_shape
property
batch_shape: torch.SizeLogical homogeneous batch dimensions, excluding CKKS axes.
batch_size
property
batch_size: intFlattened logical batch size; one for an unbatched value.
is_batched
property
is_batched: boolWhether this value has at least one logical batch dimension.
component
method
def component(index: int) -> torch.Tensor: ...Return the storage-sharing [*batch, limb, index] component view.
c0
property
c0: torch.Tensorc1
property
c1: torch.Tensorc2
property
c2: torch.Tensoris_ntt_domain
property
is_ntt_domain: boolis_coefficient_domain
property
is_coefficient_domain: boolincludes_p
property
includes_p: boolassert_state
method
def assert_state(*, polynomial_domain: PolynomialDomain | None=None, residue_representation: ResidueRepresentation | None=None, modulus_basis: ModulusBasis | None=None, components: int | None=None) -> Ciphertext: ...clone
method
def clone() -> Ciphertext: ...Return a metadata-equivalent ciphertext with independent storage.
with_data
method
def with_data(data: torch.Tensor) -> Ciphertext: ...Construct the same semantic layout around replacement storage.
The payload is not cloned; the result aliases data exactly.
slice_limbs
method
def slice_limbs(start: int, stop: int) -> Ciphertext: ...Return a storage-sharing view over [start:stop] RNS limbs.
This is a local tensor operation, not a placement decision. In-place arithmetic on the returned value also modifies the corresponding rows of this ciphertext.
stack_batch
method
def stack_batch(values: tuple[Ciphertext, ...] | list[Ciphertext]) -> Ciphertext: ...Allocate and copy compatible values into one new batch dimension.
Stacking separately allocated values cannot be zero-copy. This named constructor makes that cost visible rather than hiding a torch.stack inside an engine operation. The new logical batch axis is inserted before any batch axes already owned by each value.
context_id does not identify an encryption key. The caller must ensure every value has the same effective key lineage, applying an key switch first when necessary.
select_batch
method
def select_batch(index: int, *, dim: int=0) -> Ciphertext: ...Return a storage-sharing view selected from one batch axis.
unbind_batch
method
def unbind_batch(*, dim: int=0) -> tuple[Ciphertext, ...]: ...Return storage-sharing views along one logical batch axis.
replace_
method
def replace_(other: Ciphertext) -> Ciphertext: ...Replace this value without changing its Python object identity.
The result aliases other.data; prior aliases of self.data keep the old allocation. All observable CKKS state fields are replaced.
CkksConfig
class View source
CkksConfig(*, buffer_bit_length: int=62, scale_bits: int=40, base_prime_bits: int | None=None, logN: int=15, num_scale_primes: int | None=16, num_p_primes: int=2, sigma: float=3.19, security_bits: int=128, enforce_security_budget: bool=True)Immutable CKKS mathematical and security parameters.
The configuration defines CKKS over
At public level num_scale_primes is the positive number of scale-prime rows selected into the Q chain and the number of public levels. The final public level contains the last scale prime and the structural base Q prime, so level zero has num_scale_primes - 1 public one-level transitions. num_q_primes includes the additional structural base. The bootstrap-entry transition produces the one-prime structural basis. The key-switch modulus is
scale_bits selects ordinary scale primes and the default encoding/planning scale base_prime_bits independently selects the structural base Q prime. An omitted value selects the message-prime catalog width. The packaged catalog accepts a provided value equal to scale_bits.
total_modulus_bits covers the complete QP parameter modulus, both maximum_modulus_bits is the corresponding security budget. The exact built-in table supports Gaussian error standard deviation sigma=3.19 and classical categories 128, 192, and 256. Engine construction checks the complete QP product before native initialization when enforce_security_budget is true. Disabling that check transfers parameter and sampler assessment to the caller.
dumps
method
def dumps() -> dict[str, object]: ...Serialize to a dictionary for easy saving or logging.
parse
method
def parse(src: Mapping[str, Any] | Preset, **overrides: Any) -> 'CkksConfig': ...Resolve a parameter baseline into a CKKS configuration.
src is either a maintained Preset or a mapping accepted by CkksConfig. Keyword overrides replace fields from that baseline before configuration validation and derived-value evaluation.
N
property
N: intRing dimension
The corresponding complex CKKS slot count is
inverse_ntt_scale
property
inverse_ntt_scale: tuple[int, ...]Return
The result follows moduli order: ordinary
int_scale
property
int_scale: intInteger default scale
default_scale
property
default_scale: floatBinary64 default encoding and planning scale
Value creation selects this scale when its scale argument is omitted. Arithmetic reads and updates the actual scale stored on each value.
torch_dtype
property
torch_dtype: Anymessage_bits
property
message_bits: intLegacy message-prime catalog width used for structural Q and P.
This name does not denote CKKS message precision. Renaming the catalog selector and its packaged resources requires a separate versioned catalog migration.
maximum_modulus_bits
property
maximum_modulus_bits: intExact built-in budget for the complete QP modulus bit width.
Raises
SecurityParametersUnsupportedError: If this configuration does not match an exact table row.
security_assessment
property
security_assessment: SecurityAssessmentStructured exact-table assessment of the complete QP modulus.
num_scale_primes
property
num_scale_primes: intNumber of selected scale-prime rows and ordinary public levels.
Public levels are [0, num_scale_primes). The final public level retains one scale prime plus the structural base, giving num_scale_primes - 1 public transitions from level zero. The count is at least one. A configured count is validated against catalog capacity when moduli is constructed. An omitted count is filled greedily within the security-table modulus-bit budget.
Raises
ValueError: If automatic derivation cannot fit one scale prime in the security budget.
moduli
property
moduli: tuple[int, ...]Complete ordered QP parameter-modulus list.
The order is [scale_q_primes, structural_q_prime, p_primes]. The ordinary rows form
q_moduli
property
q_moduli: tuple[int, ...]Ordered ordinary-prime rows whose level subsets form
p_moduli
property
p_moduli: tuple[int, ...]Ordered special-prime rows whose product is
num_q_primes
property
num_q_primes: intNumber of ordinary Q primes, including one structural base prime.
Therefore
total_num_primes
property
total_num_primes: intNumber of rows in the complete QP parameter basis.
total_modulus_bits
property
total_modulus_bits: intBit width
This value covers both ordinary Q primes and special P primes; it is not the width of Q alone.
validate_security_budget
method
def validate_security_budget() -> SecurityAssessment: ...Require an exact supported assessment that meets its QP budget.
Returns
The immutable structured assessment when the budget is met.
Raises
SecurityParametersUnsupportedError: If no exact built-in row matches this configuration.SecurityBudgetExceededError: If the complete QP modulus exceeds the matching table budget.
CkksContextSpec
class View source
CkksContextSpec(logN: int, default_scale: float, q_moduli: tuple[int, ...], p_moduli: tuple[int, ...] = (), galois_generator: int = 3)Device-placement-independent CKKS context description.
The context fixes default_scale is not an invariant imposed on values: every plaintext and ciphertext carries its own actual scale
Attributes
| Name | Type | Default/value |
|---|---|---|
representation | ClassVar[str] | 'direct_per_value_scale_v1' |
logN | int | |
default_scale | float | |
q_moduli | tuple[int, ...] | |
p_moduli | tuple[int, ...] | () |
galois_generator | int | 3 |
N
property
N: intnum_slots
property
num_slots: intnum_q_primes
property
num_q_primes: intnum_p_primes
property
num_p_primes: intcontext_id
property
context_id: strStable SHA-256 identity of all mathematical context parameters.
CkksEngine
class View source
CkksEngine(ckks_config: CkksConfig | Preset | dict[str, object] | None=None, *, device: torch.device | str | None=None, allow_sk_gen: bool=True, galois_generator: int=3, ntt_backend: str | None=None, rng_seed: int | None=None, rng_nonce: int | None=None)CKKS execution facade for dense process-local values.
The engine fixes prime_ids; operations never infer hidden level or scale alignment.
ntt_backend is an exact engine execution-policy name. When omitted, CUDA engines select fhelium.DEFAULT_NTT_BACKEND and CPU engines select fhelium.DEFAULT_CPU_NTT_BACKEND. Engine construction does not benchmark hardware. A selected backend name must support both the device and ring dimension. The backend affects table layout and kernel execution, not CKKS context identity.
Construction creates one fhelium.rng.Csprng from the engine configuration and device. rng_seed and rng_nonce provide fixed stream material for controlled tests and benchmarks; applications should leave them unset so the generator obtains production entropy.
public_level_count
property
public_level_count: intNumber of ordinary public CKKS levels.
The count equals config.num_scale_primes. Public levels satisfy
final_public_level
property
final_public_level: intGreatest ordinary public CKKS level.
The value is public_level_count - 1. Its active Q basis contains the final scale prime and the structural base prime. Public next-level transitions require a source below this level. The bootstrap structural transition consumes a ciphertext at this level.
rng
property
rng: CsprngStable random-number generator shared by all engine components.
num_slots
property
num_slots: intSemantic CKKS slot count
create_secret_key
method
def create_secret_key(*, modulus_basis: ModulusBasis='QP') -> SecretKey: ...Sample a fresh secret polynomial without installing it.
Coefficients of {-1, 0, 1}, reduced over the complete level-zero Q or QP basis, and transformed to NTT-domain Montgomery residues. The result has layout [limb, ntt_index], engine integral dtype/device, final extent prime_ids. Generation allocates independent key storage and does not change the engine's installed key lifecycle.
create_public_key
method
def create_public_key(secret_key: SecretKey, *, modulus_basis: ModulusBasis='Q') -> PublicKey: ...Create a public encryption key for secret_key.
The two generated components satisfy
where [key_component=2, limb, ntt_index] in level-zero NTT-domain Montgomery form with engine integral dtype/device and exact prime_ids. The input secret key is not mutated and the public key is not installed on the engine.
create_relinearization_key
method
def create_relinearization_key(secret_key: SecretKey) -> RelinearizationKey: ...Create QP key-switch material from
The result replaces [key_digit, key_component=2, limb, ntt_index] in complete level-zero QP, NTT-domain Montgomery form on the engine device. It is returned without being installed; secret_key is not mutated.
create_rotation_key
method
def create_rotation_key(rotation_step: int, secret_key: SecretKey) -> RotationKey: ...Create QP key-switch material for one signed slot rotation.
For canonical step torch.roll(m, shifts=r). The result uses the full level-zero QP basis, NTT-domain Montgomery form, engine integral dtype/device, and independent storage; it is not installed automatically.
create_conjugation_key
method
def create_conjugation_key(secret_key: SecretKey) -> ConjugationKey: ...Create QP material from
The result has layout [key_digit, key_component=2, limb, ntt_index] in complete level-zero QP, NTT-domain Montgomery form with engine integral dtype/device and exact prime_ids. It enables semantic slot conjugation and is returned without installation; secret_key is not mutated.
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) -> KeySwitchKey: ...Create QP material that switches source phases to destination phases.
The direction is
Both secret keys must be complete level-zero QP NTT/Montgomery values for this engine. The output layout is [key_digit, key_component=2, limb, ntt_index] with engine integral dtype/device and exact QP prime_ids. Optional uniform components are indexed by stable key_digit_index. Inputs are not mutated and the result is not installed.
secret_key
property
secret_key: SecretKeyReturn the installed secret key, generating one lazily if allowed.
set_secret_key
method
def set_secret_key(key: SecretKey) -> None: ...Install key and invalidate all dependent installed keys.
The key tensor is retained rather than cloned. Installed public, relinearization, and rotation keys are cleared because this value type does not carry a symbolic key-lineage identifier.
public_key
property
public_key: PublicKeyReturn or lazily generate the installed public encryption key.
set_public_key
method
def set_public_key(key: PublicKey) -> None: ...Validate and install key by reference without changing others.
relinearization_key
property
relinearization_key: RelinearizationKeyReturn or lazily generate installed
set_relinearization_key
method
def set_relinearization_key(key: RelinearizationKey) -> None: ...Validate and install QP relinearization material by reference.
rotation_keys
property
rotation_keys: RotationKeySetMutable installed mapping from canonical signed steps to keys.
rotation_key
method
def rotation_key(rotation_step: int) -> RotationKey: ...Return the matching installed key, generating it lazily if allowed.
set_rotation_key
method
def set_rotation_key(key: RotationKey) -> None: ...Install a key under its self-described canonical rotation step.
plaintext
method
def plaintext(message, *, level: int=0, scale=None) -> Plaintext: ...Create a lazy slots-only plaintext with an actual scale argument.
No encoding arithmetic is performed. The value stores semantic slots
Parameters
message: Tensor-like real or complex slot values.level: Public CKKS level at which a later encode will materialize the message.scale: Positive finite per-value scale. The context'sconfig.default_scaleis used only when this isNone.
Returns
A detached, cloned slots Plaintext on the engine device. It has no polynomial domain, modulus basis, residue form, or prime_ids and does not alias the caller's tensor.
Raises
InvalidScaleError: Ifscaleis not positive and finite.ValueError: If the requested level or message layout is invalid.
encode
method
def encode(message, *, level: int=0, scale=None) -> Plaintext: ...Encode slots at one programmer-selected level and actual scale.
For
Parameters
message: Tensor-like real or complex slot values.level: Public CKKS level for the encoded value.scale: Positive finite per-value scale, orNoneto useconfig.default_scale.
Returns
A new exact integer_coefficients plaintext with layout [*batch, coefficient], final extent prime_ids.
Raises
InvalidScaleError: Ifscaleis not positive and finite.ValueError: If the requested level or arithmetic state is invalid.
integer_coefficients_to_rns
method
def integer_coefficients_to_rns(plaintext: Plaintext, *, modulus_basis: ModulusBasis='Q') -> Plaintext: ...Reduce an integer polynomial to coefficient-domain standard RNS.
For every exact active prime_ids[i] with modulus
Input [*batch, coefficient] becomes [*batch, limb, coefficient] with engine integral dtype/device and final extent
The result has representation="rns", polynomial_domain="coefficient", and residue_representation="standard". Its level, scale, semantic polynomial, and exact active prime_ids are preserved. The input must be the integer_coefficients result of encode; this transition never performs encoding or CRT reconstruction implicitly.
prepare_plaintext_for_addition
method
def prepare_plaintext_for_addition(plaintext: Plaintext, *, modulus_basis: ModulusBasis='Q') -> Plaintext: ...Prepare coefficient-domain Montgomery RNS data for addition.
For each exact active prime_ids[i] with modulus
The result has layout [*batch, limb, coefficient], engine integral dtype/device, and final extent
The result's state is (representation="rns", polynomial_domain="coefficient", residue_representation="montgomery"). Level, scale, semantic polynomial, modulus basis, and exact prime_ids are preserved.
Semantically, this convenience operation is equivalent to
standard_residues_to_montgomery_residues( integer_coefficients_to_rns(plaintext)).
The implementation reuses its newly allocated intermediate storage.
prepare_plaintext_for_multiplication
method
def prepare_plaintext_for_multiplication(plaintext: Plaintext, *, modulus_basis: ModulusBasis='Q') -> Plaintext: ...Prepare NTT-domain Montgomery RNS data for multiplication.
For each exact active prime_ids[i] with modulus [*batch, coefficient] becomes [*batch, limb, ntt_index] with engine integral dtype/device and final extent
The result's state is (representation="rns", polynomial_domain="ntt", residue_representation="montgomery") with the selected Q or QP modulus_basis and its exact prime_ids.
Semantically, this convenience operation is equivalent to
coefficient_domain_to_ntt_domain( standard_residues_to_montgomery_residues( integer_coefficients_to_rns(plaintext))).
The implementation reuses its newly allocated intermediate storage.
decode
method
def decode(plaintext: Plaintext, *, is_real: bool=False): ...Decode a plaintext with its own actual per-value scale.
Slots input is encoded first at its stored scale. Otherwise the input is exact integral integer_coefficients or finite binary64 approximate_coefficients with layout [*batch, coefficient], final extent [*batch, slot] with extent is_real=True selects its real part.
encrypt
method
def encrypt(plaintext: Plaintext, public_key: PublicKey | None=None) -> Ciphertext: ...Encrypt slots or exact integer coefficients under a public key.
The output phase satisfies
Slots input is first encoded at its stored actual scale. Decode-only approximate_coefficients and RNS input are rejected. With configured encryption noise [component=2, *batch, limb, coefficient] ciphertext in coefficient domain and standard residues, over Q or QP according to the public key. It uses engine integral dtype/device, exact active prime_ids, unchanged level, and
decrypt
method
def decrypt(ct: Ciphertext, secret_key: SecretKey | None=None) -> Plaintext: ...Decrypt to bounded binary64 coefficients for decoding.
The RNS phase is
The current decrypt path reconstructs the centered class from the trailing Q-prime pair into a finite torch.float64[*batch, coefficient] tensor on the engine device. It is bounded approximate_coefficients for decoding, not an exact full-ct.level and decode. Inputs are unchanged and output storage is independent.
encrypt_message
method
def encrypt_message(message, public_key: PublicKey | None=None, *, level: int=0, scale=None) -> Ciphertext: ...Encode and encrypt slots at the requested level and actual scale.
First compute
then encrypt so that
Parameters
message: Tensor-like real or complex slot values.public_key: Compatible key, or the engine-installed/default key.level: Public CKKS level for the new ciphertext.scale: Positive finite per-value scale, orNoneto useconfig.default_scale.
Returns
A new two-component [component, *batch, limb, coefficient] ciphertext in coefficient domain and standard residues, with engine integral dtype/device, exact Q or QP prime_ids selected by the public key, unchanged level, and actual scale
Raises
InvalidScaleError: Ifscaleis not positive and finite.ValueError: If the message, level, key, or direct-encode range is invalid.
decrypt_message
method
def decrypt_message(ct: Ciphertext, secret_key: SecretKey | None=None, *, is_real: bool=False): ...Decrypt and decode using the ciphertext's actual scale.
Decryption uses the bounded approximate-coefficient reconstruction described by decrypt; it is not exact CRT. The result is CPU [*batch, slot] and is complex unless is_real=True. The ciphertext and secret key are unchanged.
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
Return an RNS value after its negacyclic forward NTT.
For every limb prime (coefficient, montgomery) to (ntt, montgomery). Ciphertext states are deliberately coupled: the transition is (coefficient, standard) to (ntt, montgomery) and includes standard-to-Montgomery conversion.
Layout [*batch, limb, N] for plaintext or [component, *batch, limb, N] for ciphertext, engine integral dtype/device, level, actual scale, component count, Q/QP basis, and exact prime_ids are preserved. The functional result has independent storage. Input already in NTT domain is rejected because this is a strict source-to-target transition. No CRT reconstruction occurs.
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
Apply coefficient_domain_to_ntt_domain in place.
The payload tensor is transformed in its existing storage and polynomial_domain is updated; ciphertext also changes residue_representation to "montgomery". Aliases observe both payload and metadata mutation. Input must be in coefficient domain.
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
Return an RNS value after its normalized inverse NTT.
For every limb prime (ntt, montgomery) becomes (coefficient, montgomery). Ciphertext states are coupled: (ntt, montgomery) becomes (coefficient, standard) through inverse NTT and Montgomery reduction.
Tensor shape, engine integral dtype/device, level, actual scale, component count, Q/QP basis, and exact prime_ids are preserved. The functional result owns independent storage. Input already in coefficient domain is rejected because this is a strict source-to-target transition. It remains RNS; no CRT reconstruction occurs.
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
Apply ntt_domain_to_coefficient_domain in place; result remains RNS.
The payload tensor is transformed in its existing storage and polynomial_domain is updated; ciphertext also changes residue_representation to "standard". Aliases observe payload and metadata mutation. Input must be in NTT domain.
standard_residues_to_montgomery_residues
method
def standard_residues_to_montgomery_residues(plaintext: Plaintext) -> Plaintext: ...Convert coefficient-domain standard RNS to Montgomery residues.
For limb prime [*batch, limb, coefficient] with engine integral dtype/device. Representation, level, actual scale, Q/QP basis, and exact prime_ids are preserved. The functional output has independent storage. Input already using Montgomery residues is rejected because this is a strict source-to-target transition.
standard_residues_to_montgomery_residues_
method
def standard_residues_to_montgomery_residues_(plaintext: Plaintext) -> Plaintext: ...Apply standard_residues_to_montgomery_residues in existing storage.
residue_representation becomes "montgomery" and aliases observe payload/metadata mutation. Input must use standard residues.
montgomery_residues_to_standard_residues
method
def montgomery_residues_to_standard_residues(plaintext: Plaintext) -> Plaintext: ...Convert coefficient-domain Montgomery RNS to standard residues.
For limb prime [*batch, limb, coefficient] with engine integral dtype/device. Representation, level, actual scale, Q/QP basis, and exact prime_ids are preserved. The functional output has independent storage. Input already using standard residues is rejected because this is a strict source-to-target transition.
montgomery_residues_to_standard_residues_
method
def montgomery_residues_to_standard_residues_(plaintext: Plaintext) -> Plaintext: ...Apply montgomery_residues_to_standard_residues in existing storage.
residue_representation becomes "standard" and aliases observe payload/metadata mutation. Input must use Montgomery residues.
rescale_to_next_drop_prime
method
def rescale_to_next_drop_prime(*, level: int) -> int: ...Return the Q prime used by one rescale-to-next transition.
For source level rescale_to_next_level divides by this integer and removes its residue row.
Parameters
level: Current public CKKS level. It must have a following public level, so the final legal public level is not accepted.
Returns
The canonical leading active Q modulus at level.
Raises
TypeError: Iflevelis not an integer.ValueError: Iflevelis negative.MaximumLevelError: If no further public rescale level exists.
rescale_to_next_output_scale
method
def rescale_to_next_output_scale(input_scale: float, *, level: int) -> float: ...Calculate the binary64 output scale of one rescale transition.
The result is the same binary64 calculation used by rescale_to_next_level:
Parameters
input_scale: Positive finite scale immediately before rescale.level: Current public CKKS level.
Returns
The positive finite binary64 scale after dropping the level's leading active Q modulus.
Raises
InvalidScaleError: Ifinput_scaleor the resulting quotient is not a positive finite binary64 value.TypeError: Iflevelis not an integer.ValueError: Iflevelis negative.MaximumLevelError: If no further public rescale level exists.
rescale_to_next_level
method
def rescale_to_next_level(ct: Ciphertext, *, rounding: Literal['nearest', 'floor']='nearest') -> Ciphertext: ...Rescale a ciphertext to the next public CKKS level.
For each component polynomial,
For Q input, rounding="nearest" selects nearest-integer quotient and rounding="floor" subtracts the least nonnegative dropped residue before exact division.
Parameters
ct: Full-layout coefficient-domain, standard-residue ciphertext at a non-final public level. Two- and three-component Q or QP values are accepted.rounding: Quotient rule, either"nearest"or"floor".
Returns
A new coefficient-domain standard ciphertext at ct.level + 1 with the same two/three component count and Q/QP basis, engine integral dtype/device, exact prime_ids=ct.prime_ids[1:], and canonical residues in ct is unchanged and output storage does not alias it.
Raises
MaximumLevelError: Ifctis already at the final public level.InvalidScaleError: If the output scale is not positive and finite.ValueError: If the ciphertext state or engine layout is invalid.
rescale_to_next_level_
method
def rescale_to_next_level_(ct: Ciphertext, *, rounding: Literal['nearest', 'floor']='nearest') -> Ciphertext: ...Advance one public level and update ct in place.
Native kernels update the remaining RNS rows through views into the original allocation. The method then narrows ct.data and updates level, prime_ids, and the actual per-value scale.
The mathematical quotient, scale transition, Q/QP row selection, and canonical standard-residue output are identical to rescale_to_next_level. Only storage ownership differs.
Parameters
ct: Full-layout coefficient-domain, standard-residue ciphertext at a non-final public level. Aliases observe the mutation.rounding: Quotient rule, either"nearest"or"floor".
Returns
ct itself after the rescale transition.
Raises
MaximumLevelError: Ifctis already at the final public level.InvalidScaleError: If the output scale is not positive and finite.ValueError: If the ciphertext state or engine layout is invalid.
mod_switch_to_next_level
method
def mod_switch_to_next_level(ct: Ciphertext) -> Ciphertext: ...Restrict a ciphertext to the next public RNS basis.
For every component,
This transition drops the leading Q row, preserves coefficient representatives and scale, and retains all P rows for QP input. Message preservation requires the represented centered value to remain within the smaller modulus.
Parameters
ct: Full-layout ciphertext at a non-final public CKKS level. Its component count, polynomial domain, representation, and Q/QP basis are preserved.
Returns
A new ciphertext at ct.level + 1 with unchanged component count, domain, basis, residue form, dtype/device, actual scale, and prime_ids=ct.prime_ids[1:]. ct is unchanged and storage is independent.
Raises
MaximumLevelError: Ifctis already at the final public level.ValueError: Ifctis incompatible with this engine or does not contain the complete active RNS layout.
mod_switch_to_next_level_
method
def mod_switch_to_next_level_(ct: Ciphertext) -> Ciphertext: ...Restrict ct to the next public RNS basis in place.
The mathematical RNS restriction and no-wrap condition are identical to mod_switch_to_next_level. ct.data is narrowed to a view of its existing allocation; level and exact prime_ids change, while actual scale and all other state axes are preserved. Aliases observe metadata mutation and retained storage rows.
Parameters
ct: Full-layout ciphertext at a non-final public level. Aliases observe its narrowed tensor and updated level metadata.
Returns
ct itself with unchanged scale and one fewer active Q row.
Raises
MaximumLevelError: Ifctis already at the final public level.ValueError: Ifctis incompatible with this engine or does not contain the complete active RNS layout.
mod_switch_to_level
method
def mod_switch_to_level(ct: Ciphertext, target_level: int) -> Ciphertext: ...Restrict a ciphertext to the RNS basis at target_level.
For target level
The transition drops the first
Parameters
ct: Full-layout ciphertext whose current level is no later thantarget_level.target_level: Destination public level in the inclusive range[ct.level, final_public_level].
Returns
A new ciphertext at target_level with unchanged component count, domain, Q/QP basis, residue form, dtype/device, and actual scale. Exact prime_ids are restricted accordingly. Passing the current level returns a full clone; output never aliases ct.
Raises
TypeError: Iftarget_levelis not an integer.ValueError: If the target is earlier thanct.level, beyond the final public level, or the ciphertext layout is incompatible.
mod_switch_to_level_
method
def mod_switch_to_level_(ct: Ciphertext, target_level: int) -> Ciphertext: ...In-place form of mod_switch_to_level.
The same RNS restriction and no-wrap condition apply. The narrowed tensor remains a view into the original allocation; level and exact prime_ids change while actual scale and other state axes are preserved. Aliases observe mutation.
Parameters
ct: Full-layout ciphertext to mutate.target_level: Destination public level in the inclusive range[ct.level, final_public_level].
Returns
ct itself with unchanged scale. Passing its current level is a no-op.
Raises
TypeError: Iftarget_levelis not an integer.ValueError: If the target or ciphertext layout is invalid.
reinterpret_at_scale
method
def reinterpret_at_scale(ct: Ciphertext, target_scale: float, *, max_relative_change: float | None=None) -> Ciphertext: ...Return a metadata-only reinterpretation at target_scale.
Ciphertext residues are not modified. Consequently the decoded message obeys
When supplied, max_relative_change bounds the symmetric ratio between the current and target scales.
Parameters
ct: Ciphertext whose payload and original metadata remain unchanged.target_scale: Positive finite scale used to reinterpret the same residues.max_relative_change: Optional upper bound on the symmetric ratio .
Returns
A new ciphertext with cloned payload, independent storage, and target_scale. Level, component count, domain, basis, residue form, dtype/device, and exact prime_ids are unchanged.
Raises
InvalidScaleError: Iftarget_scaleis invalid.ScaleMismatchError: If the provided relative-change bound is exceeded.ValueError: If the bound itself or ciphertext state is invalid.
reinterpret_at_scale_
method
def reinterpret_at_scale_(ct: Ciphertext, target_scale: float, *, max_relative_change: float | None=None) -> Ciphertext: ...Reinterpret ct at target_scale in place.
The equations and guard are identical to reinterpret_at_scale. Only ct.scale is mutated; payload storage and every other state axis remain unchanged. Aliases to the object observe the metadata change.
Parameters
ct: Ciphertext whose scale metadata is mutated; residues are not.target_scale: Positive finite replacement scale.max_relative_change: Optional symmetric relative-change bound.
Returns
ct itself after changing only its scale metadata.
Raises
InvalidScaleError: Iftarget_scaleis invalid.ScaleMismatchError: If the provided relative-change bound is exceeded.ValueError: If the bound itself or ciphertext state is invalid.
zero_plaintext_like
method
def zero_plaintext_like(plaintext: Plaintext) -> Plaintext: ...Construct semantic zero in the same exact plaintext state.
Slots, integer coefficients, approximate coefficients, or RNS payloads are materialized as zero with matching batch shape, level, actual scale, representation, domain, Q/QP basis, residue form, and exact prime_ids. The result uses the engine-compatible dtype/device for newly encoded storage and owns independent storage. The input is not mutated.
encrypt_zero_like
method
def encrypt_zero_like(ct: Ciphertext, public_key: PublicKey | None=None) -> Ciphertext: ...Create a randomized secure encryption of semantic zero.
The output phase satisfies ct's batch shape, level, actual scale, coefficient/NTT domain, Q/QP basis, standard/Montgomery form, engine dtype/device, and exact prime_ids. The supplied public key must select the same basis. Neither input nor key is mutated and no storage aliases them.
multiply
method
def multiply(lhs: Ciphertext, rhs: Ciphertext) -> Ciphertext: ...Multiply two NTT ciphertexts without relinearization or rescale.
Both inputs must be two-component NTT values, and the output is a three-component NTT value. Programs call relinearize and rescale_to_next_level as separate calls. This also makes communication required by a limb-parallel implementation visible.
For
with
Parameters
lhs: Two-component NTT/Montgomery ciphertext.rhs: Layout-compatible two-component NTT/Montgomery ciphertext. Its scale may differ fromlhs.scale.
Returns
A new three-component NTT/Montgomery ciphertext at unchanged level and Q/QP basis, with engine integral dtype/device, the exact shared prime_ids, the operands' batch shape, and product actual scale. Inputs are unchanged and output storage is independent.
Raises
InvalidScaleError: If the binary64 product scale is not positive and finite.ValueError: If either input state or the shared layout is invalid.
relinearize
method
def relinearize(ct: Ciphertext, relinearization_key: RelinearizationKey | None=None) -> Ciphertext: ...Key-switch a three-component product back to two components.
Relinearization transforms the phase relation
using QP material directed from
Parameters
ct: Three-component Q-basis NTT/Montgomery ciphertext.relinearization_key: Compatible QP key. The engine-installed key is used when this argument is omitted.
Returns
A new two-component coefficient-domain standard ciphertext with Q basis, the same batch shape, engine integral dtype/device, exact active Q prime_ids, level, and actual scale as ct. Inputs are unchanged and output storage is independent.
Raises
ValueError: If the ciphertext or key state is incompatible.
switch_key
method
def switch_key(ct: Ciphertext, key: KeySwitchKey) -> Ciphertext: ...Switch a two-component ciphertext from source to destination key.
key must have been generated for the declared direction
The key object does not self-identify these lineages; the caller owns that invariant. The represented message, level, and actual scale are preserved up to key-switch error. Input must be coefficient-domain standard, two-component, full-layout Q RNS. Output is a new Q value with unchanged batch shape, engine dtype/device, and exact active Q prime_ids; inputs are not mutated and storage is independent.
add
method
def add(lhs: Ciphertext, rhs: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...Add ciphertexts with exactly equal scale and arithmetic state.
The method performs no level alignment, scale reinterpretation, relinearization, or domain conversion.
Parameters
lhs: Left ciphertext and, wheninplaceis true, destination.rhs: Ciphertext with identical layout, shape, and binary64 scale.inplace: Mutate and returnlhswhen true; otherwise return a new ciphertext and leave both inputs unchanged.
Returns
The sum with unchanged component count, level, domain, Q/QP basis, residue form, engine dtype/device, and exact prime_ids. The functional result owns independent storage; inplace=True mutates and returns lhs so aliases observe canonicalized payload changes.
Raises
ScaleMismatchError: Iflhs.scale != rhs.scale.ValueError: If context, level, state, shape, or RNS layout differs.
add_
method
def add_(lhs: Ciphertext, rhs: Ciphertext) -> Ciphertext: ...Add rhs to lhs in place with add's state requirements.
Only lhs payload storage is mutated; all metadata is preserved and aliases of lhs observe the component-wise modular sum.
sum_ciphertexts
method
def sum_ciphertexts(ciphertexts: Sequence[Ciphertext]) -> Ciphertext: ...Return the rank-local sum of compatible ciphertexts.
For each component
with one exactly shared actual scale. Every state axis, batch shape, dtype/device, and exact prime_ids must match.
Parameters
ciphertexts: Non-empty sequence satisfyingadd's exact layout and exact-scale requirements.
Returns
A new ciphertext. Every input remains unchanged.
Raises
ScaleMismatchError: If any scale differs from the first value.ValueError: If the sequence is empty or another value is layout incompatible.
sum_ciphertext_batch
method
def sum_ciphertext_batch(batch: Ciphertext, *, dim: int=0) -> Ciphertext: ...Reduce one logical batch axis by modular ciphertext addition.
A binary tree adds contiguous halves through the native batched RNS kernels. This exposes the complete remaining batch, component, limb, and polynomial-index work to each round instead of launching one addition per selected value. Odd tails are folded after the batched rounds.
Parameters
batch: Ciphertext with at least one logical batch axis.dim: Logical batch axis to remove. Ciphertext component and RNS axes are not addressable through this argument.
Returns
A new ciphertext with the selected batch axis removed. Level, scale, polynomial domain, modulus basis, residue representation, component count, device, dtype, and exact prime_ids are preserved. The input is unchanged.
Raises
IndexError: Ifdimdoes not identify a logical batch axis.ValueError: Ifbatchis unbatched or incompatible with this engine.
subtract
method
def subtract(lhs: Ciphertext, rhs: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...Subtract ciphertexts with exactly equal scale and state.
Parameters
lhs: Minuend and, wheninplaceis true, destination.rhs: Subtrahend with identical layout, shape, and binary64 scale.inplace: Mutate and returnlhswhen true.
Returns
The difference with unchanged component count, level, domain, Q/QP basis, residue form, engine dtype/device, and exact prime_ids. The functional result owns independent storage; inplace=True mutates and returns lhs.
Raises
ScaleMismatchError: Iflhs.scale != rhs.scale.ValueError: If context, level, state, shape, or RNS layout differs.
subtract_
method
def subtract_(lhs: Ciphertext, rhs: Ciphertext) -> Ciphertext: ...Subtract rhs from lhs in place under subtract.
Only lhs payload storage is mutated; all metadata is preserved and aliases observe the component-wise modular difference.
negate
method
def negate(ct: Ciphertext, *, inplace: bool=False) -> Ciphertext: ...Negate a ciphertext without changing its state metadata.
Component count, level, domain, Q/QP basis, residue form, dtype/device, and exact prime_ids are preserved. The functional result owns independent storage; inplace=True mutates canonicalized residues in ct and aliases observe the change.
negate_
method
def negate_(ct: Ciphertext) -> Ciphertext: ...Negate ct in place with negate's state requirements.
add_plaintext
method
def add_plaintext(ct: Ciphertext, plaintext: Plaintext | CompressedPlaintext, *, inplace: bool=False) -> Ciphertext: ...Add an operation-ready plaintext at exactly the ciphertext scale.
No scale or level alignment is implicit.
Parameters
ct: Two-component coefficient-domain standard ciphertext.plaintext: Coefficient-domain RNSPlaintextor compatible compressed form at the same level, basis, rows, and exact binary64 scale. A batched plaintext must matchct.batch_shapeexactly; an unbatched plaintext broadcasts over every ciphertext batch entry.inplace: Update onlyct.c0and returnctwhen true.
Returns
A two-component coefficient-domain standard ciphertext with unchanged level, Q/QP basis, batch shape, engine dtype/device, exact prime_ids, and shared actual scale. Functional mode allocates independent output; inplace=True mutates only ct.c0 and aliases observe the change.
Raises
ScaleMismatchError: If the two scale values are not exactly equal.ValueError: If the plaintext or ciphertext arithmetic state, context, layout, device, or batch shape is incompatible.
add_plaintext_
method
def add_plaintext_(ct: Ciphertext, plaintext: Plaintext | CompressedPlaintext) -> Ciphertext: ...Mutate ct.c0 with add_plaintext's exact input requirements.
multiply_plaintext
method
def multiply_plaintext(ct: Ciphertext, plaintext: Plaintext | CompressedPlaintext, *, inplace: bool=False) -> Ciphertext: ...Multiply an NTT ciphertext by an operation-ready plaintext.
The operands need not have equal scales. This operation preserves the ciphertext level and records their binary64 scale product.
Both operands remain in NTT/Montgomery representation. Callers place coefficient_domain_to_ntt_domain before a multiplication region and ntt_domain_to_coefficient_domain before an operation that requires coefficient-domain standard residues, such as rescale.
Parameters
ct: Two-component NTT-domain Montgomery ciphertext.plaintext: NTT/Montgomery RNSPlaintextor compatible compressed form at the same context, level, basis, rows, and batch layout. A batched plaintext must matchct.batch_shapeexactly; an unbatched plaintext broadcasts over every ciphertext batch entry.inplace: Replacectwith the result and return it when true.
Returns
A new two-component NTT-domain Montgomery ciphertext at unchanged level and Q/QP basis, with the ciphertext batch shape, engine integral dtype/device, exact prime_ids, and product actual scale. Functional mode leaves inputs unchanged and owns independent storage; inplace=True replaces all ct state with the new storage, so old tensor aliases keep the old allocation.
Raises
InvalidScaleError: If the product scale is not positive and finite.ValueError: If the plaintext or ciphertext arithmetic state, context, layout, device, or batch shape is incompatible.
multiply_plaintext_
method
def multiply_plaintext_(ct: Ciphertext, plaintext: Plaintext | CompressedPlaintext) -> Ciphertext: ...Replace ct by its product under multiply_plaintext.
rotate_by_step
method
def rotate_by_step(ct: Ciphertext, rotation_step: int) -> Ciphertext: ...Rotate by one signed step using the engine-owned key inventory.
For
The step is canonicalized modulo rotate_with_key when the caller owns the exact direct key.
rotate_with_key
method
def rotate_with_key(ct: Ciphertext, key: RotationKey) -> Ciphertext: ...Rotate slots using the canonical signed step carried by key.
For
matching torch.roll(m, shifts=r). The backend applies the Galois automorphism key in the direction rotation_step is a slot displacement and is not the Galois element.
Input must be a two-component coefficient-domain standard full-layout Q ciphertext. Output is a new Q ciphertext with unchanged batch shape, level, actual scale, engine integral dtype/device, and exact active Q prime_ids; key switching adds its configured approximation error. Inputs are unchanged and output storage is independent. Step zero returns a clone without automorphism or key switch.
rotate_many_by_steps
method
def rotate_many_by_steps(ct: Ciphertext, rotation_steps: Sequence[int], *, use_hoisting: bool=True) -> list[Ciphertext]: ...Rotate by ordered signed steps using engine-owned keys.
Output order matches rotation_steps. Every result owns independent storage, including duplicate and zero-step entries. Direct-key paths share hybrid decomposition when use_hoisting is true; a step that requires a composed key path is evaluated independently.
rotate_many_with_keys
method
def rotate_many_with_keys(ct: Ciphertext, rotation_keys: Sequence[RotationKey], *, use_hoisting: bool=True) -> list[Ciphertext]: ...Rotate once for each ordered caller-owned direct key.
Every key self-describes its canonical signed step. Output order and duplicates match rotation_keys; results own independent storage. The keys are not installed into the engine.
rotate_by_step_
method
def rotate_by_step_(ct: Ciphertext, rotation_step: int) -> Ciphertext: ...Replace ct by rotate_by_step's result.
The result satisfies ct.data is replaced by newly allocated rotated/key-switched storage; aliases to the old tensor retain the old allocation, while aliases to the object observe all replaced state.
conjugate
method
def conjugate(ct: Ciphertext, key: ConjugationKey) -> Ciphertext: ...Apply complex conjugation to every semantic CKKS slot.
The backend applies key in the direction prime_ids, up to key-switch error. Inputs are unchanged and output storage is independent.
validate_ciphertext
method
def validate_ciphertext(ciphertext: Ciphertext) -> None: ...Validate a complete dense ciphertext against this engine.
The check re-runs the value's mutable-storage invariants and requires the exact context, ring dimension, dtype, device, public level, modulus basis, and complete active prime_ids expected by ordinary engine operations. It performs no evaluator work and does not mutate the ciphertext.
validate_public_key
method
def validate_public_key(key: PublicKey) -> None: ...Validate public encryption material against this engine.
The check re-runs the key's mutable-storage invariants and requires the exact context, ring dimension, dtype, device, polynomial domain, residue representation, and prime layout consumed by online encryption. The key is not installed or mutated.
validate_key_switch_key
method
def validate_key_switch_key(key: KeySwitchKey) -> None: ...Validate complete QP key-switch material against this engine.
The concrete key type is preserved while context, ring dimension, dtype, device, NTT/Montgomery state, QP prime layout, and hybrid digit count are checked. The key is not installed or mutated.
CompressedPlaintext
class View source
CompressedPlaintext(data: torch.Tensor, ring_dimension: int, compression_layout: CompressedPlaintextLayout, level: int, scale: float, context_id: str, polynomial_domain: PolynomialDomain, modulus_basis: ModulusBasis, residue_representation: ResidueRepresentation, prime_ids: tuple[int, ...], implicit_data: torch.Tensor | None = None, compression_format_version: int = COMPRESSED_PLAINTEXT_FORMAT_VERSION)Bases: TensorResident
An exact operation-ready RNS plaintext with compressed storage.
data is a dense integral tensor with layout [*batch, limb, unique_index] rather than the dense [*batch, limb, coefficient_or_ntt_index] layout used by Plaintext. Limb row prime_ids[i] in polynomial_domain determines whether the expanded last axis indexes coefficients or NTT evaluations. Operation-ready compressed values always use Montgomery residues. compression_layout defines the exact, lossless expansion of each compact row:
"cyclic"expands[a, b]as[a, b, a, b, ...];"contiguous"expands[a, b]as[a, ..., a, b, ..., b]."strided_sparse": compact values occupy positions separated by , where isring_dimensionand isunique_count; all other positions use the stored per-batch/per-limbimplicit_datavalue.
These modes describe the encoded polynomial/NTT tensor axis, not the user-visible CKKS slot order. CKKS encoding permutes slots, and coefficient rounding can destroy repetition that exists only in semantic slot space. Construct this type from a dense operation-ready plaintext with from_plaintext; that conversion verifies exact representability.
implicit_data is absent except for "strided_sparse", where it has layout [*batch, limb] and the same integral dtype and device as data. Direct construction retains supplied storage. clone and decompression allocate independent storage; batch selection and unbinding return storage-sharing views. All batch entries share level, actual scale prime_ids. The value has no engine, cache, placement, or persistence policy.
Attributes
| Name | Type | Default/value |
|---|---|---|
data | torch.Tensor | |
ring_dimension | int | |
compression_layout | CompressedPlaintextLayout | |
level | int | |
scale | float | |
context_id | str | |
polynomial_domain | PolynomialDomain | |
modulus_basis | ModulusBasis | |
residue_representation | ResidueRepresentation | |
prime_ids | tuple[int, ...] | |
implicit_data | torch.Tensor | None | None |
compression_format_version | int | COMPRESSED_PLAINTEXT_FORMAT_VERSION |
unique_count
property
unique_count: intNumber of physically stored values per RNS row.
repeat_count
property
repeat_count: intNumber of dense positions represented by each stored extent.
batch_shape
property
batch_shape: torch.SizeLogical homogeneous batch dimensions.
batch_size
property
batch_size: intFlattened logical batch size; one for an unbatched value.
is_batched
property
is_batched: boolWhether this value has at least one logical batch dimension.
from_plaintext
method
def from_plaintext(plaintext: Plaintext, *, unique_count: int, compression_layout: CompressedPlaintextLayout) -> CompressedPlaintext: ...Losslessly compress one operation-ready dense RNS plaintext.
The encoded last axis is checked bit-for-bit. The compact tensor is cloned so it does not retain the dense input's backing storage. Level, actual scale, domain, basis, residue form, dtype, device, and exact prime_ids are preserved.
decompress_data
method
def decompress_data() -> torch.Tensor: ...Materialize the exact dense RNS encoded tensor.
The output layout is [*batch, limb, coefficient_or_ntt_index] with last extent ring_dimension. It preserves dtype, device, domain, basis, residue form, and limb-to-prime_ids mapping and does not alias compact storage.
to_plaintext
method
def to_plaintext() -> Plaintext: ...Materialize the exact equivalent dense RNS Plaintext.
"Standard" here means the ordinary dense value type; the returned residue representation remains exactly self.residue_representation.
clone
method
def clone() -> CompressedPlaintext: ...with_data
method
def with_data(data: torch.Tensor) -> CompressedPlaintext: ...Return the same exact metadata around replacement tensor storage.
with_storage
method
def with_storage(data: torch.Tensor, implicit_data: torch.Tensor | None) -> CompressedPlaintext: ...Return the same metadata around complete replacement storage.
stack_batch
method
def stack_batch(values: tuple[CompressedPlaintext, ...] | list[CompressedPlaintext]) -> CompressedPlaintext: ...Allocate and copy compatible values into one new batch axis.
select_batch
method
def select_batch(index: int, *, dim: int=0) -> CompressedPlaintext: ...Return a storage-sharing view selected from one batch axis.
unbind_batch
method
def unbind_batch(*, dim: int=0) -> tuple[CompressedPlaintext, ...]: ...Return storage-sharing views along one logical batch axis.
CompressedPlaintextLayout
type alias View source
CompressedPlaintextLayout = Literal['cyclic', 'contiguous', 'strided_sparse']ConjugationKey
class View source
ConjugationKey(data: torch.Tensor, context_id: str, prime_ids: tuple[int, ...], polynomial_domain: PolynomialDomain = 'ntt', modulus_basis: ModulusBasis = 'QP', residue_representation: ResidueRepresentation = 'montgomery')Bases: KeySwitchKey
Key-switch material from
After the conjugation automorphism it restores the original key relation, producing semantic slots
EvaluationKeyRequirements
class View source
EvaluationKeyRequirements(rotation_steps: frozenset[int] = frozenset(), requires_relinearization: bool = False, requires_conjugation: bool = False)Evaluation-key roles and rotations required by one evaluator.
This is a value-independent capability description. It contains no key tensors, device placement, generation policy, or secret-key material. Consumers derive requirements; applications decide how to generate, load, distribute, and retain matching keys.
Attributes
| Name | Type | Default/value |
|---|---|---|
rotation_steps | frozenset[int] | frozenset() |
requires_relinearization | bool | False |
requires_conjugation | bool | False |
EvaluationKeySet
class View source
EvaluationKeySet(rotations: RotationKeySet = field(default_factory=RotationKeySet), relinearization: RelinearizationKey | None = None, conjugation: ConjugationKey | None = None)Validated inventory of evaluator-only CKKS key capabilities.
The inventory contains rotation, relinearization, and conjugation keys. It deliberately excludes PublicKey and SecretKey: encryption, decryption, and key generation are separate capabilities from public evaluation. The set is not a TensorResident and does not move or serialize its members as one large value, so residency policies may continue to manage individual keys and rotation windows independently.
Construction and validate reject mixed structural key states. Key tensors remain ordinary primitive values and may still be passed directly to low-level engine operations.
Attributes
| Name | Type | Default/value |
|---|---|---|
rotations | RotationKeySet | field(default_factory=RotationKeySet) |
relinearization | RelinearizationKey | None | None |
conjugation | ConjugationKey | None | None |
validate
method
def validate() -> EvaluationKeySet: ...Validate all current members and return this inventory.
RotationKeySet is intentionally mutable for application-owned key planning, so consumers call this method again before use. The check re-establishes capability-role types, exact rotation mapping, and one shared context/prime/domain/basis/residue/ring/digit/dtype/device structure. It does not select or validate an evaluator engine.
require
method
def require(requirements: EvaluationKeyRequirements) -> EvaluationKeySet: ...Validate and require every evaluator capability in requirements.
Required rotations are canonicalized with the inventory's ring dimension when at least one rotation key is present. The method checks capability presence only; a consuming engine must separately preflight context, device, and native key compatibility. It returns this mutable inventory for fluent validation.
Raises
TypeError: Ifrequirementsor a current capability role has an invalid type.ValueError: If members are structurally inconsistent or a required rotation/relinearization/conjugation capability is absent.
KeySwitchKey
class View source
KeySwitchKey(data: torch.Tensor, context_id: str, prime_ids: tuple[int, ...], polynomial_domain: PolynomialDomain = 'ntt', modulus_basis: ModulusBasis = 'QP', residue_representation: ResidueRepresentation = 'montgomery')Bases: TensorResident
Hybrid-RNS material for one source-to-destination key relation.
A key generated from
to an equivalent destination phase
up to configured key-switch error. The object does not store symbolic source/destination identifiers; the caller must preserve that direction.
data is a dense integral [key_digit, key_component=2, limb, coefficient_or_ntt_index] tensor. key_digit is stable key-storage identity, not the local active digit_index used at a later level. Limb row prime_ids[i]. Generated keys use the complete level-zero QP basis, NTT domain, Montgomery form, the engine integral dtype, and one engine device. Direct construction and digit/component access retain/share storage; clone allocates independent storage.
Attributes
| Name | Type | Default/value |
|---|---|---|
data | torch.Tensor | |
context_id | str | |
prime_ids | tuple[int, ...] | |
polynomial_domain | PolynomialDomain | 'ntt' |
modulus_basis | ModulusBasis | 'QP' |
residue_representation | ResidueRepresentation | 'montgomery' |
digit_count
property
digit_count: intdigit
method
def digit(key_digit_index: int) -> torch.Tensor: ...Return a storage-sharing [key_component, limb, index] view.
digit_component
method
def digit_component(key_digit_index: int, component_id: int) -> torch.Tensor: ...Return a storage-sharing [limb, index] key-component view.
clone
method
def clone(): ...ModulusBasis
type alias View source
ModulusBasis = Literal['Q', 'QP']Plaintext
class View source
Plaintext(message: torch.Tensor | None, level: int, scale: float, data: torch.Tensor | None = None, context_id: str | None = None, representation: PlaintextRepresentation = 'slots', polynomial_domain: PolynomialDomain | None = None, modulus_basis: ModulusBasis | None = None, residue_representation: ResidueRepresentation | None = None, prime_ids: tuple[int, ...] = ())Bases: TensorResident
One homogeneous CKKS plaintext or dense batch at one exact state tuple.
The state fields describe tensor layout and arithmetic form independently:
representation="slots"stores a scalar (repeated to all slots during encoding) or[*batch, slot]real/complex semantic messages. Encoding has not occurred;dataand all RNS-state metadata are absent.representation="integer_coefficients"stores an exact integral[*batch, coefficient]tensor for , before RNS reduction.representation="approximate_coefficients"stores the bounded binary64[*batch, coefficient]tail-Q reconstruction produced by decryption. It is valid only for decoding and cannot be encrypted or reduced back to RNS; it is not an exact full- CRT inverse.representation="rns"stores a dense integral[*batch, limb, coefficient_or_ntt_index]tensor. Limb row is modulo the exact parameter primeprime_ids[i]. The last axis indexes coefficients of in"coefficient"domain or NTT evaluations in"ntt"domain.modulus_basisselects or , andresidue_representationdistinguishes standard from Montgomery residues.
Tensor payloads retain their input dtype, device, and storage at direct construction; validation requires dense strided storage and the dtype constraints above. Engine operations additionally require the engine's configured integral dtype, device, ring dimension, and complete ordered prime_ids. Construction does not clone an input tensor. clone allocates independent storage, while batch selection and unbinding return storage-sharing views.
A program that needs the same semantic message in multiple arithmetic states constructs separate values. The object owns no engine, cache, placement, or persistence reference. scale is the positive finite actual scale level identifies prime_ids.
Attributes
| Name | Type | Default/value |
|---|---|---|
message | torch.Tensor | None | |
level | int | |
scale | float | |
data | torch.Tensor | None | None |
context_id | str | None | None |
representation | PlaintextRepresentation | 'slots' |
polynomial_domain | PolynomialDomain | None | None |
modulus_basis | ModulusBasis | None | None |
residue_representation | ResidueRepresentation | None | None |
prime_ids | tuple[int, ...] | () |
is_slots
property
is_slots: boolis_integer_coefficients
property
is_integer_coefficients: boolis_approximate_coefficients
property
is_approximate_coefficients: boolis_rns
property
is_rns: boolbatch_shape
property
batch_shape: torch.SizeLogical homogeneous batch dimensions for the active form.
batch_size
property
batch_size: intFlattened logical batch size; one for an unbatched value.
is_batched
property
is_batched: boolWhether this value has at least one logical batch dimension.
clone
method
def clone() -> Plaintext: ...Return a metadata-equivalent value with independent tensor storage.
stack_batch
method
def stack_batch(values: tuple[Plaintext, ...] | list[Plaintext]) -> Plaintext: ...Allocate and copy compatible plaintexts into one new batch axis.
Scalar slots plaintexts are rejected because stacking them would change their repeat-to-all-slots meaning; materialize slot vectors first. Inputs must have identical representation, state, exact prime_ids, shape, dtype, and device. The result does not alias an input.
select_batch
method
def select_batch(index: int, *, dim: int=0) -> Plaintext: ...Return a storage-sharing view selected from one batch axis.
unbind_batch
method
def unbind_batch(*, dim: int=0) -> tuple[Plaintext, ...]: ...Return storage-sharing views along one logical batch axis.
PlaintextRepresentation
type alias View source
PlaintextRepresentation = Literal['slots', 'integer_coefficients', 'approximate_coefficients', 'rns']PolynomialDomain
type alias View source
PolynomialDomain = Literal['coefficient', 'ntt']Preset
class View source
Preset()Bases: Enum
Maintained CKKS parameter baselines.
Each member name records the complex slot capacity, default scale-prime bit width, number of public levels, and integral tensor dtype in its baseline configuration. int32 members use the 30-bit residue buffer; int64 members use the 62-bit residue buffer. All baselines select the 128-bit classical security category, Gaussian error standard deviation 3.19, uniform-ternary secret sampling, and a ring-specific P-prime count. CkksConfig.parse accepts keyword overrides when an application needs a derived configuration.
Attributes
| Name | Type | Default/value |
|---|---|---|
slots8192_scale30_levels9_int64 | 'slots8192-scale30-levels9-int64' | |
slots8192_scale40_levels7_int64 | 'slots8192-scale40-levels7-int64' | |
slots8192_scale50_levels5_int64 | 'slots8192-scale50-levels5-int64' | |
slots16384_scale30_levels21_int64 | 'slots16384-scale30-levels21-int64' | |
slots16384_scale40_levels16_int64 | 'slots16384-scale40-levels16-int64' | |
slots16384_scale50_levels12_int64 | 'slots16384-scale50-levels12-int64' | |
slots32768_scale30_levels45_int64 | 'slots32768-scale30-levels45-int64' | |
slots32768_scale40_levels34_int64 | 'slots32768-scale40-levels34-int64' | |
slots32768_scale50_levels27_int64 | 'slots32768-scale50-levels27-int64' | |
slots65536_scale30_levels95_int64 | 'slots65536-scale30-levels95-int64' | |
slots65536_scale40_levels72_int64 | 'slots65536-scale40-levels72-int64' | |
slots65536_scale50_levels58_int64 | 'slots65536-scale50-levels58-int64' | |
slots8192_scale25_levels14_int32 | 'slots8192-scale25-levels14-int32' | |
slots16384_scale25_levels29_int32 | 'slots16384-scale25-levels29-int32' | |
slots32768_scale25_levels24_int32 | 'slots32768-scale25-levels24-int32' | |
slots65536_scale25_levels14_int32 | 'slots65536-scale25-levels14-int32' |
PublicKey
class View source
PublicKey(data: torch.Tensor, context_id: str, prime_ids: tuple[int, ...], polynomial_domain: PolynomialDomain = 'ntt', modulus_basis: ModulusBasis = 'Q', residue_representation: ResidueRepresentation = 'montgomery')Bases: TensorResident
Public encryption key for one destination secret polynomial.
data is a dense integral [key_component=2, limb, coefficient_or_ntt_index] tensor. In each RNS row the generated components satisfy
where modulus_basis. Row prime_ids[i]; generated keys are level-zero NTT-domain Montgomery residues on one device. The object does not record a symbolic key-lineage identifier, so callers must keep the key paired with its destination secret key. Direct construction and component access retain/share storage; clone allocates independent storage.
Attributes
| Name | Type | Default/value |
|---|---|---|
data | torch.Tensor | |
context_id | str | |
prime_ids | tuple[int, ...] | |
polynomial_domain | PolynomialDomain | 'ntt' |
modulus_basis | ModulusBasis | 'Q' |
residue_representation | ResidueRepresentation | 'montgomery' |
k0
property
k0: torch.Tensork1
property
k1: torch.Tensorcomponent
method
def component(component_id: int) -> torch.Tensor: ...Return a storage-sharing [limb, ntt_index] component view.
clone
method
def clone() -> PublicKey: ...RelinearizationKey
class View source
RelinearizationKey(data: torch.Tensor, context_id: str, prime_ids: tuple[int, ...], polynomial_domain: PolynomialDomain = 'ntt', modulus_basis: ModulusBasis = 'QP', residue_representation: ResidueRepresentation = 'montgomery')Bases: KeySwitchKey
Key-switch material from source key
It replaces the
ResidueRepresentation
type alias View source
ResidueRepresentation = Literal['standard', 'montgomery']RotationKey
class View source
RotationKey(data: torch.Tensor, context_id: str, prime_ids: tuple[int, ...], polynomial_domain: PolynomialDomain = 'ntt', modulus_basis: ModulusBasis = 'QP', residue_representation: ResidueRepresentation = 'montgomery', *, rotation_step: int)Bases: KeySwitchKey
Key-switch material from
rotation_step is the canonical signed user-visible displacement torch.roll(m, shifts=r).
Attributes
| Name | Type | Default/value |
|---|---|---|
rotation_step | int |
canonical_step
method
def canonical_step(step: int, *, ring_dimension: int) -> int: ...Map a step modulo [-S/2, S/2).
clone
method
def clone() -> RotationKey: ...RotationKeySet
class View source
RotationKeySet(table: dict[int, RotationKey] = field(default_factory=dict))Bases: MutableMapping[int, RotationKey]
Mapping from canonical signed rotation steps to matching local keys.
Attributes
| Name | Type | Default/value |
|---|---|---|
table | dict[int, RotationKey] | field(default_factory=dict) |
add
method
def add(key: RotationKey) -> RotationKeySet: ...Install a key under its self-described canonical rotation step.
SecretKey
class View source
SecretKey(data: torch.Tensor, context_id: str, prime_ids: tuple[int, ...], polynomial_domain: PolynomialDomain = 'ntt', modulus_basis: ModulusBasis = 'QP', residue_representation: ResidueRepresentation = 'montgomery')Bases: TensorResident
RNS storage for the secret polynomial
data is a dense integral [limb, coefficient_or_ntt_index] tensor; row prime_ids[i]. Engine-generated keys are level-zero Q or QP values in NTT domain and Montgomery form on the engine device, with final extent clone allocates independent storage; residency views may alias their source. The key carries context and representation metadata but no device owner or persistence policy.
Attributes
| Name | Type | Default/value |
|---|---|---|
data | torch.Tensor | |
context_id | str | |
prime_ids | tuple[int, ...] | |
polynomial_domain | PolynomialDomain | 'ntt' |
modulus_basis | ModulusBasis | 'QP' |
residue_representation | ResidueRepresentation | 'montgomery' |
clone
method
def clone() -> SecretKey: ...Return the same key value in independent tensor storage.
TensorResident
class View source
TensorResident()Bases: ABC
An exact FHElium value whose declared tensor fields move together.
Subclasses enumerate their direct tensor fields and reconstruct the same exact value state around replacement tensors. The capability exposes one common device, logical payload bytes, unique backing-storage bytes, and functional movement for one value.
TensorResident values expose ordinary PyTorch tensors. Functional movement creates independent storage when copy=True and leaves the source object accessible to its caller.
device
property
device: torch.deviceCommon device of every declared tensor field.
nbytes
property
nbytes: intLogical tensor payload bytes, counting every declared tensor field.
storage_nbytes
property
storage_nbytes: intBytes in unique backing storages referenced by declared tensors.
This differs from nbytes when tensor fields share storage or a view references a backing allocation larger than its logical payload. It remains a tensor-storage measure, not CUDA allocator reservation or process memory reported by NVML.
is_cpu
property
is_cpu: boolWhether all declared tensors reside on CPU.
is_cuda
property
is_cuda: boolWhether all declared tensors reside on one CUDA device.
is_pinned
property
is_pinned: boolWhether every declared tensor uses pinned CPU storage.
CUDA values return False. A CPU value whose fields mix pageable and pinned storage also returns False; managed residency validates and rejects such mixed materializations rather than treating them as pageable.
to
method
def to(device: torch.device | str, *, non_blocking: bool=False, copy: bool=False) -> Self: ...Functionally move all declared tensors to one PyTorch device.
cpu
method
def cpu(*, copy: bool=False) -> Self: ...Return this exact value in ordinary pageable CPU storage.
pin_memory
method
def pin_memory(*, copy: bool=False) -> Self: ...Return this exact value backed by pinned CPU tensor storage.
Parameters
copy: Create independent pinned storage even when every source tensor is already pinned. WithFalse, an already uniformly pinned CPU value is returned unchanged.
ValueFileMetadata
class View source
ValueFileMetadata(file_schema_version: int, value_schema_version: int, value_type: str, context_id: str | None, nbytes: int, tensor_metadata: dict[str, dict[str, Any]], value_metadata: dict[str, Any])Validated metadata inspectable without materializing tensor payloads.
Attributes
| Name | Type | Default/value |
|---|---|---|
file_schema_version | int | |
value_schema_version | int | |
value_type | str | |
context_id | str | None | |
nbytes | int | |
tensor_metadata | dict[str, dict[str, Any]] | |
value_metadata | dict[str, Any] |
compatible_ntt_backends
function View source
def compatible_ntt_backends(log_ring_dimension: int) -> tuple[str, ...]: ...Return canonical policy names executable for one logN.
Names retain registry order. Strict fixed-radix policies whose digit width does not divide log_ring_dimension are omitted; grouped radix-2 policies remain available for every supported ring dimension. A non-positive dimension raises ValueError.
errors
module
fhelium.errors
inspect_value
function View source
def inspect_value(path: str | os.PathLike[str]) -> ValueFileMetadata: ...Inspect one value file without materializing its tensor payloads.
load_value
function View source
def load_value(path: str | os.PathLike[str], *, device: torch.device | str='cpu', expected_type: type[T] | None=None, expected_context_id: str | None=None) -> T: ...Load one exact value from a caller-selected value-file path.
This is a file-codec operation: the caller owns path naming, replacement, and lifecycle. ArtifactStore.get is the separate repository operation for logical names, generations, checksums, and catalog transactions. Materialization defaults to CPU unless device selects another target.
save_value
function View source
def save_value(value: TensorResident, path: str | os.PathLike[str], *, allow_secret: bool=False, overwrite: bool=False) -> ValueFileMetadata: ...Atomically save one exact value to the caller-selected file path.
This function provides a versioned file representation, not a namespace, cache, encryption-at-rest policy, or storage manager. Secret-key material requires explicit opt-in and remains unencrypted unless the caller wraps this API in an appropriate security layer.