diff --git a/CMakeLists.txt b/CMakeLists.txt index 1efceb8b..8746e923 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,8 @@ message(STATUS "Microsoft SEAL debug mode: ${SEAL_DEBUG}") # Use C++17, use C++14 otherwise. set(SEAL_USE_CXX17_OPTION_STR "Use C++17") option(SEAL_USE_CXX17 ${SEAL_USE_CXX17_OPTION_STR} ON) +message(STATUS "SEAL_USE_CXX17: ${SEAL_USE_CXX17}") + # Enable features from C++17 if available, disable features if set to OFF. include(EnableCXX17) @@ -123,6 +125,7 @@ include(CleanArtifacts) # Download and build missing dependencies, throw error if disabled. set(SEAL_BUILD_DEPS_OPTION_STR "Automatically download and build unmet dependencies") option(SEAL_BUILD_DEPS ${SEAL_BUILD_DEPS_OPTION_STR} ON) +message(STATUS "SEAL_BUILD_DEPS: ${SEAL_BUILD_DEPS}") if(SEAL_BUILD_DEPS) include(FetchContent) @@ -135,6 +138,8 @@ endif() # [option] SEAL_USE_MSGSL (default: ON) set(SEAL_USE_MSGSL_OPTION_STR "Use Microsoft GSL") option(SEAL_USE_MSGSL ${SEAL_USE_MSGSL_OPTION_STR} ON) +message(STATUS "SEAL_USE_MSGSL: ${SEAL_USE_MSGSL}") + if(SEAL_USE_MSGSL) if(SEAL_BUILD_DEPS) message(STATUS "Microsoft GSL: download ...") @@ -152,6 +157,8 @@ endif() # [option] SEAL_USE_ZLIB (default: ON) set(SEAL_USE_ZLIB_OPTION_STR "Use ZLIB for compressed serialization") option(SEAL_USE_ZLIB ${SEAL_USE_ZLIB_OPTION_STR} ON) +message(STATUS "SEAL_USE_ZLIB: ${SEAL_USE_ZLIB}") + if(SEAL_USE_ZLIB) if(SEAL_BUILD_DEPS) message(STATUS "ZLIB: download ...") @@ -171,6 +178,8 @@ endif() # [option] SEAL_USE_ZSTD (default: ON) set(SEAL_USE_ZSTD_OPTION_STR "Use Zstandard for compressed serialization") option(SEAL_USE_ZSTD ${SEAL_USE_ZSTD_OPTION_STR} ON) +message(STATUS "SEAL_USE_ZSTD: ${SEAL_USE_ZSTD}") + if(SEAL_USE_ZSTD) if(SEAL_BUILD_DEPS) message(STATUS "Zstandard: download ...") @@ -200,6 +209,23 @@ if(SEAL_USE_ZSTD) endif() endif() +# [option] SEAL_USE_INTEL_HEXL (default: OFF) +set(SEAL_USE_INTEL_HEXL_OPTION_STR "Use Intel HEXL library") +option(SEAL_USE_INTEL_HEXL ${SEAL_USE_INTEL_HEXL_OPTION_STR} OFF) +message(STATUS "SEAL_USE_INTEL_HEXL: ${SEAL_USE_INTEL_HEXL}") + +if(SEAL_USE_INTEL_HEXL) + if(SEAL_BUILD_DEPS) + message(STATUS "Intel HEXL: download ...") + seal_fetch_thirdparty_content(ExternalIntelHEXL) + else() + find_package(HEXL REQUIRED) + if (NOT TARGET HEXL::hexl) + FATAL_ERROR("Intel HEXL: not found") + endif() + endif() +endif() + #################### # SEAL C++ library # #################### @@ -208,6 +234,7 @@ endif() # Build a shared library if set to ON. Build a static library regardlessly. set(BUILD_SHARED_LIBS_STR "Build shared library") option(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_STR} OFF) +message(STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}") if(WIN32 AND BUILD_SHARED_LIBS) message(FATAL_ERROR "On Windows only static build is supported; set `BUILD_SHARED_LIBS=OFF`") endif() @@ -215,18 +242,21 @@ endif() # [option] SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT (default: ON) set(SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT_STR "Throw an exception when Evaluator outputs a transparent ciphertext") option(SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT ${SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT_STR} ON) +message(STATUS "SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT: ${SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT}") mark_as_advanced(FORCE SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT) # [option] SEAL_USE_GAUSSIAN_NOISE (default: OFF) # Use Gaussian distribution for noise sampling if set to ON, use centered binomial otherwise. set(SEAL_USE_GAUSSIAN_NOISE_STR "Use a rounded Gaussian distribution for noise sampling instead of a Centered Binomial Distribution") option(SEAL_USE_GAUSSIAN_NOISE ${SEAL_USE_GAUSSIAN_NOISE_STR} OFF) +message(STATUS "SEAL_USE_GAUSSIAN_NOISE: ${SEAL_USE_GAUSSIAN_NOISE}") mark_as_advanced(FORCE SEAL_USE_GAUSSIAN_NOISE) # [option] SEAL_DEFAULT_PRNG (default: Blake2xb) # Choose either Blake2xb or Shake256 to be the default PRNG. set(SEAL_DEFAULT_PRNG_STR "Choose the default PRNG") set(SEAL_DEFAULT_PRNG "Blake2xb" CACHE STRING ${SEAL_DEFAULT_PRNG_STR} FORCE) +message(STATUS "SEAL_DEFAULT_PRNG: ${SEAL_DEFAULT_PRNG}") set_property(CACHE SEAL_DEFAULT_PRNG PROPERTY STRINGS "Blake2xb" "Shake256") mark_as_advanced(FORCE SEAL_DEFAULT_PRNG) @@ -239,6 +269,7 @@ include(CheckCXXIntrinsicsHeader) if(NOT SEAL_INTRIN_HEADER_FOUND) set(SEAL_USE_INTRIN OFF CACHE BOOL ${SEAL_USE_INTRIN_OPTION_STR} FORCE) endif() +message(STATUS "SEAL_USE_INTRIN: ${SEAL_USE_INTRIN}") # [option] SEAL_USE_${A_SPECIFIC_INTRIN} (default: ON, advanced) # Not available if SEAL_USE_INTRIN is OFF. @@ -299,6 +330,7 @@ mark_as_advanced(FORCE SEAL_USE_MEMSET_S) if(NOT SEAL_MEMSET_S_FOUND) set(SEAL_USE_MEMSET_S OFF CACHE BOOL ${SEAL_USE_MEMSET_S_OPTION_STR} FORCE) endif() +message(STATUS "SEAL_USE_MEMSET_S: ${SEAL_USE_MEMSET_S}") set(SEAL_USE_EXPLICIT_BZERO_OPTION_STR "Use explicit_bzero") option(SEAL_USE_EXPLICIT_BZERO ${SEAL_USE_EXPLICIT_BZERO_OPTION_STR} ON) @@ -306,6 +338,7 @@ mark_as_advanced(FORCE SEAL_USE_EXPLICIT_BZERO) if(NOT SEAL_EXPLICIT_BZERO_FOUND) set(SEAL_USE_EXPLICIT_BZERO OFF CACHE BOOL ${SEAL_USE_EXPLICIT_BZERO_OPTION_STR} FORCE) endif() +message(STATUS "SEAL_USE_EXPLICIT_BZERO: ${SEAL_USE_EXPLICIT_BZERO}") set(SEAL_USE_EXPLICIT_MEMSET_OPTION_STR "Use explicit_memset") option(SEAL_USE_EXPLICIT_MEMSET ${SEAL_USE_EXPLICIT_MEMSET_OPTION_STR} ON) @@ -313,6 +346,7 @@ mark_as_advanced(FORCE SEAL_USE_EXPLICIT_MEMSET) if(NOT SEAL_EXPLICIT_MEMSET_FOUND) set(SEAL_USE_EXPLICIT_MEMSET OFF CACHE BOOL ${SEAL_USE_EXPLICIT_MEMSET_OPTION_STR} FORCE) endif() +message(STATUS "SEAL_USE_EXPLICIT_MEMSET: ${SEAL_USE_EXPLICIT_MEMSET}") # Add source files to library and header files to install set(SEAL_SOURCE_FILES "") @@ -364,6 +398,21 @@ if(NOT BUILD_SHARED_LIBS) endif() endif() + if(SEAL_USE_INTEL_HEXL) + if(SEAL_BUILD_DEPS) + add_dependencies(seal HEXL::hexl) + target_include_directories(seal PUBLIC $) + seal_combine_archives(seal HEXL::hexl) + else() + target_link_libraries(seal PRIVATE HEXL::hexl) + get_target_property( + HEXL_INCLUDE_DIR + HEXL::hexl + INTERFACE_INCLUDE_DIRECTORIES) + target_include_directories(seal PUBLIC ${HEXL_INCLUDE_DIR}) + endif() + endif() + # Set secure compile options if SEAL_SECURE_COMPILE_OPTIONS is ON; only supported on MSVC if(SEAL_SECURE_COMPILE_OPTIONS) seal_set_secure_compile_options(seal PUBLIC) @@ -399,6 +448,11 @@ else() target_include_directories(seal_shared PRIVATE $) target_link_libraries(seal_shared PRIVATE ${zstd_static}) endif() + + if(SEAL_USE_INTEL_HEXL) + target_include_directories(seal_shared PRIVATE $) + target_link_libraries(seal_shared PRIVATE hexl) + endif() endif() # Add standard alias targets for SEAL::seal and SEAL::seal_shared @@ -416,6 +470,7 @@ endif() # [option] SEAL_BUILD_SEAL_C (default: OFF) set(SEAL_BUILD_SEAL_C_OPTION_STR "Build C export library for Microsoft SEAL") option(SEAL_BUILD_SEAL_C ${SEAL_BUILD_SEAL_C_OPTION_STR} OFF) +message(STATUS "SEAL_BUILD_SEAL_C: ${SEAL_BUILD_SEAL_C}") set(SEAL_BUILD_STATIC_SEAL_C_OPTION_STR "Build static C library for Microsoft SEAL") cmake_dependent_option(SEAL_BUILD_STATIC_SEAL_C ${SEAL_BUILD_STATIC_SEAL_C_OPTION_STR} OFF "SEAL_BUILD_SEAL_C" OFF) @@ -458,6 +513,9 @@ if(SEAL_BUILD_SEAL_C) endif() seal_set_language(sealc) seal_set_include_directories(sealc) + if (SEAL_USE_INTEL_HEXL) + target_include_directories(sealc PRIVATE $) + endif() target_link_libraries(sealc PUBLIC seal) @@ -512,6 +570,13 @@ if(SEAL_USE_MSGSL AND SEAL_BUILD_DEPS) DESTINATION ${SEAL_INCLUDES_INSTALL_DIR}) endif() +# Install Intel HEXL header files if SEAL_BUILD_DEPS is ON +if(SEAL_USE_INTEL_HEXL AND SEAL_BUILD_DEPS) + install( + DIRECTORY ${hexl_SOURCE_DIR}/hexl/include/intel-hexl + DESTINATION ${SEAL_INCLUDES_INSTALL_DIR}) +endif() + ############## # pkg-config # ############## @@ -570,6 +635,7 @@ endif() # [option] SEAL_BUILD_EXAMPLES set(SEAL_BUILD_EXAMPLES_OPTION_STR "Build C++ examples for Microsoft SEAL") option(SEAL_BUILD_EXAMPLES ${SEAL_BUILD_EXAMPLES_OPTION_STR} OFF) +message(STATUS "SEAL_BUILD_EXAMPLES: ${SEAL_BUILD_EXAMPLES}") if(SEAL_BUILD_EXAMPLES) add_subdirectory(native/examples) @@ -582,6 +648,7 @@ endif() # [option] SEAL_BUILD_TESTS set(SEAL_BUILD_TESTS_OPTION_STR "Build C++ tests for Microsoft SEAL") option(SEAL_BUILD_TESTS ${SEAL_BUILD_TESTS_OPTION_STR} OFF) +message(STATUS "SEAL_BUILD_TESTS: ${SEAL_BUILD_TESTS}") if(SEAL_BUILD_TESTS) add_subdirectory(native/tests) @@ -594,6 +661,7 @@ endif() # [option] SEAL_BUILD_BENCH set(SEAL_BUILD_BENCH_OPTION_STR "Build C++ benchmarks for Microsoft SEAL") option(SEAL_BUILD_BENCH ${SEAL_BUILD_BENCH_OPTION_STR} OFF) +message(STATUS "SEAL_BUILD_BENCH: ${SEAL_BUILD_BENCH}") if(SEAL_BUILD_BENCH) add_subdirectory(native/bench) diff --git a/README.md b/README.md index 2edfaa4a..df3eee42 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ The [EVA compiler for CKKS](https://arxiv.org/abs/1912.11951) is available at [G - [Microsoft SEAL](#microsoft-seal-1) - [Getting Started](#getting-started) - [Optional Dependencies](#optional-dependencies) + - [Intel HEXL](#intel-hexl) - [Microsoft GSL](#microsoft-gsl) - [ZLIB and Zstandard](#zlib-and-zstandard) - [Installing from NuGet Package](#installing-from-nuget-package-windows-linux-macos-android-ios) @@ -115,12 +116,17 @@ The optional dependencies and their tested versions (other versions may work as | Optional dependency | Tested version | Use | | ------------------------------------------------------ | -------------- | ------------------------------------------------ | +| [Intel HEXL](https://github.com/intel/hexl) | 1.0.0 | Acceleration of low-level kernels | | [Microsoft GSL](https://github.com/microsoft/GSL) | 3.1.0 | API extensions | | [ZLIB](https://github.com/madler/zlib) | 1.2.11 | Compressed serialization | | [Zstandard](https://github.com/facebook/zstd) | 1.4.5 | Compressed serialization (much faster than ZLIB) | | [GoogleTest](https://github.com/google/googletest) | 1.10.0 | For running tests | | [GoogleBenchmark](https://github.com/google/benchmark) | 1.5.2 | For running benchmarks | +#### Intel HEXL + +Intel HEXL is a library providing efficient implementations of cryptographic primitives common in homomorphic encryption. The acceleration is particularly evident on Intel processors with the Intel AVX512-IMA52 instruction set. + #### Microsoft GSL Microsoft GSL (Guidelines Support Library) is a header-only library that implements `gsl::span`: a *view type* that provides safe (bounds-checked) array access to memory. @@ -374,20 +380,21 @@ Notice the file sizes for the artifacts are very small. This is because the opti The following options can be used with CMake to configure the build. The default value for each option is denoted with boldface in the **Values** column. -| CMake option | Values | Information | -| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| CMAKE_BUILD_TYPE | **Release**
Debug
RelWithDebInfo
MinSizeRel
| `Debug` and `MinSizeRel` have worse run-time performance. `Debug` inserts additional assertion code. Set to `Release` unless you are developing Microsoft SEAL itself or debugging some complex issue. | -| SEAL_BUILD_EXAMPLES | ON / **OFF** | Build the C++ examples in [native/examples](native/examples). | -| SEAL_BUILD_TESTS | ON / **OFF** | Build the tests to check that Microsoft SEAL works correctly. | -| SEAL_BUILD_BENCH | ON / **OFF** | Build the performance benchmark. | -| SEAL_BUILD_DEPS | **ON** / OFF | Set to `ON` to automatically download and build [optional dependencies](#optional-dependencies); otherwise CMake will attempt to locate pre-installed dependencies. | -| SEAL_USE_MSGSL | **ON** / OFF | Build with Microsoft GSL support. | -| SEAL_USE_ZLIB | **ON** / OFF | Build with ZLIB support. | -| SEAL_USE_ZSTD | **ON** / OFF | Build with Zstandard support. | -| BUILD_SHARED_LIBS | ON / **OFF** | Set to `ON` to build a shared library instead of a static library. Not supported in Windows. | -| SEAL_BUILD_SEAL_C | ON / **OFF** | Build the C wrapper library SEAL_C. This is used by the C# wrapper and most users should have no reason to build it. | -| SEAL_USE_CXX17 | **ON** / OFF | Set to `ON` to build Microsoft SEAL as C++17 for a positive performance impact. | -| SEAL_USE_INTRIN | **ON** / OFF | Set to `ON` to use compiler intrinsics for improved performance. CMake will automatically detect which intrinsics are available and enable them accordingly. | +| CMake option | Values | Information | +| ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| CMAKE_BUILD_TYPE | **Release**
Debug
RelWithDebInfo
MinSizeRel
| `Debug` and `MinSizeRel` have worse run-time performance. `Debug` inserts additional assertion code. Set to `Release` unless you are developing Microsoft SEAL itself or debugging some complex issue. | +| SEAL_BUILD_EXAMPLES | ON / **OFF** | Build the C++ examples in [native/examples](native/examples). | +| SEAL_BUILD_TESTS | ON / **OFF** | Build the tests to check that Microsoft SEAL works correctly. | +| SEAL_BUILD_BENCH | ON / **OFF** | Build the performance benchmark. | +| SEAL_BUILD_DEPS | **ON** / OFF | Set to `ON` to automatically download and build [optional dependencies](#optional-dependencies); otherwise CMake will attempt to locate pre-installed dependencies. | +| SEAL_USE_INTEL_HEXL | ON / **OFF** | Set to `ON` to use Intel HEXL for low-level kernels. | +| SEAL_USE_MSGSL | **ON** / OFF | Build with Microsoft GSL support. | +| SEAL_USE_ZLIB | **ON** / OFF | Build with ZLIB support. | +| SEAL_USE_ZSTD | **ON** / OFF | Build with Zstandard support. | +| BUILD_SHARED_LIBS | ON / **OFF** | Set to `ON` to build a shared library instead of a static library. Not supported in Windows. | +| SEAL_BUILD_SEAL_C | ON / **OFF** | Build the C wrapper library SEAL_C. This is used by the C# wrapper and most users should have no reason to build it. | +| SEAL_USE_CXX17 | **ON** / OFF | Set to `ON` to build Microsoft SEAL as C++17 for a positive performance impact. | +| SEAL_USE_INTRIN | **ON** / OFF | Set to `ON` to use compiler intrinsics for improved performance. CMake will automatically detect which intrinsics are available and enable them accordingly. | As usual, these options can be passed to CMake with the `-D` flag. For example, one could run @@ -409,6 +416,7 @@ The following options can be used with CMake to further configure the build. Mos | SEAL_DEFAULT_PRNG | **Blake2xb**
Shake256 | Microsoft SEAL supports both Blake2xb and Shake256 XOFs for generating random bytes. Blake2xb is much faster, but it is not standardized, whereas Shake256 is a FIPS standard. | | SEAL_USE_GAUSSIAN_NOISE | ON / **OFF** | Set to `ON` to use a non-constant time rounded continuous Gaussian for the error distribution; otherwise a centered binomial distribution – with slightly larger standard deviation – is used. | | SEAL_SECURE_COMPILE_OPTIONS | ON / **OFF** | Set to `ON` to compile/link with Control-Flow Guard (`/guard:cf`) and Spectre mitigations (`/Qspectre`). This has an effect only when compiling with MSVC. | +| SEAL_USE_ALIGN_64 | **ON** / OFF | Set to `ON` to use 64-byte aligned memory allocations. This can improve performance of AVX512 primitives when Intel HEXL is enabled. | #### Linking with Microsoft SEAL through CMake diff --git a/cmake/EnableCXX17.cmake b/cmake/EnableCXX17.cmake index 2d33f089..9ef05332 100644 --- a/cmake/EnableCXX17.cmake +++ b/cmake/EnableCXX17.cmake @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT license. +set(SEAL_USE_ALIGN_64 OFF) set(SEAL_USE_STD_BYTE OFF) set(SEAL_USE_SHARED_MUTEX OFF) set(SEAL_USE_IF_CONSTEXPR OFF) @@ -9,6 +10,7 @@ set(SEAL_USE_NODISCARD OFF) set(SEAL_USE_STD_FOR_EACH_N OFF) set(SEAL_LANG_FLAG "-std=c++14") if(SEAL_USE_CXX17) + set(SEAL_USE_ALIGN_64 ON) set(SEAL_USE_STD_BYTE ON) set(SEAL_USE_SHARED_MUTEX ON) set(SEAL_USE_IF_CONSTEXPR ON) @@ -41,4 +43,4 @@ if(SEAL_USE_STD_FOR_EACH_N) endif() cmake_pop_check_state() -endif() \ No newline at end of file +endif() diff --git a/cmake/ExternalIntelHEXL.cmake b/cmake/ExternalIntelHEXL.cmake new file mode 100644 index 00000000..4d5ed9f3 --- /dev/null +++ b/cmake/ExternalIntelHEXL.cmake @@ -0,0 +1,36 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT license. + +FetchContent_Declare( + hexl + PREFIX hexl + GIT_REPOSITORY https://github.com/intel/hexl.git + GIT_TAG v1.0.0 +) +FetchContent_GetProperties(hexl) + +if(NOT hexl_POPULATED) + FetchContent_Populate(hexl) + set(HEXL_DEBUG OFF) # Set to ON/OFF to toggle debugging + + set(CMAKE_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING "" FORCE) + set(CMAKE_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING "" FORCE) + set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE STRING "" FORCE) + set(HEXL_DEBUG ${HEXL_DEBUG} CACHE BOOL "" FORCE) + set(HEXL_BENCHMARK OFF CACHE BOOL "" FORCE) + set(HEXL_EXPORT OFF CACHE BOOL "" FORCE) + set(HEXL_COVERAGE OFF CACHE BOOL "" FORCE) + set(HEXL_TESTING OFF CACHE BOOL "" FORCE) + set(HEXL_SHARED_LIB OFF CACHE BOOL "" FORCE) + set(EXCLUDE_FROM_ALL TRUE) + + mark_as_advanced(BUILD_HEXL) + mark_as_advanced(INSTALL_HEXL) + mark_as_advanced(FETCHCONTENT_SOURCE_DIR_HEXL) + mark_as_advanced(FETCHCONTENT_UPDATES_DISCONNECTED_HEXL) + + add_subdirectory( + ${hexl_SOURCE_DIR} + EXCLUDE_FROM_ALL + ) +endif() diff --git a/cmake/SEALConfig.cmake.in b/cmake/SEALConfig.cmake.in index c368bcc0..f07c4f60 100644 --- a/cmake/SEALConfig.cmake.in +++ b/cmake/SEALConfig.cmake.in @@ -17,6 +17,7 @@ # SEAL_USE_CXX17 : Set to non-zero value if library is compiled as C++17 instead of C++14 # SEAL_ENFORCE_HE_STD_SECURITY : Set to non-zero value if library is compiled to enforce at least # a 128-bit security level based on HomomorphicEncryption.org security estimates +# SEAL_USE_INTEL_HEXL: Set to non-zero value if library is compiled with Intel HEXL support # SEAL_USE_MSGSL : Set to non-zero value if library is compiled with Microsoft GSL support # SEAL_USE_ZLIB : Set to non-zero value if library is compiled with ZLIB support # SEAL_USE_ZSTD : Set to non-zero value if library is compiled with Zstandard support @@ -51,6 +52,7 @@ set(SEAL_DEBUG @SEAL_DEBUG@) set(SEAL_USE_CXX17 @SEAL_USE_CXX17@) set(SEAL_ENFORCE_HE_STD_SECURITY @SEAL_ENFORCE_HE_STD_SECURITY@) +set(SEAL_USE_INTEL_HEXL @SEAL_USE_INTEL_HEXL@) set(SEAL_USE_MSGSL @SEAL_USE_MSGSL@) set(SEAL_USE_ZLIB @SEAL_USE_ZLIB@) set(SEAL_USE_ZSTD @SEAL_USE_ZSTD@) diff --git a/native/src/seal/util/CMakeLists.txt b/native/src/seal/util/CMakeLists.txt index d5a9637c..b0885bc6 100644 --- a/native/src/seal/util/CMakeLists.txt +++ b/native/src/seal/util/CMakeLists.txt @@ -45,6 +45,7 @@ install( ${CMAKE_CURRENT_LIST_DIR}/globals.h ${CMAKE_CURRENT_LIST_DIR}/hash.h ${CMAKE_CURRENT_LIST_DIR}/hestdparms.h + ${CMAKE_CURRENT_LIST_DIR}/intel_seal_ext.h ${CMAKE_CURRENT_LIST_DIR}/iterator.h ${CMAKE_CURRENT_LIST_DIR}/locks.h ${CMAKE_CURRENT_LIST_DIR}/mempool.h @@ -67,4 +68,4 @@ install( ${SEAL_INCLUDES_INSTALL_DIR}/seal/util ) -set(SEAL_SOURCE_FILES ${SEAL_SOURCE_FILES} PARENT_SCOPE) \ No newline at end of file +set(SEAL_SOURCE_FILES ${SEAL_SOURCE_FILES} PARENT_SCOPE) diff --git a/native/src/seal/util/clang.h b/native/src/seal/util/clang.h index 92496ea9..d2bccb36 100644 --- a/native/src/seal/util/clang.h +++ b/native/src/seal/util/clang.h @@ -13,6 +13,13 @@ // Read in config.h #include "seal/util/config.h" +#ifdef SEAL_USE_ALIGN_64 +#include +#define SEAL_ALIGNED_ALLOC(alignment, size) \ + ((size) % (alignment) == 0) ? aligned_alloc((alignment), (size)) : malloc((size)) +#define SEAL_ALIGNED_FREE(ptr) free(ptr) +#endif + // Are intrinsics enabled? #ifdef SEAL_USE_INTRIN #if defined(__aarch64__) diff --git a/native/src/seal/util/config.h.in b/native/src/seal/util/config.h.in index 91fc427b..ea08fac4 100644 --- a/native/src/seal/util/config.h.in +++ b/native/src/seal/util/config.h.in @@ -13,6 +13,7 @@ // C++17 features #cmakedefine SEAL_USE_STD_BYTE +#cmakedefine SEAL_USE_ALIGN_64 #cmakedefine SEAL_USE_SHARED_MUTEX #cmakedefine SEAL_USE_IF_CONSTEXPR #cmakedefine SEAL_USE_MAYBE_UNUSED @@ -42,3 +43,4 @@ #cmakedefine SEAL_USE_MSGSL #cmakedefine SEAL_USE_ZLIB #cmakedefine SEAL_USE_ZSTD +#cmakedefine SEAL_USE_INTEL_HEXL diff --git a/native/src/seal/util/gcc.h b/native/src/seal/util/gcc.h index de4149f5..5b1cbaa5 100644 --- a/native/src/seal/util/gcc.h +++ b/native/src/seal/util/gcc.h @@ -19,6 +19,13 @@ #define SEAL_FORCE_INLINE __always_inline +#ifdef SEAL_USE_ALIGN_64 +#include +#define SEAL_ALIGNED_ALLOC(alignment, size) \ + ((size) % (alignment) == 0) ? std::aligned_alloc((alignment), (size)) : malloc((size)) +#define SEAL_ALIGNED_FREE(ptr) free(ptr) +#endif + // Are intrinsics enabled? #ifdef SEAL_USE_INTRIN #if defined(__aarch64__) diff --git a/native/src/seal/util/intel_seal_ext.h b/native/src/seal/util/intel_seal_ext.h new file mode 100644 index 00000000..98708da1 --- /dev/null +++ b/native/src/seal/util/intel_seal_ext.h @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +#pragma once + +#ifdef SEAL_USE_INTEL_HEXL +#include "seal/util/locks.h" +#include +#include "hexl/hexl.hpp" + +namespace intel +{ + namespace seal_ext + { + struct HashPair + { + template + size_t operator()(const std::pair &p) const + { + auto hash1 = std::hash{}(std::get<0>(p)); + auto hash2 = std::hash{}(std::get<1>(p)); + return hash_combine(hash1, hash2); + } + + static size_t hash_combine(size_t lhs, size_t rhs) + { + lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); + return lhs; + } + }; + + static std::unordered_map, intel::hexl::NTT, HashPair> ntt_cache_; + + static seal::util::ReaderWriterLocker ntt_cache_locker_; + + /** + Returns a HEXL NTT object corresponding to the given parameters. + + @param[in] N The polynomial modulus degree + @param[in] modulus The modulus + @param[in] root The root of unity + */ + static intel::hexl::NTT get_ntt(size_t N, uint64_t modulus, uint64_t root) + { + std::pair key{ N, modulus }; + + // Enable shared access of NTT already present + { + seal::util::ReaderLock reader_lock(ntt_cache_locker_.acquire_read()); + auto ntt_it = ntt_cache_.find(key); + if (ntt_it != ntt_cache_.end()) + { + return ntt_it->second; + } + } + + // Deal with NTT not yet present + seal::util::WriterLock write_lock(ntt_cache_locker_.acquire_write()); + + // Check ntt_cache for value (maybe added by another thread) + auto ntt_it = ntt_cache_.find(key); + if (ntt_it == ntt_cache_.end()) + { + ntt_it = ntt_cache_.emplace(std::move(key), intel::hexl::NTT(N, modulus, root)).first; + } + return ntt_it->second; + } + + /** + Computes for forward negacyclic NTT from the given parameters. + + @param[in,out] operand The data on which to compute the NTT. + @param[in] N The polynomial modulus degree + @param[in] modulus The modulus + @param[in] root The root of unity + @param[in] input_mod_factor Bounds the input data to the range [0, input_mod_factor * modulus) + @param[in] output_mod_factor Bounds the output data to the range [0, output_mod_factor * modulus) + */ + static void compute_forward_ntt( + seal::util::CoeffIter operand, size_t N, uint64_t modulus, uint64_t root, uint64_t input_mod_factor, + uint64_t output_mod_factor) + { + get_ntt(N, modulus, root).ComputeForward(operand, operand, input_mod_factor, output_mod_factor); + } + + /** + Computes for inverse negacyclic NTT from the given parameters. + + @param[in,out] operand The data on which to compute the NTT. + @param[in] N The polynomial modulus degree + @param[in] modulus The modulus + @param[in] root The root of unity + @param[in] input_mod_factor Bounds the input data to the range [0, input_mod_factor * modulus) + @param[in] output_mod_factor Bounds the output data to the range [0, output_mod_factor * modulus) + */ + static void compute_inverse_ntt( + seal::util::CoeffIter operand, size_t N, uint64_t modulus, uint64_t root, uint64_t input_mod_factor, + uint64_t output_mod_factor) + { + get_ntt(N, modulus, root).ComputeInverse(operand, operand, input_mod_factor, output_mod_factor); + } + + } // namespace seal_ext +} // namespace intel +#endif diff --git a/native/src/seal/util/mempool.cpp b/native/src/seal/util/mempool.cpp index d1e4cab3..26318abe 100644 --- a/native/src/seal/util/mempool.cpp +++ b/native/src/seal/util/mempool.cpp @@ -40,7 +40,12 @@ namespace seal allocation new_alloc; try { +#ifdef SEAL_USE_ALIGN_64 + new_alloc.data_ptr = static_cast( + SEAL_ALIGNED_ALLOC(64, mul_safe(MemoryPool::first_alloc_count, item_byte_count_))); +#else new_alloc.data_ptr = new seal_byte[mul_safe(MemoryPool::first_alloc_count, item_byte_count_)]; +#endif } catch (const bad_alloc &) { @@ -83,7 +88,11 @@ namespace seal seal_memzero(alloc.data_ptr, curr_alloc_byte_count); // Delete this allocation +#ifdef SEAL_USE_ALIGN_64 + SEAL_ALIGNED_FREE(alloc.data_ptr); +#else delete[] alloc.data_ptr; +#endif } } else @@ -92,7 +101,11 @@ namespace seal for (auto &alloc : allocs_) { // Delete this allocation +#ifdef SEAL_USE_ALIGN_64 + SEAL_ALIGNED_FREE(alloc.data_ptr); +#else delete[] alloc.data_ptr; +#endif } } @@ -137,7 +150,11 @@ namespace seal try { +#ifdef SEAL_USE_ALIGN_64 + new_alloc.data_ptr = static_cast(SEAL_ALIGNED_ALLOC(64, new_alloc_byte_count)); +#else new_alloc.data_ptr = new seal_byte[new_alloc_byte_count]; +#endif } catch (const bad_alloc &) { @@ -178,7 +195,12 @@ namespace seal allocation new_alloc; try { +#ifdef SEAL_USE_ALIGN_64 + new_alloc.data_ptr = static_cast( + SEAL_ALIGNED_ALLOC(64, mul_safe(MemoryPool::first_alloc_count, item_byte_count_))); +#else new_alloc.data_ptr = new seal_byte[mul_safe(MemoryPool::first_alloc_count, item_byte_count_)]; +#endif } catch (const bad_alloc &) { @@ -215,7 +237,11 @@ namespace seal seal_memzero(alloc.data_ptr, curr_alloc_byte_count); // Delete this allocation +#ifdef SEAL_USE_ALIGN_64 + SEAL_ALIGNED_FREE(alloc.data_ptr); +#else delete[] alloc.data_ptr; +#endif } } else @@ -224,7 +250,11 @@ namespace seal for (auto &alloc : allocs_) { // Delete this allocation +#ifdef SEAL_USE_ALIGN_64 + SEAL_ALIGNED_FREE(alloc.data_ptr); +#else delete[] alloc.data_ptr; +#endif } } @@ -264,7 +294,11 @@ namespace seal try { +#ifdef SEAL_USE_ALIGN_64 + new_alloc.data_ptr = static_cast(SEAL_ALIGNED_ALLOC(64, new_alloc_byte_count)); +#else new_alloc.data_ptr = new seal_byte[new_alloc_byte_count]; +#endif } catch (const bad_alloc &) { diff --git a/native/src/seal/util/msvc.h b/native/src/seal/util/msvc.h index 70e04949..d0541568 100644 --- a/native/src/seal/util/msvc.h +++ b/native/src/seal/util/msvc.h @@ -34,20 +34,27 @@ #else #ifdef SEAL_USE_IF_CONSTEXPR -#pragma message("Disabling `if constexpr` based on _MSVC_LANG value " SEAL_STRINGIZE(_MSVC_LANG) ": undefining SEAL_USE_IF_CONSTEXPR") +#pragma message("Disabling `if constexpr` based on _MSVC_LANG value " SEAL_STRINGIZE( \ + _MSVC_LANG) ": undefining SEAL_USE_IF_CONSTEXPR") #undef SEAL_USE_IF_CONSTEXPR #endif #ifdef SEAL_USE_MAYBE_UNUSED -#pragma message("Disabling `[[maybe_unused]]` based on _MSVC_LANG value " SEAL_STRINGIZE(_MSVC_LANG) ": undefining SEAL_USE_MAYBE_UNUSED") +#pragma message("Disabling `[[maybe_unused]]` based on _MSVC_LANG value " SEAL_STRINGIZE( \ + _MSVC_LANG) ": undefining SEAL_USE_MAYBE_UNUSED") #undef SEAL_USE_MAYBE_UNUSED #endif #ifdef SEAL_USE_NODISCARD -#pragma message("Disabling `[[nodiscard]]` based on _MSVC_LANG value " SEAL_STRINGIZE(_MSVC_LANG) ": undefining SEAL_USE_NODISCARD") +#pragma message("Disabling `[[nodiscard]]` based on _MSVC_LANG value " SEAL_STRINGIZE( \ + _MSVC_LANG) ": undefining SEAL_USE_NODISCARD") #undef SEAL_USE_NODISCARD #endif +#endif +#ifdef SEAL_USE_ALIGN_64 +#define SEAL_ALIGNED_ALLOC(alignment, size) _aligned_malloc((size), (alignment)) +#define SEAL_ALIGNED_FREE(ptr) _aligned_free(ptr) #endif // X64 diff --git a/native/src/seal/util/ntt.cpp b/native/src/seal/util/ntt.cpp index b71c9212..621df387 100644 --- a/native/src/seal/util/ntt.cpp +++ b/native/src/seal/util/ntt.cpp @@ -6,6 +6,10 @@ #include "seal/util/uintarithsmallmod.h" #include +#ifdef SEAL_USE_INTEL_HEXL +#include "hexl/hexl.hpp" +#endif + using namespace std; namespace seal @@ -173,15 +177,30 @@ namespace seal void ntt_negacyclic_harvey_lazy(CoeffIter operand, const NTTTables &tables) { +#ifdef SEAL_USE_INTEL_HEXL + size_t N = size_t(1) << tables.coeff_count_power(); + uint64_t p = tables.modulus().value(); + uint64_t root = tables.get_root(); + + intel::seal_ext::compute_forward_ntt(operand, N, p, root, 4, 4); +#else tables.ntt_handler().transform_to_rev( operand.ptr(), tables.coeff_count_power(), tables.get_from_root_powers()); +#endif } void inverse_ntt_negacyclic_harvey_lazy(CoeffIter operand, const NTTTables &tables) { +#ifdef SEAL_USE_INTEL_HEXL + size_t N = size_t(1) << tables.coeff_count_power(); + uint64_t p = tables.modulus().value(); + uint64_t root = tables.get_root(); + intel::seal_ext::compute_inverse_ntt(operand, N, p, root, 2, 2); +#else MultiplyUIntModOperand inv_degree_modulo = tables.inv_degree_modulo(); tables.ntt_handler().transform_from_rev( operand.ptr(), tables.coeff_count_power(), tables.get_from_inv_root_powers(), &inv_degree_modulo); +#endif } } // namespace util } // namespace seal diff --git a/native/src/seal/util/ntt.h b/native/src/seal/util/ntt.h index 8e269ed6..c528a117 100644 --- a/native/src/seal/util/ntt.h +++ b/native/src/seal/util/ntt.h @@ -13,6 +13,10 @@ #include "seal/util/uintcore.h" #include +#ifdef SEAL_USE_INTEL_HEXL +#include "seal/util/intel_seal_ext.h" +#endif + namespace seal { namespace util @@ -230,8 +234,14 @@ namespace seal inline void ntt_negacyclic_harvey(CoeffIter operand, const NTTTables &tables) { - ntt_negacyclic_harvey_lazy(operand, tables); +#ifdef SEAL_USE_INTEL_HEXL + size_t N = size_t(1) << tables.coeff_count_power(); + uint64_t p = tables.modulus().value(); + uint64_t root = tables.get_root(); + intel::seal_ext::compute_forward_ntt(operand, N, p, root, 4, 1); +#else + ntt_negacyclic_harvey_lazy(operand, tables); // Finally maybe we need to reduce every coefficient modulo q, but we // know that they are in the range [0, 4q). // Since word size is controlled this is fast. @@ -250,6 +260,7 @@ namespace seal I -= modulus; } }); +#endif } inline void ntt_negacyclic_harvey(RNSIter operand, std::size_t coeff_modulus_size, ConstNTTTablesIter tables) @@ -324,8 +335,13 @@ namespace seal inline void inverse_ntt_negacyclic_harvey(CoeffIter operand, const NTTTables &tables) { +#ifdef SEAL_USE_INTEL_HEXL + size_t N = size_t(1) << tables.coeff_count_power(); + uint64_t p = tables.modulus().value(); + uint64_t root = tables.get_root(); + intel::seal_ext::compute_inverse_ntt(operand, N, p, root, 2, 1); +#else inverse_ntt_negacyclic_harvey_lazy(operand, tables); - std::uint64_t modulus = tables.modulus().value(); std::size_t n = std::size_t(1) << tables.coeff_count_power(); @@ -338,6 +354,7 @@ namespace seal I -= modulus; } }); +#endif } inline void inverse_ntt_negacyclic_harvey( diff --git a/native/src/seal/util/polyarithsmallmod.cpp b/native/src/seal/util/polyarithsmallmod.cpp index d63d133b..0ea55396 100644 --- a/native/src/seal/util/polyarithsmallmod.cpp +++ b/native/src/seal/util/polyarithsmallmod.cpp @@ -5,6 +5,10 @@ #include "seal/util/uintarith.h" #include "seal/util/uintcore.h" +#ifdef SEAL_USE_INTEL_HEXL +#include "hexl/hexl.hpp" +#endif + using namespace std; namespace seal @@ -85,10 +89,15 @@ namespace seal throw invalid_argument("modulus"); } #endif + +#ifdef SEAL_USE_INTEL_HEXL + intel::hexl::EltwiseFMAMod(&result[0], &poly[0], scalar.operand, nullptr, coeff_count, modulus.value(), 8); +#else SEAL_ITERATE(iter(poly, result), coeff_count, [&](auto I) { const uint64_t x = get<0>(I); get<1>(I) = multiply_uint_mod(x, scalar, modulus); }); +#endif } void dyadic_product_coeffmod( @@ -117,6 +126,9 @@ namespace seal throw invalid_argument("modulus"); } #endif +#ifdef SEAL_USE_INTEL_HEXL + intel::hexl::EltwiseMultMod(&result[0], &operand1[0], &operand2[0], coeff_count, modulus.value(), 4); +#else const uint64_t modulus_value = modulus.value(); const uint64_t const_ratio_0 = modulus.const_ratio()[0]; const uint64_t const_ratio_1 = modulus.const_ratio()[1]; @@ -145,6 +157,7 @@ namespace seal // Claim: One more subtraction is enough get<2>(I) = SEAL_COND_SELECT(tmp3 >= modulus_value, tmp3 - modulus_value, tmp3); }); +#endif } uint64_t poly_infty_norm_coeffmod(ConstCoeffIter operand, size_t coeff_count, const Modulus &modulus) diff --git a/native/src/seal/util/polyarithsmallmod.h b/native/src/seal/util/polyarithsmallmod.h index a85df55a..b736996c 100644 --- a/native/src/seal/util/polyarithsmallmod.h +++ b/native/src/seal/util/polyarithsmallmod.h @@ -14,6 +14,10 @@ #include #include +#ifdef SEAL_USE_INTEL_HEXL +#include "hexl/hexl.hpp" +#endif + namespace seal { namespace util @@ -201,6 +205,11 @@ namespace seal } #endif const uint64_t modulus_value = modulus.value(); + +#ifdef SEAL_USE_INTEL_HEXL + intel::hexl::EltwiseAddMod(&result[0], &operand1[0], &operand2[0], coeff_count, modulus_value); +#else + SEAL_ITERATE(iter(operand1, operand2, result), coeff_count, [&](auto I) { #ifdef SEAL_DEBUG if (get<0>(I) >= modulus_value) @@ -215,6 +224,7 @@ namespace seal std::uint64_t sum = get<0>(I) + get<1>(I); get<2>(I) = SEAL_COND_SELECT(sum >= modulus_value, sum - modulus_value, sum); }); +#endif } inline void add_poly_coeffmod(