Open-source project
google/heir avatar
google/heir

HEIR: an MLIR compiler that lowers homomorphic encryption code to OpenFHE, Lattigo or tfhe-rs

The compiler for homomorphic encryption

939 stars180 forksMLIRApache-2.0

At a glance

What is it?
HEIR is an MLIR based toolchain that lets teams write homomorphic encryption circuits in a high level dialect and compile them down to a concrete backend library. It ships two tools, heir-opt and heir-translate, a Bazel integration through rules_heir, and a Python package heir_py, with a build that depends on LLVM from source and is the project's real cost of entry.
Who is it for?
HEIR fits research and platform teams who want one circuit description to target several homomorphic encryption libraries, and who already have Bazel and a long build budget, since the toolchain depends on LLVM from source and a clean build takes about 30 minutes.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly MLIR, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One circuit description, several encryption libraries

HEIR is described in one line as an MLIR based toolchain for homomorphic encryption compilers. The name stands for Homomorphic Encryption Intermediate Representation, and the interesting idea is the intermediate representation itself. A homomorphic encryption program has to be written against a particular library, with its own ciphertext types, its own key handling and its own evaluation API, and those libraries differ enough that porting between them is real work.

The HEIR approach inserts a layer in between. You write against HEIR's dialect, and the compiler lowers that to code for a concrete backend. The README lists four backend libraries and shows which schemes each one covers. OpenFHE and Lattigo cover BGV, BFV and CKKS. tfhe-rs and Jaxite cover CGGI. The README adds a note that some backends do not support all schemes, which is the same statement made as a table of gaps.

For a team evaluating more than one FHE library, that is the payoff. The same source circuit can be pointed at different backends, and the choice of library becomes a configuration decision rather than a rewrite. For a team that has already committed to one library, the payoff shrinks to a nicer authoring experience and a possible exit path later.

The project is hosted under the google organisation but the README is explicit about its status: this is not an officially supported Google product.

Three ways in, and they lead to different levels of control

The README lays out three routes, and the choice between them is really a choice about how much of the build you want to own.

The first is Bazel, using the rules_heir module from the Bazel registry, with either OpenFHE or Lattigo as the backend. This is the route for teams that already run Bazel, since rules_heir wires the compiler into a normal build graph and the generated backend code becomes a build artefact rather than something you copy by hand.

The second is the Python route, which requires OpenFHE to be installed and uses the `heir_py` package from PyPI. The package metadata makes the packaging design explicit: the base package ships the heir-opt and heir-translate binaries and declares no dependencies at all, while the real weight sits in optional extras. There is a `python` extra holding the Python frontend dependencies, and an `openfhe` extra holding the pybind11 bindings and colorama needed for the OpenFHE backend.

The third is building from source and invoking the `heir-opt` and `heir-translate` binaries directly, extracting the generated backend code and integrating it into the project manually. That is the lowest level option and the most work per project.

The Getting Started page at heir.dev carries the detail, and the full documentation lives at heir.dev.

heir-opt and heir-translate are the two entry points

The two binaries named in the README, `heir-opt` and `heir-translate`, are the pass running tools at the heart of the toolchain. `heir-opt` is the one the build instructions name as the main pass running tool, and the MLIR convention is visible in the naming: an opt tool applies passes over the intermediate representation, and a translate tool converts that representation into something else, in this case the backend code.

The repository layout confirms the structure. There is a `lib/` directory for the implementation, `include/` for headers, `tools/` for the binaries, `frontend/` for the language frontends, `tests/` for the test suite, `benchmark/` for performance work, `docs/` for documentation, and `patches/` for patches to other projects. The primary language of the repository is listed as MLIR, which is the dialect definition and pass infrastructure, while `frontend/` holds the higher level language frontends.

Two other files hint at how much of the ecosystem HEIR touches. There is a `go.mod` declaring the module `github.com/google/heir` with a dependency on `github.com/tuneinsight/lattigo/v6` at v6.1.0, which means Go tooling is used to drive or test the Lattigo path. And there is a `requirements.txt` autogenerated by pip-compile with hashes, so the Python dependency set is pinned reproducibly rather than resolved at install time.

