Skip to content

tutorial_hello

Sergiu Carpov edited this page Jun 13, 2019 · 3 revisions

Hello world application with Cingulata

This step-by-step tutorial is aimed to guide you on how you can write a new application, configure, optimize and run it within Cingulata. You may also want to take a look at the different code examples, present in the tests directory.

By now, you have installed and configured the compilation chain and the runtime. You have a main directory named cingulata and several sub-directories, including build_bfv and tests.

To create a new test "hello", go to the tests/bfv folder and create a new directory hello_my:

cd tests/bfv
mkdir hello_my

Inside this directory, you will write your source code hello.cxx and the execution script run.sh.

Let's create source file hello.cxx performing the addition of two integers:

/* local includes */
#include <bit_exec/tracker.hxx>
#include <ci_context.hxx>
#include <ci_int.hxx>
#include <int_op_gen/mult_depth.hxx>

/* namespaces */
using namespace std;
using namespace cingulata;

int main() {
  /* Set context to bit tracker and multiplicative depth minimized integer
   * operations */
  CiContext::set_config(make_shared<BitTracker>(), make_shared<IntOpGenDepth>());

  CiInt a{CiInt::u8};      // create from unsigned 8-bit template
  CiInt b{CiInt::u8v(42)}; // use helper function to create an unsigned 8-bit
  CiInt c{-1, 16, false};  // or manually specify value, size and signedness

  a.read("a");            // read variable a and set name

  b.set_name("b");        // set name and ...
  cin >> b;               //  read variable b

  c = a + b;

  cout << c.set_name("c");// set name and write variable with stream operator
  // c.write("c");           //  or do it at once

  /* Export to file the "tracked" circuit */
  CiContext::get_bit_exec_t<BitTracker>()->export_blif(blif_name, "hello");
}

On the first line a bit tracker is set as executor and Boolean circuits of optimized multiplicative depth are employed. As you can see, the two integers a and b are defined using the special type CiInt. These integers are "read" and added together. The result is a variable c of type which will be outputted on the standard output. The bit-size and signedness of CiInt variables are defined in the constructor. The final line specifies that the Boolean circuit associated with this code will be saved in a file whose name is given by blif_name.

Now, we will create a template for the execution shell script run.sh.in with the following content:

CIRCUIT=@CIRCUIT@
APPS_DIR=@APPS_DIR@

