1 // @file cryptocontext.cpp -- Control for encryption operations.
2 // @author TPOC: contact@palisade-crypto.org
3 //
4 // @copyright Copyright (c) 2019, New Jersey Institute of Technology (NJIT))
5 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution. THIS SOFTWARE IS
13 // PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
14 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
16 // EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
17 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 
24 #include "cryptocontext.h"
25 #include "utils/serial.h"
26 
27 namespace lbcrypto {
28 
29 // Initialize global config variable
30 bool SERIALIZE_PRECOMPUTE = true;
31 
32 template <typename Element>
EvalMultKeyGen(const LPPrivateKey<Element> key)33 void CryptoContextImpl<Element>::EvalMultKeyGen(
34     const LPPrivateKey<Element> key) {
35   if (key == nullptr || Mismatched(key->GetCryptoContext()))
36     PALISADE_THROW(config_error,
37                    "Key passed to EvalMultKeyGen were not generated with this "
38                    "crypto context");
39 
40   LPEvalKey<Element> k = GetEncryptionAlgorithm()->EvalMultKeyGen(key);
41 
42   GetAllEvalMultKeys()[k->GetKeyTag()] = {k};
43 }
44 
45 template <typename Element>
EvalMultKeysGen(const LPPrivateKey<Element> key)46 void CryptoContextImpl<Element>::EvalMultKeysGen(
47     const LPPrivateKey<Element> key) {
48   if (key == nullptr || Mismatched(key->GetCryptoContext()))
49     PALISADE_THROW(config_error,
50                    "Key passed to EvalMultsKeyGen were not generated with this "
51                    "crypto context");
52 
53   const vector<LPEvalKey<Element>>& evalKeys =
54       GetEncryptionAlgorithm()->EvalMultKeysGen(key);
55 
56   GetAllEvalMultKeys()[evalKeys[0]->GetKeyTag()] = evalKeys;
57 }
58 
59 template <typename Element>
60 const vector<LPEvalKey<Element>>&
GetEvalMultKeyVector(const string & keyID)61 CryptoContextImpl<Element>::GetEvalMultKeyVector(const string& keyID) {
62   auto ekv = GetAllEvalMultKeys().find(keyID);
63   if (ekv == GetAllEvalMultKeys().end())
64     PALISADE_THROW(not_available_error,
65                    "You need to use EvalMultKeyGen so that you have an "
66                    "EvalMultKey available for this ID");
67   return ekv->second;
68 }
69 
70 template <typename Element>
71 std::map<string, std::vector<LPEvalKey<Element>>>&
GetAllEvalMultKeys()72 CryptoContextImpl<Element>::GetAllEvalMultKeys() {
73   return evalMultKeyMap();
74 }
75 
76 template <typename Element>
ClearEvalMultKeys()77 void CryptoContextImpl<Element>::ClearEvalMultKeys() {
78   GetAllEvalMultKeys().clear();
79 }
80 
81 /**
82  * ClearEvalMultKeys - flush EvalMultKey cache for a given id
83  * @param id
84  */
85 template <typename Element>
ClearEvalMultKeys(const string & id)86 void CryptoContextImpl<Element>::ClearEvalMultKeys(const string& id) {
87   auto kd = GetAllEvalMultKeys().find(id);
88   if (kd != GetAllEvalMultKeys().end()) GetAllEvalMultKeys().erase(kd);
89 }
90 
91 /**
92  * ClearEvalMultKeys - flush EvalMultKey cache for a given context
93  * @param cc
94  */
95 template <typename Element>
ClearEvalMultKeys(const CryptoContext<Element> cc)96 void CryptoContextImpl<Element>::ClearEvalMultKeys(
97     const CryptoContext<Element> cc) {
98   for (auto it = GetAllEvalMultKeys().begin();
99        it != GetAllEvalMultKeys().end();) {
100     if (it->second[0]->GetCryptoContext() == cc) {
101       it = GetAllEvalMultKeys().erase(it);
102     } else {
103       ++it;
104     }
105   }
106 }
107 
108 template <typename Element>
InsertEvalMultKey(const std::vector<LPEvalKey<Element>> & vectorToInsert)109 void CryptoContextImpl<Element>::InsertEvalMultKey(
110     const std::vector<LPEvalKey<Element>>& vectorToInsert) {
111   GetAllEvalMultKeys()[vectorToInsert[0]->GetKeyTag()] = vectorToInsert;
112 }
113 
114 template <typename Element>
EvalSumKeyGen(const LPPrivateKey<Element> privateKey,const LPPublicKey<Element> publicKey)115 void CryptoContextImpl<Element>::EvalSumKeyGen(
116     const LPPrivateKey<Element> privateKey,
117     const LPPublicKey<Element> publicKey) {
118   if (privateKey == nullptr || Mismatched(privateKey->GetCryptoContext())) {
119     PALISADE_THROW(config_error,
120                    "Private key passed to EvalSumKeyGen were not generated "
121                    "with this crypto context");
122   }
123 
124   if (publicKey != nullptr &&
125       privateKey->GetKeyTag() != publicKey->GetKeyTag()) {
126     PALISADE_THROW(
127         config_error,
128         "Public key passed to EvalSumKeyGen does not match private key");
129   }
130 
131   auto evalKeys =
132       GetEncryptionAlgorithm()->EvalSumKeyGen(privateKey, publicKey);
133 
134   GetAllEvalSumKeys()[privateKey->GetKeyTag()] = evalKeys;
135 }
136 
137 template <typename Element>
138 shared_ptr<std::map<usint, LPEvalKey<Element>>>
EvalSumRowsKeyGen(const LPPrivateKey<Element> privateKey,const LPPublicKey<Element> publicKey,usint rowSize,usint subringDim)139 CryptoContextImpl<Element>::EvalSumRowsKeyGen(
140     const LPPrivateKey<Element> privateKey,
141     const LPPublicKey<Element> publicKey, usint rowSize, usint subringDim) {
142   if (privateKey == nullptr || Mismatched(privateKey->GetCryptoContext())) {
143     PALISADE_THROW(config_error,
144                    "Private key passed to EvalSumKeyGen were not generated "
145                    "with this crypto context");
146   }
147 
148   if (publicKey != nullptr &&
149       privateKey->GetKeyTag() != publicKey->GetKeyTag()) {
150     PALISADE_THROW(
151         config_error,
152         "Public key passed to EvalSumKeyGen does not match private key");
153   }
154 
155   auto evalKeys = GetEncryptionAlgorithm()->EvalSumRowsKeyGen(
156       privateKey, publicKey, rowSize, subringDim);
157 
158   return evalKeys;
159 }
160 
161 template <typename Element>
162 shared_ptr<std::map<usint, LPEvalKey<Element>>>
EvalSumColsKeyGen(const LPPrivateKey<Element> privateKey,const LPPublicKey<Element> publicKey)163 CryptoContextImpl<Element>::EvalSumColsKeyGen(
164     const LPPrivateKey<Element> privateKey,
165     const LPPublicKey<Element> publicKey) {
166   if (privateKey == nullptr || Mismatched(privateKey->GetCryptoContext())) {
167     PALISADE_THROW(config_error,
168                    "Private key passed to EvalSumKeyGen were not generated "
169                    "with this crypto context");
170   }
171 
172   if (publicKey != nullptr &&
173       privateKey->GetKeyTag() != publicKey->GetKeyTag()) {
174     PALISADE_THROW(
175         config_error,
176         "Public key passed to EvalSumKeyGen does not match private key");
177   }
178 
179   auto evalKeys =
180       GetEncryptionAlgorithm()->EvalSumColsKeyGen(privateKey, publicKey);
181 
182   return evalKeys;
183 }
184 
185 template <typename Element>
186 const std::map<usint, LPEvalKey<Element>>&
GetEvalSumKeyMap(const string & keyID)187 CryptoContextImpl<Element>::GetEvalSumKeyMap(const string& keyID) {
188   auto ekv = GetAllEvalSumKeys().find(keyID);
189   if (ekv == GetAllEvalSumKeys().end())
190     PALISADE_THROW(not_available_error,
191                    "You need to use EvalSumKeyGen so that you have EvalSumKeys "
192                    "available for this ID");
193   return *ekv->second;
194 }
195 
196 template <typename Element>
197 std::map<string, shared_ptr<std::map<usint, LPEvalKey<Element>>>>&
GetAllEvalSumKeys()198 CryptoContextImpl<Element>::GetAllEvalSumKeys() {
199   return evalSumKeyMap();
200 }
201 
202 template <typename Element>
ClearEvalSumKeys()203 void CryptoContextImpl<Element>::ClearEvalSumKeys() {
204   GetAllEvalSumKeys().clear();
205 }
206 
207 /**
208  * ClearEvalMultKeys - flush EvalMultKey cache for a given id
209  * @param id
210  */
211 template <typename Element>
ClearEvalSumKeys(const string & id)212 void CryptoContextImpl<Element>::ClearEvalSumKeys(const string& id) {
213   auto kd = GetAllEvalSumKeys().find(id);
214   if (kd != GetAllEvalSumKeys().end()) GetAllEvalSumKeys().erase(kd);
215 }
216 
217 /**
218  * ClearEvalMultKeys - flush EvalMultKey cache for a given context
219  * @param cc
220  */
221 template <typename Element>
ClearEvalSumKeys(const CryptoContext<Element> cc)222 void CryptoContextImpl<Element>::ClearEvalSumKeys(
223     const CryptoContext<Element> cc) {
224   for (auto it = GetAllEvalSumKeys().begin();
225        it != GetAllEvalSumKeys().end();) {
226     if (it->second->begin()->second->GetCryptoContext() == cc) {
227       it = GetAllEvalSumKeys().erase(it);
228     } else {
229       ++it;
230     }
231   }
232 }
233 
234 template <typename Element>
InsertEvalSumKey(const shared_ptr<std::map<usint,LPEvalKey<Element>>> mapToInsert)235 void CryptoContextImpl<Element>::InsertEvalSumKey(
236     const shared_ptr<std::map<usint, LPEvalKey<Element>>> mapToInsert) {
237   // find the tag
238   if (!mapToInsert->empty()) {
239     auto onekey = mapToInsert->begin();
240     GetAllEvalSumKeys()[onekey->second->GetKeyTag()] = mapToInsert;
241   }
242 }
243 
244 template <typename Element>
EvalAtIndexKeyGen(const LPPrivateKey<Element> privateKey,const std::vector<int32_t> & indexList,const LPPublicKey<Element> publicKey)245 void CryptoContextImpl<Element>::EvalAtIndexKeyGen(
246     const LPPrivateKey<Element> privateKey,
247     const std::vector<int32_t>& indexList,
248     const LPPublicKey<Element> publicKey) {
249   if (privateKey == nullptr || Mismatched(privateKey->GetCryptoContext())) {
250     PALISADE_THROW(config_error,
251                    "Private key passed to EvalAtIndexKeyGen were not generated "
252                    "with this crypto context");
253   }
254 
255   if (publicKey != nullptr &&
256       privateKey->GetKeyTag() != publicKey->GetKeyTag()) {
257     PALISADE_THROW(
258         config_error,
259         "Public key passed to EvalAtIndexKeyGen does not match private key");
260   }
261 
262   auto evalKeys = GetEncryptionAlgorithm()->EvalAtIndexKeyGen(
263       publicKey, privateKey, indexList);
264 
265   evalAutomorphismKeyMap()[privateKey->GetKeyTag()] = evalKeys;
266 }
267 
268 template <typename Element>
269 const std::map<usint, LPEvalKey<Element>>&
GetEvalAutomorphismKeyMap(const string & keyID)270 CryptoContextImpl<Element>::GetEvalAutomorphismKeyMap(const string& keyID) {
271   auto ekv = evalAutomorphismKeyMap().find(keyID);
272   if (ekv == evalAutomorphismKeyMap().end())
273     PALISADE_THROW(not_available_error,
274                    "You need to use EvalAutomorphismKeyGen so that you have "
275                    "EvalAutomorphismKeys available for this ID");
276   return *ekv->second;
277 }
278 
279 template <typename Element>
280 std::map<string, shared_ptr<std::map<usint, LPEvalKey<Element>>>>&
GetAllEvalAutomorphismKeys()281 CryptoContextImpl<Element>::GetAllEvalAutomorphismKeys() {
282   return evalAutomorphismKeyMap();
283 }
284 
285 template <typename Element>
ClearEvalAutomorphismKeys()286 void CryptoContextImpl<Element>::ClearEvalAutomorphismKeys() {
287   evalAutomorphismKeyMap().clear();
288 }
289 
290 /**
291  * ClearEvalAutomorphismKeys - flush EvalAutomorphismKey cache for a given id
292  * @param id
293  */
294 template <typename Element>
ClearEvalAutomorphismKeys(const string & id)295 void CryptoContextImpl<Element>::ClearEvalAutomorphismKeys(const string& id) {
296   auto kd = evalAutomorphismKeyMap().find(id);
297   if (kd != evalAutomorphismKeyMap().end()) evalAutomorphismKeyMap().erase(kd);
298 }
299 
300 /**
301  * ClearEvalAutomorphismKeys - flush EvalAutomorphismKey cache for a given
302  * context
303  * @param cc
304  */
305 template <typename Element>
ClearEvalAutomorphismKeys(const CryptoContext<Element> cc)306 void CryptoContextImpl<Element>::ClearEvalAutomorphismKeys(
307     const CryptoContext<Element> cc) {
308   for (auto it = evalAutomorphismKeyMap().begin();
309        it != evalAutomorphismKeyMap().end();) {
310     if (it->second->begin()->second->GetCryptoContext() == cc) {
311       it = evalAutomorphismKeyMap().erase(it);
312     } else {
313       ++it;
314     }
315   }
316 }
317 
318 template <typename Element>
InsertEvalAutomorphismKey(const shared_ptr<std::map<usint,LPEvalKey<Element>>> mapToInsert)319 void CryptoContextImpl<Element>::InsertEvalAutomorphismKey(
320     const shared_ptr<std::map<usint, LPEvalKey<Element>>> mapToInsert) {
321   // find the tag
322   auto onekey = mapToInsert->begin();
323   evalAutomorphismKeyMap()[onekey->second->GetKeyTag()] = mapToInsert;
324 }
325 
326 template <typename Element>
EvalSum(ConstCiphertext<Element> ciphertext,usint batchSize) const327 Ciphertext<Element> CryptoContextImpl<Element>::EvalSum(
328     ConstCiphertext<Element> ciphertext, usint batchSize) const {
329   if (ciphertext == nullptr || Mismatched(ciphertext->GetCryptoContext()))
330     PALISADE_THROW(config_error,
331                    "Information passed to EvalSum was not generated with this "
332                    "crypto context");
333 
334   auto evalSumKeys =
335       CryptoContextImpl<Element>::GetEvalSumKeyMap(ciphertext->GetKeyTag());
336   auto rv =
337       GetEncryptionAlgorithm()->EvalSum(ciphertext, batchSize, evalSumKeys);
338   return rv;
339 }
340 
341 template <typename Element>
EvalSumRows(ConstCiphertext<Element> ciphertext,usint rowSize,const std::map<usint,LPEvalKey<Element>> & evalSumKeys,usint subringDim) const342 Ciphertext<Element> CryptoContextImpl<Element>::EvalSumRows(
343     ConstCiphertext<Element> ciphertext, usint rowSize,
344     const std::map<usint, LPEvalKey<Element>>& evalSumKeys,
345     usint subringDim) const {
346   if (ciphertext == nullptr || Mismatched(ciphertext->GetCryptoContext()))
347     PALISADE_THROW(config_error,
348                    "Information passed to EvalSum was not generated with this "
349                    "crypto context");
350 
351   auto rv = GetEncryptionAlgorithm()->EvalSumRows(ciphertext, rowSize,
352                                                   evalSumKeys, subringDim);
353   return rv;
354 }
355 
356 template <typename Element>
EvalSumCols(ConstCiphertext<Element> ciphertext,usint rowSize,const std::map<usint,LPEvalKey<Element>> & evalSumKeysRight) const357 Ciphertext<Element> CryptoContextImpl<Element>::EvalSumCols(
358     ConstCiphertext<Element> ciphertext, usint rowSize,
359     const std::map<usint, LPEvalKey<Element>>& evalSumKeysRight) const {
360   if (ciphertext == nullptr || Mismatched(ciphertext->GetCryptoContext()))
361     PALISADE_THROW(config_error,
362                    "Information passed to EvalSum was not generated with this "
363                    "crypto context");
364 
365   auto evalSumKeys =
366       CryptoContextImpl<Element>::GetEvalSumKeyMap(ciphertext->GetKeyTag());
367 
368   auto rv = GetEncryptionAlgorithm()->EvalSumCols(
369       ciphertext, rowSize, evalSumKeys, evalSumKeysRight);
370   return rv;
371 }
372 
373 template <typename Element>
EvalAtIndex(ConstCiphertext<Element> ciphertext,int32_t index) const374 Ciphertext<Element> CryptoContextImpl<Element>::EvalAtIndex(
375     ConstCiphertext<Element> ciphertext, int32_t index) const {
376   if (ciphertext == nullptr || Mismatched(ciphertext->GetCryptoContext()))
377     PALISADE_THROW(config_error,
378                    "Information passed to EvalAtIndex was not generated with "
379                    "this crypto context");
380 
381   // If the index is zero, no rotation is needed, copy the ciphertext and return
382   // This is done after the keyMap so that it is protected if there's not a valid key.
383   if (0 == index) {
384     auto rv = ciphertext->Clone();
385     return rv;
386   }
387 
388   auto evalAutomorphismKeys =
389       CryptoContextImpl<Element>::GetEvalAutomorphismKeyMap(
390           ciphertext->GetKeyTag());
391 
392   auto rv = GetEncryptionAlgorithm()->EvalAtIndex(ciphertext, index,
393                                                   evalAutomorphismKeys);
394   return rv;
395 }
396 
397 template <typename Element>
EvalMerge(const vector<Ciphertext<Element>> & ciphertextVector) const398 Ciphertext<Element> CryptoContextImpl<Element>::EvalMerge(
399     const vector<Ciphertext<Element>>& ciphertextVector) const {
400   if (ciphertextVector[0] == nullptr ||
401       Mismatched(ciphertextVector[0]->GetCryptoContext()))
402     PALISADE_THROW(config_error,
403                    "Information passed to EvalMerge was not generated with "
404                    "this crypto context");
405 
406   auto evalAutomorphismKeys =
407       CryptoContextImpl<Element>::GetEvalAutomorphismKeyMap(
408           ciphertextVector[0]->GetKeyTag());
409 
410   auto rv = GetEncryptionAlgorithm()->EvalMerge(ciphertextVector,
411                                                 evalAutomorphismKeys);
412 
413   return rv;
414 }
415 
416 template <typename Element>
EvalInnerProduct(ConstCiphertext<Element> ct1,ConstCiphertext<Element> ct2,usint batchSize) const417 Ciphertext<Element> CryptoContextImpl<Element>::EvalInnerProduct(
418     ConstCiphertext<Element> ct1, ConstCiphertext<Element> ct2,
419     usint batchSize) const {
420   if (ct1 == nullptr || ct2 == nullptr ||
421       ct1->GetKeyTag() != ct2->GetKeyTag() ||
422       Mismatched(ct1->GetCryptoContext()))
423     PALISADE_THROW(config_error,
424                    "Information passed to EvalInnerProduct was not generated "
425                    "with this crypto context");
426 
427   auto evalSumKeys =
428       CryptoContextImpl<Element>::GetEvalSumKeyMap(ct1->GetKeyTag());
429   auto ek = GetEvalMultKeyVector(ct1->GetKeyTag());
430 
431   auto rv = GetEncryptionAlgorithm()->EvalInnerProduct(ct1, ct2, batchSize,
432                                                        evalSumKeys, ek[0]);
433   return rv;
434 }
435 
436 template <typename Element>
EvalInnerProduct(ConstCiphertext<Element> ct1,ConstPlaintext ct2,usint batchSize) const437 Ciphertext<Element> CryptoContextImpl<Element>::EvalInnerProduct(
438     ConstCiphertext<Element> ct1, ConstPlaintext ct2, usint batchSize) const {
439   if (ct1 == nullptr || ct2 == nullptr || Mismatched(ct1->GetCryptoContext()))
440     PALISADE_THROW(config_error,
441                    "Information passed to EvalInnerProduct was not generated "
442                    "with this crypto context");
443 
444   auto evalSumKeys =
445       CryptoContextImpl<Element>::GetEvalSumKeyMap(ct1->GetKeyTag());
446 
447   auto rv = GetEncryptionAlgorithm()->EvalInnerProduct(ct1, ct2, batchSize,
448                                                        evalSumKeys);
449   return rv;
450 }
451 
452 template <typename Element>
GetPlaintextForDecrypt(PlaintextEncodings pte,shared_ptr<ParmType> evp,EncodingParams ep)453 Plaintext CryptoContextImpl<Element>::GetPlaintextForDecrypt(
454     PlaintextEncodings pte, shared_ptr<ParmType> evp, EncodingParams ep) {
455   auto vp = std::make_shared<typename NativePoly::Params>(
456       evp->GetCyclotomicOrder(), ep->GetPlaintextModulus(), 1);
457 
458   if (pte == CKKSPacked) return PlaintextFactory::MakePlaintext(pte, evp, ep);
459 
460   return PlaintextFactory::MakePlaintext(pte, vp, ep);
461 }
462 
463 template <typename Element>
Decrypt(const LPPrivateKey<Element> privateKey,ConstCiphertext<Element> ciphertext,Plaintext * plaintext)464 DecryptResult CryptoContextImpl<Element>::Decrypt(
465     const LPPrivateKey<Element> privateKey, ConstCiphertext<Element> ciphertext,
466     Plaintext* plaintext) {
467   if (ciphertext == nullptr)
468     PALISADE_THROW(config_error, "ciphertext passed to Decrypt is empty");
469   if (plaintext == nullptr)
470     PALISADE_THROW(config_error, "plaintext passed to Decrypt is empty");
471   if (privateKey == nullptr || Mismatched(privateKey->GetCryptoContext()))
472     PALISADE_THROW(config_error,
473                    "Information passed to Decrypt was not generated with "
474                    "this crypto context");
475 
476   // determine which type of plaintext that you need to decrypt into
477   // Plaintext decrypted =
478   // GetPlaintextForDecrypt(ciphertext->GetEncodingType(),
479   // this->GetElementParams(), this->GetEncodingParams());
480   Plaintext decrypted = GetPlaintextForDecrypt(
481       ciphertext->GetEncodingType(), ciphertext->GetElements()[0].GetParams(),
482       this->GetEncodingParams());
483 
484   DecryptResult result;
485 
486   if ((ciphertext->GetEncodingType() == CKKSPacked) &&
487       (typeid(Element) != typeid(NativePoly))) {
488     result = GetEncryptionAlgorithm()->Decrypt(privateKey, ciphertext,
489                                                &decrypted->GetElement<Poly>());
490   } else {
491     result = GetEncryptionAlgorithm()->Decrypt(
492         privateKey, ciphertext, &decrypted->GetElement<NativePoly>());
493   }
494 
495   if (result.isValid == false) return result;
496 
497   if (ciphertext->GetEncodingType() == CKKSPacked) {
498     auto decryptedCKKS =
499         std::static_pointer_cast<CKKSPackedEncoding>(decrypted);
500     decryptedCKKS->SetDepth(ciphertext->GetDepth());
501     decryptedCKKS->SetLevel(ciphertext->GetLevel());
502     decryptedCKKS->SetScalingFactor(ciphertext->GetScalingFactor());
503 
504     const auto cryptoParamsCKKS =
505         std::dynamic_pointer_cast<LPCryptoParametersCKKS<DCRTPoly>>(
506             this->GetCryptoParameters());
507 
508     decryptedCKKS->Decode(ciphertext->GetDepth(),
509                           ciphertext->GetScalingFactor(),
510                           cryptoParamsCKKS->GetRescalingTechnique());
511 
512   } else {
513     decrypted->Decode();
514   }
515 
516   *plaintext = std::move(decrypted);
517   return result;
518 }
519 
520 template <typename Element>
MultipartyDecryptFusion(const vector<Ciphertext<Element>> & partialCiphertextVec,Plaintext * plaintext) const521 DecryptResult CryptoContextImpl<Element>::MultipartyDecryptFusion(
522     const vector<Ciphertext<Element>>& partialCiphertextVec,
523     Plaintext* plaintext) const {
524   DecryptResult result;
525 
526   // Make sure we're processing ciphertexts.
527   size_t last_ciphertext = partialCiphertextVec.size();
528   if (last_ciphertext < 1) return result;
529 
530   for (size_t i = 0; i < last_ciphertext; i++) {
531     if (partialCiphertextVec[i] == nullptr ||
532         Mismatched(partialCiphertextVec[i]->GetCryptoContext()))
533       PALISADE_THROW(config_error,
534                      "A ciphertext passed to MultipartyDecryptFusion was not "
535                      "generated with this crypto context");
536     if (partialCiphertextVec[i]->GetEncodingType() !=
537         partialCiphertextVec[0]->GetEncodingType())
538       PALISADE_THROW(type_error,
539                      "Ciphertexts passed to MultipartyDecryptFusion have "
540                      "mismatched encoding types");
541   }
542 
543   // determine which type of plaintext that you need to decrypt into
544   Plaintext decrypted = GetPlaintextForDecrypt(
545       partialCiphertextVec[0]->GetEncodingType(),
546       partialCiphertextVec[0]->GetElements()[0].GetParams(),
547       this->GetEncodingParams());
548 
549   if ((partialCiphertextVec[0]->GetEncodingType() == CKKSPacked) &&
550       (typeid(Element) != typeid(NativePoly)))
551     result = GetEncryptionAlgorithm()->MultipartyDecryptFusion(
552         partialCiphertextVec, &decrypted->GetElement<Poly>());
553   else
554     result = GetEncryptionAlgorithm()->MultipartyDecryptFusion(
555         partialCiphertextVec, &decrypted->GetElement<NativePoly>());
556 
557   if (result.isValid == false) return result;
558 
559   if (partialCiphertextVec[0]->GetEncodingType() == CKKSPacked) {
560     auto decryptedCKKS =
561         std::static_pointer_cast<CKKSPackedEncoding>(decrypted);
562     const auto cryptoParamsCKKS =
563         std::dynamic_pointer_cast<LPCryptoParametersCKKS<DCRTPoly>>(
564             this->GetCryptoParameters());
565     decryptedCKKS->Decode(partialCiphertextVec[0]->GetDepth(),
566                           partialCiphertextVec[0]->GetScalingFactor(),
567                           cryptoParamsCKKS->GetRescalingTechnique());
568   } else {
569     decrypted->Decode();
570   }
571 
572   *plaintext = std::move(decrypted);
573 
574   return result;
575 }
576 
577 }  // namespace lbcrypto
578