1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the MIT license. 3 4 #pragma once 5 6 #include "seal/ciphertext.h" 7 #include "seal/context.h" 8 #include "seal/encryptionparams.h" 9 #include "seal/memorymanager.h" 10 #include "seal/modulus.h" 11 #include "seal/plaintext.h" 12 #include "seal/randomgen.h" 13 #include "seal/secretkey.h" 14 #include "seal/util/defines.h" 15 #include "seal/util/iterator.h" 16 #include "seal/util/locks.h" 17 #include "seal/util/ntt.h" 18 #include "seal/util/rns.h" 19 20 namespace seal 21 { 22 /** 23 Decrypts Ciphertext objects into Plaintext objects. Constructing a Decryptor 24 requires a SEALContext with valid encryption parameters, and the secret key. 25 The Decryptor is also used to compute the invariant noise budget in a given 26 ciphertext. 27 28 @par Overloads 29 For the decrypt function we provide two overloads concerning the memory pool 30 used in allocations needed during the operation. In one overload the global 31 memory pool is used for this purpose, and in another overload the user can 32 supply a MemoryPoolHandle to be used instead. This is to allow one single 33 Decryptor to be used concurrently by several threads without running into 34 thread contention in allocations taking place during operations. For example, 35 one can share one single Decryptor across any number of threads, but in each 36 thread call the decrypt function by giving it a thread-local MemoryPoolHandle 37 to use. It is important for a developer to understand how this works to avoid 38 unnecessary performance bottlenecks. 39 40 41 @par NTT form 42 When using the BFV scheme (scheme_type::bfv), all plaintext and ciphertexts 43 should remain by default in the usual coefficient representation, i.e. not in 44 NTT form. When using the CKKS scheme (scheme_type::ckks), all plaintexts and 45 ciphertexts should remain by default in NTT form. We call these scheme-specific 46 NTT states the "default NTT form". Decryption requires the input ciphertexts 47 to be in the default NTT form, and will throw an exception if this is not the 48 case. 49 */ 50 class Decryptor 51 { 52 public: 53 /** 54 Creates a Decryptor instance initialized with the specified SEALContext 55 and secret key. 56 57 @param[in] context The SEALContext 58 @param[in] secret_key The secret key 59 @throws std::invalid_argument if the encryption parameters are not valid 60 @throws std::invalid_argument if secret_key is not valid 61 */ 62 Decryptor(const SEALContext &context, const SecretKey &secret_key); 63 64 /* 65 Decrypts a Ciphertext and stores the result in the destination parameter. 66 67 @param[in] encrypted The ciphertext to decrypt 68 @param[out] destination The plaintext to overwrite with the decrypted 69 ciphertext 70 @throws std::invalid_argument if encrypted is not valid for the encryption 71 parameters 72 @throws std::invalid_argument if encrypted is not in the default NTT form 73 */ 74 void decrypt(const Ciphertext &encrypted, Plaintext &destination); 75 76 /* 77 Computes the invariant noise budget (in bits) of a ciphertext. The 78 invariant noise budget measures the amount of room there is for the noise 79 to grow while ensuring correct decryptions. This function works only with 80 the BFV scheme. 81 82 @par Invariant Noise Budget 83 The invariant noise polynomial of a ciphertext is a rational coefficient 84 polynomial, such that a ciphertext decrypts correctly as long as the 85 coefficients of the invariantnoise polynomial are of absolute value less 86 than 1/2. Thus, we call the infinity-norm of the invariant noise polynomial 87 the invariant noise, and for correct decryption requireit to be less than 88 1/2. If v denotes the invariant noise, we define the invariant noise budget 89 as -log2(2v). Thus, the invariant noise budget starts from some initial 90 value, which depends on the encryption parameters, and decreases when 91 computations are performed. When the budget reaches zero, the ciphertext 92 becomes too noisy to decrypt correctly. 93 94 @param[in] encrypted The ciphertext 95 @throws std::invalid_argument if the scheme is not BFV 96 @throws std::invalid_argument if encrypted is not valid for the encryption 97 parameters 98 @throws std::invalid_argument if encrypted is in NTT form 99 */ 100 SEAL_NODISCARD int invariant_noise_budget(const Ciphertext &encrypted); 101 102 private: 103 void bfv_decrypt(const Ciphertext &encrypted, Plaintext &destination, MemoryPoolHandle pool); 104 105 void ckks_decrypt(const Ciphertext &encrypted, Plaintext &destination, MemoryPoolHandle pool); 106 107 Decryptor(const Decryptor ©) = delete; 108 109 Decryptor(Decryptor &&source) = delete; 110 111 Decryptor &operator=(const Decryptor &assign) = delete; 112 113 Decryptor &operator=(Decryptor &&assign) = delete; 114 115 void compute_secret_key_array(std::size_t max_power); 116 117 // Compute c_0 + c_1 *s + ... + c_{count-1} * s^{count-1} mod q. 118 // Store result in destination in RNS form. 119 // destination has the size of an RNS polynomial. 120 void dot_product_ct_sk_array(const Ciphertext &encrypted, util::RNSIter destination, MemoryPoolHandle pool); 121 122 // We use a fresh memory pool with `clear_on_destruction' enabled. 123 MemoryPoolHandle pool_ = MemoryManager::GetPool(mm_prof_opt::mm_force_new, true); 124 125 SEALContext context_; 126 127 std::size_t secret_key_array_size_ = 0; 128 129 util::Pointer<std::uint64_t> secret_key_array_; 130 131 mutable util::ReaderWriterLocker secret_key_array_locker_; 132 }; 133 } // namespace seal 134