Skip to content

Commit

Permalink
feat(hlapi): add glwe compression c-api
Browse files Browse the repository at this point in the history
  • Loading branch information
mayeul-zama committed Jun 19, 2024
1 parent 25e7158 commit 82f2d4a
Show file tree
Hide file tree
Showing 4 changed files with 381 additions and 0 deletions.
145 changes: 145 additions & 0 deletions tfhe/c_api_tests/test_compressed_list.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#include "tfhe.h"

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

int main(void) {
int ok = 0;

// First, we create a ClientKey and a CompactPublicKey
ClientKey *client_key = NULL;
ServerKey *server_key = NULL;

{
ConfigBuilder *builder;
Config *config;
ok = config_builder_default(&builder);
assert(ok == 0);

config_builder_enable_compression(&builder, COMP_PARAMS_FOR_MESSAGE_2_CARRY_2_KS_PBS);

ok = config_builder_build(builder, &config);
assert(ok == 0);

ok = generate_keys(config, &client_key, &server_key);
assert(ok == 0);

ok = set_server_key(server_key);
assert(ok == 0);
}

// Then, we create the compact list
CompressedCiphertextList *list = NULL;
{
CompressedCiphertextListBuilder *builder;
ok = compressed_ciphertext_list_builder_new(&builder);
assert(ok == 0);

FheUint32 *a = NULL;
FheInt64 *b = NULL;
FheBool *c = NULL;
FheUint2 *d = NULL;

// Encrypt
{
ok = fhe_uint32_try_encrypt_with_client_key_u32(38382, client_key, &a);
assert(ok == 0);

ok = fhe_int64_try_encrypt_with_client_key_i64(-1, client_key, &b);
assert(ok == 0);

ok = fhe_bool_try_encrypt_with_client_key_bool(true, client_key, &c);
assert(ok == 0);

ok = fhe_uint2_try_encrypt_with_client_key_u8(3, client_key, &d);
assert(ok == 0);
}

// Push some values
ok = compressed_ciphertext_list_builder_push_u32(builder, a);
assert(ok == 0);

ok = compressed_ciphertext_list_builder_push_i64(builder, b);
assert(ok == 0);

ok = compressed_ciphertext_list_builder_push_bool(builder, c);
assert(ok == 0);

ok = compressed_ciphertext_list_builder_push_u2(builder, d);
assert(ok == 0);

ok = compressed_ciphertext_list_builder_build(builder, &list);
assert(ok == 0);

// Don't forget to destroy the builder
compressed_ciphertext_list_builder_destroy(builder);
}

// Now we can expand values
FheUint32 *a = NULL;
FheInt64 *b = NULL;
FheBool *c = NULL;
FheUint2 *d = NULL;
{
FheTypes type = Type_FheBool;

size_t len = 0;
ok = compressed_ciphertext_list_len(list, &len);
assert(ok == 0 && len == 4);

// First, an example of getting the type in a slot
ok = compressed_ciphertext_list_get_kind_of(list, 0, &type);
assert(ok == 0 && type == Type_FheUint32);

ok = compressed_ciphertext_list_get_kind_of(list, 1, &type);
assert(ok == 0 && type == Type_FheInt64);

ok = compressed_ciphertext_list_get_kind_of(list, 2, &type);
assert(ok == 0 && type == Type_FheBool);

ok = compressed_ciphertext_list_get_kind_of(list, 3, &type);
assert(ok == 0 && type == Type_FheUint2);

// Then how to get the values
ok = compressed_ciphertext_list_get_fhe_uint32(list, 0, &a);
assert(ok == 0);

ok = compressed_ciphertext_list_get_fhe_int64(list, 1, &b);
assert(ok == 0);

ok = compressed_ciphertext_list_get_fhe_bool(list, 2, &c);
assert(ok == 0);

ok = compressed_ciphertext_list_get_fhe_uint2(list, 3, &d);
assert(ok == 0);
}

uint32_t clear_a = 0;
ok = fhe_uint32_decrypt(a, client_key, &clear_a);
assert(ok == 0);
assert(clear_a == 38382);

int64_t clear_b = 0;
ok = fhe_int64_decrypt(b, client_key, &clear_b);
assert(ok == 0);
assert(clear_b == -1);

bool clear_c = false;
ok = fhe_bool_decrypt(c, client_key, &clear_c);
assert(ok == 0);
assert(clear_c == true);

uint8_t clear_d = 0;
ok = fhe_uint2_decrypt(d, client_key, &clear_d);
assert(ok == 0);
assert(clear_d == 3);

fhe_uint32_destroy(a);
fhe_int64_destroy(b);
fhe_bool_destroy(c);
fhe_uint2_destroy(d);
client_key_destroy(client_key);
return EXIT_SUCCESS;
}
29 changes: 29 additions & 0 deletions tfhe/src/c_api/high_level_api/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,32 @@ pub unsafe extern "C" fn config_builder_build(
*result = Box::into_raw(Box::new(Config(config)));
})
}