mkdir -p input
rm -f input/*.ct

mkdir -p output
rm -f output/*.ct

# Generate keys
echo "FHE key generation"
$APPS_DIR/generate_keys

echo "Input encryption"
NR_THREADS=1

# Encrypt input "a"
TMP=`$APPS_DIR/helper --bit-cnt 8 --prefix input/i:a_ 5`
$APPS_DIR/encrypt -v --threads $NR_THREADS $TMP

# Encrypt input "b"
TMP=`$APPS_DIR/helper --bit-cnt 8 --prefix input/i:b_ 3`
$APPS_DIR/encrypt -v --threads $NR_THREADS $TMP

echo "Homomorphic execution..."
time $APPS_DIR/dyn_omp $CIRCUIT --threads $NR_THREADS # -v

echo "Output decryption"
OUT_FILES=`ls -v output/*`
$APPS_DIR/helper --from-bin --bit-cnt 16 `$APPS_DIR/decrypt $OUT_FILES`

This script creates two empty directories: input and output (or clean them if they were created before). It calls the binary generate_keys to generate the binary files for the private and public keys. The encryption of the two input variables is done bitwise, on 8 bits (--bit-cnt option) (remember they were defined as 8-bit CiInts in the input code) using a given number of threads. The encrypted bits will be saved in the folder input as individual binary files with prefixes i:a_ and respectively i:b_. The homomorphic execution is realized by calling the parallel runtime dyn_omp on the optimized Boolean circuit. Finally, the 16 bits of the result are read from the output directory and decrypted, each decrypted bit is packed in a nice format using the helper binary.

You're almost at the end but, before running the test, you will have to create a cmake file CMakeLists.txt in the directory hello_my with the following content:

cmake_minimum_required(VERSION 3.0)

set(TEST_NAME bfv-hello_my)

set(SRCS hello.cxx)
set(BLIF_NAME ${TEST_NAME}.blif)
set(BLOP_NAME ${TEST_NAME}-opt.blif)

add_compile_options(-Dblif_name="${BLIF_NAME}")

set(GEN_NAME ${TEST_NAME}-gen)

add_executable(${GEN_NAME} ${SRCS})

target_link_libraries(${GEN_NAME} common)

add_custom_command(OUTPUT ${BLIF_NAME}
  COMMAND ./${GEN_NAME}
  DEPENDS ${GEN_NAME})

add_custom_command(OUTPUT ${BLOP_NAME}
  COMMAND python3 ${OPTIM_DIR}/abc_optimize.py -i ${BLIF_NAME} -o ${BLOP_NAME} -v
  DEPENDS abc ${BLIF_NAME})

set(XML_PARAMS fhe_params.xml)
set(MUL_DEPTH_SCRIPT ${OPTIM_DIR}/graph_info.py)

add_custom_command(OUTPUT ${XML_PARAMS}
        COMMAND bash ${SCRIPT_DIR}/selectParams.sh ${TEST_NAME} `python3 ${MUL_DEPTH_SCRIPT} ${BLOP_NAME} --mult_depth_max` ${MODEL} ${MIN_SECU}
        DEPENDS ${BLOP_NAME})

add_custom_target(${TEST_NAME} ALL
  DEPENDS ${XML_PARAMS} runtime)

set(APPS_DIR ${CMAKE_BINARY_DIR}/apps)
set(CIRCUIT ${BLOP_NAME})
configure_file("run.sh.in" "run.sh" @ONLY)

At the beginning variables for the C++ source code and the Boolean circuits are defined. The C++ source code is then compiled and executed. The execution outputs a Boolean circuit which is optimized afterwards (python program abc_optimize.py). Using the multiplicative depth of the optimized Boolean circuit a set of homomorphic encryption parameters is generated (shell script selectParams.sh). Finally, the execution script template is parametrized and copied to build directory.

Note 1: The python script graph_info.py analyses the Boolean circuit specified as a .blif file and gives information about the size of the circuit, the number of particular gates (AND and XOR), the maximal multiplicative depth, etc.

Note 2: The 'CMakeLists.txt' file is very similar from a test to another. You can just copy one from an existing test and simply change the test name, i.e. the line:

set(TEST_NAME hello)

That's all for the configuration of the application. All you have to do now is to compile and run it. For this, you have to go to the build_bfv directory and run:

cd ../../build_bfv/
cmake ..
make

At the end, in build_bfv/tests/bfv a new directory named hello_my is created containing all the necessary files and executables for running the test (the xml file with the FHE parameters, the Boolean circuit files (.blif) -- the original and optimized one, the execution script run.sh, etc.).

Now, you can finally execute your first application with Cingulata:

cd tests/bfv/hello_my/
bash run.sh

If all went well, you can see in the terminal all the steps: the key generation, the encryption (bit by bit), the execution details, and the output result:

FHE key generation
Input encryption
Command line arguments:
FHE parameters file fhe_params.xml
Public key file fhe_key.pk
Encrypting message [1] into file input/i:a_0.ct
Encrypting message [0] into file input/i:a_1.ct
Encrypting message [1] into file input/i:a_2.ct
Encrypting message [0] into file input/i:a_3.ct
Encrypting message [0] into file input/i:a_4.ct
Encrypting message [0] into file input/i:a_5.ct
Encrypting message [0] into file input/i:a_6.ct
Encrypting message [0] into file input/i:a_7.ct
Command line arguments:
FHE parameters file fhe_params.xml
Public key file fhe_key.pk
Encrypting message [1] into file input/i:b_0.ct
Encrypting message [1] into file input/i:b_1.ct
Encrypting message [0] into file input/i:b_2.ct
Encrypting message [0] into file input/i:b_3.ct
Encrypting message [0] into file input/i:b_4.ct
Encrypting message [0] into file input/i:b_5.ct
Encrypting message [0] into file input/i:b_6.ct
Encrypting message [0] into file input/i:b_7.ct
Homomorphic execution...
Total execution real time 4.66193 seconds
CPU time:
READ time 0.0661443 seconds, #execs 16
COPY time 0.0380457 seconds, #execs 71
XOR gates execution time 0.0448051 seconds, #execs 24
NOT gates execution time 0.0138237 seconds, #execs 20
AND gates execution time 4.17691 seconds, #execs 18
OR gates execution time 0.240259 seconds, #execs 1
WRITE time 0.0249645 seconds, #execs 16
Maximal number of simultaneously allocated ciphertexts 23

real  0m4.694s
user  0m4.601s
sys 0m0.092s
Output decryption
8

It is not a surprise since the sum of 5 and 3 is 8!

For more complicated examples of applications using Cingulata, go to the tests/bfv directory.

We hope that you have found this tutorial helpful! If you have any issues or suggestions, please drop us a note on how we can improve !

Enjoy your walk through Cingulata world!

Clone this wiki locally