OpenFHE.jl is a Julia wrapper package for OpenFHE, a C++ library for fully homomorphic encryption. The C++ functionality is exposed in native Julia via the CxxWrap.jl package, using OpenFHE-julia as its backend.
Note: This package is work in progress and not all capabilities of OpenFHE have been translated to Julia yet. Community contributions are very welcome!
If you have not yet installed Julia, please follow the instructions for your operating system. OpenFHE.jl works with Julia v1.8 and later on Linux and macOS platforms, and with Julia v1.9 or later on Windows platforms.
Since OpenFHE.jl is a registered Julia package, you can install it by executing the following commands in the Julia REPL:
julia> import Pkg; Pkg.add("OpenFHE")
Internally, OpenFHE.jl relies on OpenFHE-julia to provide bindings for the C++ library OpenFHE. Precompiled binares for OpenFHE-julia and OpenFHE are automatically for your platform when you install OpenFHE.jl, thus there is no need to compile anything manually.
The easiest way to get started is to run one of the examples from the
examples
directory by
include
ing them in Julia, e.g.,
julia> using OpenFHE
julia> include(joinpath(pkgdir(OpenFHE), "examples", "simple_real_numbers.jl"))
CKKS scheme is using ring dimension 16384
Input x1: (0.25, 0.5, 0.75, 1, 2, 3, 4, 5, ... ); Estimated precision: 50 bits
Input x2: (5, 4, 3, 2, 1, 0.75, 0.5, 0.25, ... ); Estimated precision: 50 bits
Results of homomorphic computations:
x1 = (0.25, 0.5, 0.75, 1, 2, 3, 4, 5, ... ); Estimated precision: 43 bits
Estimated precision in bits: 43.0
x1 + x2 = (5.25, 4.5, 3.75, 3, 3, 3.75, 4.5, 5.25, ... ); Estimated precision: 43 bits
Estimated precision in bits: 43.0
x1 - x2 = (-4.75, -3.5, -2.25, -1, 1, 2.25, 3.5, 4.75, ... ); Estimated precision: 43 bits
4 * x1 = (1, 2, 3, 4, 8, 12, 16, 20, ... ); Estimated precision: 41 bits
x1 * x2 = (1.25, 2, 2.25, 2, 2, 2.25, 2, 1.25, ... ); Estimated precision: 41 bits
In rotations, very small outputs (~10^-10 here) correspond to 0's:
x1 rotate by 1 = (0.5, 0.75, 1, 2, 3, 4, 5, 0.25, ... ); Estimated precision: 43 bits
x1 rotate by -2 = (4, 5, 0.25, 0.5, 0.75, 1, 2, 3, ... ); Estimated precision: 43 bits
By default, OpenFHE.jl uses the OpenFHE-julia
library provided by the openfhe_julia_jll.jl package, which is automatically obtained when
installing OpenFHE.jl. Someimtes, however, it might be beneficial to instead use a
system-provided OpenFHE-julia library, e.g., for development or performance purposes. You
can change the default by providing a different library with the OpenFHE.set_library!
function, i.e., by running
julia> using OpenFHE
julia> OpenFHE.set_library!("/abs/path/to/library.so")
[ Info: Please restart Julia and reload OpenFHE.jl for the library changes to take effect
This will create a LocalPreferences.toml
file in your current project directory with the
libopenfhe_julia
preference set accordingly. As advised, you need to restart Julia for
the change to take effect. By calling set_library!()
without an argument, you revert to
using JLL-provided library again.
In case the custom library has been deleted, loading OpenFHE.jl will fail. In that case,
either remove the LocalPreferences.toml
file or manually reset the preferences by
executing
julia> using UUIDs, Preferences
julia> delete_preferences!(UUID("77ce9b8e-ecf5-45d1-bd8a-d31f384f2f95"), # UUID of OpenFHE.jl
"libopenfhe_julia"; force = true)
OpenFHE.jl using CxxWrap.jl to wrap the C++ library OpenFHE for use in Julia. In general, we try to stick as close to the original library's names and conentions as possible. Since some concepts of C++ do not directly translate to Julia, however, some differences are unavoidable. The most notable one is likely that Julia does not know the concept of class member functions. CxxWrap.jl (and OpenFHE.jl) translates this to Julia functions that expect the object as its first argument. Thus, a C++ member function call
my_object.member_function(arg1, arg2);
will look like
member_function(my_object, arg1, arg2)
in Julia.
To simplify switching back and forth between OpenFHE.jl and the C++ library OpenFHE,
OpenFHE.jl tries to use the same type and function names as OpenFHE. Since PascalCase
is
used for types and functions in OpenFHE, the same style is used in OpenFHE.jl, even though
this is contrary to typical Julia best practices (where PascalCase
is only used for types
and snake_case
is used for functions).
Furthermore, all OpenFHE types are wrapped by corresponding CxxWrap.jl types, which can
sometimes be very verbose. To reduce clutter in the Julia REPL, OpenFHE.jl thus often uses a
simpler canonical output when printing an object. For example, the output of
GenCryptoContext(parameters)
is an object of type
CxxWrap.StdLib.SharedPtrAllocated{CryptoContextImpl{DCRTPoly}}
, but when show
ing the
object we just print SharedPtr{CryptoContext{DCRTPoly}}()
. To find out the actual
underlying type, use typeof
.
If you use OpenFHE.jl in your own research, please cite this repository as follows:
@misc{schlottkelakemper2024openfhejulia,
title={{O}pen{FHE}.jl: {F}ully homomorphic encryption in {J}ulia using {O}pen{FHE}},
author={Schlottke-Lakemper, Michael},
year={2024},
howpublished={\url{https://github.com/sloede/OpenFHE.jl}},
doi={10.5281/zenodo.10460452}
}
OpenFHE.jl was initiated by Michael Schlottke-Lakemper (RWTH Aachen University/High-Performance Computing Center Stuttgart (HLRS), Germany), who is also its principal maintainer.
Further contributions to OpenFHE.jl have been made by the following people:
- Arseniy Kholod (RWTH Aachen University, Germany)
OpenFHE.jl is available under the MIT license (see LICENSE.md). OpenFHE itself is available under the BSD 2-Clause license.
Contributions by the community are very welcome! A good start would be to compare the
examples
folder in OpenFHE.jl
(link)
and in OpenFHE
(link) and to
port a missing example file to OpenFHE.jl. In case some OpenFHE functionality is not yet
exposed by OpenFHE-julia, it would have to be
added there first.