Transitioning to MHE (Shechi)¶
This tutorial explains when and how to switch from Sequre's additive secret sharing to Shechi, the multiparty homomorphic encryption (MHE) sub-system.
Why MHE?¶
Additive secret sharing excels at linear operations on smaller data scale (addition is free, multiplication costs one communication round). But for workloads heavy in:
- Consecutive multiplications — each requires a full network round
- Matrix multiplications — communication scales with matrix dimensions
- Floating-point batched arithmetic — fixed-point truncation adds overhead
- Large scale data — MHE scales better than secret-sharing MPC
MHE can be significantly faster because computations happen locally on data-parallel encrypted data with communication only for:
- Collective key generation (one-time setup)
- Key-switching / relinearization (after multiplications)
- Ciphertext refresh / bootstrapping (when noise budget runs low)
The CKKS advantage¶
Shechi uses the CKKS homomorphic encryption scheme, which natively supports:
- Approximate arithmetic on real/complex numbers (no fixed-point encoding needed)
- SIMD batching — a single ciphertext holds thousands of values in "slots"
- Efficient rotations — reorder data within a ciphertext without decrypting
Using Shechi types¶
Ciphertensor — encrypted local tensor¶
from sequre.lattiseq.ckks import Ciphertext
from sequre.types.ciphertensor import Ciphertensor
# Encrypt a vector into CKKS ciphertexts
ct_list = mpc.mhe.enc_vector[Ciphertext](my_values)
ct = Ciphertensor(ct_list, shape=[len(my_values)], slots=params.slots())
# Arithmetic works via operator overloading
result = ct_a + ct_b # HE addition
result = ct_a * ct_b # HE multiplication + relinearization
MPU — multiparty union¶
MPU is the highest-level abstraction. It allows writing code that looks like ordinary tensor arithmetic while the framework handles encryption, distribution, and collective operations:
from sequre.types.multiparty_union import MPU
# Each party provides its local rows
mpu = MPU(mpc, my_local_data, "partition")
# Standard operations dispatch to HE under the hood
result = mpu @ weights + bias
MPP vs MPA¶
MPU is internally backed by one of:
| Type | Data distribution | Use case |
|---|---|---|
MPP (partition) |
Each party holds a block of rows | Horizontal data partitioning (e.g., each hospital has patients) |
MPA (aggregate) |
Each party holds an additive share | Additive sharing with optional encryption |
Choose via the second argument to MPU(mpc, data, "partition") or MPU(mpc, data, "additive").
MHE setup¶
MHE requires a one-time collective key generation phase:
This runs:
- Secret key shard generation — each party generates a local secret key shard
- Collective public key generation (CKG) — interactive protocol produces a joint public key
- Collective relinearization key generation (RKG) — joint key for post-multiplication cleanup
- Collective rotation key generation — joint Galois keys for slot rotations
Adding --skip-mhe-setup flag skips MHE setup. Useful when only MPC is needed.
When to use which¶
| Criterion | MPC (Sharetensor) | MHE (Shechi) |
|---|---|---|
| Setup cost | None | Key generation (seconds) |
| Per-multiply cost | 1 network round | Local HE op (~34ms, no network) |
| Batching | No | Yes (thousands of values per ciphertext) |
| Precision | Exact (integer/fixed-point) | Approximate (CKKS) |
| Best for | Exact results, smaller data scale | Dense linear algebra, large scale ML training |
Next steps¶
- One Algorithm, Many Secure Types — Validate and debug the same protocol across plaintext and secure representations.
- Dropping Down the Stack — Learn when to stay high-level and when to descend into MHE/Lattiseq internals.
- Distributed Tensors (MPU) — Deep dive into MPU semantics.
- Ciphertensor API — Complete reference.
- Core MHE module — Internals of the collective protocols.