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