Announcing TFHE-rs: a fast, pure Rust implementation of TFHE

January 12, 2023
Jean-Baptiste Orfila

Today, we are releasing TFHE-rs, a pure Rust implementation of TFHE for booleans and small integer arithmetics over encrypted data. 

The library is meant for developers and researchers who want full control over what they do with TFHE, while not  concerning themselves with the low level implementation. TFHE-rs aims at being the new reference implementation for TFHE by extending the usual scheme possibilities, including up-to-date security parameters and state-of-the-art features. 

TFHE-rs is great if you are:

  • A researcher working on TFHE who needs both access to low-level, cryptographic primitives as well as high-level operators;
  • An application developer who needs an FHE library that doesn’t require expertise in cryptography;
  • A compiler developer who wants to target TFHE as the backend.

TFHE-rs comes packed with powerful features, such as:

  • A low-level, cryptographic library that implements Zama’s variant of TFHE, including programmable bootstrapping;
  • An implementation of the original TFHE boolean API, which can be used as a drop-in replacement for other TFHE libraries;
  • A short integer API, which enables exact, unbounded FHE integer arithmetics with up to 8 bits of message space;
  • A public key encryption implementation for TFHE;
  • Ciphertext and server key compression for efficient data transfer;
  • A full Rust and C API, and a client-side WASM API.

In the next months, we will release two additional APIs, one for large-integer FHE arithmetics and one for floating-point FHE arithmetics, as well as significant performance improvements throughout the board.

TFHE-rs vs Concrete 

Until now, all of Zama’s FHE products were under a single name, “Concrete”. This included both our FHE library and FHE compiler, creating confusion for our users and customers. To avoid any further issues, we have decided to do a major refactoring and now have two distinct products:

  • TFHE-rs is now Zama’s FHE library, replacing the original Rust Concrete library (the main Concrete repository on Github) as well as Concrete-Core. Use TFHE-rs if you need full control over the FHE circuit execution. Please note that you should avoid using the original Concrete Rust library and start using TFHE-rs instead.
  • Concrete itself will be exclusively centered around Zama’s compiler, Concrete-Numpy and Concrete-ML being built on top of it. Use Concrete if you want optimal performance for a given circuit. The new version of Concrete will be released in April. You can safely continue using Concrete-Numpy and Concrete-ML, as their APIs won’t materially change when Concrete v2 is released in the coming months.

We appreciate that this is a material change for many of you, but we had to make this difficult migration now before things become too complicated!

TFHE-rs by example

Boolean API

The boolean API works just like the original TFHE library, and enables you to chain an infinite number of boolean gates. This can be used as a drop-in replacement for other TFHE libraries.

use tfhe::boolean::prelude::*;

fn main() {
    // Generate a set of client/server keys, using the default parameters:
    let (client_key, server_key) = gen_keys();

    // Encrypt two messages using the (private) client key:
    let ct_1 = client_key.encrypt(true);
    let ct_2 = client_key.encrypt(false);

    // Execute the Boolean circuit using the (public) server key
    // if ((NOT ct_2) NAND (ct_1 AND ct_2)) then (NOT ct_2) else (ct_1 AND ct_2)
    let ct_3 = server_key.not(&ct_2);
    let ct_4 = server_key.and(&ct_1, &ct_2);
    let ct_5 = server_key.nand(&ct_3, &ct_4);
    let ct_6 = server_key.mux(&ct_5, &ct_3, &ct_4);

     // Decrypt the ciphertext using the (private) client key
    let output = client_key.decrypt(&ct_6);
    assert_eq!(output, true);
}

Short Integers API

The shortint API enables you to compute on short integers (up to 8 bits of message), using both classical integer operations (add, multiply, shift, mod, etc..) and programmable bootstrapping (which enables you to compute arbitrary functions).

use tfhe::shortint::prelude::*;

fn main() {
   // Generate a set of client/server keys, using the default parameters:
   let (client_key, server_key) = gen_keys(Parameters::default());

   let msg1 = 3;
   let msg2 = 2;

   // Encrypt two messages using the (private) client key:
   let ct_1 = client_key.encrypt(msg1);
   let ct_2 = client_key.encrypt(msg2);

   // Homomorphically compute an addition
   let ct_add = server_key.unchecked_add(&ct_1, &ct_2);

   // Define the Hamming weight function
   // f: x -> sum of the bits of x
   let f = |x:u64| x.count_ones() as u64;

   // Generate the accumulator for the function
   let acc = server_key.generate_accumulator(f);

   // Compute the function over the ciphertext using the PBS
   let ct_res = server_key.keyswitch_programmable_bootstrap(&ct_add, &acc);

   // Decrypt the ciphertext using the (private) client key
   let output = client_key.decrypt(&ct_res);
   assert_eq!(output, f(msg1 + msg2));
}

Low-level TFHE API

The cryptographic API is dedicated to low-level primitives. It contains the implementations of the main cryptographic tools defined by TFHE. Roughly, this is split in two parts: one for the entity definitions and another one focused on the algorithms. For instance, the entities contain the definition of useful types, like LWE ciphertext or bootstrapping keys. The algorithms are then naturally defined to work using these entities. 

Having dedicated types is not only useful to perform safety tests (e.g., on the dimensions), but also to propose an elegant way to implement cryptography that stays true to the theoretical notations. As a result, code browsing and readability has been drastically improved. 

Benchmarks

TFHE-rs is the fastest public implementation of the TFHE scheme. It supports AVX512 acceleration when available and on our benchmark setup, an AWS machine with Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz. Additionally, the average time for a boolean operation is down to 7 ms for 128 bits of security and an error probability of $2^{-40}$ or better. This benchmark shows how boolean operators in TFHE-rs compares to other libraries (full benchmarks, including shortints can be found here):

Additional links

Read more related posts