Skip to main content

← HomOps Reference

HomConstAdd

Add a fixed plaintext (a bias, an offset) to an encrypted value.

CaArithmetic
RunsServer, or client side
Changes shapeYes - broadcast with the plaintext
Changes scaleNo
Levels spent0
RotatesNo
KeysNone

What it does​

HomConstAdd adds a plaintext tensor to a ciphertext. One operand is encrypted, the other is fixed data you attach with set_data: a bias after a linear layer, a shift, any constant offset.
It is the plaintext counterpart of HomAdd, which adds two ciphertexts. Like all additions it is cheap: no key, no level spent, no scale change.
You will often meet it without writing it: HomLinear with bias=True chains a HomConstAdd after its matmul, and HomBatchNorm uses one for the shift.

Implicit HomConstAdd: just write x + pt​

When you add a plaintext to an encrypted value with the + operator, the compiler infers a HomConstAdd behind the scenes:
pipeline.pyPYTHON
y = x + pt        # HomConstAdd inferred (ciphertext + plaintext)
result = x * y    # HomMul inferred (ciphertext × ciphertext)
Write HomConstAdd(dims=...) explicitly when the plaintext arrives later via set_data, for example a bias tensor loaded at deploy time. dims is required at construct time for broadcast shape inference.

Signature​

HomConstAdd(dims)   # required: plaintext / bias shape
dims is required. The plaintext values come in through set_data and are reshaped to dims when set:
pipeline.pyPYTHON
add = HomConstAdd(dims=bias_tensor.shape)
pipeline.set_data(op_index, bias_tensor)   # reshaped to dims when set

Parameters​

ParameterTypeDefaultDescription
dimsTensorShaperequiredExpected plaintext / bias tensor shape used for broadcast shape inference at construct and compile time. Must be compatible with the tensor passed to set_data (reshaped to dims when set).
set_data rules

set_data rules​

RuleDetail
ShapeThe plaintext must broadcast with the ciphertext shape, like array shapes do.
n axisWhen the plaintext spans the n axis at full length, it is packed along the slots (the efficient path). When it is broadcast on the n axis instead (e.g. bias (C, 1, 1) against (C, H, W)), a broadcast fallback runs. Anything else fails at compile time.
ScaleYou don't pass a scale. The plaintext is encoded at the ciphertext's current scale automatically.
dtypeStored as float (CKKS) or integer (RBGV).

Requirements​

  • set_data called. The plaintext must be attached before the pipeline compiles. A HomConstAdd without data fails at compile time.
  • Broadcastable shapes. The plaintext shape must broadcast with the ciphertext shape, with the n axis rules above.
These surface as compilation errors; see Compilation errors.

Shape effect - yes​

Rule: the output shape is the broadcast of the ciphertext shape and the plaintext shape.
The n axis is marked in bold:
CiphertextPlaintextOutput
(128,)(128,)(128,) - packed along the n axis
(10, 128)(10, 1)(10, 128) - broadcast on the n axis
(16, 8, 8)(16, 1, 1)(16, 8, 8) - per-channel bias
tensor shape: (16, 8, 8)pt_scale: 2^30
HomConstAdd(bias: (16, 1, 1))
tensor shape: (16, 8, 8)pt_scale: 2^30
Shape and the n axis are covered on Concepts.

Scale effect - no​

The plaintext is encoded at the ciphertext's current scale, so the addition lands correctly and the scale carries through unchanged. Contrast with HomConstMul, which multiplies the scale.

Level budget​

Zero. No mod-switch runs and there is no with_modswitch option; the chain is untouched.

Keys​

None.

Example​

Bias inside HomLinear​

The common case: you never write HomConstAdd at all, bias=True does it.
pipeline.pyPYTHON
from lattica_build.operators import HomLinear
from lattica_build.base_classes.hom_pipeline import HomomorphicPipeline
from lattica_build.operators.composite.sequential import SequentialHomOp

pipeline = HomomorphicPipeline(
    hom=SequentialHomOp(
        HomLinear((64, 784), bias=True),   # HomMatMul + HomConstAdd inside
    ),
    input_shape=(784,),
)
pipeline.set_data(0, weight_tensor, bias_tensor)

See also​