1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT license.
3 
4 #include "seal/ciphertext.h"
5 #include "seal/galoiskeys.h"
6 #include "seal/kswitchkeys.h"
7 #include "seal/plaintext.h"
8 #include "seal/publickey.h"
9 #include "seal/relinkeys.h"
10 #include "seal/secretkey.h"
11 #include "seal/valcheck.h"
12 #include "seal/util/common.h"
13 #include "seal/util/defines.h"
14 
15 using namespace std;
16 using namespace seal::util;
17 
18 namespace seal
19 {
is_metadata_valid_for(const Plaintext & in,const SEALContext & context,bool allow_pure_key_levels)20     bool is_metadata_valid_for(const Plaintext &in, const SEALContext &context, bool allow_pure_key_levels)
21     {
22         // Verify parameters
23         if (!context.parameters_set())
24         {
25             return false;
26         }
27 
28         if (in.is_ntt_form())
29         {
30             // Are the parameters valid for the plaintext?
31             auto context_data_ptr = context.get_context_data(in.parms_id());
32             if (!context_data_ptr)
33             {
34                 return false;
35             }
36 
37             // Check whether the parms_id is in the pure key range
38             bool is_parms_pure_key = context_data_ptr->chain_index() > context.first_context_data()->chain_index();
39             if (!allow_pure_key_levels && is_parms_pure_key)
40             {
41                 return false;
42             }
43 
44             auto &parms = context_data_ptr->parms();
45             auto &coeff_modulus = parms.coeff_modulus();
46             size_t poly_modulus_degree = parms.poly_modulus_degree();
47 
48             // Check that coeff_count is appropriately set
49             if (mul_safe(coeff_modulus.size(), poly_modulus_degree) != in.coeff_count())
50             {
51                 return false;
52             }
53         }
54         else
55         {
56             auto &parms = context.first_context_data()->parms();
57             size_t poly_modulus_degree = parms.poly_modulus_degree();
58             if (in.coeff_count() > poly_modulus_degree)
59             {
60                 return false;
61             }
62         }
63 
64         return true;
65     }
66 
is_metadata_valid_for(const Ciphertext & in,const SEALContext & context,bool allow_pure_key_levels)67     bool is_metadata_valid_for(const Ciphertext &in, const SEALContext &context, bool allow_pure_key_levels)
68     {
69         // Verify parameters
70         if (!context.parameters_set())
71         {
72             return false;
73         }
74 
75         // Are the parameters valid for the ciphertext?
76         auto context_data_ptr = context.get_context_data(in.parms_id());
77         if (!context_data_ptr)
78         {
79             return false;
80         }
81 
82         // Check whether the parms_id is in the pure key range
83         bool is_parms_pure_key = context_data_ptr->chain_index() > context.first_context_data()->chain_index();
84         if (!allow_pure_key_levels && is_parms_pure_key)
85         {
86             return false;
87         }
88 
89         // Check that the metadata matches
90         auto &coeff_modulus = context_data_ptr->parms().coeff_modulus();
91         size_t poly_modulus_degree = context_data_ptr->parms().poly_modulus_degree();
92         if ((coeff_modulus.size() != in.coeff_modulus_size()) || (poly_modulus_degree != in.poly_modulus_degree()))
93         {
94             return false;
95         }
96 
97         // Check that size is either 0 or within right bounds
98         auto size = in.size();
99         if ((size < SEAL_CIPHERTEXT_SIZE_MIN && size != 0) || size > SEAL_CIPHERTEXT_SIZE_MAX)
100         {
101             return false;
102         }
103 
104         return true;
105     }
106 
is_metadata_valid_for(const SecretKey & in,const SEALContext & context)107     bool is_metadata_valid_for(const SecretKey &in, const SEALContext &context)
108     {
109         // Note: we check the underlying Plaintext and allow pure key levels in
110         // this check. Then, also need to check that the parms_id matches the
111         // key level parms_id; this also means the Plaintext is in NTT form.
112         auto key_parms_id = context.key_parms_id();
113         return is_metadata_valid_for(in.data(), context, true) && (in.parms_id() == key_parms_id);
114     }
115 
is_metadata_valid_for(const PublicKey & in,const SEALContext & context)116     bool is_metadata_valid_for(const PublicKey &in, const SEALContext &context)
117     {
118         // Note: we check the underlying Ciphertext and allow pure key levels in
119         // this check. Then, also need to check that the parms_id matches the
120         // key level parms_id, that the Ciphertext is in NTT form, and that the
121         // size is minimal (i.e., SEAL_CIPHERTEXT_SIZE_MIN).
122         auto key_parms_id = context.key_parms_id();
123         return is_metadata_valid_for(in.data(), context, true) && in.data().is_ntt_form() &&
124                (in.parms_id() == key_parms_id) && (in.data().size() == SEAL_CIPHERTEXT_SIZE_MIN);
125     }
126 
is_metadata_valid_for(const KSwitchKeys & in,const SEALContext & context)127     bool is_metadata_valid_for(const KSwitchKeys &in, const SEALContext &context)
128     {
129         // Verify parameters
130         if (!context.parameters_set())
131         {
132             return false;
133         }
134 
135         // Are the parameters valid and at key level?
136         if (in.parms_id() != context.key_parms_id())
137         {
138             return false;
139         }
140 
141         size_t decomp_mod_count = context.first_context_data()->parms().coeff_modulus().size();
142         for (auto &a : in.data())
143         {
144             // Check that each highest level component has right size
145             if (a.size() && (a.size() != decomp_mod_count))
146             {
147                 return false;
148             }
149             for (auto &b : a)
150             {
151                 // Check that b is a valid public key (metadata only); this also
152                 // checks that its parms_id matches key_parms_id.
153                 if (!is_metadata_valid_for(b, context))
154                 {
155                     return false;
156                 }
157             }
158         }
159 
160         return true;
161     }
162 
is_metadata_valid_for(const RelinKeys & in,const SEALContext & context)163     bool is_metadata_valid_for(const RelinKeys &in, const SEALContext &context)
164     {
165         // Check that the size is within bounds.
166         bool size_check =
167             !in.size() || (in.size() <= SEAL_CIPHERTEXT_SIZE_MAX - 2 && in.size() >= SEAL_CIPHERTEXT_SIZE_MIN - 2);
168         return is_metadata_valid_for(static_cast<const KSwitchKeys &>(in), context) && size_check;
169     }
170 
is_metadata_valid_for(const GaloisKeys & in,const SEALContext & context)171     bool is_metadata_valid_for(const GaloisKeys &in, const SEALContext &context)
172     {
173         // Check the metadata; then we know context is OK
174         bool metadata_check = is_metadata_valid_for(static_cast<const KSwitchKeys &>(in), context);
175         bool size_check = !in.size() || in.size() <= context.key_context_data()->parms().poly_modulus_degree();
176         return metadata_check && size_check;
177     }
178 
is_buffer_valid(const Plaintext & in)179     bool is_buffer_valid(const Plaintext &in)
180     {
181         if (in.coeff_count() != in.dyn_array().size())
182         {
183             return false;
184         }
185 
186         return true;
187     }
188 
is_buffer_valid(const Ciphertext & in)189     bool is_buffer_valid(const Ciphertext &in)
190     {
191         // Check that the buffer size is correct
192         if (in.dyn_array().size() != mul_safe(in.size(), in.coeff_modulus_size(), in.poly_modulus_degree()))
193         {
194             return false;
195         }
196 
197         return true;
198     }
199 
is_buffer_valid(const SecretKey & in)200     bool is_buffer_valid(const SecretKey &in)
201     {
202         return is_buffer_valid(in.data());
203     }
204 
is_buffer_valid(const PublicKey & in)205     bool is_buffer_valid(const PublicKey &in)
206     {
207         return is_buffer_valid(in.data());
208     }
209 
is_buffer_valid(const KSwitchKeys & in)210     bool is_buffer_valid(const KSwitchKeys &in)
211     {
212         for (auto &a : in.data())
213         {
214             for (auto &b : a)
215             {
216                 if (!is_buffer_valid(b))
217                 {
218                     return false;
219                 }
220             }
221         }
222 
223         return true;
224     }
225 
is_buffer_valid(const RelinKeys & in)226     bool is_buffer_valid(const RelinKeys &in)
227     {
228         return is_buffer_valid(static_cast<const KSwitchKeys &>(in));
229     }
230 
is_buffer_valid(const GaloisKeys & in)231     bool is_buffer_valid(const GaloisKeys &in)
232     {
233         return is_buffer_valid(static_cast<const KSwitchKeys &>(in));
234     }
235 
is_data_valid_for(const Plaintext & in,const SEALContext & context)236     bool is_data_valid_for(const Plaintext &in, const SEALContext &context)
237     {
238         // Check metadata
239         if (!is_metadata_valid_for(in, context))
240         {
241             return false;
242         }
243 
244         // Check the data
245         if (in.is_ntt_form())
246         {
247             auto context_data_ptr = context.get_context_data(in.parms_id());
248             auto &parms = context_data_ptr->parms();
249             auto &coeff_modulus = parms.coeff_modulus();
250             size_t coeff_modulus_size = coeff_modulus.size();
251 
252             const Plaintext::pt_coeff_type *ptr = in.data();
253             for (size_t j = 0; j < coeff_modulus_size; j++)
254             {
255                 uint64_t modulus = coeff_modulus[j].value();
256                 size_t poly_modulus_degree = parms.poly_modulus_degree();
257                 for (; poly_modulus_degree--; ptr++)
258                 {
259                     if (*ptr >= modulus)
260                     {
261                         return false;
262                     }
263                 }
264             }
265         }
266         else
267         {
268             auto &parms = context.first_context_data()->parms();
269             uint64_t modulus = parms.plain_modulus().value();
270             const Plaintext::pt_coeff_type *ptr = in.data();
271             auto size = in.coeff_count();
272             for (size_t k = 0; k < size; k++, ptr++)
273             {
274                 if (*ptr >= modulus)
275                 {
276                     return false;
277                 }
278             }
279         }
280 
281         return true;
282     }
283 
is_data_valid_for(const Ciphertext & in,const SEALContext & context)284     bool is_data_valid_for(const Ciphertext &in, const SEALContext &context)
285     {
286         // Check metadata
287         if (!is_metadata_valid_for(in, context))
288         {
289             return false;
290         }
291 
292         // Check the data
293         auto context_data_ptr = context.get_context_data(in.parms_id());
294         const auto &coeff_modulus = context_data_ptr->parms().coeff_modulus();
295         size_t coeff_modulus_size = coeff_modulus.size();
296 
297         const Ciphertext::ct_coeff_type *ptr = in.data();
298         auto size = in.size();
299 
300         for (size_t i = 0; i < size; i++)
301         {
302             for (size_t j = 0; j < coeff_modulus_size; j++)
303             {
304                 uint64_t modulus = coeff_modulus[j].value();
305                 auto poly_modulus_degree = in.poly_modulus_degree();
306                 for (; poly_modulus_degree--; ptr++)
307                 {
308                     if (*ptr >= modulus)
309                     {
310                         return false;
311                     }
312                 }
313             }
314         }
315 
316         return true;
317     }
318 
is_data_valid_for(const SecretKey & in,const SEALContext & context)319     bool is_data_valid_for(const SecretKey &in, const SEALContext &context)
320     {
321         // Check metadata
322         if (!is_metadata_valid_for(in, context))
323         {
324             return false;
325         }
326 
327         // Check the data
328         auto context_data_ptr = context.key_context_data();
329         auto &parms = context_data_ptr->parms();
330         auto &coeff_modulus = parms.coeff_modulus();
331         size_t coeff_modulus_size = coeff_modulus.size();
332 
333         const Plaintext::pt_coeff_type *ptr = in.data().data();
334         for (size_t j = 0; j < coeff_modulus_size; j++)
335         {
336             uint64_t modulus = coeff_modulus[j].value();
337             size_t poly_modulus_degree = parms.poly_modulus_degree();
338             for (; poly_modulus_degree--; ptr++)
339             {
340                 if (*ptr >= modulus)
341                 {
342                     return false;
343                 }
344             }
345         }
346 
347         return true;
348     }
349 
is_data_valid_for(const PublicKey & in,const SEALContext & context)350     bool is_data_valid_for(const PublicKey &in, const SEALContext &context)
351     {
352         // Check metadata
353         if (!is_metadata_valid_for(in, context))
354         {
355             return false;
356         }
357 
358         // Check the data
359         auto context_data_ptr = context.key_context_data();
360         const auto &coeff_modulus = context_data_ptr->parms().coeff_modulus();
361         size_t coeff_modulus_size = coeff_modulus.size();
362 
363         const Ciphertext::ct_coeff_type *ptr = in.data().data();
364         auto size = in.data().size();
365 
366         for (size_t i = 0; i < size; i++)
367         {
368             for (size_t j = 0; j < coeff_modulus_size; j++)
369             {
370                 uint64_t modulus = coeff_modulus[j].value();
371                 auto poly_modulus_degree = in.data().poly_modulus_degree();
372                 for (; poly_modulus_degree--; ptr++)
373                 {
374                     if (*ptr >= modulus)
375                     {
376                         return false;
377                     }
378                 }
379             }
380         }
381 
382         return true;
383     }
384 
is_data_valid_for(const KSwitchKeys & in,const SEALContext & context)385     bool is_data_valid_for(const KSwitchKeys &in, const SEALContext &context)
386     {
387         // Verify parameters
388         if (!context.parameters_set())
389         {
390             return false;
391         }
392 
393         // Are the parameters valid for given relinearization keys?
394         if (in.parms_id() != context.key_parms_id())
395         {
396             return false;
397         }
398 
399         for (auto &a : in.data())
400         {
401             for (auto &b : a)
402             {
403                 // Check that b is a valid public key; this also checks that its
404                 // parms_id matches key_parms_id.
405                 if (!is_data_valid_for(b, context))
406                 {
407                     return false;
408                 }
409             }
410         }
411 
412         return true;
413     }
414 
is_data_valid_for(const RelinKeys & in,const SEALContext & context)415     bool is_data_valid_for(const RelinKeys &in, const SEALContext &context)
416     {
417         return is_data_valid_for(static_cast<const KSwitchKeys &>(in), context);
418     }
419 
is_data_valid_for(const GaloisKeys & in,const SEALContext & context)420     bool is_data_valid_for(const GaloisKeys &in, const SEALContext &context)
421     {
422         return is_data_valid_for(static_cast<const KSwitchKeys &>(in), context);
423     }
424 } // namespace seal
425