fhelium.core
Core CKKS value, context-identity, and rotation-planning types.
COMPRESSED_PLAINTEXT_FORMAT_VERSION
constant View source
COMPRESSED_PLAINTEXT_FORMAT_VERSION = 1Ciphertext
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.
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.
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']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.
decompose_power_of_two_rotation
function View source
def decompose_power_of_two_rotation(rotation_step: int, num_slots: int) -> list[int]: ...Decompose a signed rotation into positive power-of-two steps.
decompose_rotation_step
function View source
def decompose_rotation_step(rotation_step: int, num_slots: int, rotation_keys: Mapping[int, object]) -> list[int]: ...Find the shortest cyclic decomposition using installed keys only.
decompose_signed_power_of_two_rotation
function View source
def decompose_signed_power_of_two_rotation(rotation_step: int, num_slots: int) -> list[int]: ...Decompose a cyclic rotation into a minimal signed power-of-two path.
The result is the non-adjacent form of the canonical rotation in [-num_slots/2, num_slots/2). Unlike decompose_power_of_two_rotation, negative steps are retained, so a key planner can trade a smaller key inventory against composed rotations without turning a short negative rotation into a long positive path.