The layering is what makes the toolchain extensible, and it is also the reason a build can be heavy. More on that below.

The build depends on LLVM from source, and that is the price of entry

HEIR uses Bazel as its build system, and the README's guidance is to install bazelisk so the Bazel version is managed automatically. With `bazel` on the path pointing at bazelisk, the build of the main pass running tool is a single target:

bash
bazel build //tools:heir-opt

An end to end test runs the same way:

bash
bazel test //tests/Examples/openfhe/ckks/halevi_shoup_matvec:all

The path of that test target says several things at once. It is an OpenFHE backend example, the scheme is CKKS, and the test name, halevi_shoup_matvec, points at a matrix vector product example. That is a useful concrete target to point a first build at, because it exercises the whole path rather than a single pass.

The cost is stated without hedging: HEIR depends on LLVM from source, so a clean build may take 30 minutes depending on the machine. The documented escape is remote caching through BuildBuddy. The setup is a `.bazelrc.user` file in the root of the HEIR workspace containing:

code
common --remote_header=x-buildbuddy-api-key=<YOUR_API_KEY>
common --config=remote

With that in place the README puts a clean build at about 5 minutes. So the practical instruction for anyone evaluating HEIR is to set up remote caching before the first build, not after.

heir_py keeps the base install dependency free and pushes the rest into extras

The Python packaging is worth a close look because it shows deliberate care about install weight. The pyproject metadata lists `dependencies = []` with a comment explaining that the base package only ships the heir-opt and heir-translate binaries and has no deps.

Everything else lives in optional dependency groups. The `python` extra carries numba, numpy, colorama and typing_extensions, and the comments in that file explain a specific version conflict: numba 0.62 supports numpy 1.22 through 2.3, SciPy 1.14 wants numpy 1.23.5 up to 2.3.0, and the project needs numpy below 2 because numpy 2 introduces stricter type checking that raises an OverflowError for a Python integer minus one out of bounds for uint32 in some tests. The `typing_extensions` requirement is pinned to Python versions below 3.11, where TypeVarTuple and Unpack are not in the standard library typing module.

The `openfhe` extra carries pybind11 and pybind11_global for the bindings, and colorama.

The `dev` extra exists for the frontend tests and for repository tooling, and includes absl-py, tomli, sympy and mpmath for the test case generator at tests/poly/runner/generate_test_cases.py, jaxite at 0.0.2 for running the Jaxite backend examples, plus fire, jinja2, pre-commit and requests for scripts and repo utilities.

The `setup.py` file adds one more wrinkle for packagers: it patches the rules_python toolchain definitions when building inside a Docker container on Linux as root, because the toolchain definition errors on a root user, and it pins the limited API to cp310 when the interpreter is 3.10 or newer.

Where the scheme coverage gaps actually bite

The backend table is the sharpest limit in the project, and it is worth reading as a matrix rather than a list. If you need CGGI, only tfhe-rs and Jaxite are options, so OpenFHE and Lattigo users are out. If you need BGV, BFV or CKKS, both OpenFHE and Lattigo work and neither of the other two applies.

That means HEIR does not remove the backend choice, it makes the choice explicit and moves the cost. A team that wants to compare CKKS performance between OpenFHE and Lattigo gets real value from the intermediate representation, since the same circuit compiles to both. A team that only ever wants one library in one scheme gets a compiler in the middle of the path and an extra build dependency, which is a worse trade.

There is a second limitation that is not in the table at all. The published release history shows only nightly tags, dated per day, including nightly-2026.10.20, nightly-2026.10.19 and a plain nightly tag. There is no numbered release sequence in that list, which means there is no obvious stable version to pin. The last push was on 2026-10-20, so the project is moving, and the rate of tagged nightlies is high enough that pinning matters for reproducibility. The README does not document a stability policy for the nightly builds.

