From eb4b0753dce6d2043ea288e0fbae81d305c9f375 Mon Sep 17 00:00:00 2001 From: "Mayeul@Zama" Date: Mon, 20 Jun 2022 17:53:47 +0200 Subject: [PATCH] enhance(runtime): Move to the official concrete-core-ffi release 0.2.0-rc2 Co-authored-by: Mayeul@Zama Co-authored-by: Quentin Bourgerie --- compiler/.gitignore | 2 +- compiler/CMakeLists.txt | 2 +- compiler/Makefile | 78 ++++++++---- .../concretelang/ClientLib/EvaluationKeys.h | 30 ++--- .../include/concretelang/ClientLib/KeySet.h | 21 ++-- .../include/concretelang/ClientLib/Types.h | 5 +- compiler/include/concretelang/Common/Error.h | 6 + .../include/concretelang/Runtime/context.h | 34 +++-- .../concretelang/Runtime/key_manager.hpp | 85 +++++++++---- .../include/concretelang/Runtime/seeder.h | 13 ++ .../include/concretelang/Runtime/wrappers.h | 1 - compiler/lib/ClientLib/KeySet.cpp | 118 ++++++++++++++---- compiler/lib/ClientLib/KeySetCache.cpp | 96 ++++++++++---- compiler/lib/ClientLib/PublicArguments.cpp | 4 - compiler/lib/ClientLib/Serializers.cpp | 70 ++++++++--- compiler/lib/Runtime/CMakeLists.txt | 1 + compiler/lib/Runtime/context.cpp | 27 ++-- compiler/lib/Runtime/seeder.cpp | 43 +++++++ compiler/lib/Runtime/wrappers.cpp | 99 ++++++++++++--- 19 files changed, 540 insertions(+), 195 deletions(-) create mode 100644 compiler/include/concretelang/Runtime/seeder.h create mode 100644 compiler/lib/Runtime/seeder.cpp diff --git a/compiler/.gitignore b/compiler/.gitignore index f72a79eb1..76c8b1619 100644 --- a/compiler/.gitignore +++ b/compiler/.gitignore @@ -1,4 +1,4 @@ -.dependencies/ build/ *.mlir.script *.lit_test_times.txt +concrete-core-ffi* diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt index 935467e6f..fac7be971 100644 --- a/compiler/CMakeLists.txt +++ b/compiler/CMakeLists.txt @@ -53,7 +53,7 @@ set(CONCRETELANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) # ------------------------------------------------------------------------------- include_directories(${CONCRETE_FFI_RELEASE}) add_library(Concrete STATIC IMPORTED) -set_target_properties(Concrete PROPERTIES IMPORTED_LOCATION ${CONCRETE_FFI_RELEASE}/libconcrete_ffi.a) +set_target_properties(Concrete PROPERTIES IMPORTED_LOCATION ${CONCRETE_FFI_RELEASE}/libconcrete_core_ffi.a) # ------------------------------------------------------------------------------- # Python Configuration diff --git a/compiler/Makefile b/compiler/Makefile index f625be1d4..09859e466 100644 --- a/compiler/Makefile +++ b/compiler/Makefile @@ -18,6 +18,13 @@ HPX_TARBALL=$(shell pwd)/hpx-$(HPX_VERSION).tar.gz HPX_LOCAL_DIR=$(shell pwd)/hpx-$(HPX_VERSION) HPX_INSTALL_DIR?=$(HPX_LOCAL_DIR) +CONCRETE_CORE_FFI_VERSION?=0.2.0-rc.2 +ifeq ($(shell uname), Linux) + CONCRETE_CORE_FFI_TARBALL=concrete-core-ffi_$(CONCRETE_CORE_FFI_VERSION)_linux_amd64.tar.gz +else + CONCRETE_CORE_FFI_TARBALL=concrete-core-ffi_$(CONCRETE_CORE_FFI_VERSION)_darwin_amd64.tar.gz +endif + export PATH := $(abspath $(BUILD_DIR))/bin:$(PATH) ifeq ($(shell which ccache),) @@ -53,6 +60,46 @@ endif all: concretecompiler python-bindings build-tests build-benchmarks doc +# concrete-core-ffi ####################################### + +CONCRETE_CORE_FFI_FOLDER = $(shell pwd)/concrete-core-ffi-$(CONCRETE_CORE_FFI_VERSION) + +CONCRETE_CORE_FFI_ARTIFACTS=$(CONCRETE_CORE_FFI_FOLDER)/libconcrete_core_ffi.a $(CONCRETE_CORE_FFI_FOLDER)/concrete-core-ffi.h + +concrete-core-ffi: $(CONCRETE_CORE_FFI_ARTIFACTS) + +$(CONCRETE_CORE_FFI_ARTIFACTS): $(CONCRETE_CORE_FFI_FOLDER) + +$(CONCRETE_CORE_FFI_FOLDER): $(CONCRETE_CORE_FFI_TARBALL) + mkdir -p $(CONCRETE_CORE_FFI_FOLDER) + tar -xvzf $(CONCRETE_CORE_FFI_TARBALL) --directory $(CONCRETE_CORE_FFI_FOLDER) + +$(CONCRETE_CORE_FFI_TARBALL): + curl -L https://github.com/zama-ai/concrete-core/releases/download/concrete-core-ffi-$(CONCRETE_CORE_FFI_VERSION)/$(CONCRETE_CORE_FFI_TARBALL) -o $(CONCRETE_CORE_FFI_TARBALL) + +# concrete-optimizer ###################################### + +LIB_CONCRETE_OPTIMIZER_CPP = $(CONCRETE_OPTIMIZER_DIR)/target/libconcrete_optimizer_cpp.a + +concrete-optimizer-lib: + make -C $(CONCRETE_OPTIMIZER_DIR)/concrete-optimizer-cpp $(LIB_CONCRETE_OPTIMIZER_CPP) + +# HPX ##################################################### + +install-hpx-from-source: $(HPX_LOCAL_DIR) + mkdir -p $(HPX_LOCAL_DIR)/build + cd $(HPX_LOCAL_DIR)/build && cmake \ + -DHPX_WITH_FETCH_ASIO=on \ + -DHPX_FILESYSTEM_WITH_BOOST_FILESYSTEM_COMPATIBILITY=ON \ + -DHPX_WITH_MALLOC=system .. + cd $(HPX_LOCAL_DIR)/build && make -j2 + +$(HPX_TARBALL): + curl -L $(HPX_URL) -o $(HPX_TARBALL) + +$(HPX_LOCAL_DIR): $(HPX_TARBALL) + tar xzvf $(HPX_TARBALL) + $(BUILD_DIR)/configured.stamp: mkdir -p $(BUILD_DIR) cmake -B $(BUILD_DIR) -GNinja ../llvm-project/llvm/ \ @@ -68,7 +115,7 @@ $(BUILD_DIR)/configured.stamp: -DCONCRETELANG_BINDINGS_PYTHON_ENABLED=$(BINDINGS_PYTHON_ENABLED) \ -DCONCRETELANG_DATAFLOW_EXECUTION_ENABLED=$(DATAFLOW_EXECUTION_ENABLED) \ -DCONCRETELANG_TIMING_ENABLED=$(TIMING_ENABLED) \ - -DCONCRETE_FFI_RELEASE=${CONCRETE_PROJECT}/target/release \ + -DCONCRETE_FFI_RELEASE=$(CONCRETE_CORE_FFI_FOLDER) \ -DHPX_DIR=${HPX_INSTALL_DIR}/lib/cmake/HPX \ -DLLVM_EXTERNAL_PROJECTS=concretelang \ -DLLVM_EXTERNAL_CONCRETELANG_SOURCE_DIR=. \ @@ -76,30 +123,7 @@ $(BUILD_DIR)/configured.stamp: -DCONCRETE_OPTIMIZER_DIR=${CONCRETE_OPTIMIZER_DIR} touch $@ -build-initialized: concrete-optimizer-lib $(BUILD_DIR)/configured.stamp - -LIB_CONCRETE_OPTIMIZER_CPP = $(CONCRETE_OPTIMIZER_DIR)/target/libconcrete_optimizer_cpp.a - -# we need CONCRETE_OPTIMIZER_DIR here to ensure it is present before computing CONCRETE_OPTIMIZER_SRC - -concrete-optimizer-lib: - make -C $(CONCRETE_OPTIMIZER_DIR)/concrete-optimizer-cpp $(LIB_CONCRETE_OPTIMIZER_CPP) - -# HPX - -install-hpx-from-source: $(HPX_LOCAL_DIR) - mkdir -p $(HPX_LOCAL_DIR)/build - cd $(HPX_LOCAL_DIR)/build && cmake \ - -DHPX_WITH_FETCH_ASIO=on \ - -DHPX_FILESYSTEM_WITH_BOOST_FILESYSTEM_COMPATIBILITY=ON \ - -DHPX_WITH_MALLOC=system .. - cd $(HPX_LOCAL_DIR)/build && make -j2 - -$(HPX_TARBALL): - curl -L $(HPX_URL) -o $(HPX_TARBALL) - -$(HPX_LOCAL_DIR): $(HPX_TARBALL) - tar xzvf $(HPX_TARBALL) +build-initialized: concrete-optimizer-lib concrete-core-ffi $(BUILD_DIR)/configured.stamp doc: build-initialized cmake --build $(BUILD_DIR) --target mlir-doc @@ -288,6 +312,7 @@ python_lint: python_format \ check_python_format \ concrete-optimizer-lib \ + concrete-core-ffi \ build-tests \ run-tests \ run-check-tests \ @@ -296,4 +321,5 @@ python_lint: run-python-tests \ build-end-to-end-tests \ build-end-to-end-dataflow-tests \ - run-end-to-end-dataflow-tests + run-end-to-end-dataflow-tests \ + concrete-core-ffi diff --git a/compiler/include/concretelang/ClientLib/EvaluationKeys.h b/compiler/include/concretelang/ClientLib/EvaluationKeys.h index e426e0601..2f29ba468 100644 --- a/compiler/include/concretelang/ClientLib/EvaluationKeys.h +++ b/compiler/include/concretelang/ClientLib/EvaluationKeys.h @@ -8,19 +8,18 @@ #include -extern "C" { -#include "concrete-ffi.h" -} +#include "concrete-core-ffi.h" +#include "concretelang/Common/Error.h" namespace concretelang { namespace clientlib { // ============================================= -/// Wrapper for `LweKeyswitchKey_u64` so that it cleans up properly. +/// Wrapper for `LweKeyswitchKey64` so that it cleans up properly. class LweKeyswitchKey { private: - LweKeyswitchKey_u64 *ksk; + LweKeyswitchKey64 *ksk; protected: friend std::ostream &operator<<(std::ostream &ostream, @@ -29,27 +28,28 @@ protected: LweKeyswitchKey &wrappedKsk); public: - LweKeyswitchKey(LweKeyswitchKey_u64 *ksk) : ksk{ksk} {} + LweKeyswitchKey(LweKeyswitchKey64 *ksk) : ksk{ksk} {} LweKeyswitchKey(LweKeyswitchKey &other) = delete; LweKeyswitchKey(LweKeyswitchKey &&other) : ksk{other.ksk} { other.ksk = nullptr; } ~LweKeyswitchKey() { if (this->ksk != nullptr) { - free_lwe_keyswitch_key_u64(this->ksk); + CAPI_ASSERT_ERROR(destroy_lwe_keyswitch_key_u64(this->ksk)); + this->ksk = nullptr; } } - LweKeyswitchKey_u64 *get() { return this->ksk; } + LweKeyswitchKey64 *get() { return this->ksk; } }; // ============================================= -/// Wrapper for `LweBootstrapKey_u64` so that it cleans up properly. +/// Wrapper for `FftwFourierLweBootstrapKey64` so that it cleans up properly. class LweBootstrapKey { private: - LweBootstrapKey_u64 *bsk; + FftwFourierLweBootstrapKey64 *bsk; protected: friend std::ostream &operator<<(std::ostream &ostream, @@ -58,19 +58,19 @@ protected: LweBootstrapKey &wrappedBsk); public: - LweBootstrapKey(LweBootstrapKey_u64 *bsk) : bsk{bsk} {} + LweBootstrapKey(FftwFourierLweBootstrapKey64 *bsk) : bsk{bsk} {} LweBootstrapKey(LweBootstrapKey &other) = delete; LweBootstrapKey(LweBootstrapKey &&other) : bsk{other.bsk} { other.bsk = nullptr; } ~LweBootstrapKey() { if (this->bsk != nullptr) { - free_lwe_bootstrap_key_u64(this->bsk); + CAPI_ASSERT_ERROR(destroy_fftw_fourier_lwe_bootstrap_key_u64(this->bsk)); this->bsk = nullptr; } } - LweBootstrapKey_u64 *get() { return this->bsk; } + FftwFourierLweBootstrapKey64 *get() { return this->bsk; } }; // ============================================= @@ -96,8 +96,8 @@ public: std::shared_ptr sharedBsk) : sharedKsk{sharedKsk}, sharedBsk{sharedBsk} {} - LweKeyswitchKey_u64 *getKsk() { return this->sharedKsk->get(); } - LweBootstrapKey_u64 *getBsk() { return this->sharedBsk->get(); } + LweKeyswitchKey64 *getKsk() { return this->sharedKsk->get(); } + FftwFourierLweBootstrapKey64 *getBsk() { return this->sharedBsk->get(); } }; // ============================================= diff --git a/compiler/include/concretelang/ClientLib/KeySet.h b/compiler/include/concretelang/ClientLib/KeySet.h index 4aa2c8904..d3b189e3b 100644 --- a/compiler/include/concretelang/ClientLib/KeySet.h +++ b/compiler/include/concretelang/ClientLib/KeySet.h @@ -10,9 +10,7 @@ #include "boost/outcome.h" -extern "C" { -#include "concrete-ffi.h" -} +#include "concrete-core-ffi.h" #include "concretelang/Runtime/DFRuntime.hpp" #include "concretelang/Runtime/context.h" @@ -102,9 +100,8 @@ public: return EvaluationKeys(); } - const std::map> & - getSecretKeys(); + const std::map> + &getSecretKeys(); const std::map>> @@ -135,8 +132,10 @@ protected: friend class KeySetCache; private: - Engine *engine; - std::map> + DefaultEngine *engine; + DefaultParallelEngine *par_engine; + FftwEngine *fftw_engine; + std::map> secretKeys; std::map>> @@ -144,13 +143,13 @@ private: std::map>> keyswitchKeys; - std::vector> + std::vector> inputs; - std::vector> + std::vector> outputs; void setKeys( - std::map> + std::map> secretKeys, std::map>> diff --git a/compiler/include/concretelang/ClientLib/Types.h b/compiler/include/concretelang/ClientLib/Types.h index 0ea3470b0..e2b5de0fc 100644 --- a/compiler/include/concretelang/ClientLib/Types.h +++ b/compiler/include/concretelang/ClientLib/Types.h @@ -7,12 +7,9 @@ #define CONCRETELANG_CLIENTLIB_TYPES_H_ #include +#include #include -extern "C" { -#include "concrete-ffi.h" -} - namespace concretelang { namespace clientlib { diff --git a/compiler/include/concretelang/Common/Error.h b/compiler/include/concretelang/Common/Error.h index 508c175a1..74cdc0dc8 100644 --- a/compiler/include/concretelang/Common/Error.h +++ b/compiler/include/concretelang/Common/Error.h @@ -7,6 +7,12 @@ #include +#define CAPI_ASSERT_ERROR(instr) \ + { \ + int err = instr; \ + assert(err == 0); \ + } + namespace concretelang { namespace error { diff --git a/compiler/include/concretelang/Runtime/context.h b/compiler/include/concretelang/Runtime/context.h index 1bb0e1121..551104bb7 100644 --- a/compiler/include/concretelang/Runtime/context.h +++ b/compiler/include/concretelang/Runtime/context.h @@ -6,35 +6,43 @@ #ifndef CONCRETELANG_RUNTIME_CONTEXT_H #define CONCRETELANG_RUNTIME_CONTEXT_H +#include #include #include #include #include "concretelang/ClientLib/EvaluationKeys.h" +#include "concretelang/Runtime/seeder.h" -extern "C" { -#include "concrete-ffi.h" -} +#include "concrete-core-ffi.h" +#include "concretelang/Common/Error.h" namespace mlir { namespace concretelang { typedef struct RuntimeContext { ::concretelang::clientlib::EvaluationKeys evaluationKeys; - std::map engines; + DefaultEngine *default_engine; + std::map fftw_engines; std::mutex engines_map_guard; - RuntimeContext() {} + RuntimeContext() { + CAPI_ASSERT_ERROR(new_default_engine(best_seeder, &default_engine)); + } /// Ensure that the engines map is not copied RuntimeContext(const RuntimeContext &ctx) - : evaluationKeys(ctx.evaluationKeys) {} + : evaluationKeys(ctx.evaluationKeys) { + CAPI_ASSERT_ERROR(new_default_engine(best_seeder, &default_engine)); + } RuntimeContext(const RuntimeContext &&other) - : evaluationKeys(other.evaluationKeys) {} + : evaluationKeys(other.evaluationKeys), + default_engine(other.default_engine) {} ~RuntimeContext() { - for (const auto &key : engines) { - free_engine(key.second); + CAPI_ASSERT_ERROR(destroy_default_engine(default_engine)); + for (const auto &key : fftw_engines) { + CAPI_ASSERT_ERROR(destroy_fftw_engine(key.second)); } } @@ -48,12 +56,14 @@ typedef struct RuntimeContext { } // namespace mlir extern "C" { -LweKeyswitchKey_u64 * +LweKeyswitchKey64 * get_keyswitch_key_u64(mlir::concretelang::RuntimeContext *context); -LweBootstrapKey_u64 * +FftwFourierLweBootstrapKey64 * get_bootstrap_key_u64(mlir::concretelang::RuntimeContext *context); -Engine *get_engine(mlir::concretelang::RuntimeContext *context); +DefaultEngine *get_engine(mlir::concretelang::RuntimeContext *context); + +FftwEngine *get_fftw_engine(mlir::concretelang::RuntimeContext *context); } #endif diff --git a/compiler/include/concretelang/Runtime/key_manager.hpp b/compiler/include/concretelang/Runtime/key_manager.hpp index 2d63a4186..a3e648280 100644 --- a/compiler/include/concretelang/Runtime/key_manager.hpp +++ b/compiler/include/concretelang/Runtime/key_manager.hpp @@ -17,9 +17,8 @@ #include "concretelang/Runtime/DFRuntime.hpp" #include "concretelang/Runtime/context.h" -extern "C" { -#include "concrete-ffi.h" -} +#include "concrete-core-ffi.h" +#include "concretelang/Common/Error.h" namespace mlir { namespace concretelang { @@ -54,11 +53,30 @@ template struct KeyWrapper { }; template <> -KeyWrapper::KeyWrapper(LweKeyswitchKey_u64 *key) - : key(key), buffer(serialize_lwe_keyswitching_key_u64(key)) {} +KeyWrapper::KeyWrapper(LweKeyswitchKey64 *key) : key(key) { + + DefaultSerializationEngine *engine; + + CAPI_ASSERT_ERROR(new_default_serialization_engine(&engine)); + // No Freeing as it doesn't allocate anything. + CAPI_ASSERT_ERROR( + default_serialization_engine_serialize_lwe_keyswitch_key_u64(engine, key, + &buffer)); +} template <> -KeyWrapper::KeyWrapper(LweBootstrapKey_u64 *key) - : key(key), buffer(serialize_lwe_bootstrap_key_u64(key)) {} +KeyWrapper::KeyWrapper( + FftwFourierLweBootstrapKey64 *key) + : key(key) { + + FftwSerializationEngine *engine; + + CAPI_ASSERT_ERROR(new_fftw_serialization_engine(&engine)); + + // No Freeing as it doesn't allocate anything. + CAPI_ASSERT_ERROR( + fftw_serialization_engine_serialize_fftw_fourier_lwe_bootstrap_key_u64( + engine, key, &buffer)); +} template bool operator==(const KeyWrapper &lhs, @@ -68,36 +86,50 @@ bool operator==(const KeyWrapper &lhs, template <> template -void KeyWrapper::save(Archive &ar, - const unsigned int version) const { +void KeyWrapper::save( + Archive &ar, const unsigned int version) const { ar << buffer.length; ar << hpx::serialization::make_array(buffer.pointer, buffer.length); } template <> template -void KeyWrapper::load(Archive &ar, - const unsigned int version) { +void KeyWrapper::load( + Archive &ar, const unsigned int version) { + FftwSerializationEngine *engine; + + // No Freeing as it doesn't allocate anything. + CAPI_ASSERT_ERROR(new_fftw_serialization_engine(&engine)); + ar >> buffer.length; buffer.pointer = new uint8_t[buffer.length]; ar >> hpx::serialization::make_array(buffer.pointer, buffer.length); - key = deserialize_lwe_bootstrap_key_u64({buffer.pointer, buffer.length}); + CAPI_ASSERT_ERROR( + fftw_serialization_engine_deserialize_fftw_fourier_lwe_bootstrap_key_u64( + engine, {buffer.pointer, buffer.length}, &key)); } template <> template -void KeyWrapper::save(Archive &ar, - const unsigned int version) const { +void KeyWrapper::save(Archive &ar, + const unsigned int version) const { ar << buffer.length; ar << hpx::serialization::make_array(buffer.pointer, buffer.length); } template <> template -void KeyWrapper::load(Archive &ar, - const unsigned int version) { +void KeyWrapper::load(Archive &ar, + const unsigned int version) { + DefaultSerializationEngine *engine; + + // No Freeing as it doesn't allocate anything. + CAPI_ASSERT_ERROR(new_default_serialization_engine(&engine)); + ar >> buffer.length; buffer.pointer = new uint8_t[buffer.length]; ar >> hpx::serialization::make_array(buffer.pointer, buffer.length); - key = deserialize_lwe_keyswitching_key_u64({buffer.pointer, buffer.length}); + CAPI_ASSERT_ERROR( + default_serialization_engine_deserialize_lwe_keyswitch_key_u64( + engine, {buffer.pointer, buffer.length}, &key)); } /************************/ @@ -122,23 +154,22 @@ struct RuntimeContextManager { // instantiates a local RuntimeContext. if (_dfr_is_root_node()) { RuntimeContext *context = (RuntimeContext *)ctx; - LweKeyswitchKey_u64 *ksk = get_keyswitch_key_u64(context); - LweBootstrapKey_u64 *bsk = get_bootstrap_key_u64(context); + LweKeyswitchKey64 *ksk = get_keyswitch_key_u64(context); + FftwFourierLweBootstrapKey64 *bsk = get_bootstrap_key_u64(context); - KeyWrapper kskw(ksk); - KeyWrapper bskw(bsk); + KeyWrapper kskw(ksk); + KeyWrapper bskw(bsk); hpx::collectives::broadcast_to("ksk_keystore", kskw); hpx::collectives::broadcast_to("bsk_keystore", bskw); } else { auto kskFut = - hpx::collectives::broadcast_from>( + hpx::collectives::broadcast_from>( "ksk_keystore"); - auto bskFut = - hpx::collectives::broadcast_from>( - "bsk_keystore"); + auto bskFut = hpx::collectives::broadcast_from< + KeyWrapper>("bsk_keystore"); - KeyWrapper kskw = kskFut.get(); - KeyWrapper bskw = bskFut.get(); + KeyWrapper kskw = kskFut.get(); + KeyWrapper bskw = bskFut.get(); context = new mlir::concretelang::RuntimeContext(); context->evaluationKeys = ::concretelang::clientlib::EvaluationKeys( std::shared_ptr<::concretelang::clientlib::LweKeyswitchKey>( diff --git a/compiler/include/concretelang/Runtime/seeder.h b/compiler/include/concretelang/Runtime/seeder.h new file mode 100644 index 000000000..8e8076202 --- /dev/null +++ b/compiler/include/concretelang/Runtime/seeder.h @@ -0,0 +1,13 @@ +// Part of the Concrete Compiler Project, under the BSD3 License with Zama +// Exceptions. See +// https://github.com/zama-ai/concrete-compiler-internal/blob/main/LICENSE.txt +// for license information. + +#ifndef CONCRETELANG_RUNTIME_SEEDER_H +#define CONCRETELANG_RUNTIME_SEEDER_H + +#include "concrete-core-ffi.h" + +extern SeederBuilder *best_seeder; + +#endif diff --git a/compiler/include/concretelang/Runtime/wrappers.h b/compiler/include/concretelang/Runtime/wrappers.h index d9cd39363..4b40380f6 100644 --- a/compiler/include/concretelang/Runtime/wrappers.h +++ b/compiler/include/concretelang/Runtime/wrappers.h @@ -9,7 +9,6 @@ #include "concretelang/Runtime/context.h" extern "C" { -#include "concrete-ffi.h" void memref_expand_lut_in_trivial_glwe_ct_u64( uint64_t *glwe_ct_allocated, uint64_t *glwe_ct_aligned, diff --git a/compiler/lib/ClientLib/KeySet.cpp b/compiler/lib/ClientLib/KeySet.cpp index 412de824f..eb322acfc 100644 --- a/compiler/lib/ClientLib/KeySet.cpp +++ b/compiler/lib/ClientLib/KeySet.cpp @@ -5,6 +5,8 @@ #include "concretelang/ClientLib/KeySet.h" #include "concretelang/ClientLib/CRT.h" +#include "concretelang/Common/Error.h" +#include "concretelang/Runtime/seeder.h" #include "concretelang/Support/Error.h" #define CAPI_ERR_TO_STRINGERROR(instr, msg) \ @@ -16,16 +18,49 @@ } \ } +int clone_transform_lwe_secret_key_to_glwe_secret_key_u64( + DefaultEngine *default_engine, LweSecretKey64 *output_lwe_sk, + size_t poly_size, GlweSecretKey64 **output_glwe_sk) { + LweSecretKey64 *output_lwe_sk_clone = NULL; + int lwe_out_sk_clone_ok = + clone_lwe_secret_key_u64(output_lwe_sk, &output_lwe_sk_clone); + if (lwe_out_sk_clone_ok != 0) { + return 1; + } + + int glwe_sk_ok = + default_engine_transform_lwe_secret_key_to_glwe_secret_key_u64( + default_engine, &output_lwe_sk_clone, poly_size, output_glwe_sk); + if (glwe_sk_ok != 0) { + return 1; + } + + if (output_lwe_sk_clone != NULL) { + return 1; + } + + return 0; +} + namespace concretelang { namespace clientlib { -KeySet::KeySet() : engine(new_engine()) {} +KeySet::KeySet() { + + CAPI_ASSERT_ERROR(new_default_engine(best_seeder, &engine)); + + CAPI_ASSERT_ERROR(new_default_parallel_engine(best_seeder, &par_engine)); + + CAPI_ASSERT_ERROR(new_fftw_engine(&fftw_engine)); +} KeySet::~KeySet() { for (auto it : secretKeys) { - free_lwe_secret_key_u64(it.second.second); + CAPI_ASSERT_ERROR(destroy_lwe_secret_key_u64(it.second.second)); } - free_engine(engine); + CAPI_ASSERT_ERROR(destroy_default_engine(engine)); + CAPI_ASSERT_ERROR(destroy_fftw_engine(fftw_engine)); + CAPI_ASSERT_ERROR(destroy_default_parallel_engine(par_engine)); } outcome::checked, StringError> @@ -46,7 +81,7 @@ KeySet::setupEncryptionMaterial(ClientParameters ¶ms, uint64_t seed_msb, { for (auto param : params.inputs) { LweSecretKeyParam secretKeyParam = {0}; - LweSecretKey_u64 *secretKey = nullptr; + LweSecretKey64 *secretKey = nullptr; if (param.encryption.hasValue()) { auto inputSk = this->secretKeys.find(param.encryption->secretKeyID); if (inputSk == this->secretKeys.end()) { @@ -56,13 +91,13 @@ KeySet::setupEncryptionMaterial(ClientParameters ¶ms, uint64_t seed_msb, secretKeyParam = inputSk->second.first; secretKey = inputSk->second.second; } - std::tuple input = { + std::tuple input = { param, secretKeyParam, secretKey}; this->inputs.push_back(input); } for (auto param : params.outputs) { LweSecretKeyParam secretKeyParam = {0}; - LweSecretKey_u64 *secretKey = nullptr; + LweSecretKey64 *secretKey = nullptr; if (param.encryption.hasValue()) { auto outputSk = this->secretKeys.find(param.encryption->secretKeyID); if (outputSk == this->secretKeys.end()) { @@ -72,7 +107,7 @@ KeySet::setupEncryptionMaterial(ClientParameters ¶ms, uint64_t seed_msb, secretKeyParam = outputSk->second.first; secretKey = outputSk->second.second; } - std::tuple output = { + std::tuple output = { param, secretKeyParam, secretKey}; this->outputs.push_back(output); } @@ -107,7 +142,7 @@ KeySet::generateKeysFromParams(ClientParameters ¶ms, uint64_t seed_msb, } void KeySet::setKeys( - std::map> + std::map> secretKeys, std::map>> @@ -122,8 +157,9 @@ void KeySet::setKeys( outcome::checked KeySet::generateSecretKey(LweSecretKeyID id, LweSecretKeyParam param) { - LweSecretKey_u64 *sk; - sk = generate_lwe_secret_key_u64(engine, param.dimension); + LweSecretKey64 *sk; + CAPI_ASSERT_ERROR(default_engine_generate_new_lwe_secret_key_u64( + engine, param.dimension, &sk)); secretKeys[id] = {param, sk}; @@ -142,7 +178,7 @@ KeySet::generateBootstrapKey(BootstrapKeyID id, BootstrapKeyParam param) { return StringError("cannot find output key to generate bootstrap key"); } // Allocate the bootstrap key - LweBootstrapKey_u64 *bsk; + LweBootstrapKey64 *bsk; uint64_t total_dimension = outputSk->second.first.dimension; @@ -150,12 +186,27 @@ KeySet::generateBootstrapKey(BootstrapKeyID id, BootstrapKeyParam param) { uint64_t polynomialSize = total_dimension / param.glweDimension; - bsk = generate_lwe_bootstrap_key_u64( - engine, inputSk->second.second, outputSk->second.second, param.baseLog, - param.level, param.variance, param.glweDimension, polynomialSize); + GlweSecretKey64 *output_glwe_sk = nullptr; + + // This is not part of the C FFI but rather is a C util exposed for + // convenience in tests. + CAPI_ASSERT_ERROR(clone_transform_lwe_secret_key_to_glwe_secret_key_u64( + engine, outputSk->second.second, polynomialSize, &output_glwe_sk)); + + CAPI_ASSERT_ERROR(default_parallel_engine_generate_new_lwe_bootstrap_key_u64( + par_engine, inputSk->second.second, output_glwe_sk, param.baseLog, + param.level, param.variance, &bsk)); + + FftwFourierLweBootstrapKey64 *fbsk; + + CAPI_ASSERT_ERROR( + fftw_engine_convert_lwe_bootstrap_key_to_fftw_fourier_lwe_bootstrap_key_u64( + fftw_engine, bsk, &fbsk)); + + CAPI_ASSERT_ERROR(destroy_lwe_bootstrap_key_u64(bsk)); // Store the bootstrap key - bootstrapKeys[id] = {param, std::make_shared(bsk)}; + bootstrapKeys[id] = {param, std::make_shared(fbsk)}; return outcome::success(); } @@ -172,11 +223,11 @@ KeySet::generateKeyswitchKey(KeyswitchKeyID id, KeyswitchKeyParam param) { return StringError("cannot find output key to generate keyswitch key"); } // Allocate the keyswitch key - LweKeyswitchKey_u64 *ksk; + LweKeyswitchKey64 *ksk; - ksk = generate_lwe_keyswitch_key_u64(engine, inputSk->second.second, - outputSk->second.second, param.level, - param.baseLog, param.variance); + CAPI_ASSERT_ERROR(default_engine_generate_new_lwe_keyswitch_key_u64( + engine, inputSk->second.second, outputSk->second.second, param.level, + param.baseLog, param.variance, &ksk)); // Store the keyswitch key keyswitchKeys[id] = {param, std::make_shared(ksk)}; @@ -236,8 +287,11 @@ KeySet::encrypt_lwe(size_t argPos, uint64_t *ciphertext, uint64_t input) { auto product = crt::productOfModuli(crt); for (auto modulus : crt) { auto plaintext = crt::encode(input, modulus, product); - ::encrypt_lwe_u64(engine, lweSecretKey, ciphertext, plaintext, - encryption->variance); + CAPI_ASSERT_ERROR( + default_engine_discard_encrypt_lwe_ciphertext_u64_raw_ptr_buffers( + engine, lweSecretKey, ciphertext, plaintext, + encryption->variance)); + ciphertext = ciphertext + lweSecretKeyParam.lweSize(); } return outcome::success(); @@ -245,8 +299,10 @@ KeySet::encrypt_lwe(size_t argPos, uint64_t *ciphertext, uint64_t input) { // Simple TFHE integers - 1 blocks with one padding bits // TODO we could check if the input value is in the right range uint64_t plaintext = input << (64 - (encryption->encoding.precision + 1)); - ::encrypt_lwe_u64(engine, lweSecretKey, ciphertext, plaintext, - encryption->variance); + CAPI_ASSERT_ERROR( + default_engine_discard_encrypt_lwe_ciphertext_u64_raw_ptr_buffers( + engine, lweSecretKey, ciphertext, plaintext, encryption->variance)); + return outcome::success(); } @@ -268,7 +324,11 @@ KeySet::decrypt_lwe(size_t argPos, uint64_t *ciphertext, uint64_t &output) { std::vector remainders; // decrypt and decode remainders for (auto modulus : crt) { - auto decrypted = ::decrypt_lwe_u64(engine, lweSecretKey, ciphertext); + uint64_t decrypted; + CAPI_ASSERT_ERROR( + default_engine_decrypt_lwe_ciphertext_u64_raw_ptr_buffers( + engine, lweSecretKey, ciphertext, &decrypted)); + auto plaintext = crt::decode(decrypted, modulus); remainders.push_back(plaintext); ciphertext = ciphertext + lweSecretKeyParam.lweSize(); @@ -278,7 +338,11 @@ KeySet::decrypt_lwe(size_t argPos, uint64_t *ciphertext, uint64_t &output) { return outcome::success(); } // Simple TFHE integers - 1 blocks with one padding bits - uint64_t plaintext = ::decrypt_lwe_u64(engine, lweSecretKey, ciphertext); + uint64_t plaintext; + + CAPI_ASSERT_ERROR(default_engine_decrypt_lwe_ciphertext_u64_raw_ptr_buffers( + engine, lweSecretKey, ciphertext, &plaintext)); + // Decode uint64_t precision = encryption->encoding.precision; output = plaintext >> (64 - precision - 2); @@ -289,8 +353,8 @@ KeySet::decrypt_lwe(size_t argPos, uint64_t *ciphertext, uint64_t &output) { return outcome::success(); } -const std::map> - &KeySet::getSecretKeys() { +const std::map> & +KeySet::getSecretKeys() { return secretKeys; } diff --git a/compiler/lib/ClientLib/KeySetCache.cpp b/compiler/lib/ClientLib/KeySetCache.cpp index 3cfb72d71..4d7cd1123 100644 --- a/compiler/lib/ClientLib/KeySetCache.cpp +++ b/compiler/lib/ClientLib/KeySetCache.cpp @@ -16,18 +16,17 @@ #include #include -extern "C" { -#include "concrete-ffi.h" -} +#include "concrete-core-ffi.h" namespace concretelang { namespace clientlib { using StringError = concretelang::error::StringError; -template -outcome::checked load(llvm::SmallString<0> &path, - Key *(*deser)(BufferView buffer)) { +template +outcome::checked +load(llvm::SmallString<0> &path, + int (*deser)(Engine *, BufferView buffer, Key **), Engine *engine) { std::ifstream in((std::string)path, std::ofstream::binary); if (in.fail()) { return StringError("Cannot access " + (std::string)path); @@ -39,8 +38,11 @@ outcome::checked load(llvm::SmallString<0> &path, } auto content = sbuffer.str(); BufferView buffer = {(const uint8_t *)content.c_str(), content.length()}; - auto result = deser(buffer); - if (result == nullptr) { + Key *result = nullptr; + + int error_code = deser(engine, buffer, &result); + + if (result == nullptr || error_code != 0) { return StringError("Cannot deserialize " + (std::string)path); } return result; @@ -52,35 +54,81 @@ static void writeFile(llvm::SmallString<0> &path, Buffer content) { out.close(); } -outcome::checked +outcome::checked loadSecretKey(llvm::SmallString<0> &path) { - return load(path, deserialize_lwe_secret_key_u64); + DefaultSerializationEngine *engine; + + CAPI_ASSERT_ERROR(new_default_serialization_engine(&engine)); + + return load(path, default_serialization_engine_deserialize_lwe_secret_key_u64, + engine); } -outcome::checked +outcome::checked loadKeyswitchKey(llvm::SmallString<0> &path) { - return load(path, deserialize_lwe_keyswitching_key_u64); + DefaultSerializationEngine *engine; + + CAPI_ASSERT_ERROR(new_default_serialization_engine(&engine)); + + return load(path, + default_serialization_engine_deserialize_lwe_keyswitch_key_u64, + engine); } -outcome::checked +outcome::checked loadBootstrapKey(llvm::SmallString<0> &path) { - return load(path, deserialize_lwe_bootstrap_key_u64); + + FftwSerializationEngine *engine; + + CAPI_ASSERT_ERROR(new_fftw_serialization_engine(&engine)); + + return load( + path, + fftw_serialization_engine_deserialize_fftw_fourier_lwe_bootstrap_key_u64, + engine); } -void saveSecretKey(llvm::SmallString<0> &path, LweSecretKey_u64 *key) { - Buffer buffer = serialize_lwe_secret_key_u64(key); +void saveSecretKey(llvm::SmallString<0> &path, LweSecretKey64 *key) { + + DefaultSerializationEngine *engine; + + CAPI_ASSERT_ERROR(new_default_serialization_engine(&engine)); + + Buffer buffer; + + CAPI_ASSERT_ERROR(default_serialization_engine_serialize_lwe_secret_key_u64( + engine, key, &buffer)); + writeFile(path, buffer); free(buffer.pointer); } -void saveBootstrapKey(llvm::SmallString<0> &path, LweBootstrapKey_u64 *key) { - Buffer buffer = serialize_lwe_bootstrap_key_u64(key); +void saveBootstrapKey(llvm::SmallString<0> &path, + FftwFourierLweBootstrapKey64 *key) { + FftwSerializationEngine *engine; + + CAPI_ASSERT_ERROR(new_fftw_serialization_engine(&engine)); + + Buffer buffer; + + CAPI_ASSERT_ERROR( + fftw_serialization_engine_serialize_fftw_fourier_lwe_bootstrap_key_u64( + engine, key, &buffer)); + writeFile(path, buffer); free(buffer.pointer); } -void saveKeyswitchKey(llvm::SmallString<0> &path, LweKeyswitchKey_u64 *key) { - Buffer buffer = serialize_lwe_keyswitching_key_u64(key); +void saveKeyswitchKey(llvm::SmallString<0> &path, LweKeyswitchKey64 *key) { + + DefaultSerializationEngine *engine; + + CAPI_ASSERT_ERROR(new_default_serialization_engine(&engine)); + + Buffer buffer; + CAPI_ASSERT_ERROR( + default_serialization_engine_serialize_lwe_keyswitch_key_u64(engine, key, + &buffer)); writeFile(path, buffer); free(buffer.pointer); } @@ -94,7 +142,7 @@ KeySetCache::loadKeys(ClientParameters ¶ms, uint64_t seed_msb, // e.g. so the CI can do some cleanup of unused keys. utime(folderPath.c_str(), nullptr); - std::map> + std::map> secretKeys; std::map>> @@ -109,7 +157,7 @@ KeySetCache::loadKeys(ClientParameters ¶ms, uint64_t seed_msb, auto param = secretKeyParam.second; llvm::SmallString<0> path(folderPath); llvm::sys::path::append(path, "secretKey_" + id); - OUTCOME_TRY(LweSecretKey_u64 * sk, loadSecretKey(path)); + OUTCOME_TRY(LweSecretKey64 * sk, loadSecretKey(path)); secretKeys[id] = {param, sk}; } // Load bootstrap keys @@ -118,7 +166,7 @@ KeySetCache::loadKeys(ClientParameters ¶ms, uint64_t seed_msb, auto param = bootstrapKeyParam.second; llvm::SmallString<0> path(folderPath); llvm::sys::path::append(path, "pbsKey_" + id); - OUTCOME_TRY(LweBootstrapKey_u64 * bsk, loadBootstrapKey(path)); + OUTCOME_TRY(FftwFourierLweBootstrapKey64 * bsk, loadBootstrapKey(path)); bootstrapKeys[id] = {param, std::make_shared(bsk)}; } // Load keyswitch keys @@ -127,7 +175,7 @@ KeySetCache::loadKeys(ClientParameters ¶ms, uint64_t seed_msb, auto param = keyswitchParam.second; llvm::SmallString<0> path(folderPath); llvm::sys::path::append(path, "ksKey_" + id); - OUTCOME_TRY(LweKeyswitchKey_u64 * ksk, loadKeyswitchKey(path)); + OUTCOME_TRY(LweKeyswitchKey64 * ksk, loadKeyswitchKey(path)); keyswitchKeys[id] = {param, std::make_shared(ksk)}; } diff --git a/compiler/lib/ClientLib/PublicArguments.cpp b/compiler/lib/ClientLib/PublicArguments.cpp index 188d4ebf7..9bab5e433 100644 --- a/compiler/lib/ClientLib/PublicArguments.cpp +++ b/compiler/lib/ClientLib/PublicArguments.cpp @@ -6,10 +6,6 @@ #include #include -extern "C" { -#include "concrete-ffi.h" -} - #include "concretelang/ClientLib/PublicArguments.h" #include "concretelang/ClientLib/Serializers.h" diff --git a/compiler/lib/ClientLib/Serializers.cpp b/compiler/lib/ClientLib/Serializers.cpp index f60cfc68b..dafe977ea 100644 --- a/compiler/lib/ClientLib/Serializers.cpp +++ b/compiler/lib/ClientLib/Serializers.cpp @@ -7,18 +7,19 @@ #include #include -extern "C" { -#include "concrete-ffi.h" -} +#include "concrete-core-ffi.h" #include "concretelang/ClientLib/PublicArguments.h" #include "concretelang/ClientLib/Serializers.h" +#include "concretelang/Common/Error.h" namespace concretelang { namespace clientlib { -template -Result read_deser(std::istream &istream, Result (*deser)(BufferView)) { +template +Result read_deser(std::istream &istream, + int (*deser)(Engine *, BufferView, Result *), + Engine *engine) { size_t length; readSize(istream, length); // buffer is too big to be allocated on stack @@ -26,7 +27,11 @@ Result read_deser(std::istream &istream, Result (*deser)(BufferView)) { std::vector buffer(length); istream.read((char *)buffer.data(), length); assert(istream.good()); - return deser({buffer.data(), length}); + Result result; + + CAPI_ASSERT_ERROR(deser(engine, {buffer.data(), length}, &result)); + + return result; } template @@ -37,9 +42,18 @@ std::ostream &writeBufferLike(std::ostream &ostream, BufferLike &buffer) { return ostream; } -std::ostream &operator<<(std::ostream &ostream, - const LweKeyswitchKey_u64 *key) { - Buffer b = serialize_lwe_keyswitching_key_u64(key); +std::ostream &operator<<(std::ostream &ostream, const LweKeyswitchKey64 *key) { + DefaultSerializationEngine *engine; + + // No Freeing as it doesn't allocate anything. + CAPI_ASSERT_ERROR(new_default_serialization_engine(&engine)); + + Buffer b; + + CAPI_ASSERT_ERROR( + default_serialization_engine_serialize_lwe_keyswitch_key_u64(engine, key, + &b)); + writeBufferLike(ostream, b); free((void *)b.pointer); b.pointer = nullptr; @@ -47,21 +61,47 @@ std::ostream &operator<<(std::ostream &ostream, } std::ostream &operator<<(std::ostream &ostream, - const LweBootstrapKey_u64 *key) { - Buffer b = serialize_lwe_bootstrap_key_u64(key); + const FftwFourierLweBootstrapKey64 *key) { + FftwSerializationEngine *engine; + + // No Freeing as it doesn't allocate anything. + CAPI_ASSERT_ERROR(new_fftw_serialization_engine(&engine)); + + Buffer b; + + CAPI_ASSERT_ERROR( + fftw_serialization_engine_serialize_fftw_fourier_lwe_bootstrap_key_u64( + engine, key, &b)) + writeBufferLike(ostream, b); free((void *)b.pointer); b.pointer = nullptr; return ostream; } -std::istream &operator>>(std::istream &istream, LweKeyswitchKey_u64 *&key) { - key = read_deser(istream, deserialize_lwe_keyswitching_key_u64); +std::istream &operator>>(std::istream &istream, LweKeyswitchKey64 *&key) { + DefaultSerializationEngine *engine; + + // No Freeing as it doesn't allocate anything. + CAPI_ASSERT_ERROR(new_default_serialization_engine(&engine)); + + key = read_deser( + istream, default_serialization_engine_deserialize_lwe_keyswitch_key_u64, + engine); return istream; } -std::istream &operator>>(std::istream &istream, LweBootstrapKey_u64 *&key) { - key = read_deser(istream, deserialize_lwe_bootstrap_key_u64); +std::istream &operator>>(std::istream &istream, + FftwFourierLweBootstrapKey64 *&key) { + FftwSerializationEngine *engine; + + // No Freeing as it doesn't allocate anything. + CAPI_ASSERT_ERROR(new_fftw_serialization_engine(&engine)); + + key = read_deser( + istream, + fftw_serialization_engine_deserialize_fftw_fourier_lwe_bootstrap_key_u64, + engine); return istream; } diff --git a/compiler/lib/Runtime/CMakeLists.txt b/compiler/lib/Runtime/CMakeLists.txt index 0aaf8ba82..0a2f470dd 100644 --- a/compiler/lib/Runtime/CMakeLists.txt +++ b/compiler/lib/Runtime/CMakeLists.txt @@ -2,6 +2,7 @@ add_library(ConcretelangRuntime SHARED context.cpp wrappers.cpp DFRuntime.cpp + seeder.cpp ) if(CONCRETELANG_DATAFLOW_EXECUTION_ENABLED) diff --git a/compiler/lib/Runtime/context.cpp b/compiler/lib/Runtime/context.cpp index 888793007..1e9af538e 100644 --- a/compiler/lib/Runtime/context.cpp +++ b/compiler/lib/Runtime/context.cpp @@ -3,29 +3,38 @@ // https://github.com/zama-ai/concrete-compiler-internal/blob/main/LICENSE.txt // for license information. +#include "concretelang/Runtime/context.h" +#include "concretelang/Common/Error.h" +#include "concretelang/Runtime/seeder.h" #include -#include #include -LweKeyswitchKey_u64 * +LweKeyswitchKey64 * get_keyswitch_key_u64(mlir::concretelang::RuntimeContext *context) { return context->evaluationKeys.getKsk(); } -LweBootstrapKey_u64 * +FftwFourierLweBootstrapKey64 * get_bootstrap_key_u64(mlir::concretelang::RuntimeContext *context) { return context->evaluationKeys.getBsk(); } -/// Instantiate one engine per thread on demand -Engine *get_engine(mlir::concretelang::RuntimeContext *context) { +DefaultEngine *get_engine(mlir::concretelang::RuntimeContext *context) { + return context->default_engine; +} + +FftwEngine *get_fftw_engine(mlir::concretelang::RuntimeContext *context) { pthread_t threadId = pthread_self(); std::lock_guard guard(context->engines_map_guard); - auto engineIt = context->engines.find(threadId); - if (engineIt == context->engines.end()) { + auto engineIt = context->fftw_engines.find(threadId); + if (engineIt == context->fftw_engines.end()) { + FftwEngine *fftw_engine = nullptr; + + CAPI_ASSERT_ERROR(new_fftw_engine(&fftw_engine)); + engineIt = - context->engines - .insert(std::pair(threadId, new_engine())) + context->fftw_engines + .insert(std::pair(threadId, fftw_engine)) .first; } assert(engineIt->second && "No engine available in context"); diff --git a/compiler/lib/Runtime/seeder.cpp b/compiler/lib/Runtime/seeder.cpp new file mode 100644 index 000000000..f54fb18f4 --- /dev/null +++ b/compiler/lib/Runtime/seeder.cpp @@ -0,0 +1,43 @@ +// Part of the Concrete Compiler Project, under the BSD3 License with Zama +// Exceptions. See +// https://github.com/zama-ai/concrete-compiler-internal/blob/main/LICENSE.txt +// for license information. + +#include "concretelang/Runtime/seeder.h" +#include +#include + +#include "concrete-core-ffi.h" +#include "concretelang/Common/Error.h" + +SeederBuilder *get_best_seeder() { + SeederBuilder *builder = NULL; + bool rdseed_seeder_available = false; + CAPI_ASSERT_ERROR(rdseed_seeder_is_available(&rdseed_seeder_available)); + + if (rdseed_seeder_available) { + CAPI_ASSERT_ERROR(get_rdseed_seeder_builder(&builder)); + std::cout << "Using rdseed seeder." << std::endl; + return builder; + } + + bool unix_seeder_available = false; + CAPI_ASSERT_ERROR(unix_seeder_is_available(&unix_seeder_available)); + + if (unix_seeder_available) { + // Security depends on /dev/random security + uint64_t secret_high_64 = 0; + uint64_t secret_low_64 = 0; + CAPI_ASSERT_ERROR( + get_unix_seeder_builder(secret_high_64, secret_low_64, &builder)); + std::cout << "Using Unix /dev/random seeder without an additionnal secret." + << std::endl; + + return builder; + } + + std::cout << "No available seeder." << std::endl; + return builder; +} + +SeederBuilder *best_seeder = get_best_seeder(); diff --git a/compiler/lib/Runtime/wrappers.cpp b/compiler/lib/Runtime/wrappers.cpp index 502e98abd..ae2795ff1 100644 --- a/compiler/lib/Runtime/wrappers.cpp +++ b/compiler/lib/Runtime/wrappers.cpp @@ -3,9 +3,54 @@ // https://github.com/zama-ai/concrete-compiler-internal/blob/main/LICENSE.txt // for license information. +#include "concretelang/Runtime/wrappers.h" +#include "concretelang/Common/Error.h" +#include "concretelang/Runtime/seeder.h" #include +#include #include +#include #include +#include + +static DefaultEngine *levelled_engine = nullptr; + +DefaultEngine *get_levelled_engine() { + if (levelled_engine == nullptr) { + CAPI_ASSERT_ERROR(new_default_engine(best_seeder, &levelled_engine)); + } + return levelled_engine; +} +// This helper function expands the input LUT into output, duplicating values as +// needed to fill mega cases, taking care of the encoding and the half mega case +// shift in the process as well. All sizes should be powers of 2. +void encode_and_expand_lut(uint64_t *output, size_t output_size, + size_t out_MESSAGE_BITS, const uint64_t *lut, + size_t lut_size) { + assert((output_size % lut_size) == 0); + + size_t mega_case_size = output_size / lut_size; + + assert((mega_case_size % 2) == 0); + + for (size_t idx = 0; idx < mega_case_size / 2; ++idx) { + output[idx] = lut[0] << (64 - out_MESSAGE_BITS - 1); + } + + for (size_t idx = (lut_size - 1) * mega_case_size + mega_case_size / 2; + idx < output_size; ++idx) { + output[idx] = -(lut[0] << (64 - out_MESSAGE_BITS - 1)); + } + + for (size_t lut_idx = 1; lut_idx < lut_size; ++lut_idx) { + uint64_t lut_value = lut[lut_idx] << (64 - out_MESSAGE_BITS - 1); + size_t start = mega_case_size * (lut_idx - 1) + mega_case_size / 2; + for (size_t output_idx = start; output_idx < start + mega_case_size; + ++output_idx) { + output[output_idx] = lut_value; + } + } +} #include "concretelang/ClientLib/CRT.h" #include "concretelang/Runtime/wrappers.h" @@ -23,8 +68,17 @@ void memref_expand_lut_in_trivial_glwe_ct_u64( assert(glwe_ct_stride == 1 && "Runtime: stride not equal to 1, check " "memref_expand_lut_in_trivial_glwe_ct_u64"); - expand_lut_in_trivial_glwe_ct_u64(glwe_ct_aligned, poly_size, glwe_dimension, - out_precision, lut_aligned, lut_size); + assert(glwe_ct_size == poly_size * (glwe_dimension + 1)); + + std::vector expanded_tabulated_function_array(poly_size); + + encode_and_expand_lut(expanded_tabulated_function_array.data(), poly_size, + out_precision, lut_aligned + lut_offset, lut_size); + + CAPI_ASSERT_ERROR( + default_engine_discard_trivially_encrypt_glwe_ciphertext_u64_raw_ptr_buffers( + get_levelled_engine(), glwe_ct_aligned + glwe_ct_offset, glwe_ct_size, + expanded_tabulated_function_array.data(), poly_size)); return; } @@ -38,9 +92,10 @@ void memref_add_lwe_ciphertexts_u64( assert(out_size == ct0_size && out_size == ct1_size && "size of lwe buffer are incompatible"); size_t lwe_dimension = {out_size - 1}; - add_two_lwe_ciphertexts_u64(out_aligned + out_offset, - ct0_aligned + ct0_offset, - ct1_aligned + ct1_offset, lwe_dimension); + CAPI_ASSERT_ERROR( + default_engine_discard_add_lwe_ciphertext_u64_raw_ptr_buffers( + get_levelled_engine(), out_aligned + out_offset, + ct0_aligned + ct0_offset, ct1_aligned + ct1_offset, lwe_dimension)); } void memref_add_plaintext_lwe_ciphertext_u64( @@ -50,9 +105,10 @@ void memref_add_plaintext_lwe_ciphertext_u64( uint64_t ct0_stride, uint64_t plaintext) { assert(out_size == ct0_size && "size of lwe buffer are incompatible"); size_t lwe_dimension = {out_size - 1}; - add_plaintext_to_lwe_ciphertext_u64(out_aligned + out_offset, - ct0_aligned + ct0_offset, plaintext, - lwe_dimension); + CAPI_ASSERT_ERROR( + default_engine_discard_add_lwe_ciphertext_plaintext_u64_raw_ptr_buffers( + get_levelled_engine(), out_aligned + out_offset, + ct0_aligned + ct0_offset, lwe_dimension, plaintext)); } void memref_mul_cleartext_lwe_ciphertext_u64( @@ -62,9 +118,10 @@ void memref_mul_cleartext_lwe_ciphertext_u64( uint64_t ct0_stride, uint64_t cleartext) { assert(out_size == ct0_size && "size of lwe buffer are incompatible"); size_t lwe_dimension = {out_size - 1}; - mul_cleartext_lwe_ciphertext_u64(out_aligned + out_offset, - ct0_aligned + ct0_offset, cleartext, - lwe_dimension); + CAPI_ASSERT_ERROR( + default_engine_discard_mul_lwe_ciphertext_cleartext_u64_raw_ptr_buffers( + get_levelled_engine(), out_aligned + out_offset, + ct0_aligned + ct0_offset, lwe_dimension, cleartext)); } void memref_negate_lwe_ciphertext_u64( @@ -74,8 +131,10 @@ void memref_negate_lwe_ciphertext_u64( uint64_t ct0_stride) { assert(out_size == ct0_size && "size of lwe buffer are incompatible"); size_t lwe_dimension = {out_size - 1}; - neg_lwe_ciphertext_u64(out_aligned + out_offset, ct0_aligned + ct0_offset, - lwe_dimension); + CAPI_ASSERT_ERROR( + default_engine_discard_opp_lwe_ciphertext_u64_raw_ptr_buffers( + get_levelled_engine(), out_aligned + out_offset, + ct0_aligned + ct0_offset, lwe_dimension)); } void memref_keyswitch_lwe_u64(uint64_t *out_allocated, uint64_t *out_aligned, @@ -84,8 +143,10 @@ void memref_keyswitch_lwe_u64(uint64_t *out_allocated, uint64_t *out_aligned, uint64_t *ct0_aligned, uint64_t ct0_offset, uint64_t ct0_size, uint64_t ct0_stride, mlir::concretelang::RuntimeContext *context) { - keyswitch_lwe_u64(get_engine(context), get_keyswitch_key_u64(context), - out_aligned + out_offset, ct0_aligned + ct0_offset); + CAPI_ASSERT_ERROR( + default_engine_discard_keyswitch_lwe_ciphertext_u64_raw_ptr_buffers( + get_engine(context), get_keyswitch_key_u64(context), + out_aligned + out_offset, ct0_aligned + ct0_offset)); } void memref_bootstrap_lwe_u64( @@ -95,9 +156,11 @@ void memref_bootstrap_lwe_u64( uint64_t ct0_stride, uint64_t *glwe_ct_allocated, uint64_t *glwe_ct_aligned, uint64_t glwe_ct_offset, uint64_t glwe_ct_size, uint64_t glwe_ct_stride, mlir::concretelang::RuntimeContext *context) { - bootstrap_lwe_u64(get_engine(context), get_bootstrap_key_u64(context), - out_aligned + out_offset, ct0_aligned + ct0_offset, - glwe_ct_aligned + glwe_ct_offset); + CAPI_ASSERT_ERROR( + fftw_engine_lwe_ciphertext_discarding_bootstrap_u64_raw_ptr_buffers( + get_fftw_engine(context), get_engine(context), + get_bootstrap_key_u64(context), out_aligned + out_offset, + ct0_aligned + ct0_offset, glwe_ct_aligned + glwe_ct_offset)); } uint64_t encode_crt(int64_t plaintext, uint64_t modulus, uint64_t product) {