Skip to content

Cingulata

Patrick Jattke edited this page Aug 27, 2020 · 6 revisions

Cingulata, previously known as Armadillo (eprint), is a compiler that translates high-level programs written in C++ (against the Cingulata API) into circuits to be executed using FHE. It bundles its own implementation of the BFV scheme, and also has partial support for the TFHE library.

The compiler is bundled with a runtime environment that supports an offline mode (BFV only) and an online mode (TFHE only). In the offline mode, the given input C++ program is transformed into its equivalent Boolean circuit, optimized by the ABC tool, and finally executed. The online mode can be compared to an on-the-fly execution in that the input program is executed directly using a low-level implementation of the TFHE scheme.

Compilation Process

The following describes how programs for BFV are compiled by Cingulata. The whole compilation process is fully automated using cmake/make files, and as such the following steps are enough to build Cingulata including its examples:

git clone https://github.com/CEA-LIST/Cingulata.git
cd Cingulata
mkdir build; cd "$_"
cmake ..
make

As an example for the following explanation, we consider the cardio test program that is part of Cingulata and consists of two files:

  • cardio.cxx - The program's logic. It uses the BitTracker class to record operations to be transformed into their equivalent circuit at run-time.
  • run.sh.in - A script template that automates key generation, input data encryption, execution, and decryption.

During the cmake step, the Makefiles are created that contain the commands required for building and optimizing the circuit. Also, the run.sh.in script template is configured, i.e., placeholder variables (e.g., paths) that are formatted as @KEY_NAME@ are replaced by concrete values, resulting in the executable file run.sh.

Executing the make command starts the actual build process. Essential part of it is building the helper utilities (apps/ directory) for encoding data into binary numbers (helper), en- and decryption (encrypt/decrypt), key generation (generate_keys), and homomorphic evaluation (dyn_omp). Furthermore, the program cardio.cxx is built and automatically executed, resulting in a circuit file bfv-cardio.blif. Thereafter, a Python script is executed that invokes the ABC circuit optimizer on that circuit, resulting in an optimized circuit bfv-cardio-opt.blif. A helper script (selectParams.sh) then uses CinguParam to derive suitable parameters for the circuit. These are stored in the fhe_params.xml file.

After the build process finished, the user can execute the run.sh file to run the program: This first generates the required FHE keys – a public key (fhe_key.pk), a private key (fhe_key.sk), and an evaluation key (fhe_key.evk). Then, the input values that are hard-coded in the script (run.sh) are encoded as binary numbers and encrypted by bitwise-XOR with the hard-coded Kreyvium keystream. A clear-text representation of that is written into clear_data.data for debugging purposes. The ciphertexts that serve as the circuit inputs are written into the input/ directory. This directory contains a ciphertext file for each bit of an input parameter, e.g., i:ks_X_Y denotes the Y-th bit of the X-th input parameter. In the cardio example, each input value is encrypted using a 8 bit binary encoding. Afterward, the program is homomorphically executed over the encrypted inputs and the encrypted result is written into the output/ directory in a bit-encoded style, similar as the input. Finally, the execution's result is decrypted and printed to the screen.

Primitive Operations

There exist multiple circuits for the primitive operations (e.g., addition, multiplication). In the circuit generation file it is possible to choose between a multiplicative depth-optimized circuit (IntOpGenDepth) or a low-sized circuit (IntOpGenSize).

For example, IntOpGenDepth uses the following circuits for the primitive operations:

namespace cingulata
{
  class IntOpGenDepth : public IIntOpGen {
  ...
  private:
    int_ops::SklanskyAdder      m_add;
    int_ops::Negate             m_neg;
    int_ops::WallaceMultiplier  m_mul;
    int_ops::EqualDepth         m_equal;
    int_ops::LowerCompDepth     m_lower;
  };
}

In the circuit generation file (e.g., cardio.cxx), the desired optimization strategy must be chosen by passing the strategy to the CiContext:

CiContext::set_config(
  make_shared<BitTracker>(), 
  make_shared<IntOpGenDepth>());  <---

SoK Build Process

We have created a FindCingulata.cmake file for use in our benchmarking applications that provides the necessary boilerplate to integrate Cingulata into a traditional cmake based project. The system searches for Cingulata in /cingu and exposes the necessary libraries and include files to allow successful compilation of the program logic file (e.g. cardio.cxx). Support for generating actual circuits and running them is planned for a future iteration.

Note: FindCingulata.cmake is not used anymore as we use the generated circuits directly during the benchmarking (instead of re-creating it every time) and as such do not need to link against Cingulata. See commit 6631f06c for the solution with FindCingulata.

Clone this wiki locally