Skip to main content

HomOps Reference

HomMatMul

Multiply an encrypted value by a plaintext weight matrix along one axis.

MmML
RunsServer
Changes shapeYes - the multiplied axis: in_dim becomes out_dim
Changes scaleYes - plaintext encoding scale pt_scale
Levels spentPath-dependent; mod-switch enabled by default
RotatesYes - internal slot sum
KeysRotation key

What it does

HomMatMul computes weight @ input along one axis of the ciphertext: multiply by a plaintext weight matrix, then sum along that axis. The weights are fixed data you attach with set_data; the input is encrypted.
It is the weight step of a linear layer. HomLinear is HomMatMul plus a bias (HomConstAdd); use HomMatMul directly when there is no bias, or when the multiply is not a layer at all (a fixed projection, a pooling mask, RGB to grayscale).
The backend selects a Simple, Diags, or Masks path from mul_axis, the packing axis, and new_n_axis. Slot-axis reductions can rotate internally and require rotation-key entries; simpler layouts avoid that work.

Signature

HomMatMul(
    dims,                      # required: weight / plaintext factor shape
    mul_axis=-1,
    new_n_axis=None,
    with_modswitch=True,
    rows_budget=None,
    pt_scale=None,              # defaults to context / scheme
    num_steps=None,
)
The weights come in through set_data:
pipeline.pyPYTHON
pipeline.set_data(op_index, weight_tensor)   # shape must equal dims

Parameters

ParameterTypeDefaultDescription
dims(out, in)requiredThe weight matrix shape, same layout as weight.shape for out = weight @ input.
mul_axisint-1The ciphertext axis to multiply and reduce.
new_n_axisint | NoneNoneWhen mul_axis is the packing axis, selects the output axis that becomes the new packing axis. The backend chooses one when unset.
with_modswitchboolTrueEnable path-dependent mod-switching after packed multiplies.
rows_budgetsequence | NoneNoneAbsolute rows allowed for automatic mod-switches.
pt_scaleintcontext pt_scaleEncoding scale for the plaintext weights. If unset, the backend uses the context or scheme default.
num_stepsint | NoneNoneRotation decomposition steps for the Diags/Masks paths; this affects staging, not the mathematical result.
Rules that depend on the value
SettingRuleIf you break it
dimsThe weight dimension being reduced must equal the ciphertext size along mul_axis, and the tensor passed to set_data must have shape dims.Compilation fails.
mul_axis / new_n_axisThese packing choices select Simple, Diags, or Masks. When the selected path reduces across slots, rotation-key entries are required.-

Requirements

  • set_data called. The weights must be attached before the pipeline compiles.
  • Rotation key entries. Diags and Masks paths may require internal rotations. The compiler derives the offsets for the evaluation key; you don't list them yourself.
These surface as compilation errors; see Compilation errors.

Shape effect - yes

Rule: the multiplied axis changes size from in_dim to out_dim; every other axis is preserved.
shape.pyPYTHON
# input shape:  (..., in_dim, ...)      with in_dim at mul_axis
# output shape: (..., out_dim, ...)     dims = (out_dim, in_dim) for 2D weights
Input shapedimsmul_axisOutput shape
(128,)(10, 128)-1(10,)
(128, 512)(16, 128)-1(16, 512)
pt_shape: (128,)dims=(10, 128)
HomMatMul
pt_shape: (10,)

Scale effect - yes

Rule: plaintext factors are encoded at pt_scale. The resulting scale depends on the selected Simple, Diags, or Masks path and its internal plaintext multiplies.
Use pt_scale to control plaintext encoding precision; inspect the compiled pipeline for the resulting output scale rather than assuming one fixed multiplication factor.
pt_scaleOutput scale
2^30 (context default)Path-dependent compiled output scale
2^20Lower plaintext encoding scale; inspect compilation output
MatMul can grow scale through its plaintext multiplications. The compiler reports the exact outcome for the selected path; use that report when planning the next operation.

Level budget

with_modswitch=True by default permits path-dependent mod-switching after packed multiplies. Set rows_budget to constrain the rows it may use; inspect the compiled plan for the exact level cost.

Keys

Rotation key. Required by Diags/Masks paths that rotate packed ciphertext slots; offsets are derived at compile time. No square key: the encrypted operand is multiplied only by plaintexts.

Example

Minimal matmul

pipeline.pyPYTHON
from lattica_build.operators import HomMatMul
from lattica_build.base_classes.hom_pipeline import HomomorphicPipeline
from lattica_build.operators.composite.sequential import SequentialHomOp
import torch

mat_dims = (16, 128)

pipeline = HomomorphicPipeline(
    hom=SequentialHomOp(
        HomMatMul(mat_dims, mul_axis=0),
    ),
    input_shape=(128, 512),
)
pipeline.set_data(0, torch.rand(mat_dims))
# output shape: (16, 512)

The FC tail of a classifier

After a quadratic activation, project 128 features to 10 classes:
Stagept_shapept_scale
After HomSquare(128,)2^60
After HomMatMul((10, 128))(10,)Depends on pt_scale and the selected backend path
With bias, write HomLinear instead; it chains the same matmul plus a HomConstAdd.

See also