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