SkillAgentSearch skills...

Einhops

Einsum Notation for FHE

Install / Use

/learn @baahl-nyu/Einhops
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

EinHops: Einsum Notation for Expressive Homomorphic Operations on RNS-CKKS Tensors

EinHops enables the intuitive einsum notation for performing tensor operations directly on encrypted tensors in Fully Homomorphic Encryption (FHE). The example below demonstrates batched matrix-matrix multiplication on encrypted data.

import torch
import einhops

a = torch.randn(2, 3, 4)
b = torch.randn(2, 4, 5)
c = torch.einsum("bik,bkj->bij", a, b)

a_ctxt = einhops.encrypt(a)
b_ctxt = einhops.encrypt(b)
c_ctxt = einhops.einsum("bik,bkj->bij", a_ctxt, b_ctxt)

assert c.shape == c_ctxt.shape == (2, 3, 5)
assert torch.allclose(c, einhops.decrypt(c_ctxt), atol=1e-4)

What is EinHops?

EinHops ia a system for performing tensor operations via einsum expressions in FHE (RNS-CKKS). The high level goal of EinHops is to build a simple packing strategy that provides transparency into how your data is arranged within ciphertext slots and provide a minimalist implementation. We decompose einsum expressions into a series of FHE-friendly operations and implement each step directly in Python. For more information, check out our paper!

Requirements

  • Python 3.11 or greater
  • 3GB RAM (low memory mode) or 32GB RAM (full BSGS keys)
  • (Optional) NVIDIA GPU with CUDA 12.x

We've tested EinHops on an Intel Xeon Platinum 8480+ processor with an H100 80GB, an AMD EPYC 7502 32-Core Processor with an RTX 3090, and a Macbook Air with an Apple M2 chip.

Installation

Clone the repo and change directories:

git clone https://github.com/baahl-nyu/einhops.git
cd einhops

We recommend installing EinHops in a virtual environment using Python version 3.11. We use uv, but conda or pyenv would also work. For uv, you can run the following in the einhops repo:

uv venv --python 3.11
source .venv/bin/activate

You should now see (einhops) at the beginning of your shell prompt. Next, we will make sure to install the correct Desilo FHE library version based on your system setup.

CPU Installation

If you wish to install EinHops to run on your CPU, run:

uv pip install -e."[cpu]"

GPU Installation

If you have an NVIDIA GPU and CUDA version >=12.1, you can install the appropriate Desilo version by checking your CUDA version (top right corner of nvidia-smi). More details on Desilo GPU versions can be found here. In our case, we have version 12.8 so we run:

uv pip install -e ."[cuda128]"  # or cuda121, cuda124, cuda126, cuda129, cuda130

You should now be able to run the examples within the examples folder.

Tests

The following will run all test cases:

pytest test/ --cov=einhops

Running EinHops

There are a couple of configurations to help you run EinHops under different circumstances:

Low Memory Environment

If you are constrained on RAM or VRAM, you can choose to generate only the power-of-two rotations keys which requires roughly 3GB of memory. Set the following environment flag:

EINHOPS_DISABLE_BSGS_KEYS=1

This mode will be slightly slower, but otherwise EinHops will generate the rotation keys needed for baby-step giant-step linear transformations, which will require roughly 32GB of memory.

Verbosity

You can set the verbosity level through the logger.

import einhops
einhops.set_log_level("DEBUG") # DEBUG -> INFO -> WARNING (default) -> ERROR -> CRITICAL

Setting to DEBUG level will help with understanding the dataflow for each stage of the einsum call listed in the paper.

Simulated CKKS Backend

You can also replace the CKKS backend with PyTorch to help debug and understand the dataflow of FHE programs you build in EinHops. This will still execute the same dataflow but with torch Tensors rather than ciphertexts.

import einhops
einhops.set_backend("torch") # torch or ckks (default)

Fun Examples

Sum over a dimension

import torch
import einhops
a = torch.randn(128, 128)
o = torch.einsum("ij->j", a)

a_ckks = einhops.encrypt(a)
o_ckks = einhops.einsum("ij->j", a_ckks)

print(o)
print(einhops.decrypt(o_ckks))

Multi-Head Self-Attention Scores

import torch
import einhops

einhops.set_log_level('DEBUG')

# batch_size, seq_len, n_heads, h_dim_per_head
q = torch.randn(2, 5, 8, 16)
k = torch.randn(2, 5, 8, 16)
attn = torch.einsum("bthd,bThd->bhtT", q, k)

q_ckks = einhops.encrypt(q, level=3)
k_ckks = einhops.encrypt(k, level=3)

attn_ckks = einhops.einsum("bthd,bThd->bhtT", q_ckks, k_ckks)

print('validate:')
print("L2 norm: ", torch.norm(einhops.decrypt(attn_ckks) - attn))

Citation

If you found our work useful, please use the following citation:

@misc{garimella2025einhopseinsumnotationexpressive,
      title={EinHops: Einsum Notation for Expressive Homomorphic Operations on RNS-CKKS Tensors},
      author={Karthik Garimella and Austin Ebel and Brandon Reagen},
      year={2025},
      eprint={2507.07972},
      archivePrefix={arXiv},
      primaryClass={cs.CR},
      url={https://arxiv.org/abs/2507.07972},
}

Issues

Please feel free to open an issue or make a pull request!

View on GitHub
GitHub Stars11
CategoryDevelopment
Updated2mo ago
Forks1

Languages

Python

Security Score

90/100

Audited on Jan 16, 2026

No findings