For a cryptography toolchain, that combination matters more than it would for an ordinary library. The scheme coverage gaps are a functional limit you can design around, but the absence of a documented stable release line is the kind of thing that has to be settled inside your own process, because HEIR will not settle it for you.

Licence, community cadence and what the project asks of contributors

The repository is licensed under Apache-2.0. The Python package is more specific, with the licence field reading MIT AND Apache-2.0, which reflects the split between the packaged wrapper code and the compiler it ships.

The project publishes an academic citation for use in papers, giving HEIR: A Universal Compiler for Homomorphic Encryption, with the arXiv identifier 2508.11095 and the primary class cs.CR. The author list spans multiple institutions, and the pyproject metadata lists maintainers at Google and Intel addresses.

The contribution model is unusually explicit for a compiler project, and it tells you something about what the maintainers consider valuable. Beyond the usual issue labels, there is a `research synthesis` label with a defined two way contract. One direction asks contributors to read papers tagged under research synthesis and summarise novel techniques that could be ported to HEIR. The other asks contributors to file issues under that label to alert the project to papers that should be investigated and incorporated. In effect, new FHE research enters the compiler through a named queue rather than through ad hoc feature requests.

There are monthly meetings, with recordings posted to the project blog and a YouTube channel, weekly office hours for debugging help, a `#heir` channel on the FHE.org Discord, and issues marked as good first issue for newcomers. The repository also carries an AGENTS.md, a .agents directory, a .gemini directory, pre-commit configuration files, and a fuzztest.bazelrc, which indicates that fuzzing is wired into the build.

Editorial conclusion

HEIR fits research and platform teams who want one circuit description to target several homomorphic encryption libraries, and who already have Bazel and a long build budget, since the toolchain depends on LLVM from source and a clean build takes about 30 minutes. It is the wrong choice for a team that needs a supported product, because the README states plainly that this is not an officially supported Google product, and it is the wrong choice if you rely on CGGI through OpenFHE or Lattigo, since neither supports that scheme. Verify three things first: that your target scheme appears in the backend table for the library you plan to use, that your CI can absorb the LLVM build or you can point Bazel at a remote cache through BuildBuddy, and that the nightly tagged releases you pin are actually the ones your patch set applies to.

Frequently asked questions

What is HEIR and which homomorphic encryption backends does it support?

HEIR is an MLIR based toolchain for homomorphic encryption compilers, published as an intermediate representation so one circuit can be lowered to several libraries. The README table lists OpenFHE and Lattigo for BGV, BFV and CKKS, and tfhe-rs and Jaxite for CGGI.

How do I build HEIR from source?

Install bazelisk so the Bazel version is managed, then run `bazel build //tools:heir-opt` to build the main pass running tool. HEIR depends on LLVM from source, so the README puts a clean build at about 30 minutes, reduced to about 5 minutes with a BuildBuddy remote cache configured in `.bazelrc.user`.

What are heir-opt and heir-translate used for?

They are the two binaries of the toolchain. `heir-opt` is the pass running tool, and the README describes invoking `heir-opt` and `heir-translate` directly as the route where you build from source, extract the generated backend code and integrate it into your project manually.

Can I use HEIR from Python?

Yes, through the `heir_py` package on PyPI, which requires OpenFHE to be installed. The base package ships the heir-opt and heir-translate binaries with no dependencies, and the Python frontend and OpenFHE backend dependencies live in the `python` and `openfhe` optional extras.

Does HEIR support CGGI with OpenFHE or Lattigo?

No. The backend table shows CGGI supported only by tfhe-rs and Jaxite, and the README notes that some backends do not support all schemes. OpenFHE and Lattigo cover BGV, BFV and CKKS.

Is HEIR an officially supported Google product?

No. The README states in a support disclaimer that this is not an officially supported Google product, so there is no vendor support commitment behind the toolchain.

Official sources

  1. google/heir on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community

Where developers are discussing it

Posts on Hacker News, dev.to and Lobsters that link to this repository, found by our scan of those communities. 1 in the last 30 days; newest first.

Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/google-heir.svg)](https://hysenlabs.com/projects/google-heir)

Was this useful?