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
pt_shape: (16, 8, 8)pt_scale: 2^30
HomConstAdd(bias: (16, 1, 1))
pt_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