#[no_mangle]
pub unsafe extern "C" fn config_builder_enable_compression(
builder: *mut *mut ConfigBuilder,
compression_parameters: CompressionParameters,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(builder).unwrap();

let compression_parameters = get_ref_checked(compression_parameters.0).unwrap();

let inner = Box::from_raw(*builder)
.0
.enable_compression(compression_parameters.to_owned());
*builder = Box::into_raw(Box::new(ConfigBuilder(inner)));
})
}

#[repr(C)]
pub struct CompressionParameters(
*const crate::shortint::parameters::glwe_compression::CompressionParameters,
);

unsafe impl Sync for CompressionParameters {}

#[no_mangle]
pub static COMP_PARAMS_FOR_MESSAGE_2_CARRY_2_KS_PBS: CompressionParameters = CompressionParameters(
&crate::shortint::parameters::glwe_compression::COMP_PARAMS_FOR_MESSAGE_2_CARRY_2_KS_PBS,
);
206 changes: 206 additions & 0 deletions tfhe/src/c_api/high_level_api/glwe_ct_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
use crate::c_api::high_level_api::booleans::FheBool;
use crate::c_api::high_level_api::integers::{
FheInt10, FheInt12, FheInt128, FheInt14, FheInt16, FheInt160, FheInt2, FheInt256, FheInt32,
FheInt4, FheInt6, FheInt64, FheInt8, FheUint10, FheUint12, FheUint128, FheUint14, FheUint16,
FheUint160, FheUint2, FheUint256, FheUint32, FheUint4, FheUint6, FheUint64, FheUint8,
};
use crate::c_api::high_level_api::utils::{
impl_destroy_on_type, impl_serialize_deserialize_on_type,
};
use crate::c_api::utils::{catch_panic, get_mut_checked, get_ref_checked};
use std::ffi::c_int;

pub struct CompressedCiphertextListBuilder(crate::high_level_api::CompressedCiphertextListBuilder);
impl_destroy_on_type!(CompressedCiphertextListBuilder);

pub struct CompressedCiphertextList(crate::high_level_api::CompressedCiphertextList);
impl_destroy_on_type!(CompressedCiphertextList);
impl_serialize_deserialize_on_type!(CompressedCiphertextList);

#[no_mangle]
pub unsafe extern "C" fn compressed_ciphertext_list_builder_new(
builder: *mut *mut CompressedCiphertextListBuilder,
) -> c_int {
catch_panic(|| {
let inner = crate::high_level_api::CompressedCiphertextListBuilder::new();

*builder = Box::into_raw(Box::new(CompressedCiphertextListBuilder(inner)));
})
}

#[no_mangle]
pub unsafe extern "C" fn compressed_ciphertext_list_builder_build(
builder: *const CompressedCiphertextListBuilder,
list: *mut *mut CompressedCiphertextList,
) -> c_int {
catch_panic(|| {
let builder: &CompressedCiphertextListBuilder = get_ref_checked(builder).unwrap();

let inner = builder.0.build().unwrap();

*list = Box::into_raw(Box::new(CompressedCiphertextList(inner)));
})
}

/// Pushes a boolean into the list
#[no_mangle]
pub unsafe extern "C" fn compressed_ciphertext_list_builder_push_bool(
builder: *mut CompressedCiphertextListBuilder,
value: *const FheBool,
) -> c_int {
catch_panic(|| {
let builder = get_mut_checked(builder).unwrap();

let value: &FheBool = get_ref_checked(value).unwrap();

builder.0.push(value.0.clone());
})
}

