fhelium.values
Runtime CKKS values, keys, and value-state types.
Ciphertext
class View source
Ciphertext(data: torch.Tensor, depth: int, scale: float, 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 same depth, scale, component count, domain, basis, residue form, 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 | |
depth | int | |
scale | float | |
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 RNS row interval and its prime IDs.
[start, stop) indexes stored limb positions, not global prime IDs. Component and batch axes, depth, scale, and representation state are preserved; the result represents part of the same basis, not a rescaled value. In-place arithmetic also modifies the corresponding source rows.
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.
The caller must ensure every value has the same effective key lineage, applying a key switch first when necessary.
slice_batch
method
def slice_batch(start: int, stop: int, *, dim: int=0) -> Ciphertext: ...Return a storage-sharing interval along one logical batch axis.
[start, stop) must be a nonempty interval within the selected axis. dim indexes batch_shape and accepts negative dimensions. The axis is retained even for a one-item interval. Depth, scale, prime IDs, and polynomial and residue representations are preserved. Mutations through the returned view also update the corresponding source data.
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.
CompressedPlaintext
class View source
CompressedPlaintext(data: torch.Tensor, ring_dimension: int, compression_layout: CompressedPlaintextLayout, depth: int, scale: float, polynomial_domain: PolynomialDomain, modulus_basis: ModulusBasis, residue_representation: ResidueRepresentation, prime_ids: tuple[int, ...], implicit_data: torch.Tensor | None = None)Bases: TensorResident
An RNS plaintext with compact polynomial or NTT 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. Coefficient data may use standard or Montgomery residues; NTT data uses Montgomery residues, as in Plaintext. compression_layout defines the 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. from_plaintext verifies bit-for-bit representability of existing encoded data. Engine.prepare_compressed_plaintext prepares compact data directly from one periodic message; its rounding need not reproduce a prior full-ring encoding bit for bit.
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 depth, 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 | |
depth | int | |
scale | float | |
polynomial_domain | PolynomialDomain | |
modulus_basis | ModulusBasis | |
residue_representation | ResidueRepresentation | |
prime_ids | tuple[int, ...] | |
implicit_data | torch.Tensor | None | None |
representation
property
representation: Literal['rns']The compact payload represents RNS polynomial rows.
is_rns
property
is_rns: boolis_slots
property
is_slots: boolis_integer_coefficients
property
is_integer_coefficients: boolis_approximate_coefficients
property
is_approximate_coefficients: boolunique_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.
limb_count
property
limb_count: intNumber of represented RNS rows.
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. Depth, actual scale, domain, basis, residue form, dtype, device, and prime_ids are preserved.
decompress_data
method
def decompress_data() -> torch.Tensor: ...Materialize the 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 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 unchanged 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.
slice_limbs
method
def slice_limbs(start: int, stop: int) -> CompressedPlaintext: ...Return a storage-sharing RNS row interval and its prime IDs.
[start, stop) indexes stored limb positions, not global prime IDs. Compact data and any implicit row values are sliced together. Batch axes, depth, scale, compression layout, and representation state are preserved; slicing does not rescale or change the compression format.
stack_batch
method
def stack_batch(values: tuple[CompressedPlaintext, ...] | list[CompressedPlaintext]) -> CompressedPlaintext: ...Allocate and copy compatible values into one new batch axis.
slice_batch
method
def slice_batch(start: int, stop: int, *, dim: int=0) -> CompressedPlaintext: ...Return a storage-sharing interval along one logical batch axis.
[start, stop) must be a nonempty interval within the selected axis. dim indexes batch_shape and accepts negative dimensions. The axis is retained even for a one-item interval. The same interval selects both compact data and any implicit row values. Arithmetic state and compression metadata are unchanged.
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, 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, rotation-step mapping, and one shared prime/domain/basis/residue/ring/digit/dtype/device structure.
require
method
def require(requirements: EvaluationKeyRequirements) -> EvaluationKeySet: ...Validate and require every evaluator capability in requirements.
Required rotations are normalized 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 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, 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 depth. Limb row prime_ids[i]. Generated keys use the complete depth-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 | |
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() -> Self: ...ModulusBasis
type alias View source
ModulusBasis = Literal['Q', 'QP']Plaintext
class View source
Plaintext(message: torch.Tensor | None, depth: int, scale: float, data: torch.Tensor | 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 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 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 a full- CRT inverse.representation="rns"stores a dense integral[*batch, limb, coefficient_or_ntt_index]tensor. Limb row is modulo the 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; encoded payloads require dense strided storage and the dtype constraints above. Engine operations additionally require the engine's configured integral dtype, device, ring dimension, and matching prime-row parameters. Row-local operations can use a sliced RNS interval; operations requiring the complete active basis must receive every required row. 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 depth identifies prime_ids.
Attributes
| Name | Type | Default/value |
|---|---|---|
message | torch.Tensor | None | |
depth | int | |
scale | float | |
data | torch.Tensor | 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: boollimb_count
property
limb_count: intNumber of represented RNS rows; zero for non-RNS representations.
batch_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.
slice_limbs
method
def slice_limbs(start: int, stop: int) -> Plaintext: ...Return a storage-sharing RNS row interval and its prime IDs.
[start, stop) indexes stored limb positions, not global prime IDs. All batch axes, depth, scale, and representation state are preserved; the result represents part of the same basis, not a rescaled value. Slots and non-RNS coefficient representations have no limb axis.
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, prime_ids, shape, dtype, and device. The result does not alias an input.
slice_batch
method
def slice_batch(start: int, stop: int, *, dim: int=0) -> Plaintext: ...Return a storage-sharing interval along one logical batch axis.
[start, stop) must be a nonempty interval within the selected axis. dim indexes batch_shape and accepts negative dimensions. The axis is retained even for a one-item interval. The active slots, coefficient, or RNS representation is preserved. Depth, scale, prime IDs, and representation state are unchanged.
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']PublicKey
class View source
PublicKey(data: torch.Tensor, 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 depth-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 | |
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, 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, 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 normalized signed user-visible displacement torch.roll(m, shifts=r).
Attributes
| Name | Type | Default/value |
|---|---|---|
rotation_step | int |
normalize_step
method
def normalize_step(step: int, *, ring_dimension: int) -> int: ...Map a step modulo [-S/2, S/2).
RotationKeySet
class View source
RotationKeySet(table: dict[int, RotationKey] = field(default_factory=dict))Bases: MutableMapping[int, RotationKey]
Mapping from normalized 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 normalized rotation step.
SecretKey
class View source
SecretKey(data: torch.Tensor, 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 depth-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 representation metadata but no device owner or persistence policy.
Attributes
| Name | Type | Default/value |
|---|---|---|
data | torch.Tensor | |
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
A FHElium value whose declared tensor fields move together.
Subclasses enumerate their direct tensor fields and reconstruct the same 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 value in ordinary pageable CPU storage.
pin_memory
method
def pin_memory(*, copy: bool=False) -> Self: ...Return this 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.