1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the MIT license. 3 4 #pragma once 5 6 // Debugging help 7 #define SEAL_ASSERT(condition) \ 8 { \ 9 if (!(condition)) \ 10 { \ 11 std::cerr << "ASSERT FAILED: " << #condition << " @ " << __FILE__ << " (" << __LINE__ << ")" << std::endl; \ 12 } \ 13 } 14 15 // String expansion 16 #define _SEAL_STRINGIZE(x) #x 17 #define SEAL_STRINGIZE(x) _SEAL_STRINGIZE(x) 18 19 // Join 20 #define _SEAL_JOIN(M, N) M##N 21 #define SEAL_JOIN(M, N) _SEAL_JOIN(M, N) 22 23 // Check that double is 64 bits 24 static_assert(sizeof(double) == 8, "Require sizeof(double) == 8"); 25 26 // Check that int is 32 bits 27 static_assert(sizeof(int) == 4, "Require sizeof(int) == 4"); 28 29 // Check that unsigned long long is 64 bits 30 static_assert(sizeof(unsigned long long) == 8, "Require sizeof(unsigned long long) == 8"); 31 32 // Bounds for bit-length of all coefficient moduli 33 #define SEAL_MOD_BIT_COUNT_MAX 61 34 #define SEAL_MOD_BIT_COUNT_MIN 2 35 36 // Bit-length of internally used coefficient moduli, e.g., auxiliary base in BFV 37 #define SEAL_INTERNAL_MOD_BIT_COUNT 61 38 39 // Bounds for bit-length of user-defined coefficient moduli 40 #define SEAL_USER_MOD_BIT_COUNT_MAX 60 41 #define SEAL_USER_MOD_BIT_COUNT_MIN 2 42 43 // Bounds for bit-length of the plaintext modulus 44 #define SEAL_PLAIN_MOD_BIT_COUNT_MAX SEAL_USER_MOD_BIT_COUNT_MAX 45 #define SEAL_PLAIN_MOD_BIT_COUNT_MIN SEAL_USER_MOD_BIT_COUNT_MIN 46 47 // Bounds for number of coefficient moduli (no hard requirement) 48 #define SEAL_COEFF_MOD_COUNT_MAX 64 49 #define SEAL_COEFF_MOD_COUNT_MIN 1 50 51 // Bounds for polynomial modulus degree (no hard requirement) 52 #define SEAL_POLY_MOD_DEGREE_MAX 131072 53 #define SEAL_POLY_MOD_DEGREE_MIN 2 54 55 // Upper bound on the size of a ciphertext (cannot exceed 2^32 / poly_modulus_degree) 56 #define SEAL_CIPHERTEXT_SIZE_MAX 16 57 #if SEAL_CIPHERTEXT_SIZE_MAX > 0x100000000ULL / SEAL_POLY_MOD_DEGREE_MAX 58 #error "SEAL_CIPHERTEXT_SIZE_MAX is too large" 59 #endif 60 #define SEAL_CIPHERTEXT_SIZE_MIN 2 61 62 // How many pairs of modular integers can we multiply and accumulate in a 128-bit data type 63 #if SEAL_MOD_BIT_COUNT_MAX > 32 64 #define SEAL_MULTIPLY_ACCUMULATE_MOD_MAX (1 << (128 - (SEAL_MOD_BIT_COUNT_MAX << 1))) 65 #define SEAL_MULTIPLY_ACCUMULATE_INTERNAL_MOD_MAX (1 << (128 - (SEAL_INTERNAL_MOD_BIT_COUNT_MAX << 1))) 66 #define SEAL_MULTIPLY_ACCUMULATE_USER_MOD_MAX (1 << (128 - (SEAL_USER_MOD_BIT_COUNT_MAX << 1))) 67 #else 68 #define SEAL_MULTIPLY_ACCUMULATE_MOD_MAX SIZE_MAX 69 #define SEAL_MULTIPLY_ACCUMULATE_INTERNAL_MOD_MAX SIZE_MAX 70 #define SEAL_MULTIPLY_ACCUMULATE_USER_MOD_MAX SIZE_MAX 71 #endif 72 73 // Detect system 74 #define SEAL_SYSTEM_OTHER 1 75 #define SEAL_SYSTEM_WINDOWS 2 76 #define SEAL_SYSTEM_UNIX_LIKE 3 77 78 #if defined(_WIN32) 79 #define SEAL_SYSTEM SEAL_SYSTEM_WINDOWS 80 #elif defined(__linux__) || defined(__FreeBSD__) || defined(EMSCRIPTEN) || (defined(__APPLE__) && defined(__MACH__)) || defined(__DragonFly__) 81 #define SEAL_SYSTEM SEAL_SYSTEM_UNIX_LIKE 82 #else 83 #define SEAL_SYSTEM SEAL_SYSTEM_OTHER 84 #error "Unsupported system" 85 #endif 86 87 // Detect compiler 88 #define SEAL_COMPILER_MSVC 1 89 #define SEAL_COMPILER_CLANG 2 90 #define SEAL_COMPILER_GCC 3 91 92 #if defined(_MSC_VER) 93 #define SEAL_COMPILER SEAL_COMPILER_MSVC 94 #elif defined(__clang__) 95 #define SEAL_COMPILER SEAL_COMPILER_CLANG 96 #elif defined(__GNUC__) && !defined(__clang__) 97 #define SEAL_COMPILER SEAL_COMPILER_GCC 98 #else 99 #error "Unsupported compiler" 100 #endif 101 102 // MSVC support 103 #include "seal/util/msvc.h" 104 105 // clang support 106 #include "seal/util/clang.h" 107 108 // gcc support 109 #include "seal/util/gcc.h" 110 111 // Create a true/false value for indicating debug mode 112 #ifdef SEAL_DEBUG 113 #define SEAL_DEBUG_V true 114 #else 115 #define SEAL_DEBUG_V false 116 #endif 117 118 // Use std::byte as byte type 119 #ifdef SEAL_USE_STD_BYTE 120 #include <cstddef> 121 namespace seal 122 { 123 using seal_byte = std::byte; 124 } // namespace seal 125 #else 126 namespace seal 127 { 128 enum class seal_byte : unsigned char 129 { 130 }; 131 } // namespace seal 132 #endif 133 134 // Force inline 135 #ifndef SEAL_FORCE_INLINE 136 #define SEAL_FORCE_INLINE inline 137 #endif 138 139 // Use `if constexpr' from C++17 140 #ifdef SEAL_USE_IF_CONSTEXPR 141 #define SEAL_IF_CONSTEXPR if constexpr 142 #else 143 #define SEAL_IF_CONSTEXPR if 144 #endif 145 146 // Use [[maybe_unused]] from C++17 147 #ifdef SEAL_USE_MAYBE_UNUSED 148 #define SEAL_MAYBE_UNUSED [[maybe_unused]] 149 #else 150 #define SEAL_MAYBE_UNUSED 151 #endif 152 153 // Use [[nodiscard]] from C++17 154 #ifdef SEAL_USE_NODISCARD 155 #define SEAL_NODISCARD [[nodiscard]] 156 #else 157 #define SEAL_NODISCARD 158 #endif 159 160 // C++14 does not have std::for_each_n so we use a custom implementation 161 #ifndef SEAL_USE_STD_FOR_EACH_N 162 #define SEAL_ITERATE seal::util::seal_for_each_n 163 #else 164 #define SEAL_ITERATE std::for_each_n 165 #endif 166 167 // Allocate "size" bytes in memory and returns a seal_byte pointer 168 // If SEAL_USE_ALIGNED_ALLOC is defined, use _aligned_malloc and ::aligned_alloc (or std::malloc) 169 // Use `new seal_byte[size]` as fallback 170 #ifndef SEAL_MALLOC 171 #define SEAL_MALLOC(size) (new seal_byte[size]) 172 #endif 173 174 // Deallocate a pointer in memory 175 // If SEAL_USE_ALIGNED_ALLOC is defined, use _aligned_free or std::free 176 // Use `delete [] ptr` as fallback 177 #ifndef SEAL_FREE 178 #define SEAL_FREE(ptr) (delete[] ptr) 179 #endif 180 181 // Which random number generator to use by default 182 #define SEAL_DEFAULT_PRNG_FACTORY SEAL_JOIN(SEAL_DEFAULT_PRNG, PRNGFactory) 183 184 // Which distribution to use for noise sampling: rounded Gaussian or Centered Binomial Distribution 185 #ifdef SEAL_USE_GAUSSIAN_NOISE 186 #define SEAL_NOISE_SAMPLER sample_poly_normal 187 #else 188 #define SEAL_NOISE_SAMPLER sample_poly_cbd 189 #endif 190 191 // Use generic functions as (slower) fallback 192 #ifndef SEAL_ADD_CARRY_UINT64 193 #define SEAL_ADD_CARRY_UINT64(operand1, operand2, carry, result) add_uint64_generic(operand1, operand2, carry, result) 194 #endif 195 196 #ifndef SEAL_SUB_BORROW_UINT64 197 #define SEAL_SUB_BORROW_UINT64(operand1, operand2, borrow, result) \ 198 sub_uint64_generic(operand1, operand2, borrow, result) 199 #endif 200 201 #ifndef SEAL_MULTIPLY_UINT64 202 #define SEAL_MULTIPLY_UINT64(operand1, operand2, result128) multiply_uint64_generic(operand1, operand2, result128) 203 #endif 204 205 #ifndef SEAL_DIVIDE_UINT128_UINT64 206 #define SEAL_DIVIDE_UINT128_UINT64(numerator, denominator, result) \ 207 divide_uint128_uint64_inplace_generic(numerator, denominator, result); 208 #endif 209 210 #ifndef SEAL_MULTIPLY_UINT64_HW64 211 #define SEAL_MULTIPLY_UINT64_HW64(operand1, operand2, hw64) multiply_uint64_hw64_generic(operand1, operand2, hw64) 212 #endif 213 214 #ifndef SEAL_MSB_INDEX_UINT64 215 #define SEAL_MSB_INDEX_UINT64(result, value) get_msb_index_generic(result, value) 216 #endif 217 218 // Check whether an object is of expected type; this requires the type_traits header to be included 219 #define SEAL_ASSERT_TYPE(obj, expected, message) \ 220 do \ 221 { \ 222 static_assert( \ 223 std::is_same<decltype(obj), expected>::value, \ 224 "In " __FILE__ ":" SEAL_STRINGIZE(__LINE__) " expected " SEAL_STRINGIZE(expected) " (message: " message \ 225 ")"); \ 226 } while (false) 227 228 // This macro can be used to allocate a temporary buffer and create a PtrIter<T *> object pointing to it. This is 229 // convenient when the Pointer holding the buffer is not explicitly needed and the memory is only accessed through the 230 // iterator. 231 #define SEAL_ALLOCATE_GET_PTR_ITER(name, type, size, pool) \ 232 auto SEAL_JOIN(_seal_temp_alloc_, __LINE__)(seal::util::allocate<type>(size, pool)); \ 233 seal::util::PtrIter<type *> name(SEAL_JOIN(_seal_temp_alloc_, __LINE__).get()); 234 235 // This macro can be used to allocate a temporary buffer and create a StrideIter<T *> object pointing to it. This is 236 // convenient when the Pointer holding the buffer is not explicitly needed and the memory is only accessed through the 237 // iterator. 238 #define SEAL_ALLOCATE_GET_STRIDE_ITER(name, type, size, stride, pool) \ 239 auto SEAL_JOIN(_seal_temp_alloc_, __LINE__)(seal::util::allocate<type>(seal::util::mul_safe(size, stride), pool)); \ 240 seal::util::StrideIter<type *> name(SEAL_JOIN(_seal_temp_alloc_, __LINE__).get(), stride); 241 242 // This macro can be used to allocate a temporary buffer and create a PolyIter object pointing to it. This is convenient 243 // when the Pointer holding the buffer is not explicitly needed and the memory is only accessed through the iterator. 244 #define SEAL_ALLOCATE_GET_POLY_ITER(name, poly_count, poly_modulus_degree, coeff_modulus_size, pool) \ 245 auto SEAL_JOIN(_seal_temp_alloc_, __LINE__)( \ 246 seal::util::allocate_poly_array(poly_count, poly_modulus_degree, coeff_modulus_size, pool)); \ 247 seal::util::PolyIter name(SEAL_JOIN(_seal_temp_alloc_, __LINE__).get(), poly_modulus_degree, coeff_modulus_size); 248 249 // This macro can be used to allocate a temporary buffer (set to zero) and create a PolyIter object pointing to it. This 250 // is convenient when the Pointer holding the buffer is not explicitly needed and the memory is only accessed through 251 // the iterator. 252 #define SEAL_ALLOCATE_ZERO_GET_POLY_ITER(name, poly_count, poly_modulus_degree, coeff_modulus_size, pool) \ 253 auto SEAL_JOIN(_seal_temp_alloc_, __LINE__)( \ 254 seal::util::allocate_zero_poly_array(poly_count, poly_modulus_degree, coeff_modulus_size, pool)); \ 255 seal::util::PolyIter name(SEAL_JOIN(_seal_temp_alloc_, __LINE__).get(), poly_modulus_degree, coeff_modulus_size); 256 257 // This macro can be used to allocate a temporary buffer and create a RNSIter object pointing to it. This is convenient 258 // when the Pointer holding the buffer is not explicitly needed and the memory is only accessed through the iterator. 259 #define SEAL_ALLOCATE_GET_RNS_ITER(name, poly_modulus_degree, coeff_modulus_size, pool) \ 260 auto SEAL_JOIN(_seal_temp_alloc_, __LINE__)( \ 261 seal::util::allocate_poly(poly_modulus_degree, coeff_modulus_size, pool)); \ 262 seal::util::RNSIter name(SEAL_JOIN(_seal_temp_alloc_, __LINE__).get(), poly_modulus_degree); 263 264 // This macro can be used to allocate a temporary buffer (set to zero) and create a RNSIter object pointing to it. This 265 // is convenient when the Pointer holding the buffer is not explicitly needed and the memory is only accessed through 266 // the iterator. 267 #define SEAL_ALLOCATE_ZERO_GET_RNS_ITER(name, poly_modulus_degree, coeff_modulus_size, pool) \ 268 auto SEAL_JOIN(_seal_temp_alloc_, __LINE__)( \ 269 seal::util::allocate_zero_poly(poly_modulus_degree, coeff_modulus_size, pool)); \ 270 seal::util::RNSIter name(SEAL_JOIN(_seal_temp_alloc_, __LINE__).get(), poly_modulus_degree); 271 272 // This macro can be used to allocate a temporary buffer and create a CoeffIter object pointing to it. This is 273 // convenient when the Pointer holding the buffer is not explicitly needed and the memory is only accessed through the 274 // iterator. 275 #define SEAL_ALLOCATE_GET_COEFF_ITER(name, poly_modulus_degree, pool) \ 276 auto SEAL_JOIN(_seal_temp_alloc_, __LINE__)(seal::util::allocate_uint(poly_modulus_degree, pool)); \ 277 seal::util::CoeffIter name(SEAL_JOIN(_seal_temp_alloc_, __LINE__).get()); 278 279 // This macro can be used to allocate a temporary buffer (set to zero) and create a CoeffIter object pointing to it. 280 // This is convenient when the Pointer holding the buffer is not explicitly needed and the memory is only accessed 281 // through the iterator. 282 #define SEAL_ALLOCATE_ZERO_GET_COEFF_ITER(name, poly_modulus_degree, pool) \ 283 auto SEAL_JOIN(_seal_temp_alloc_, __LINE__)(seal::util::allocate_zero_uint(poly_modulus_degree, pool)); \ 284 seal::util::CoeffIter name(SEAL_JOIN(_seal_temp_alloc_, __LINE__).get()); 285 286 // Conditionally select the former if true and the latter if false 287 // This is a temporary solution that generates constant-time code with all compilers on all platforms. 288 #define SEAL_COND_SELECT(cond, if_true, if_false) (cond ? if_true : if_false) 289