macro_rules! define_compressed_ciphertext_list_builder_push_method {
(
unsigned: $($num_bits:literal),*
$(,)?
) => {
::paste::paste!{
$(
#[doc = concat!("Pushes an unsigned integer of ", stringify!($num_bits), " bits to the list")]
#[no_mangle]
pub unsafe extern "C" fn [<compressed_ciphertext_list_builder_push_u $num_bits>](
builder: *mut CompressedCiphertextListBuilder,
value: *const [<FheUint $num_bits>],
) -> c_int {
catch_panic(|| {
let builder = get_mut_checked(builder).unwrap();

let value: &[<FheUint $num_bits>] = get_ref_checked(value).unwrap();


builder.0.push(value.0.clone());
})
}
)*
}
};
(
signed: $($num_bits:literal),*
$(,)?
) => {
::paste::paste!{
$(
#[doc = concat!("Pushes a signed integer of ", stringify!($num_bits), " bits to the list")]
#[no_mangle]
pub unsafe extern "C" fn [<compressed_ciphertext_list_builder_push_i $num_bits>](
builder: *mut CompressedCiphertextListBuilder,
value: *const [<FheInt $num_bits>],
) -> c_int {
catch_panic(|| {
let builder = get_mut_checked(builder).unwrap();

let value: &[<FheInt $num_bits>] = get_ref_checked(value).unwrap();

builder.0.push(value.0.clone());
})
}
)*
}
};
}

define_compressed_ciphertext_list_builder_push_method!(unsigned: 2, 4, 6, 8, 10, 12, 14, 16, 32, 64, 128, 160, 256);
define_compressed_ciphertext_list_builder_push_method!(signed: 2, 4, 6, 8, 10, 12, 14, 16, 32, 64, 128, 160, 256);

#[no_mangle]
pub unsafe extern "C" fn compressed_ciphertext_list_len(
expander: *mut CompressedCiphertextList,
out: *mut usize,
) -> c_int {
catch_panic(|| {
let expander = get_ref_checked(expander).unwrap();
*out = expander.0.len();
})
}

#[no_mangle]
pub unsafe extern "C" fn compressed_ciphertext_list_get_kind_of(
expander: *mut CompressedCiphertextList,
index: usize,
out: *mut super::FheTypes,
) -> c_int {
let mut result = None;
catch_panic(|| {
let expander = get_ref_checked(expander).unwrap();
result = expander.0.get_kind_of(index);
});
result.map_or(1, |r| {
*out = r.into();
0
})
}

macro_rules! define_ciphertext_list_get {
(
unsigned: $($num_bits:literal),*
$(,)?
) => {
::paste::paste!(
$(
#[no_mangle]
pub unsafe extern "C" fn [<compressed_ciphertext_list_get_fhe_uint $num_bits>](
expander: *mut CompressedCiphertextList,
index: usize,
out: *mut *mut [<FheUint $num_bits>],
) -> c_int {
catch_panic(|| {
let expander = get_mut_checked(expander).unwrap();

let inner = expander.0.get(index).unwrap().unwrap();

*out = Box::into_raw(Box::new([<FheUint $num_bits>](inner)));
})
}
)*
);
};
(
signed: $($num_bits:literal),*
$(,)?
) => {
::paste::paste!(
$(
#[no_mangle]
pub unsafe extern "C" fn [<compressed_ciphertext_list_get_fhe_int $num_bits>](
expander: *mut CompressedCiphertextList,
index: usize,
out: *mut *mut [<FheInt $num_bits>],
) -> c_int {
catch_panic(|| {
let expander = get_mut_checked(expander).unwrap();

let inner = expander.0.get(index).unwrap().unwrap();

*out = Box::into_raw(Box::new([<FheInt $num_bits>](inner)));
})
}
)*
);
}
}

define_ciphertext_list_get!(unsigned: 2, 4, 6, 8, 10, 12, 14, 16, 32, 64, 128, 160, 256);
define_ciphertext_list_get!(signed: 2, 4, 6, 8, 10, 12, 14, 16, 32, 64, 128, 160, 256);

#[no_mangle]
pub unsafe extern "C" fn compressed_ciphertext_list_get_fhe_bool(
expander: *mut CompressedCiphertextList,
index: usize,
out: *mut *mut FheBool,
) -> c_int {
catch_panic(|| {
let expander = get_mut_checked(expander).unwrap();

let inner = expander.0.get(index).unwrap().unwrap();

*out = Box::into_raw(Box::new(FheBool(inner)));
})
}
1 change: 1 addition & 0 deletions tfhe/src/c_api/high_level_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod array;
pub mod booleans;
mod compact_list;
pub mod config;
pub mod glwe_ct_list;
pub mod i128;
pub mod i256;
pub mod integers;
Expand Down

0 comments on commit 82f2d4a

Please sign in to comment.