1 // @file pubkeylp.h -- Public key type for lattice crypto 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 #ifndef LBCRYPTO_CRYPTO_PUBKEYLP_H 25 #define LBCRYPTO_CRYPTO_PUBKEYLP_H 26 27 #include <iomanip> 28 #include <limits> 29 #include <map> 30 #include <memory> 31 #include <string> 32 #include <utility> 33 #include <vector> 34 35 #include "lattice/elemparams.h" 36 #include "lattice/ilparams.h" 37 38 #include "lattice/ildcrtparams.h" 39 #include "lattice/ilelement.h" 40 #include "utils/caller_info.h" 41 #include "utils/hashutil.h" 42 #include "utils/inttypes.h" 43 44 #include "math/distrgen.h" 45 46 #include "encoding/encodingparams.h" 47 48 /** 49 * @namespace lbcrypto 50 * The namespace of lbcrypto 51 */ 52 namespace lbcrypto { 53 54 /* This struct holds the different options for 55 * key switching algorithms that are supported 56 * by the library. 57 * 58 */ 59 enum KeySwitchTechnique { BV, GHS, HYBRID }; 60 61 /* This struct holds the different options for 62 * mod switching algorithms that are supported 63 * by the library. 64 * 65 */ 66 enum ModSwitchMethod { MANUAL, AUTO }; 67 68 // forward declarations, used to resolve circular header dependencies 69 template <typename Element> 70 class CiphertextImpl; 71 72 template <typename Element> 73 class LPCryptoParameters; 74 75 template <typename Element> 76 class LPCryptoParametersBFV; 77 78 template <typename Element> 79 class CryptoObject; 80 81 struct EncryptResult { EncryptResultEncryptResult82 EncryptResult() : isValid(false), numBytesEncrypted(0) {} 83 EncryptResultEncryptResult84 explicit EncryptResult(size_t len) : isValid(true), numBytesEncrypted(len) {} 85 86 bool isValid; // whether the encryption was successful 87 // count of the number of plaintext bytes that were encrypted 88 usint numBytesEncrypted; 89 }; 90 91 /** 92 * @brief Decryption result. This represents whether the decryption of a 93 * cipheretext was performed correctly. 94 * 95 * This is intended to eventually incorporate information about the amount of 96 * padding in a decoded ciphertext, to ensure that the correct amount of 97 * padding is stripped away. It is intended to provided a very simple kind of 98 * checksum eventually. This notion of a decoding output is inherited from the 99 * crypto++ library. It is also intended to be used in a recover and restart 100 * robust functionality if not all ciphertext is recieved over a lossy 101 * channel, so that if all information is eventually recieved, 102 * decoding/decryption can be performed eventually. This is intended to be 103 * returned with the output of a decryption operation. 104 */ 105 struct DecryptResult { 106 /** 107 * Constructor that initializes all message lengths to 0. 108 */ DecryptResultDecryptResult109 DecryptResult() : isValid(false), messageLength(0) {} 110 111 /** 112 * Constructor that initializes all message lengths. 113 * @param len the new length. 114 */ DecryptResultDecryptResult115 explicit DecryptResult(size_t len) : isValid(true), messageLength(len) {} 116 117 bool isValid; /**< whether the decryption was successful */ 118 usint messageLength; /**< the length of the decrypted plaintext message */ 119 }; 120 121 /** 122 * @brief Abstract interface class for LP Keys 123 * 124 * @tparam Element a ring element. 125 */ 126 template <class Element> 127 class LPKey : public CryptoObject<Element>, public Serializable { 128 public: 129 explicit LPKey(CryptoContext<Element> cc, const string &id = "") 130 : CryptoObject<Element>(cc, id) {} 131 LPKey(shared_ptr<CryptoObject<Element>> co)132 explicit LPKey(shared_ptr<CryptoObject<Element>> co) 133 : CryptoObject<Element>(co) {} 134 ~LPKey()135 virtual ~LPKey() {} 136 137 template <class Archive> save(Archive & ar,std::uint32_t const version)138 void save(Archive &ar, std::uint32_t const version) const { 139 ar(::cereal::base_class<CryptoObject<Element>>(this)); 140 } 141 142 template <class Archive> load(Archive & ar,std::uint32_t const version)143 void load(Archive &ar, std::uint32_t const version) { 144 ar(::cereal::base_class<CryptoObject<Element>>(this)); 145 } 146 }; 147 148 template <typename Element> 149 class LPPublicKeyImpl; 150 151 template <typename Element> 152 using LPPublicKey = shared_ptr<LPPublicKeyImpl<Element>>; 153 154 /** 155 * @brief Class for LP public keys 156 * @tparam Element a ring element. 157 */ 158 template <typename Element> 159 class LPPublicKeyImpl : public LPKey<Element> { 160 public: 161 /** 162 * Basic constructor 163 * 164 * @param cc - CryptoContext 165 * @param id - key identifier 166 */ 167 explicit LPPublicKeyImpl(CryptoContext<Element> cc = 0, const string &id = "") 168 : LPKey<Element>(cc, id) {} 169 170 /** 171 * Copy constructor 172 * 173 *@param &rhs LPPublicKeyImpl to copy from 174 */ LPPublicKeyImpl(const LPPublicKeyImpl<Element> & rhs)175 explicit LPPublicKeyImpl(const LPPublicKeyImpl<Element> &rhs) 176 : LPKey<Element>(rhs.GetCryptoContext(), rhs.GetKeyTag()) { 177 m_h = rhs.m_h; 178 } 179 180 /** 181 * Move constructor 182 * 183 *@param &rhs LPPublicKeyImpl to move from 184 */ LPPublicKeyImpl(LPPublicKeyImpl<Element> && rhs)185 explicit LPPublicKeyImpl(LPPublicKeyImpl<Element> &&rhs) 186 : LPKey<Element>(rhs.GetCryptoContext(), rhs.GetKeyTag()) { 187 m_h = std::move(rhs.m_h); 188 } 189 190 operator bool() const { 191 return static_cast<bool>(this->context) && m_h.size() != 0; 192 } 193 194 /** 195 * Assignment Operator. 196 * 197 * @param &rhs LPPublicKeyImpl to copy from 198 */ 199 const LPPublicKeyImpl<Element> &operator=( 200 const LPPublicKeyImpl<Element> &rhs) { 201 CryptoObject<Element>::operator=(rhs); 202 this->m_h = rhs.m_h; 203 return *this; 204 } 205 206 /** 207 * Move Assignment Operator. 208 * 209 * @param &rhs LPPublicKeyImpl to copy from 210 */ 211 const LPPublicKeyImpl<Element> &operator=(LPPublicKeyImpl<Element> &&rhs) { 212 CryptoObject<Element>::operator=(rhs); 213 m_h = std::move(rhs.m_h); 214 return *this; 215 } 216 217 // @Get Properties 218 219 /** 220 * Gets the computed public key 221 * @return the public key element. 222 */ GetPublicElements()223 const std::vector<Element> &GetPublicElements() const { return this->m_h; } 224 225 // @Set Properties 226 227 /** 228 * Sets the public key vector of Element. 229 * @param &element is the public key Element vector to be copied. 230 */ SetPublicElements(const std::vector<Element> & element)231 void SetPublicElements(const std::vector<Element> &element) { m_h = element; } 232 233 /** 234 * Sets the public key vector of Element. 235 * @param &&element is the public key Element vector to be moved. 236 */ SetPublicElements(std::vector<Element> && element)237 void SetPublicElements(std::vector<Element> &&element) { 238 m_h = std::move(element); 239 } 240 241 /** 242 * Sets the public key Element at index idx. 243 * @param &element is the public key Element to be copied. 244 */ SetPublicElementAtIndex(usint idx,const Element & element)245 void SetPublicElementAtIndex(usint idx, const Element &element) { 246 m_h.insert(m_h.begin() + idx, element); 247 } 248 249 /** 250 * Sets the public key Element at index idx. 251 * @param &&element is the public key Element to be moved. 252 */ SetPublicElementAtIndex(usint idx,Element && element)253 void SetPublicElementAtIndex(usint idx, Element &&element) { 254 m_h.insert(m_h.begin() + idx, std::move(element)); 255 } 256 257 bool operator==(const LPPublicKeyImpl &other) const { 258 if (!CryptoObject<Element>::operator==(other)) { 259 return false; 260 } 261 262 if (m_h.size() != other.m_h.size()) { 263 return false; 264 } 265 266 for (size_t i = 0; i < m_h.size(); i++) { 267 if (m_h[i] != other.m_h[i]) { 268 return false; 269 } 270 } 271 272 return true; 273 } 274 275 bool operator!=(const LPPublicKeyImpl &other) const { 276 return !(*this == other); 277 } 278 279 template <class Archive> save(Archive & ar,std::uint32_t const version)280 void save(Archive &ar, std::uint32_t const version) const { 281 ar(::cereal::base_class<LPKey<Element>>(this)); 282 ar(::cereal::make_nvp("h", m_h)); 283 } 284 285 template <class Archive> load(Archive & ar,std::uint32_t const version)286 void load(Archive &ar, std::uint32_t const version) { 287 if (version > SerializedVersion()) { 288 PALISADE_THROW(deserialize_error, 289 "serialized object version " + std::to_string(version) + 290 " is from a later version of the library"); 291 } 292 ar(::cereal::base_class<LPKey<Element>>(this)); 293 ar(::cereal::make_nvp("h", m_h)); 294 } 295 SerializedObjectName()296 std::string SerializedObjectName() const { return "PublicKey"; } SerializedVersion()297 static uint32_t SerializedVersion() { return 1; } 298 299 private: 300 std::vector<Element> m_h; 301 }; 302 303 template <typename Element> 304 class LPEvalKeyImpl; 305 306 template <typename Element> 307 using LPEvalKey = shared_ptr<LPEvalKeyImpl<Element>>; 308 309 /** 310 * @brief Abstract interface for LP evaluation/proxy keys 311 * @tparam Element a ring element. 312 */ 313 template <class Element> 314 class LPEvalKeyImpl : public LPKey<Element> { 315 public: 316 /** 317 * Basic constructor for setting crypto params 318 * 319 * @param &cryptoParams is the reference to cryptoParams 320 */ 321 322 explicit LPEvalKeyImpl(CryptoContext<Element> cc = 0) : LPKey<Element>(cc) {} 323 ~LPEvalKeyImpl()324 virtual ~LPEvalKeyImpl() {} 325 326 /** 327 * Setter function to store Relinearization Element Vector A. 328 * Throws exception, to be overridden by derived class. 329 * 330 * @param &a is the Element vector to be copied. 331 */ 332 SetAVector(const std::vector<Element> & a)333 virtual void SetAVector(const std::vector<Element> &a) { 334 PALISADE_THROW(not_implemented_error, 335 "SetAVector copy operation not supported"); 336 } 337 338 /** 339 * Setter function to store Relinearization Element Vector A. 340 * Throws exception, to be overridden by derived class. 341 * 342 * @param &&a is the Element vector to be moved. 343 */ 344 SetAVector(std::vector<Element> && a)345 virtual void SetAVector(std::vector<Element> &&a) { 346 PALISADE_THROW(not_implemented_error, 347 "SetAVector move operation not supported"); 348 } 349 350 /** 351 * Getter function to access Relinearization Element Vector A. 352 * Throws exception, to be overridden by derived class. 353 * 354 * @return Element vector A. 355 */ 356 GetAVector()357 virtual const std::vector<Element> &GetAVector() const { 358 PALISADE_THROW(not_implemented_error, "GetAVector operation not supported"); 359 } 360 361 /** 362 * Setter function to store Relinearization Element Vector B. 363 * Throws exception, to be overridden by derived class. 364 * 365 * @param &b is the Element vector to be copied. 366 */ 367 SetBVector(const std::vector<Element> & b)368 virtual void SetBVector(const std::vector<Element> &b) { 369 PALISADE_THROW(not_implemented_error, 370 "SetBVector copy operation not supported"); 371 } 372 373 /** 374 * Setter function to store Relinearization Element Vector B. 375 * Throws exception, to be overridden by derived class. 376 * 377 * @param &&b is the Element vector to be moved. 378 */ 379 SetBVector(std::vector<Element> && b)380 virtual void SetBVector(std::vector<Element> &&b) { 381 PALISADE_THROW(not_implemented_error, 382 "SetBVector move operation not supported"); 383 } 384 385 /** 386 * Getter function to access Relinearization Element Vector B. 387 * Throws exception, to be overridden by derived class. 388 * 389 * @return Element vector B. 390 */ 391 GetBVector()392 virtual const std::vector<Element> &GetBVector() const { 393 PALISADE_THROW(not_implemented_error, "GetBVector operation not supported"); 394 } 395 396 /** 397 * Setter function to store key switch Element. 398 * Throws exception, to be overridden by derived class. 399 * 400 * @param &a is the Element to be copied. 401 */ 402 SetA(const Element & a)403 virtual void SetA(const Element &a) { 404 PALISADE_THROW(not_implemented_error, "SetA copy operation not supported"); 405 } 406 407 /** 408 * Setter function to store key switch Element. 409 * Throws exception, to be overridden by derived class. 410 * 411 * @param &&a is the Element to be moved. 412 */ SetA(Element && a)413 virtual void SetA(Element &&a) { 414 PALISADE_THROW(not_implemented_error, "SetA move operation not supported"); 415 } 416 417 /** 418 * Getter function to access key switch Element. 419 * Throws exception, to be overridden by derived class. 420 * 421 * @return Element. 422 */ 423 GetA()424 virtual const Element &GetA() const { 425 PALISADE_THROW(not_implemented_error, "GetA operation not supported"); 426 } 427 428 /** 429 * Setter function to store key switch Element. 430 * Throws exception, to be overridden by derived class. 431 * 432 * @param &a is the Element to be copied. 433 */ 434 SetAinDCRT(const DCRTPoly & a)435 virtual void SetAinDCRT(const DCRTPoly &a) { 436 PALISADE_THROW(not_implemented_error, 437 "SetAinDCRT copy operation not supported"); 438 } 439 440 /** 441 * Setter function to store key switch Element. 442 * Throws exception, to be overridden by derived class. 443 * 444 * @param &&a is the Element to be moved. 445 */ SetAinDCRT(DCRTPoly && a)446 virtual void SetAinDCRT(DCRTPoly &&a) { 447 PALISADE_THROW(not_implemented_error, 448 "SetAinDCRT move operation not supported"); 449 } 450 451 /** 452 * Getter function to access key switch Element. 453 * Throws exception, to be overridden by derived class. 454 * 455 * @return Element. 456 */ 457 GetAinDCRT()458 virtual const DCRTPoly &GetAinDCRT() const { 459 PALISADE_THROW(not_implemented_error, "GetAinDCRT operation not supported"); 460 } 461 462 /** 463 * Setter function to store key switch Element. 464 * Throws exception, to be overridden by derived class. 465 * 466 * @param &b is the Element to be copied. 467 */ 468 SetBinDCRT(const DCRTPoly & b)469 virtual void SetBinDCRT(const DCRTPoly &b) { 470 PALISADE_THROW(not_implemented_error, 471 "SetAinDCRT copy operation not supported"); 472 } 473 474 /** 475 * Setter function to store key switch Element. 476 * Throws exception, to be overridden by derived class. 477 * 478 * @param &&b is the Element to be moved. 479 */ SetBinDCRT(DCRTPoly && b)480 virtual void SetBinDCRT(DCRTPoly &&b) { 481 PALISADE_THROW(not_implemented_error, 482 "SetAinDCRT move operation not supported"); 483 } 484 485 /** 486 * Getter function to access key switch Element. 487 * Throws exception, to be overridden by derived class. 488 * 489 * @return Element. 490 */ 491 GetBinDCRT()492 virtual const DCRTPoly &GetBinDCRT() const { 493 PALISADE_THROW(not_implemented_error, "GetAinDCRT operation not supported"); 494 } 495 ClearKeys()496 virtual void ClearKeys() { 497 PALISADE_THROW(not_implemented_error, 498 "ClearKeys operation is not supported"); 499 } 500 501 friend bool operator==(const LPEvalKeyImpl &a, const LPEvalKeyImpl &b) { 502 return a.key_compare(b); 503 } 504 505 friend bool operator!=(const LPEvalKeyImpl &a, LPEvalKeyImpl &b) { 506 return !(a == b); 507 } 508 key_compare(const LPEvalKeyImpl & other)509 virtual bool key_compare(const LPEvalKeyImpl &other) const { return false; } 510 511 template <class Archive> save(Archive & ar,std::uint32_t const version)512 void save(Archive &ar, std::uint32_t const version) const { 513 ar(::cereal::base_class<LPKey<Element>>(this)); 514 } 515 516 template <class Archive> load(Archive & ar,std::uint32_t const version)517 void load(Archive &ar, std::uint32_t const version) { 518 ar(::cereal::base_class<LPKey<Element>>(this)); 519 } SerializedObjectName()520 std::string SerializedObjectName() const { return "EvalKey"; } 521 }; 522 523 template <typename Element> 524 class LPEvalKeyRelinImpl; 525 526 template <typename Element> 527 using LPEvalKeyRelin = shared_ptr<LPEvalKeyRelinImpl<Element>>; 528 529 /** 530 * @brief Concrete class for Relinearization keys of RLWE scheme 531 * @tparam Element a ring element. 532 */ 533 template <class Element> 534 class LPEvalKeyRelinImpl : public LPEvalKeyImpl<Element> { 535 public: 536 /** 537 * Basic constructor for setting crypto params 538 * 539 * @param &cryptoParams is the reference to cryptoParams 540 */ 541 explicit LPEvalKeyRelinImpl(CryptoContext<Element> cc = 0) 542 : LPEvalKeyImpl<Element>(cc) {} 543 ~LPEvalKeyRelinImpl()544 virtual ~LPEvalKeyRelinImpl() {} 545 546 /** 547 * Copy constructor 548 * 549 *@param &rhs key to copy from 550 */ LPEvalKeyRelinImpl(const LPEvalKeyRelinImpl<Element> & rhs)551 explicit LPEvalKeyRelinImpl(const LPEvalKeyRelinImpl<Element> &rhs) 552 : LPEvalKeyImpl<Element>(rhs.GetCryptoContext()) { 553 m_rKey = rhs.m_rKey; 554 } 555 556 /** 557 * Move constructor 558 * 559 *@param &rhs key to move from 560 */ LPEvalKeyRelinImpl(LPEvalKeyRelinImpl<Element> && rhs)561 explicit LPEvalKeyRelinImpl(LPEvalKeyRelinImpl<Element> &&rhs) 562 : LPEvalKeyImpl<Element>(rhs.GetCryptoContext()) { 563 m_rKey = std::move(rhs.m_rKey); 564 } 565 566 operator bool() const { 567 return static_cast<bool>(this->context) && m_rKey.size() != 0; 568 } 569 570 /** 571 * Assignment Operator. 572 * 573 * @param &rhs key to copy from 574 */ 575 const LPEvalKeyRelinImpl<Element> &operator=( 576 const LPEvalKeyRelinImpl<Element> &rhs) { 577 this->context = rhs.context; 578 this->m_rKey = rhs.m_rKey; 579 return *this; 580 } 581 582 /** 583 * Move Assignment Operator. 584 * 585 * @param &rhs key to move from 586 */ 587 const LPEvalKeyRelinImpl<Element> &operator=( 588 LPEvalKeyRelinImpl<Element> &&rhs) { 589 this->context = rhs.context; 590 rhs.context = 0; 591 m_rKey = std::move(rhs.m_rKey); 592 return *this; 593 } 594 595 /** 596 * Setter function to store Relinearization Element Vector A. 597 * Overrides base class implementation. 598 * 599 * @param &a is the Element vector to be copied. 600 */ SetAVector(const std::vector<Element> & a)601 virtual void SetAVector(const std::vector<Element> &a) { 602 m_rKey.insert(m_rKey.begin() + 0, a); 603 } 604 605 /** 606 * Setter function to store Relinearization Element Vector A. 607 * Overrides base class implementation. 608 * 609 * @param &&a is the Element vector to be moved. 610 */ SetAVector(std::vector<Element> && a)611 virtual void SetAVector(std::vector<Element> &&a) { 612 m_rKey.insert(m_rKey.begin() + 0, std::move(a)); 613 } 614 615 /** 616 * Getter function to access Relinearization Element Vector A. 617 * Overrides base class implementation. 618 * 619 * @return Element vector A. 620 */ GetAVector()621 virtual const std::vector<Element> &GetAVector() const { 622 return m_rKey.at(0); 623 } 624 625 /** 626 * Setter function to store Relinearization Element Vector B. 627 * Overrides base class implementation. 628 * 629 * @param &b is the Element vector to be copied. 630 */ SetBVector(const std::vector<Element> & b)631 virtual void SetBVector(const std::vector<Element> &b) { 632 m_rKey.insert(m_rKey.begin() + 1, b); 633 } 634 635 /** 636 * Setter function to store Relinearization Element Vector B. 637 * Overrides base class implementation. 638 * 639 * @param &&b is the Element vector to be moved. 640 */ SetBVector(std::vector<Element> && b)641 virtual void SetBVector(std::vector<Element> &&b) { 642 m_rKey.insert(m_rKey.begin() + 1, std::move(b)); 643 } 644 645 /** 646 * Getter function to access Relinearization Element Vector B. 647 * Overrides base class implementation. 648 * 649 * @return Element vector B. 650 */ GetBVector()651 virtual const std::vector<Element> &GetBVector() const { 652 return m_rKey.at(1); 653 } 654 655 /** 656 * Setter function to store key switch Element. 657 * Throws exception, to be overridden by derived class. 658 * 659 * @param &a is the Element to be copied. 660 */ 661 SetAinDCRT(const DCRTPoly & a)662 virtual void SetAinDCRT(const DCRTPoly &a) { 663 m_dcrtKeys.insert(m_dcrtKeys.begin() + 0, a); 664 } 665 666 /** 667 * Setter function to store key switch Element. 668 * Throws exception, to be overridden by derived class. 669 * 670 * @param &&a is the Element to be moved. 671 */ SetAinDCRT(DCRTPoly && a)672 virtual void SetAinDCRT(DCRTPoly &&a) { 673 m_dcrtKeys.insert(m_dcrtKeys.begin() + 0, std::move(a)); 674 } 675 676 /** 677 * Getter function to access key switch Element. 678 * Throws exception, to be overridden by derived class. 679 * 680 * @return Element. 681 */ 682 GetAinDCRT()683 virtual const DCRTPoly &GetAinDCRT() const { return m_dcrtKeys.at(0); } 684 685 /** 686 * Setter function to store key switch Element. 687 * Throws exception, to be overridden by derived class. 688 * 689 * @param &b is the Element to be copied. 690 */ 691 SetBinDCRT(const DCRTPoly & b)692 virtual void SetBinDCRT(const DCRTPoly &b) { 693 m_dcrtKeys.insert(m_dcrtKeys.begin() + 1, b); 694 } 695 696 /** 697 * Setter function to store key switch Element. 698 * Throws exception, to be overridden by derived class. 699 * 700 * @param &&b is the Element to be moved. 701 */ SetBinDCRT(DCRTPoly && b)702 virtual void SetBinDCRT(DCRTPoly &&b) { 703 m_dcrtKeys.insert(m_dcrtKeys.begin() + 1, std::move(b)); 704 } 705 706 /** 707 * Getter function to access key switch Element. 708 * Throws exception, to be overridden by derived class. 709 * 710 * @return Element. 711 */ 712 GetBinDCRT()713 virtual const DCRTPoly &GetBinDCRT() const { return m_dcrtKeys.at(1); } 714 ClearKeys()715 virtual void ClearKeys() { 716 m_rKey.clear(); 717 m_dcrtKeys.clear(); 718 } 719 720 key_compare(const LPEvalKeyImpl<Element> & other)721 bool key_compare(const LPEvalKeyImpl<Element> &other) const { 722 const auto &oth = static_cast<const LPEvalKeyRelinImpl<Element> &>(other); 723 724 if (!CryptoObject<Element>::operator==(other)) return false; 725 726 if (this->m_rKey.size() != oth.m_rKey.size()) return false; 727 for (size_t i = 0; i < this->m_rKey.size(); i++) { 728 if (this->m_rKey[i].size() != oth.m_rKey[i].size()) return false; 729 for (size_t j = 0; j < this->m_rKey[i].size(); j++) { 730 if (this->m_rKey[i][j] != oth.m_rKey[i][j]) return false; 731 } 732 } 733 return true; 734 } 735 736 template <class Archive> save(Archive & ar,std::uint32_t const version)737 void save(Archive &ar, std::uint32_t const version) const { 738 ar(::cereal::base_class<LPEvalKeyImpl<Element>>(this)); 739 ar(::cereal::make_nvp("k", m_rKey)); 740 } 741 742 template <class Archive> load(Archive & ar,std::uint32_t const version)743 void load(Archive &ar, std::uint32_t const version) { 744 if (version > SerializedVersion()) { 745 PALISADE_THROW(deserialize_error, 746 "serialized object version " + std::to_string(version) + 747 " is from a later version of the library"); 748 } 749 ar(::cereal::base_class<LPEvalKeyImpl<Element>>(this)); 750 ar(::cereal::make_nvp("k", m_rKey)); 751 } SerializedObjectName()752 std::string SerializedObjectName() const { return "EvalKeyRelin"; } SerializedVersion()753 static uint32_t SerializedVersion() { return 1; } 754 755 private: 756 // private member to store vector of vector of Element. 757 std::vector<std::vector<Element>> m_rKey; 758 759 // Used for GHS key switching 760 std::vector<DCRTPoly> m_dcrtKeys; 761 }; 762 763 template <typename Element> 764 class LPPrivateKeyImpl; 765 766 template <typename Element> 767 using LPPrivateKey = shared_ptr<LPPrivateKeyImpl<Element>>; 768 769 /** 770 * @brief Class fpr LP Private keys 771 * @tparam Element a ring element. 772 */ 773 template <class Element> 774 class LPPrivateKeyImpl : public LPKey<Element> { 775 public: 776 /** 777 * Construct in context 778 */ 779 780 explicit LPPrivateKeyImpl(CryptoContext<Element> cc = 0) 781 : LPKey<Element>(cc, GenerateUniqueKeyID()) {} 782 783 /** 784 * Copy constructor 785 *@param &rhs the LPPrivateKeyImpl to copy from 786 */ LPPrivateKeyImpl(const LPPrivateKeyImpl<Element> & rhs)787 explicit LPPrivateKeyImpl(const LPPrivateKeyImpl<Element> &rhs) 788 : LPKey<Element>(rhs.GetCryptoContext(), rhs.GetKeyTag()) { 789 this->m_sk = rhs.m_sk; 790 } 791 792 /** 793 * Move constructor 794 *@param &rhs the LPPrivateKeyImpl to move from 795 */ LPPrivateKeyImpl(LPPrivateKeyImpl<Element> && rhs)796 explicit LPPrivateKeyImpl(LPPrivateKeyImpl<Element> &&rhs) 797 : LPKey<Element>(rhs.GetCryptoContext(), rhs.GetKeyTag()) { 798 this->m_sk = std::move(rhs.m_sk); 799 } 800 801 operator bool() const { return static_cast<bool>(this->context); } 802 803 /** 804 * Assignment Operator. 805 * 806 * @param &rhs LPPrivateKeyto assign from. 807 * @return the resulting LPPrivateKeyImpl 808 */ 809 const LPPrivateKeyImpl<Element> &operator=( 810 const LPPrivateKeyImpl<Element> &rhs) { 811 CryptoObject<Element>::operator=(rhs); 812 this->m_sk = rhs.m_sk; 813 return *this; 814 } 815 816 /** 817 * Move Assignment Operator. 818 * 819 * @param &rhs LPPrivateKeyImpl to assign from. 820 * @return the resulting LPPrivateKeyImpl 821 */ 822 const LPPrivateKeyImpl<Element> &operator=(LPPrivateKeyImpl<Element> &&rhs) { 823 CryptoObject<Element>::operator=(rhs); 824 this->m_sk = std::move(rhs.m_sk); 825 return *this; 826 } 827 828 /** 829 * Implementation of the Get accessor for private element. 830 * @return the private element. 831 */ GetPrivateElement()832 const Element &GetPrivateElement() const { return m_sk; } 833 834 /** 835 * Set accessor for private element. 836 * @private &x private element to set to. 837 */ SetPrivateElement(const Element & x)838 void SetPrivateElement(const Element &x) { m_sk = x; } 839 840 /** 841 * Set accessor for private element. 842 * @private &x private element to set to. 843 */ SetPrivateElement(Element && x)844 void SetPrivateElement(Element &&x) { m_sk = std::move(x); } 845 846 bool operator==(const LPPrivateKeyImpl &other) const { 847 return CryptoObject<Element>::operator==(other) && m_sk == other.m_sk; 848 } 849 850 bool operator!=(const LPPrivateKeyImpl &other) const { 851 return !(*this == other); 852 } 853 854 template <class Archive> save(Archive & ar,std::uint32_t const version)855 void save(Archive &ar, std::uint32_t const version) const { 856 ar(::cereal::base_class<LPKey<Element>>(this)); 857 ar(::cereal::make_nvp("s", m_sk)); 858 } 859 860 template <class Archive> load(Archive & ar,std::uint32_t const version)861 void load(Archive &ar, std::uint32_t const version) { 862 if (version > SerializedVersion()) { 863 PALISADE_THROW(deserialize_error, 864 "serialized object version " + std::to_string(version) + 865 " is from a later version of the library"); 866 } 867 ar(::cereal::base_class<LPKey<Element>>(this)); 868 ar(::cereal::make_nvp("s", m_sk)); 869 } 870 SerializedObjectName()871 std::string SerializedObjectName() const { return "PrivateKey"; } SerializedVersion()872 static uint32_t SerializedVersion() { return 1; } 873 874 private: 875 Element m_sk; 876 }; 877 878 template <class Element> 879 class LPKeyPair { 880 public: 881 LPPublicKey<Element> publicKey; 882 LPPrivateKey<Element> secretKey; 883 LPKeyPair(LPPublicKey<Element> a,LPPrivateKey<Element> b)884 LPKeyPair(LPPublicKey<Element> a, LPPrivateKey<Element> b) 885 : publicKey(a), secretKey(b) {} 886 887 LPKeyPair(LPPublicKeyImpl<Element> *a = nullptr, 888 LPPrivateKeyImpl<Element> *b = nullptr) publicKey(a)889 : publicKey(a), secretKey(b) {} 890 good()891 bool good() { return publicKey && secretKey; } 892 }; 893 894 /** 895 * @brief Abstract interface for parameter generation algorithm 896 * @tparam Element a ring element. 897 */ 898 template <class Element> 899 class LPParameterGenerationAlgorithm { 900 public: ~LPParameterGenerationAlgorithm()901 virtual ~LPParameterGenerationAlgorithm() {} 902 903 /** 904 * Method for computing all derived parameters based on chosen primitive 905 * parameters 906 * 907 * @param *cryptoParams the crypto parameters object to be populated with 908 * parameters. 909 * @param evalAddCount number of EvalAdds assuming no EvalMult and KeySwitch 910 * operations are performed. 911 * @param evalMultCount number of EvalMults assuming no EvalAdd and 912 * KeySwitch operations are performed. 913 * @param keySwitchCount number of KeySwitch operations assuming no EvalAdd 914 * and EvalMult operations are performed. 915 * @param dcrtBits number of bits in each CRT modulus* 916 * @param n ring dimension in case the user wants to use a custom ring 917 * dimension 918 */ 919 virtual bool ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams, 920 int32_t evalAddCount = 0, int32_t evalMultCount = 0, 921 int32_t keySwitchCount = 0, size_t dcrtBits = 0, 922 uint32_t n = 0) const = 0; 923 924 /** 925 * Method for computing all derived parameters based on chosen primitive 926 * parameters. This is intended for CKKS and DCRTPoly. 927 * 928 * @param *cryptoParams the crypto parameters object to be populated with 929 * parameters. 930 * @param cyclOrder the cyclotomic order. 931 * @param numPrimes number of modulus towers to support. 932 * @param scaleExp the bit-width for plaintexts and DCRTPoly's. 933 * @param relinWindow the relinearization window 934 * @param mode 935 * @param ksTech the key switching technique used (e.g., BV or GHS) 936 * @param firstModSize the bit-size of the first modulus 937 * @param rsTech the rescaling technique used (e.g., APPROXRESCALE or 938 * EXACTRESCALE) 939 */ ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams,usint cyclOrder,usint numPrimes,usint scaleExp,usint relinWindow,MODE mode,KeySwitchTechnique ksTech,usint firstModSize,RescalingTechnique rsTech)940 virtual bool ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams, 941 usint cyclOrder, usint numPrimes, usint scaleExp, 942 usint relinWindow, MODE mode, 943 KeySwitchTechnique ksTech, usint firstModSize, 944 RescalingTechnique rsTech) const { 945 PALISADE_THROW( 946 config_error, 947 "This signature for ParamsGen is not supported for this scheme."); 948 } 949 950 /** 951 * Method for computing all derived parameters based on chosen primitive 952 * parameters. 953 * 954 * @param *cryptoParams the crypto parameters object to be populated with 955 * parameters. 956 * @param cyclOrder the cyclotomic order. 957 * @param numPrimes number of modulus towers to support. 958 * @param scaleExp the bit-width for plaintexts and DCRTPoly's. 959 * @param relinWindow the relinearization window 960 * @param mode 961 * @param ksTech the key switching technique used (e.g., BV or GHS) 962 * @param firstModSize the bit-size of the first modulus 963 * @param rsTech the rescaling technique used (e.g., APPROXRESCALE or 964 * EXACTRESCALE) 965 */ 966 virtual bool ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams, 967 usint cyclOrder, usint numPrimes, usint scaleExp, 968 usint relinWindow, MODE mode, 969 KeySwitchTechnique ksTech = BV, 970 usint firstModSize = 60, 971 RescalingTechnique = APPROXRESCALE, 972 uint32_t numLargeDigits = 4) const { 973 PALISADE_THROW( 974 config_error, 975 "This signature for ParamsGen is not supported for this scheme."); 976 } 977 978 /** 979 * Method for computing all derived parameters based on chosen primitive 980 * parameters. This is intended for BGVrns 981 * @param *cryptoParams the crypto parameters object to be populated with 982 * parameters. 983 * @param cyclOrder the cyclotomic order. 984 * @param numPrimes number of modulus towers to support. 985 * @param relinWindow the relinearization window 986 * @param mode 987 * @param ksTech the key switching technique used (e.g., BV or GHS) 988 * @param firstModSize the bit-size of the first modulus 989 * @param dcrtBits the bit-width of moduli. 990 */ 991 virtual bool ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams, 992 usint cyclOrder, usint ptm, usint numPrimes, 993 usint relinWindow, MODE mode, 994 KeySwitchTechnique ksTech = BV, 995 usint firstModSize = 60, usint dcrtBits = 60, 996 uint32_t numLargeDigits = 4) const { 997 PALISADE_THROW( 998 not_implemented_error, 999 "This signature for ParamsGen is not supported for this scheme."); 1000 } 1001 1002 template <class Archive> save(Archive & ar,std::uint32_t const version)1003 void save(Archive &ar, std::uint32_t const version) const {} 1004 1005 template <class Archive> load(Archive & ar,std::uint32_t const version)1006 void load(Archive &ar, std::uint32_t const version) {} 1007 SerializedObjectName()1008 std::string SerializedObjectName() const { return "ParamsGen"; } 1009 }; 1010 1011 /** 1012 * @brief Abstract interface for encryption algorithm 1013 * @tparam Element a ring element. 1014 */ 1015 template <class Element> 1016 class LPEncryptionAlgorithm { 1017 public: ~LPEncryptionAlgorithm()1018 virtual ~LPEncryptionAlgorithm() {} 1019 1020 /** 1021 * Method for encrypting plaintext using LBC 1022 * 1023 * @param&publicKey public key used for encryption. 1024 * @param plaintext copy of the plaintext element. NOTE a copy is passed! 1025 * That is NOT an error! 1026 * @param doEncryption encrypts if true, embeds (encodes) the plaintext into 1027 * cryptocontext if false 1028 * @param *ciphertext ciphertext which results from encryption. 1029 */ 1030 virtual Ciphertext<Element> Encrypt(const LPPublicKey<Element> publicKey, 1031 Element plaintext) const = 0; 1032 1033 /** 1034 * Method for encrypting plaintex using LBC 1035 * 1036 * @param privateKey private key used for encryption. 1037 * @param plaintext copy of the plaintext input. NOTE a copy is passed! That 1038 * is NOT an error! 1039 * @param doEncryption encrypts if true, embeds (encodes) the plaintext into 1040 * cryptocontext if false 1041 * @param *ciphertext ciphertext which results from encryption. 1042 */ 1043 virtual Ciphertext<Element> Encrypt(const LPPrivateKey<Element> privateKey, 1044 Element plaintext) const = 0; 1045 1046 /** 1047 * Method for decrypting plaintext using LBC 1048 * 1049 * @param &privateKey private key used for decryption. 1050 * @param &ciphertext ciphertext id decrypted. 1051 * @param *plaintext the plaintext output. 1052 * @return the decoding result. 1053 */ 1054 virtual DecryptResult Decrypt(const LPPrivateKey<Element> privateKey, 1055 ConstCiphertext<Element> ciphertext, 1056 NativePoly *plaintext) const = 0; 1057 1058 /** 1059 * Method for decrypting plaintext using LBC 1060 * 1061 * @param &privateKey private key used for decryption. 1062 * @param &ciphertext ciphertext id decrypted. 1063 * @param *plaintext the plaintext output. 1064 * @return the decoding result. 1065 */ Decrypt(const LPPrivateKey<Element> privateKey,ConstCiphertext<Element> ciphertext,Poly * plaintext)1066 virtual DecryptResult Decrypt(const LPPrivateKey<Element> privateKey, 1067 ConstCiphertext<Element> ciphertext, 1068 Poly *plaintext) const { 1069 PALISADE_THROW(config_error, "Decryption to Poly is not supported"); 1070 } 1071 1072 /** 1073 * Function to generate public and private keys 1074 * 1075 * @param &publicKey private key used for decryption. 1076 * @param &privateKey private key used for decryption. 1077 * @return function ran correctly. 1078 */ 1079 virtual LPKeyPair<Element> KeyGen(CryptoContext<Element> cc, 1080 bool makeSparse = false) = 0; 1081 }; 1082 1083 /** 1084 * @brief Abstract interface for Leveled SHE operations 1085 * @tparam Element a ring element. 1086 */ 1087 template <class Element> 1088 class LPLeveledSHEAlgorithm { 1089 public: ~LPLeveledSHEAlgorithm()1090 virtual ~LPLeveledSHEAlgorithm() {} 1091 1092 /** 1093 * Method for In-place Modulus Reduction. 1094 * 1095 * @param &cipherText Ciphertext to perform mod reduce on. 1096 * @param levels the number of towers to drop. 1097 */ 1098 virtual void ModReduceInPlace(Ciphertext<Element> &ciphertext, 1099 size_t levels = 1) const = 0; 1100 1101 /** 1102 * Method for Modulus Reduction. 1103 * 1104 * @param &cipherText Ciphertext to perform mod reduce on. 1105 * @param levels the number of towers to drop. 1106 */ 1107 virtual Ciphertext<Element> ModReduce(ConstCiphertext<Element> ciphertext, 1108 size_t levels = 1) const { 1109 auto rv = ciphertext->Clone(); 1110 ModReduceInPlace(rv, levels); 1111 return rv; 1112 } 1113 1114 /** 1115 * Method for rescaling. 1116 * 1117 * @param cipherText is the ciphertext to perform modreduce on. 1118 * @param levels the number of towers to drop. 1119 * @return ciphertext after the modulus reduction performed. 1120 */ 1121 virtual Ciphertext<Element> ModReduceInternal( 1122 ConstCiphertext<Element> ciphertext, size_t levels = 1) const { 1123 PALISADE_THROW(config_error, 1124 "ModReduceInternal is not supported for this scheme"); 1125 } 1126 1127 /** 1128 * Method for rescaling in-place. 1129 * 1130 * @param cipherText is the ciphertext to perform modreduce on. 1131 * @param levels the number of towers to drop. 1132 * @details \p cipherText will have modulus reduction performed in-place. 1133 */ 1134 virtual void ModReduceInternalInPlace(Ciphertext<Element> &ciphertext, 1135 size_t levels = 1) const { 1136 PALISADE_THROW(config_error, 1137 "ModReduceInternalInPlace is not supported for this scheme"); 1138 } 1139 1140 virtual Ciphertext<Element> Compress(ConstCiphertext<Element> ciphertext, 1141 size_t towersLeft = 1) const { 1142 PALISADE_THROW(config_error, "Compress is not supported for this scheme"); 1143 } 1144 1145 /** 1146 * Method for Composed EvalMult 1147 * 1148 * @param &cipherText1 ciphertext1, first input ciphertext to perform 1149 * multiplication on. 1150 * @param &cipherText2 cipherText2, second input ciphertext to perform 1151 * multiplication on. 1152 * @param &quadKeySwitchHint is for resultant quadratic secret key after 1153 * multiplication to the secret key of the particular level. 1154 * @param &cipherTextResult is the resulting ciphertext that can be 1155 * decrypted with the secret key of the particular level. 1156 */ 1157 virtual Ciphertext<Element> ComposedEvalMult( 1158 ConstCiphertext<Element> cipherText1, 1159 ConstCiphertext<Element> cipherText2, 1160 const LPEvalKey<Element> quadKeySwitchHint) const = 0; 1161 1162 /** 1163 * Method for Level Reduction from sk -> sk1. This method peforms a 1164 * keyswitch on the ciphertext and then performs a modulus reduction. 1165 * 1166 * @param &cipherText1 is the original ciphertext to be key switched and mod 1167 * reduced. 1168 * @param &linearKeySwitchHint is the linear key switch hint to perform the 1169 * key switch operation. 1170 * @param &cipherTextResult is the resulting ciphertext. 1171 */ 1172 virtual Ciphertext<Element> LevelReduce( 1173 ConstCiphertext<Element> cipherText1, 1174 const LPEvalKey<Element> linearKeySwitchHint, size_t levels) const = 0; 1175 1176 /** 1177 * Method for Level Reduction in the CKKS scheme. It just drops "levels" 1178 * number of the towers of the ciphertext without changing the underlying 1179 * plaintext. 1180 * 1181 * @param cipherText1 is the original ciphertext to be level reduced. 1182 * @param linearKeySwitchHint not used in the CKKS scheme. 1183 * @param levels the number of towers to drop. 1184 * @return resulting ciphertext. 1185 */ LevelReduceInternal(ConstCiphertext<Element> cipherText1,const LPEvalKey<Element> linearKeySwitchHint,size_t levels)1186 virtual Ciphertext<Element> LevelReduceInternal( 1187 ConstCiphertext<Element> cipherText1, 1188 const LPEvalKey<Element> linearKeySwitchHint, size_t levels) const { 1189 PALISADE_THROW(config_error, 1190 "LevelReduceInternal is not supported for this scheme"); 1191 } 1192 1193 /** 1194 * Method for in-place Level Reduction in the CKKS scheme. It just drops 1195 * "levels" number of the towers of the ciphertext without changing the 1196 * underlying plaintext. 1197 * 1198 * @param cipherText1 is the ciphertext to be level reduced in-place 1199 * @param linearKeySwitchHint not used in the CKKS scheme. 1200 * @param levels the number of towers to drop. 1201 */ LevelReduceInternalInPlace(Ciphertext<Element> & cipherText1,const LPEvalKey<Element> linearKeySwitchHint,size_t levels)1202 virtual void LevelReduceInternalInPlace( 1203 Ciphertext<Element> &cipherText1, 1204 const LPEvalKey<Element> linearKeySwitchHint, size_t levels) const { 1205 PALISADE_THROW( 1206 config_error, 1207 "LevelReduceInternalInPlace is not supported for this scheme"); 1208 } 1209 1210 /** 1211 * Method for polynomial evaluation for polynomials represented as power 1212 * series. 1213 * 1214 * @param &cipherText input ciphertext 1215 * @param &coefficients is the vector of coefficients in the polynomial; the 1216 * size of the vector is the degree of the polynomial + 1 1217 * @return the result of polynomial evaluation. 1218 */ EvalPoly(ConstCiphertext<Element> cipherText,const std::vector<double> & coefficients)1219 virtual Ciphertext<Element> EvalPoly( 1220 ConstCiphertext<Element> cipherText, 1221 const std::vector<double> &coefficients) const { 1222 PALISADE_THROW(config_error, "EvalPoly is not supported for the scheme."); 1223 } 1224 1225 template <class Archive> save(Archive & ar,std::uint32_t const version)1226 void save(Archive &ar, std::uint32_t const version) const {} 1227 1228 template <class Archive> load(Archive & ar,std::uint32_t const version)1229 void load(Archive &ar, std::uint32_t const version) {} 1230 SerializedObjectName()1231 std::string SerializedObjectName() const { return "LeveledSHE"; } 1232 }; 1233 1234 /** 1235 * @brief Abstract interface class for LBC PRE algorithms 1236 * @tparam Element a ring element. 1237 */ 1238 template <class Element> 1239 class LPPREAlgorithm { 1240 public: ~LPPREAlgorithm()1241 virtual ~LPPREAlgorithm() {} 1242 1243 /** 1244 * Virtual function to generate 1..log(q) encryptions for each bit of the 1245 * original private key Variant that uses the public key for the new secret 1246 * key. 1247 * 1248 * @param &newKey public key for the new secret key. 1249 * @param &origPrivateKey original private key used for decryption. 1250 * @param *evalKey the evaluation key. 1251 * @return the re-encryption key. 1252 */ 1253 virtual LPEvalKey<Element> ReKeyGen( 1254 const LPPublicKey<Element> newKey, 1255 const LPPrivateKey<Element> origPrivateKey) const = 0; 1256 1257 /** 1258 * Virtual function to define the interface for re-encypting ciphertext 1259 * using the array generated by ProxyGen 1260 * 1261 * @param &evalKey proxy re-encryption key. 1262 * @param &ciphertext the input ciphertext. 1263 * @param publicKey the public key of the recipient of the re-encrypted 1264 * ciphertext. 1265 * @param *newCiphertext the new ciphertext. 1266 */ 1267 virtual Ciphertext<Element> ReEncrypt( 1268 const LPEvalKey<Element> evalKey, ConstCiphertext<Element> ciphertext, 1269 const LPPublicKey<Element> publicKey = nullptr) const = 0; 1270 }; 1271 1272 /** 1273 * @brief Abstract interface class for LBC Multiparty algorithms based on 1274 * threshold FHE. A version of this multiparty scheme built on the BGV scheme 1275 * is seen here: 1276 * - Asharov G., Jain A., López-Alt A., Tromer E., Vaikuntanathan V., Wichs 1277 * D. (2012) Multiparty Computation with Low Communication, Computation and 1278 * Interaction via Threshold FHE. In: Pointcheval D., Johansson T. (eds) 1279 * Advances in Cryptology – EUROCRYPT 2012. EUROCRYPT 2012. Lecture Notes in 1280 * Computer Science, vol 7237. Springer, Berlin, Heidelberg 1281 * 1282 * During offline key generation, this multiparty scheme relies on the clients 1283 * coordinating their public key generation. To do this, a single client 1284 * generates a public-secret key pair. This public key is shared with other 1285 * keys which use an element in the public key to generate their own public 1286 * keys. The clients generate a shared key pair using a scheme-specific 1287 * approach, then generate re-encryption keys. Re-encryption keys are 1288 * uploaded to the server. Clients encrypt data with their public keys and 1289 * send the encrypted data server. The data is re-encrypted. Computations are 1290 * then run on the data. The result is sent to each of the clients. One client 1291 * runs a "Leader" multiparty decryption operation with its own secret key. 1292 * All other clients run a regular "Main" multiparty decryption with their own 1293 * secret key. The resulting partially decrypted ciphertext are then fully 1294 * decrypted with the decryption fusion algorithms. 1295 * 1296 * @tparam Element a ring element. 1297 */ 1298 template <class Element> 1299 class LPMultipartyAlgorithm { 1300 public: ~LPMultipartyAlgorithm()1301 virtual ~LPMultipartyAlgorithm() {} 1302 1303 /** 1304 * Threshold FHE: Generation of a public key derived 1305 * from a previous joined public key (for prior secret shares) and the secret 1306 * key share of the current party. 1307 * 1308 * @param cc cryptocontext for the keys to be generated. 1309 * @param pk1 joined public key from prior parties. 1310 * @param makeSparse set to true if ring reduce by a factor of 2 is to be 1311 * used. NOT SUPPORTED BY ANY SCHEME ANYMORE. 1312 * @param fresh set to true if proxy re-encryption is used in the multi-party 1313 * protocol or star topology is used 1314 * @return key pair including the secret share for the current party and 1315 * joined public key 1316 */ 1317 virtual LPKeyPair<Element> MultipartyKeyGen(CryptoContext<Element> cc, 1318 const LPPublicKey<Element> pk1, 1319 bool makeSparse = false, 1320 bool fresh = false) = 0; 1321 1322 /** 1323 * Threshold FHE: Generates a public key from a vector of secret shares. 1324 * ONLY FOR DEBUGGIN PURPOSES. SHOULD NOT BE USED IN PRODUCTION. 1325 * 1326 * @param cc cryptocontext for the keys to be generated. 1327 * @param secretkeys secrete key shares. 1328 * @param makeSparse set to true if ring reduce by a factor of 2 is to be 1329 * used. NOT SUPPORTED BY ANY SCHEME ANYMORE. 1330 * @return key pair including the private for the current party and joined 1331 * public key 1332 */ 1333 virtual LPKeyPair<Element> MultipartyKeyGen( 1334 CryptoContext<Element> cc, 1335 const vector<LPPrivateKey<Element>> &secretKeys, 1336 bool makeSparse = false) = 0; 1337 1338 /** 1339 * Threshold FHE: "Partial" decryption computed by all parties except for the 1340 * lead one 1341 * 1342 * @param privateKey secret key share used for decryption. 1343 * @param ciphertext ciphertext that is being decrypted. 1344 */ 1345 virtual Ciphertext<Element> MultipartyDecryptMain( 1346 const LPPrivateKey<Element> privateKey, 1347 ConstCiphertext<Element> ciphertext) const = 0; 1348 1349 /** 1350 * Threshold FHE: Method for decryption operation run by the lead decryption 1351 * client 1352 * 1353 * @param privateKey secret key share used for decryption. 1354 * @param ciphertext ciphertext id decrypted. 1355 */ 1356 virtual Ciphertext<Element> MultipartyDecryptLead( 1357 const LPPrivateKey<Element> privateKey, 1358 ConstCiphertext<Element> ciphertext) const = 0; 1359 1360 /** 1361 * Threshold FHE: Method for combining the partially decrypted ciphertexts 1362 * and getting the final decryption in the clear as a NativePoly. 1363 * 1364 * @param &ciphertextVec vector of "partial" decryptions. 1365 * @param *plaintext the plaintext output as a NativePoly. 1366 * @return the decoding result. 1367 */ 1368 virtual DecryptResult MultipartyDecryptFusion( 1369 const vector<Ciphertext<Element>> &ciphertextVec, 1370 NativePoly *plaintext) const = 0; 1371 1372 /** 1373 * Threshold FHE: Method for combining the partially decrypted ciphertexts 1374 * and getting the final decryption in the clear as a Poly. 1375 * 1376 * @param &ciphertextVec vector of "partial" decryptions. 1377 * @param *plaintext the plaintext output as a Poly. 1378 * @return the decoding result. 1379 */ MultipartyDecryptFusion(const vector<Ciphertext<Element>> & ciphertextVec,Poly * plaintext)1380 virtual DecryptResult MultipartyDecryptFusion( 1381 const vector<Ciphertext<Element>> &ciphertextVec, Poly *plaintext) const { 1382 PALISADE_THROW(config_error, "Decryption to Poly is not supported"); 1383 } 1384 1385 /** 1386 * Threshold FHE: Generates a joined evaluation key 1387 * from the current secret share and a prior joined 1388 * evaluation key 1389 * 1390 * @param originalPrivateKey secret key transformed from. 1391 * @param newPrivateKey secret key transformed to. 1392 * @param ek the prior joined evaluation key. 1393 * @return the new joined evaluation key. 1394 */ MultiKeySwitchGen(const LPPrivateKey<Element> originalPrivateKey,const LPPrivateKey<Element> newPrivateKey,const LPEvalKey<Element> ek)1395 virtual LPEvalKey<Element> MultiKeySwitchGen( 1396 const LPPrivateKey<Element> originalPrivateKey, 1397 const LPPrivateKey<Element> newPrivateKey, 1398 const LPEvalKey<Element> ek) const { 1399 PALISADE_THROW(not_implemented_error, 1400 "MultiKeySwitchGen multi-party capability is not supported " 1401 "for this scheme"); 1402 } 1403 1404 /** 1405 * Threshold FHE: Generates joined automorphism keys 1406 * from the current secret share and prior joined 1407 * automorphism keys 1408 * 1409 * @param privateKey secret key share. 1410 * @param eAuto a dictionary with prior joined automorphism keys. 1411 * @param &indexList a vector of automorphism indices. 1412 * @return a dictionary with new joined automorphism keys. 1413 */ 1414 virtual std::shared_ptr<std::map<usint, LPEvalKey<Element>>> MultiEvalAutomorphismKeyGen(const LPPrivateKey<Element> privateKey,const shared_ptr<std::map<usint,LPEvalKey<Element>>> eAuto,const std::vector<usint> & indexList)1415 MultiEvalAutomorphismKeyGen( 1416 const LPPrivateKey<Element> privateKey, 1417 const shared_ptr<std::map<usint, LPEvalKey<Element>>> eAuto, 1418 const std::vector<usint> &indexList) const { 1419 PALISADE_THROW(not_implemented_error, 1420 "MultiEvalAutomorphismKeyGen multi-party capability is not " 1421 "supported for this scheme"); 1422 } 1423 1424 /** 1425 * Threshold FHE: Generates joined summation evaluation keys 1426 * from the current secret share and prior joined 1427 * summation keys 1428 * 1429 * @param privateKey secret key share. 1430 * @param eSum a dictionary with prior joined summation keys. 1431 * @return new joined summation keys. 1432 */ MultiEvalSumKeyGen(const LPPrivateKey<Element> privateKey,const shared_ptr<std::map<usint,LPEvalKey<Element>>> eSum)1433 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> MultiEvalSumKeyGen( 1434 const LPPrivateKey<Element> privateKey, 1435 const shared_ptr<std::map<usint, LPEvalKey<Element>>> eSum) const { 1436 PALISADE_THROW(not_implemented_error, 1437 "MultiEvalSumKeyGen multi-party capability is not supported " 1438 "for this scheme"); 1439 } 1440 1441 /** 1442 * Threshold FHE: Adds two prior public keys 1443 * 1444 * @param evalKey1 first public key. 1445 * @param evalKey2 second public key. 1446 * @return the new joined key. 1447 */ MultiAddPubKeys(LPPublicKey<Element> pubKey1,LPPublicKey<Element> pubKey2)1448 virtual LPPublicKey<Element> MultiAddPubKeys( 1449 LPPublicKey<Element> pubKey1, LPPublicKey<Element> pubKey2) const { 1450 if (!pubKey1) 1451 PALISADE_THROW(config_error, "Input first public key is nullptr"); 1452 if (!pubKey2) 1453 PALISADE_THROW(config_error, "Input second public key is nullptr"); 1454 1455 LPPublicKey<Element> pubKey( 1456 new LPPublicKeyImpl<Element>(pubKey1->GetCryptoContext())); 1457 1458 if (pubKey1->GetPublicElements()[1] != pubKey2->GetPublicElements()[1]) 1459 PALISADE_THROW(type_error, 1460 "MultiAddPubKeys: public keys are not compatible"); 1461 1462 const Element &a = pubKey1->GetPublicElements()[1]; 1463 1464 const Element &b1 = pubKey1->GetPublicElements()[0]; 1465 const Element &b2 = pubKey2->GetPublicElements()[0]; 1466 1467 pubKey->SetPublicElementAtIndex(0, std::move(b1 + b2)); 1468 pubKey->SetPublicElementAtIndex(1, a); 1469 1470 return pubKey; 1471 } 1472 1473 /** 1474 * Threshold FHE: Adds two prior evaluation keys 1475 * 1476 * @param evalKey1 first evaluation key. 1477 * @param evalKey2 second evaluation key. 1478 * @return the new joined key. 1479 */ MultiAddEvalKeys(LPEvalKey<Element> evalKey1,LPEvalKey<Element> evalKey2)1480 virtual LPEvalKey<Element> MultiAddEvalKeys( 1481 LPEvalKey<Element> evalKey1, LPEvalKey<Element> evalKey2) const { 1482 if (!evalKey1) 1483 PALISADE_THROW(config_error, "Input first evaluation key is nullptr"); 1484 if (!evalKey2) 1485 PALISADE_THROW(config_error, "Input second evaluation key is nullptr"); 1486 1487 LPEvalKey<Element> evalKeySum( 1488 new LPEvalKeyRelinImpl<Element>(evalKey1->GetCryptoContext())); 1489 1490 const std::vector<Element> &a = evalKey1->GetAVector(); 1491 1492 const std::vector<Element> &b1 = evalKey1->GetBVector(); 1493 const std::vector<Element> &b2 = evalKey2->GetBVector(); 1494 1495 std::vector<Element> b; 1496 1497 for (usint i = 0; i < a.size(); i++) { 1498 b.push_back(b1[i] + b2[i]); 1499 } 1500 1501 evalKeySum->SetAVector(a); 1502 evalKeySum->SetBVector(std::move(b)); 1503 1504 return evalKeySum; 1505 } 1506 1507 /** 1508 * Threshold FHE: Generates a partial evaluation key for homomorphic 1509 * multiplication based on the current secret share and an existing partial 1510 * evaluation key 1511 * 1512 * @param evalKey prior evaluation key. 1513 * @param sk current secret share. 1514 * @return the new joined key. 1515 */ MultiMultEvalKey(LPEvalKey<Element> evalKey,LPPrivateKey<Element> sk)1516 virtual LPEvalKey<Element> MultiMultEvalKey(LPEvalKey<Element> evalKey, 1517 LPPrivateKey<Element> sk) const { 1518 PALISADE_THROW(not_implemented_error, 1519 "MultiMultEvalKey multi-party capability is not supported " 1520 "for this scheme"); 1521 } 1522 1523 /** 1524 * Threshold FHE: Adds two prior evaluation key sets for summation 1525 * 1526 * @param es1 first summation key set. 1527 * @param es2 second summation key set. 1528 * @return the new joined key set for summation. 1529 */ MultiAddEvalSumKeys(const shared_ptr<std::map<usint,LPEvalKey<Element>>> es1,const shared_ptr<std::map<usint,LPEvalKey<Element>>> es2)1530 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> MultiAddEvalSumKeys( 1531 const shared_ptr<std::map<usint, LPEvalKey<Element>>> es1, 1532 const shared_ptr<std::map<usint, LPEvalKey<Element>>> es2) const { 1533 if (!es1) 1534 PALISADE_THROW(config_error, "Input first evaluation key map is nullptr"); 1535 if (!es2) 1536 PALISADE_THROW(config_error, 1537 "Input second evaluation key map is nullptr"); 1538 1539 auto evalSumKeys = std::make_shared<std::map<usint, LPEvalKey<Element>>>(); 1540 1541 for (auto it = es1->begin(); it != es1->end(); ++it) { 1542 auto it2 = es2->find(it->first); 1543 if (it2 != es2->end()) 1544 (*evalSumKeys)[it->first] = MultiAddEvalKeys(it->second, it2->second); 1545 } 1546 1547 return evalSumKeys; 1548 } 1549 1550 /** 1551 * Threshold FHE: Adds two prior evaluation key sets for automorphisms 1552 * 1553 * @param es1 first automorphism key set. 1554 * @param es2 second automorphism key set. 1555 * @return the new joined key set for summation. 1556 */ 1557 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> MultiAddEvalAutomorphismKeys(const shared_ptr<std::map<usint,LPEvalKey<Element>>> es1,const shared_ptr<std::map<usint,LPEvalKey<Element>>> es2)1558 MultiAddEvalAutomorphismKeys( 1559 const shared_ptr<std::map<usint, LPEvalKey<Element>>> es1, 1560 const shared_ptr<std::map<usint, LPEvalKey<Element>>> es2) const { 1561 if (!es1) 1562 PALISADE_THROW(config_error, "Input first evaluation key map is nullptr"); 1563 if (!es2) 1564 PALISADE_THROW(config_error, 1565 "Input second evaluation key map is nullptr"); 1566 1567 auto evalAutomorphismKeys = 1568 std::make_shared<std::map<usint, LPEvalKey<Element>>>(); 1569 1570 for (auto it = es1->begin(); it != es1->end(); ++it) { 1571 auto it2 = es2->find(it->first); 1572 if (it2 != es2->end()) 1573 (*evalAutomorphismKeys)[it->first] = 1574 MultiAddEvalKeys(it->second, it2->second); 1575 } 1576 1577 return evalAutomorphismKeys; 1578 } 1579 1580 /** 1581 * Threshold FHE: Adds two partial evaluation keys for multiplication 1582 * 1583 * @param evalKey1 first evaluation key. 1584 * @param evalKey2 second evaluation key. 1585 * @return the new joined key. 1586 */ MultiAddEvalMultKeys(LPEvalKey<Element> evalKey1,LPEvalKey<Element> evalKey2)1587 virtual LPEvalKey<Element> MultiAddEvalMultKeys( 1588 LPEvalKey<Element> evalKey1, LPEvalKey<Element> evalKey2) const { 1589 if (!evalKey1) 1590 PALISADE_THROW(config_error, "Input first evaluation key is nullptr"); 1591 if (!evalKey2) 1592 PALISADE_THROW(config_error, "Input second evaluation key is nullptr"); 1593 1594 LPEvalKey<Element> evalKeySum( 1595 new LPEvalKeyRelinImpl<Element>(evalKey1->GetCryptoContext())); 1596 1597 const std::vector<Element> &a1 = evalKey1->GetAVector(); 1598 const std::vector<Element> &a2 = evalKey2->GetAVector(); 1599 1600 const std::vector<Element> &b1 = evalKey1->GetBVector(); 1601 const std::vector<Element> &b2 = evalKey2->GetBVector(); 1602 1603 std::vector<Element> a; 1604 std::vector<Element> b; 1605 1606 for (usint i = 0; i < a1.size(); i++) { 1607 a.push_back(a1[i] + a2[i]); 1608 b.push_back(b1[i] + b2[i]); 1609 } 1610 1611 evalKeySum->SetAVector(std::move(a)); 1612 1613 evalKeySum->SetBVector(std::move(b)); 1614 1615 return evalKeySum; 1616 } 1617 1618 /** 1619 * Threshold FHE: Generates evaluation keys for a list of indices for a 1620 * multi-party setting Currently works only for power-of-two and cyclic-group 1621 * cyclotomics 1622 * 1623 * @param secretShare secret share 1624 * @param partial evaluation key set from other party (parties) 1625 * @param indexList list of indices to be computed 1626 * @return returns the joined evaluation keys 1627 */ 1628 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> MultiEvalAtIndexKeyGen(const LPPrivateKey<Element> secretShare,const shared_ptr<std::map<usint,LPEvalKey<Element>>> eAuto,const std::vector<int32_t> & indexList)1629 MultiEvalAtIndexKeyGen( 1630 const LPPrivateKey<Element> secretShare, 1631 const shared_ptr<std::map<usint, LPEvalKey<Element>>> eAuto, 1632 const std::vector<int32_t> &indexList) const { 1633 if (!secretShare) 1634 PALISADE_THROW(config_error, "Input private key is nullptr"); 1635 if (!eAuto) 1636 PALISADE_THROW(config_error, "Input evaluation key map is nullptr"); 1637 if (!indexList.size()) 1638 PALISADE_THROW(config_error, "Input index vector is empty"); 1639 const auto cryptoParams = secretShare->GetCryptoParameters(); 1640 const auto encodingParams = cryptoParams->GetEncodingParams(); 1641 const auto elementParams = cryptoParams->GetElementParams(); 1642 uint32_t m = elementParams->GetCyclotomicOrder(); 1643 1644 std::vector<uint32_t> autoIndices(indexList.size()); 1645 1646 if (IsPowerOfTwo(m)) { // power-of-two cyclotomics 1647 for (size_t i = 0; i < indexList.size(); i++) { 1648 auto ccInst = secretShare->GetCryptoContext(); 1649 // CKKS Packing 1650 if (ccInst->getSchemeId() == "CKKS") 1651 autoIndices[i] = FindAutomorphismIndex2nComplex(indexList[i], m); 1652 else 1653 autoIndices[i] = FindAutomorphismIndex2n(indexList[i], m); 1654 } 1655 1656 } else { // cyclic groups 1657 for (size_t i = 0; i < indexList.size(); i++) 1658 autoIndices[i] = FindAutomorphismIndexCyclic( 1659 indexList[i], m, encodingParams->GetPlaintextGenerator()); 1660 } 1661 1662 return MultiEvalAutomorphismKeyGen(secretShare, eAuto, autoIndices); 1663 } 1664 1665 template <class Archive> save(Archive & ar,std::uint32_t const version)1666 void save(Archive &ar, std::uint32_t const version) const {} 1667 1668 template <class Archive> load(Archive & ar,std::uint32_t const version)1669 void load(Archive &ar, std::uint32_t const version) {} 1670 SerializedObjectName()1671 std::string SerializedObjectName() const { return "MultiParty"; } 1672 }; 1673 1674 /** 1675 * @brief Abstract interface class for LBC SHE algorithms 1676 * @tparam Element a ring element. 1677 */ 1678 template <class Element> 1679 class LPSHEAlgorithm { 1680 public: ~LPSHEAlgorithm()1681 virtual ~LPSHEAlgorithm() {} 1682 1683 /** 1684 * Virtual function to define the interface for homomorphic addition of 1685 * ciphertexts. 1686 * 1687 * @param ciphertext1 the input ciphertext. 1688 * @param ciphertext2 the input ciphertext. 1689 * @return the new ciphertext. 1690 */ EvalAdd(ConstCiphertext<Element> ciphertext1,ConstCiphertext<Element> ciphertext2)1691 virtual Ciphertext<Element> EvalAdd( 1692 ConstCiphertext<Element> ciphertext1, 1693 ConstCiphertext<Element> ciphertext2) const { 1694 auto rv = ciphertext1->Clone(); 1695 EvalAddInPlace(rv, ciphertext2); 1696 return rv; 1697 } 1698 1699 /** 1700 * Virtual function to define the interface for in-place homomorphic addition 1701 * of ciphertexts. 1702 * 1703 * @param ciphertext1 the input/output ciphertext. 1704 * @param ciphertext2 the input ciphertext. 1705 */ 1706 virtual void EvalAddInPlace(Ciphertext<Element> &ciphertext1, 1707 ConstCiphertext<Element> ciphertext2) const = 0; 1708 1709 /** 1710 * Virtual function to define the interface for homomorphic addition of 1711 * ciphertexts. This is the mutable version - input ciphertexts may change 1712 * (automatically rescaled, or towers dropped). 1713 * 1714 * @param ciphertext1 the input ciphertext. 1715 * @param ciphertext2 the input ciphertext. 1716 * @return the new ciphertext. 1717 */ EvalAddMutable(Ciphertext<Element> & ciphertext1,Ciphertext<Element> & ciphertext2)1718 virtual Ciphertext<Element> EvalAddMutable( 1719 Ciphertext<Element> &ciphertext1, 1720 Ciphertext<Element> &ciphertext2) const { 1721 PALISADE_THROW(not_implemented_error, 1722 "EvalAddMutable is not implemented for this scheme"); 1723 } 1724 1725 /** 1726 * Virtual function to define the interface for homomorphic addition of 1727 * ciphertexts. 1728 * 1729 * @param ciphertext the input ciphertext. 1730 * @param plaintext the input plaintext. 1731 * @return the new ciphertext. 1732 */ 1733 virtual Ciphertext<Element> EvalAdd(ConstCiphertext<Element> ciphertext, 1734 ConstPlaintext plaintext) const = 0; 1735 1736 /** 1737 * Virtual function to define the interface for homomorphic addition of 1738 * ciphertexts. This is the mutable version - input ciphertext may change 1739 * (automatically rescaled, or towers dropped). 1740 * 1741 * @param ciphertext the input ciphertext. 1742 * @param plaintext the input plaintext. 1743 * @return the new ciphertext. 1744 */ EvalAddMutable(Ciphertext<Element> & ciphertext,Plaintext plaintext)1745 virtual Ciphertext<Element> EvalAddMutable(Ciphertext<Element> &ciphertext, 1746 Plaintext plaintext) const { 1747 PALISADE_THROW(not_implemented_error, 1748 "EvalAddMutable is not implemented for this scheme"); 1749 } 1750 1751 /** 1752 * Virtual function to define the adding of a scalar to a ciphertext 1753 * 1754 * @param ciphertext the input ciphertext. 1755 * @param constant the input constant. 1756 * @return the new ciphertext. 1757 */ EvalAdd(ConstCiphertext<Element> ciphertext,double constant)1758 virtual Ciphertext<Element> EvalAdd(ConstCiphertext<Element> ciphertext, 1759 double constant) const { 1760 PALISADE_THROW(not_implemented_error, 1761 "Scalar addition is not implemented for this scheme"); 1762 } 1763 1764 /** 1765 * Virtual function for computing the linear weighted sum of a 1766 * vector of ciphertexts. 1767 * 1768 * @param ciphertexts vector of input ciphertexts. 1769 * @param constants vector containing double weights. 1770 * @return A ciphertext containing the linear weighted sum. 1771 */ EvalLinearWSum(vector<Ciphertext<Element>> ciphertexts,vector<double> constants)1772 virtual Ciphertext<Element> EvalLinearWSum( 1773 vector<Ciphertext<Element>> ciphertexts, vector<double> constants) const { 1774 std::string errMsg = "EvalLinearWSum is not implemented for this scheme."; 1775 PALISADE_THROW(not_implemented_error, errMsg); 1776 } 1777 1778 /** 1779 * Function for computing the linear weighted sum of a 1780 * vector of ciphertexts. This is a mutable method, 1781 * meaning that the level/depth of input ciphertexts may change. 1782 * 1783 * @param ciphertexts vector of input ciphertexts. 1784 * @param constants vector containing double weights. 1785 * @return A ciphertext containing the linear weighted sum. 1786 */ EvalLinearWSumMutable(vector<Ciphertext<Element>> ciphertexts,vector<double> constants)1787 virtual Ciphertext<Element> EvalLinearWSumMutable( 1788 vector<Ciphertext<Element>> ciphertexts, vector<double> constants) const { 1789 std::string errMsg = 1790 "EvalLinearWSumMutable is not implemented for this scheme."; 1791 PALISADE_THROW(not_implemented_error, errMsg); 1792 } 1793 1794 /** 1795 * Virtual function to define the interface for homomorphic subtraction of 1796 * ciphertexts. 1797 * 1798 * @param ciphertext1 the input ciphertext. 1799 * @param ciphertext2 the input ciphertext. 1800 * @return the new ciphertext. 1801 */ 1802 virtual Ciphertext<Element> EvalSub( 1803 ConstCiphertext<Element> ciphertext1, 1804 ConstCiphertext<Element> ciphertext2) const = 0; 1805 1806 /** 1807 * Virtual function to define the interface for homomorphic subtraction of 1808 * ciphertexts. This is the mutable version - input ciphertext may change 1809 * (automatically rescaled, or towers dropped). 1810 * 1811 * @param ciphertext1 the input ciphertext. 1812 * @param ciphertext2 the input ciphertext. 1813 * @return the new ciphertext. 1814 */ EvalSubMutable(Ciphertext<Element> & ciphertext1,Ciphertext<Element> & ciphertext2)1815 virtual Ciphertext<Element> EvalSubMutable( 1816 Ciphertext<Element> &ciphertext1, 1817 Ciphertext<Element> &ciphertext2) const { 1818 PALISADE_THROW(not_implemented_error, 1819 "EvalSubMutable is not implemented for this scheme"); 1820 } 1821 1822 /** 1823 * Virtual function to define the interface for homomorphic subtraction of 1824 * ciphertexts. 1825 * 1826 * @param ciphertext the input ciphertext. 1827 * @param plaintext the input plaintext. 1828 * @return the new ciphertext. 1829 */ 1830 virtual Ciphertext<Element> EvalSub(ConstCiphertext<Element> ciphertext, 1831 ConstPlaintext plaintext) const = 0; 1832 1833 /** 1834 * Virtual function to define the interface for homomorphic subtraction of 1835 * ciphertexts. This is the mutable version - input ciphertext may change 1836 * (automatically rescaled, or towers dropped). 1837 * 1838 * @param ciphertext the input ciphertext. 1839 * @param plaintext the input plaintext. 1840 * @return the new ciphertext. 1841 */ EvalSubMutable(Ciphertext<Element> & ciphertext,Plaintext plaintext)1842 virtual Ciphertext<Element> EvalSubMutable(Ciphertext<Element> &ciphertext, 1843 Plaintext plaintext) const { 1844 PALISADE_THROW(not_implemented_error, 1845 "EvalSubMutable is not implemented for this scheme"); 1846 } 1847 1848 /** 1849 * Virtual function to define the subtraction of a scalar from a ciphertext 1850 * 1851 * @param ciphertext the input ciphertext. 1852 * @param constant the input constant. 1853 * @return the new ciphertext. 1854 */ EvalSub(ConstCiphertext<Element> ciphertext,double constant)1855 virtual Ciphertext<Element> EvalSub(ConstCiphertext<Element> ciphertext, 1856 double constant) const { 1857 PALISADE_THROW(not_implemented_error, 1858 "Scalar subtraction is not implemented for this scheme"); 1859 } 1860 1861 /** 1862 * Virtual function to define the interface for multiplicative homomorphic 1863 * evaluation of ciphertext. 1864 * 1865 * @param ciphertext1 the input ciphertext. 1866 * @param ciphertext2 the input ciphertext. 1867 * @return the new ciphertext. 1868 */ 1869 virtual Ciphertext<Element> EvalMult( 1870 ConstCiphertext<Element> ciphertext1, 1871 ConstCiphertext<Element> ciphertext2) const = 0; 1872 1873 /** 1874 * Virtual function to define the interface for multiplicative homomorphic 1875 * evaluation of ciphertext. This is the mutable version - input ciphertexts 1876 * may change (automatically rescaled, or towers dropped). 1877 * 1878 * @param ciphertext1 the input ciphertext. 1879 * @param ciphertext2 the input ciphertext. 1880 * @return the new ciphertext. 1881 */ EvalMultMutable(Ciphertext<Element> & ciphertext1,Ciphertext<Element> & ciphertext2)1882 virtual Ciphertext<Element> EvalMultMutable( 1883 Ciphertext<Element> &ciphertext1, 1884 Ciphertext<Element> &ciphertext2) const { 1885 PALISADE_THROW(not_implemented_error, 1886 "EvalMultMutable is not implemented for this scheme"); 1887 } 1888 1889 /** 1890 * Virtual function to define the interface for multiplication of ciphertext 1891 * by plaintext. 1892 * 1893 * @param ciphertext the input ciphertext. 1894 * @param plaintext the input plaintext. 1895 * @return the new ciphertext. 1896 */ 1897 virtual Ciphertext<Element> EvalMult(ConstCiphertext<Element> ciphertext, 1898 ConstPlaintext plaintext) const = 0; 1899 1900 /** 1901 * Virtual function to define the interface for multiplication of ciphertext 1902 * by plaintext. This is the mutable version - input ciphertext may change 1903 * (automatically rescaled, or towers dropped). 1904 * 1905 * @param ciphertext the input ciphertext. 1906 * @param plaintext the input plaintext. 1907 * @return the new ciphertext. 1908 */ EvalMultMutable(Ciphertext<Element> & ciphertext,Plaintext plaintext)1909 virtual Ciphertext<Element> EvalMultMutable(Ciphertext<Element> &ciphertext, 1910 Plaintext plaintext) const { 1911 PALISADE_THROW(not_implemented_error, 1912 "EvalMultMutable is not implemented for this scheme"); 1913 } 1914 1915 /** 1916 * Virtual function to define the multiplication of a ciphertext by a 1917 * constant 1918 * 1919 * @param ciphertext the input ciphertext. 1920 * @param constant the input constant. 1921 * @return the new ciphertext. 1922 */ EvalMult(ConstCiphertext<Element> ciphertext,double constant)1923 virtual Ciphertext<Element> EvalMult(ConstCiphertext<Element> ciphertext, 1924 double constant) const { 1925 PALISADE_THROW(not_implemented_error, 1926 "Scalar multiplication is not implemented for this scheme"); 1927 } 1928 1929 /** 1930 * Virtual function to define the multiplication of a ciphertext by a 1931 * constant. This is the mutable version - input ciphertext may change 1932 * (automatically rescaled, or towers dropped). 1933 * 1934 * @param ciphertext the input ciphertext. 1935 * @param constant the input constant. 1936 * @return the new ciphertext. 1937 */ EvalMultMutable(Ciphertext<Element> & ciphertext,double constant)1938 virtual Ciphertext<Element> EvalMultMutable(Ciphertext<Element> &ciphertext, 1939 double constant) const { 1940 PALISADE_THROW(not_implemented_error, 1941 "EvalMultMutable is not implemented for this scheme"); 1942 } 1943 1944 /** 1945 * Virtual function to define the interface for multiplicative homomorphic 1946 * evaluation of ciphertext using the evaluation key. 1947 * 1948 * @param &ciphertext1 first input ciphertext. 1949 * @param &ciphertext2 second input ciphertext. 1950 * @param &ek is the evaluation key to make the newCiphertext decryptable by 1951 * the same secret key as that of ciphertext1 and ciphertext2. 1952 * @return the new ciphertext. 1953 */ 1954 virtual Ciphertext<Element> EvalMult(ConstCiphertext<Element> ciphertext1, 1955 ConstCiphertext<Element> ciphertext2, 1956 const LPEvalKey<Element> ek) const = 0; 1957 1958 /** 1959 * Virtual function to define the interface for multiplicative homomorphic 1960 * evaluation of ciphertext using the evaluation key. This is the mutable 1961 * version - input ciphertext may change (automatically rescaled, or towers 1962 * dropped). 1963 * 1964 * @param &ciphertext1 first input ciphertext. 1965 * @param &ciphertext2 second input ciphertext. 1966 * @param &ek is the evaluation key to make the newCiphertext decryptable by 1967 * the same secret key as that of ciphertext1 and ciphertext2. 1968 * @return the new ciphertext. 1969 */ EvalMultMutable(Ciphertext<Element> & ciphertext1,Ciphertext<Element> & ciphertext2,const LPEvalKey<Element> ek)1970 virtual Ciphertext<Element> EvalMultMutable( 1971 Ciphertext<Element> &ciphertext1, Ciphertext<Element> &ciphertext2, 1972 const LPEvalKey<Element> ek) const { 1973 PALISADE_THROW(not_implemented_error, 1974 "EvalMultMutable is not implemented for this scheme"); 1975 } 1976 1977 /** 1978 * Virtual function for evaluating multiplication of a ciphertext list which 1979 * each multiplication is followed by relinearization operation. 1980 * 1981 * @param cipherTextList is the ciphertext list. 1982 * @param evalKeys is the evaluation key to make the newCiphertext 1983 * decryptable by the same secret key as that of ciphertext list. 1984 * @param *newCiphertext the new resulting ciphertext. 1985 */ EvalMultMany(const vector<Ciphertext<Element>> & cipherTextList,const vector<LPEvalKey<Element>> & evalKeys)1986 virtual Ciphertext<Element> EvalMultMany( 1987 const vector<Ciphertext<Element>> &cipherTextList, 1988 const vector<LPEvalKey<Element>> &evalKeys) const { 1989 // default implementation if you don't have one in your scheme 1990 // TODO: seems that we can simply call EvalAddMany() here. 1991 // TODO: see EvalAddMany() below 1992 if (cipherTextList.size() < 1) 1993 PALISADE_THROW(config_error, 1994 "Input ciphertext vector size should be 1 or more"); 1995 1996 const size_t inSize = cipherTextList.size(); 1997 const size_t lim = inSize * 2 - 2; 1998 vector<Ciphertext<Element>> cipherTextResults; 1999 cipherTextResults.resize(inSize - 1); 2000 size_t ctrIndex = 0; 2001 2002 for (size_t i = 0; i < lim; i = i + 2) { 2003 cipherTextResults[ctrIndex++] = this->EvalMult( 2004 i < inSize ? cipherTextList[i] : cipherTextResults[i - inSize], 2005 i + 1 < inSize ? cipherTextList[i + 1] 2006 : cipherTextResults[i + 1 - inSize]); 2007 } 2008 2009 return cipherTextResults.back(); 2010 } 2011 2012 /** 2013 * Virtual function for evaluating addition of a list of ciphertexts. 2014 * 2015 * @param ctList is the ciphertext list. 2016 * @param *newCiphertext the new resulting ciphertext. 2017 */ EvalAddMany(const vector<Ciphertext<Element>> & ctList)2018 virtual Ciphertext<Element> EvalAddMany( 2019 const vector<Ciphertext<Element>> &ctList) const { 2020 // default implementation if you don't have one in your scheme 2021 if (ctList.size() < 1) 2022 PALISADE_THROW(config_error, 2023 "Input ciphertext vector size should be 1 or more"); 2024 2025 const size_t inSize = ctList.size(); 2026 const size_t lim = inSize * 2 - 2; 2027 vector<Ciphertext<Element>> cipherTextResults; 2028 cipherTextResults.resize(inSize - 1); 2029 size_t ctrIndex = 0; 2030 2031 for (size_t i = 0; i < lim; i = i + 2) { 2032 cipherTextResults[ctrIndex++] = this->EvalAdd( 2033 i < inSize ? ctList[i] : cipherTextResults[i - inSize], 2034 i + 1 < inSize ? ctList[i + 1] : cipherTextResults[i + 1 - inSize]); 2035 } 2036 2037 return cipherTextResults.back(); 2038 } 2039 2040 /** 2041 * Virtual function for evaluating addition of a list of ciphertexts. 2042 * This version uses no additional space, other than the vector provided. 2043 * 2044 * @param ctList is the ciphertext list. 2045 * @param *newCiphertext the new resulting ciphertext. 2046 */ EvalAddManyInPlace(vector<Ciphertext<Element>> & ctList)2047 virtual Ciphertext<Element> EvalAddManyInPlace( 2048 vector<Ciphertext<Element>> &ctList) const { 2049 // default implementation if you don't have one in your scheme 2050 if (ctList.size() < 1) 2051 PALISADE_THROW(config_error, 2052 "Input ciphertext vector size should be 1 or more"); 2053 2054 for (size_t j = 1; j < ctList.size(); j = j * 2) { 2055 for (size_t i = 0; i < ctList.size(); i = i + 2 * j) { 2056 if ((i + j) < ctList.size()) { 2057 if (ctList[i] != nullptr && ctList[i + j] != nullptr) { 2058 ctList[i] = EvalAdd(ctList[i], ctList[i + j]); 2059 } else if (ctList[i] == nullptr && ctList[i + j] != nullptr) { 2060 ctList[i] = ctList[i + j]; 2061 } // In all remaining cases (ctList[i+j]), ctList[i] needs to 2062 // remain unchanged. 2063 } 2064 } 2065 } 2066 2067 Ciphertext<Element> result( 2068 std::make_shared<CiphertextImpl<Element>>(*(ctList[0]))); 2069 2070 return result; 2071 } 2072 2073 /** 2074 * Virtual function to define the interface for multiplicative homomorphic 2075 * evaluation of ciphertext using the evaluation key. 2076 * 2077 * @param ct1 first input ciphertext. 2078 * @param ct2 second input ciphertext. 2079 * @param ek is the evaluation key to make the newCiphertext 2080 * decryptable by the same secret key as that of ciphertext1 and 2081 * ciphertext2. 2082 * @param *newCiphertext the new resulting ciphertext. 2083 */ 2084 virtual Ciphertext<Element> EvalMultAndRelinearize( 2085 ConstCiphertext<Element> ct1, ConstCiphertext<Element> ct2, 2086 const vector<LPEvalKey<Element>> &ek) const = 0; 2087 2088 /** 2089 * Virtual function to do relinearization 2090 * 2091 * @param ciphertext input ciphertext. 2092 * @param ek are the evaluation keys to make the newCiphertext 2093 * decryptable by the same secret key as that of ciphertext1 and 2094 * ciphertext2. 2095 * @return the new resulting ciphertext. 2096 */ Relinearize(ConstCiphertext<Element> ciphertext,const vector<LPEvalKey<Element>> & ek)2097 virtual Ciphertext<Element> Relinearize( 2098 ConstCiphertext<Element> ciphertext, 2099 const vector<LPEvalKey<Element>> &ek) const { 2100 PALISADE_THROW(config_error, "Relinearize operation not supported"); 2101 } 2102 2103 /** 2104 * Virtual function to do in-place relinearization 2105 * 2106 * @param &ciphertext input ciphertext. 2107 * @param ek are the evaluation keys 2108 * @return the new resulting ciphertext. 2109 */ RelinearizeInPlace(Ciphertext<Element> & ciphertext,const vector<LPEvalKey<Element>> & ek)2110 virtual void RelinearizeInPlace( 2111 Ciphertext<Element> &ciphertext, 2112 const vector<LPEvalKey<Element>> &ek) const { 2113 PALISADE_THROW(config_error, "RelinearizeInPlace operation not supported"); 2114 } 2115 2116 /** 2117 * Virtual function to define the interface for homomorphic negation of 2118 * ciphertext. 2119 * 2120 * @param &ciphertext the input ciphertext. 2121 * @param *newCiphertext the new ciphertext. 2122 */ 2123 virtual Ciphertext<Element> EvalNegate( 2124 ConstCiphertext<Element> ciphertext) const = 0; 2125 2126 /** 2127 * Function to add random noise to all plaintext slots except for the first 2128 * one; used in EvalInnerProduct 2129 * 2130 * @param &ciphertext the input ciphertext. 2131 * @return modified ciphertext 2132 */ AddRandomNoise(ConstCiphertext<Element> ciphertext)2133 virtual Ciphertext<Element> AddRandomNoise( 2134 ConstCiphertext<Element> ciphertext) const { 2135 if (!ciphertext) 2136 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 2137 2138 std::uniform_real_distribution<double> distribution(0.0, 1.0); 2139 2140 string kID = ciphertext->GetKeyTag(); 2141 const auto cryptoParams = ciphertext->GetCryptoParameters(); 2142 const auto encodingParams = cryptoParams->GetEncodingParams(); 2143 const auto elementParams = cryptoParams->GetElementParams(); 2144 2145 usint n = elementParams->GetRingDimension(); 2146 2147 auto cc = ciphertext->GetCryptoContext(); 2148 2149 Plaintext plaintext; 2150 2151 if (ciphertext->GetEncodingType() == CKKSPacked) { 2152 std::vector<std::complex<double>> randomIntVector(n); 2153 2154 // first plaintext slot does not need to change 2155 randomIntVector[0].real(0); 2156 2157 for (usint i = 0; i < n - 1; i++) { 2158 randomIntVector[i + 1].real( 2159 distribution(PseudoRandomNumberGenerator::GetPRNG())); 2160 } 2161 2162 plaintext = 2163 cc->MakeCKKSPackedPlaintext(randomIntVector, ciphertext->GetDepth()); 2164 2165 } else { 2166 DiscreteUniformGenerator dug; 2167 dug.SetModulus(encodingParams->GetPlaintextModulus()); 2168 BigVector randomVector = dug.GenerateVector(n - 1); 2169 2170 std::vector<int64_t> randomIntVector(n); 2171 2172 // first plaintext slot does not need to change 2173 randomIntVector[0] = 0; 2174 2175 for (usint i = 0; i < n - 1; i++) { 2176 randomIntVector[i + 1] = randomVector[i].ConvertToInt(); 2177 } 2178 2179 plaintext = cc->MakePackedPlaintext(randomIntVector); 2180 } 2181 2182 plaintext->Encode(); 2183 plaintext->GetElement<Element>().SetFormat(EVALUATION); 2184 2185 auto ans = EvalAdd(ciphertext, plaintext); 2186 2187 return ans; 2188 } 2189 2190 /** 2191 * Method for KeySwitchGen 2192 * 2193 * @param &originalPrivateKey Original private key used for encryption. 2194 * @param &newPrivateKey New private key to generate the keyswitch hint. 2195 * @param *KeySwitchHint is where the resulting keySwitchHint will be 2196 * placed. 2197 */ 2198 virtual LPEvalKey<Element> KeySwitchGen( 2199 const LPPrivateKey<Element> originalPrivateKey, 2200 const LPPrivateKey<Element> newPrivateKey) const = 0; 2201 2202 /** 2203 * Method for KeySwitch 2204 * 2205 * @param &keySwitchHint Hint required to perform the ciphertext switching. 2206 * @param &cipherText Original ciphertext to perform switching on. 2207 */ 2208 2209 virtual void KeySwitchInPlace(const LPEvalKey<Element> keySwitchHint, 2210 Ciphertext<Element> &cipherText) const = 0; 2211 KeySwitch(const LPEvalKey<Element> keySwitchHint,ConstCiphertext<Element> cipherText)2212 virtual Ciphertext<Element> KeySwitch( 2213 const LPEvalKey<Element> keySwitchHint, 2214 ConstCiphertext<Element> cipherText) const { 2215 auto ret = cipherText->Clone(); 2216 KeySwitchInPlace(keySwitchHint, ret); 2217 return ret; 2218 } 2219 2220 /** 2221 * Virtual function to define the interface for generating a evaluation key 2222 * which is used after each multiplication. 2223 * 2224 * @param &ciphertext1 first input ciphertext. 2225 * @param &ciphertext2 second input ciphertext. 2226 * @param &ek is the evaluation key to make the newCiphertext decryptable by 2227 * the same secret key as that of ciphertext1 and ciphertext2. 2228 * @param *newCiphertext the new resulting ciphertext. 2229 */ 2230 virtual LPEvalKey<Element> EvalMultKeyGen( 2231 const LPPrivateKey<Element> originalPrivateKey) const = 0; 2232 2233 /** 2234 * Virtual function to define the interface for generating a evaluation key 2235 * which is used after each multiplication for depth more than 2. 2236 * 2237 * @param &originalPrivateKey Original private key used for encryption. 2238 * @param *evalMultKeys the resulting evalution key vector list. 2239 */ 2240 virtual vector<LPEvalKey<Element>> EvalMultKeysGen( 2241 const LPPrivateKey<Element> originalPrivateKey) const = 0; 2242 2243 /** 2244 * Virtual function to generate all isomorphism keys for a given private key 2245 * 2246 * @param publicKey encryption key for the new ciphertext. 2247 * @param origPrivateKey original private key used for decryption. 2248 * @param indexList list of automorphism indices to be computed 2249 * @return returns the evaluation keys 2250 */ 2251 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> 2252 EvalAutomorphismKeyGen(const LPPublicKey<Element> publicKey, 2253 const LPPrivateKey<Element> origPrivateKey, 2254 const std::vector<usint> &indexList) const = 0; 2255 2256 /** 2257 * Virtual function for the precomputation step of hoisted 2258 * automorphisms. 2259 * 2260 * @param ct the input ciphertext on which to do the precomputation (digit 2261 * decomposition) 2262 */ EvalFastRotationPrecompute(ConstCiphertext<Element> cipherText)2263 virtual shared_ptr<vector<Element>> EvalFastRotationPrecompute( 2264 ConstCiphertext<Element> cipherText) const { 2265 std::string errMsg = 2266 "LPSHEAlgorithm::EvalFastRotationPrecompute is not implemented for " 2267 "this Scheme."; 2268 PALISADE_THROW(not_implemented_error, errMsg); 2269 } 2270 2271 /** 2272 * Virtual function for the automorphism and key switching step of 2273 * hoisted automorphisms. 2274 * 2275 * @param ct the input ciphertext to perform the automorphism on 2276 * @param index the index of the rotation. Positive indices correspond to 2277 * left rotations and negative indices correspond to right rotations. 2278 * @param m is the cyclotomic order 2279 * @param digits the digit decomposition created by 2280 * EvalFastRotationPrecompute at the precomputation step. 2281 */ EvalFastRotation(ConstCiphertext<Element> cipherText,const usint index,const usint m,const shared_ptr<vector<Element>> digits)2282 virtual Ciphertext<Element> EvalFastRotation( 2283 ConstCiphertext<Element> cipherText, const usint index, const usint m, 2284 const shared_ptr<vector<Element>> digits) const { 2285 std::string errMsg = 2286 "LPSHEAlgorithm::EvalFastRotation is not implemented for this " 2287 "Scheme."; 2288 PALISADE_THROW(not_implemented_error, errMsg); 2289 } 2290 2291 /** 2292 * Generates evaluation keys for a list of indices 2293 * Currently works only for power-of-two and cyclic-group cyclotomics 2294 * 2295 * @param publicKey encryption key for the new ciphertext. 2296 * @param origPrivateKey original private key used for decryption. 2297 * @param indexList list of indices to be computed 2298 * @return returns the evaluation keys 2299 */ EvalAtIndexKeyGen(const LPPublicKey<Element> publicKey,const LPPrivateKey<Element> origPrivateKey,const std::vector<int32_t> & indexList)2300 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalAtIndexKeyGen( 2301 const LPPublicKey<Element> publicKey, 2302 const LPPrivateKey<Element> origPrivateKey, 2303 const std::vector<int32_t> &indexList) const { 2304 /* 2305 * we don't validate publicKey as it is needed by NTRU-based scheme only 2306 * NTRU-based scheme only and it is checked for null later. 2307 */ 2308 if (!origPrivateKey) 2309 PALISADE_THROW(config_error, "Input private key is nullptr"); 2310 const auto cryptoParams = origPrivateKey->GetCryptoParameters(); 2311 const auto encodingParams = cryptoParams->GetEncodingParams(); 2312 const auto elementParams = cryptoParams->GetElementParams(); 2313 uint32_t m = elementParams->GetCyclotomicOrder(); 2314 2315 std::vector<uint32_t> autoIndices(indexList.size()); 2316 2317 if (IsPowerOfTwo(m)) { // power-of-two cyclotomics 2318 for (size_t i = 0; i < indexList.size(); i++) { 2319 auto ccInst = origPrivateKey->GetCryptoContext(); 2320 // CKKS Packing 2321 if (ccInst->getSchemeId() == "CKKS") 2322 autoIndices[i] = FindAutomorphismIndex2nComplex(indexList[i], m); 2323 else 2324 autoIndices[i] = FindAutomorphismIndex2n(indexList[i], m); 2325 } 2326 2327 } else { // cyclic groups 2328 for (size_t i = 0; i < indexList.size(); i++) 2329 autoIndices[i] = FindAutomorphismIndexCyclic( 2330 indexList[i], m, encodingParams->GetPlaintextGenerator()); 2331 } 2332 2333 if (publicKey) 2334 // NTRU-based scheme 2335 return EvalAutomorphismKeyGen(publicKey, origPrivateKey, autoIndices); 2336 else 2337 // RLWE-based scheme 2338 return EvalAutomorphismKeyGen(origPrivateKey, autoIndices); 2339 } 2340 2341 /** 2342 * Virtual function for evaluating automorphism of ciphertext at index i 2343 * 2344 * @param ciphertext the input ciphertext. 2345 * @param i automorphism index 2346 * @param &evalKeys - reference to the vector of evaluation keys generated 2347 * by EvalAutomorphismKeyGen. 2348 * @return resulting ciphertext 2349 */ 2350 virtual Ciphertext<Element> EvalAutomorphism( 2351 ConstCiphertext<Element> ciphertext, usint i, 2352 const std::map<usint, LPEvalKey<Element>> &evalKeys, 2353 CALLER_INFO_ARGS_HDR) const = 0; 2354 2355 /** 2356 * Moves i-th slot to slot 0 2357 * 2358 * @param ciphertext. 2359 * @param i the index. 2360 * @param &evalAtIndexKeys - reference to the map of evaluation keys 2361 * generated by EvalAtIndexKeyGen. 2362 * @return resulting ciphertext 2363 */ EvalAtIndex(ConstCiphertext<Element> ciphertext,int32_t index,const std::map<usint,LPEvalKey<Element>> & evalAtIndexKeys)2364 virtual Ciphertext<Element> EvalAtIndex( 2365 ConstCiphertext<Element> ciphertext, int32_t index, 2366 const std::map<usint, LPEvalKey<Element>> &evalAtIndexKeys) const { 2367 if (!ciphertext) 2368 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 2369 if (!evalAtIndexKeys.size()) 2370 PALISADE_THROW(config_error, "Input index map is empty"); 2371 const auto cryptoParams = ciphertext->GetCryptoParameters(); 2372 const auto encodingParams = cryptoParams->GetEncodingParams(); 2373 const auto elementParams = cryptoParams->GetElementParams(); 2374 uint32_t m = elementParams->GetCyclotomicOrder(); 2375 2376 uint32_t autoIndex; 2377 2378 // power-of-two cyclotomics 2379 if (IsPowerOfTwo(m)) { 2380 if (ciphertext->GetEncodingType() == CKKSPacked) 2381 autoIndex = FindAutomorphismIndex2nComplex(index, m); 2382 else 2383 autoIndex = FindAutomorphismIndex2n(index, m); 2384 } else { // cyclic-group cyclotomics 2385 autoIndex = FindAutomorphismIndexCyclic( 2386 index, m, encodingParams->GetPlaintextGenerator()); 2387 } 2388 2389 return EvalAutomorphism(ciphertext, autoIndex, evalAtIndexKeys); 2390 } 2391 2392 /** 2393 * Virtual function to generate automophism keys for a given private key; 2394 * Uses the private key for encryption 2395 * 2396 * @param privateKey private key. 2397 * @param indexList list of automorphism indices to be computed 2398 * @return returns the evaluation keys 2399 */ 2400 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> 2401 EvalAutomorphismKeyGen(const LPPrivateKey<Element> privateKey, 2402 const std::vector<usint> &indexList) const = 0; 2403 2404 /** 2405 * Virtual function to generate the automorphism keys for EvalSum; works 2406 * only for packed encoding 2407 * 2408 * @param privateKey private key. 2409 * @return returns the evaluation keys 2410 */ EvalSumKeyGen(const LPPrivateKey<Element> privateKey,const LPPublicKey<Element> publicKey)2411 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalSumKeyGen( 2412 const LPPrivateKey<Element> privateKey, 2413 const LPPublicKey<Element> publicKey) const { 2414 if (!privateKey) 2415 PALISADE_THROW(config_error, "Input private key is nullptr"); 2416 /* 2417 * we don't validate publicKey as it is needed by NTRU-based scheme only 2418 * NTRU-based scheme only and it is checked for null later. 2419 */ 2420 const auto cryptoParams = privateKey->GetCryptoParameters(); 2421 const auto encodingParams = cryptoParams->GetEncodingParams(); 2422 const auto elementParams = cryptoParams->GetElementParams(); 2423 2424 usint batchSize = encodingParams->GetBatchSize(); 2425 usint m = elementParams->GetCyclotomicOrder(); 2426 2427 // stores automorphism indices needed for EvalSum 2428 std::vector<usint> indices; 2429 2430 if (IsPowerOfTwo(m)) { 2431 auto ccInst = privateKey->GetCryptoContext(); 2432 // CKKS Packing 2433 if (ccInst->getSchemeId() == "CKKS") 2434 indices = GenerateIndices2nComplex(batchSize, m); 2435 else 2436 indices = GenerateIndices_2n(batchSize, m); 2437 } else { // Arbitrary cyclotomics 2438 usint g = encodingParams->GetPlaintextGenerator(); 2439 for (int i = 0; i < floor(log2(batchSize)); i++) { 2440 indices.push_back(g); 2441 g = (g * g) % m; 2442 } 2443 } 2444 2445 if (publicKey) // NTRU-based scheme 2446 return EvalAutomorphismKeyGen(publicKey, privateKey, indices); 2447 2448 // Regular RLWE scheme 2449 return EvalAutomorphismKeyGen(privateKey, indices); 2450 } 2451 2452 /** 2453 * Virtual function to generate the automorphism keys for EvalSumRows; works 2454 * only for packed encoding 2455 * 2456 * @param privateKey private key. 2457 * @param publicKey public key. 2458 * @param rowSize size of rows in the matrix 2459 * @param subringDim subring dimension (set to cyclotomic order if set to 0) 2460 * @return returns the evaluation keys 2461 */ 2462 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalSumRowsKeyGen( 2463 const LPPrivateKey<Element> privateKey, 2464 const LPPublicKey<Element> publicKey, usint rowSize, 2465 usint subringDim = 0) const { 2466 if (!privateKey) 2467 PALISADE_THROW(config_error, "Input private key is nullptr"); 2468 const auto cryptoParams = privateKey->GetCryptoParameters(); 2469 const auto encodingParams = cryptoParams->GetEncodingParams(); 2470 const auto elementParams = cryptoParams->GetElementParams(); 2471 2472 usint m = 2473 (subringDim == 0) ? elementParams->GetCyclotomicOrder() : subringDim; 2474 2475 // stores automorphism indices needed for EvalSum 2476 std::vector<usint> indices; 2477 2478 if (IsPowerOfTwo(m)) { 2479 auto ccInst = privateKey->GetCryptoContext(); 2480 // CKKS Packing 2481 if (ccInst->getSchemeId() == "CKKS") 2482 indices = GenerateIndices2nComplexRows(rowSize, m); 2483 else 2484 PALISADE_THROW(config_error, 2485 "Matrix summation of row-vectors is only supported for " 2486 "CKKSPackedEncoding."); 2487 2488 } else { // Arbitrary cyclotomics 2489 PALISADE_THROW(config_error, 2490 "Matrix summation of row-vectors is not supported for " 2491 "arbitrary cyclotomics."); 2492 } 2493 2494 if (publicKey) 2495 // NTRU-based scheme 2496 return EvalAutomorphismKeyGen(publicKey, privateKey, indices); 2497 else 2498 // Regular RLWE scheme 2499 return EvalAutomorphismKeyGen(privateKey, indices); 2500 } 2501 2502 /** 2503 * Virtual function to generate the automorphism keys for EvalSumCols; works 2504 * only for packed encoding 2505 * 2506 * @param privateKey private key. 2507 * @param publicKey public key. 2508 * @param rowSize size of rows in the matrix 2509 * @param colSize size of columns in the matrix 2510 * @return returns the evaluation keys 2511 */ EvalSumColsKeyGen(const LPPrivateKey<Element> privateKey,const LPPublicKey<Element> publicKey)2512 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalSumColsKeyGen( 2513 const LPPrivateKey<Element> privateKey, 2514 const LPPublicKey<Element> publicKey) const { 2515 if (!privateKey) 2516 PALISADE_THROW(config_error, "Input private key is nullptr"); 2517 const auto cryptoParams = privateKey->GetCryptoParameters(); 2518 const auto encodingParams = cryptoParams->GetEncodingParams(); 2519 const auto elementParams = cryptoParams->GetElementParams(); 2520 2521 usint batchSize = encodingParams->GetBatchSize(); 2522 usint m = elementParams->GetCyclotomicOrder(); 2523 2524 auto ccInst = privateKey->GetCryptoContext(); 2525 // CKKS Packing 2526 if (ccInst->getSchemeId() == "CKKS") { 2527 // stores automorphism indices needed for EvalSum 2528 std::vector<usint> indices; 2529 2530 if (IsPowerOfTwo(m)) { 2531 indices = GenerateIndices2nComplexCols(batchSize, m); 2532 } else { // Arbitrary cyclotomics 2533 PALISADE_THROW(config_error, 2534 "Matrix summation of column-vectors is not supported " 2535 "for arbitrary cyclotomics."); 2536 } 2537 2538 if (publicKey) 2539 // NTRU-based scheme 2540 return EvalAutomorphismKeyGen(publicKey, privateKey, indices); 2541 else 2542 // Regular RLWE scheme 2543 return EvalAutomorphismKeyGen(privateKey, indices); 2544 } else { 2545 PALISADE_THROW(config_error, 2546 "Matrix summation of column-vectors is only supported for " 2547 "CKKSPackedEncoding."); 2548 } 2549 } 2550 2551 /** 2552 * Sums all elements in log (batch size) time - works only with packed 2553 * encoding 2554 * 2555 * @param ciphertext the input ciphertext. 2556 * @param batchSize size of the batch to be summed up 2557 * @param &evalKeys - reference to the map of evaluation keys generated by 2558 * EvalAutomorphismKeyGen. 2559 * @return resulting ciphertext 2560 */ EvalSum(ConstCiphertext<Element> ciphertext,usint batchSize,const std::map<usint,LPEvalKey<Element>> & evalKeys)2561 virtual Ciphertext<Element> EvalSum( 2562 ConstCiphertext<Element> ciphertext, usint batchSize, 2563 const std::map<usint, LPEvalKey<Element>> &evalKeys) const { 2564 if (!ciphertext) 2565 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 2566 if (!evalKeys.size()) 2567 PALISADE_THROW(config_error, "Input index map is empty"); 2568 const shared_ptr<LPCryptoParameters<Element>> cryptoParams = 2569 ciphertext->GetCryptoParameters(); 2570 Ciphertext<Element> newCiphertext( 2571 std::make_shared<CiphertextImpl<Element>>(*ciphertext)); 2572 2573 const auto encodingParams = cryptoParams->GetEncodingParams(); 2574 const auto elementParams = cryptoParams->GetElementParams(); 2575 2576 usint m = elementParams->GetCyclotomicOrder(); 2577 2578 if ((encodingParams->GetBatchSize() == 0)) { 2579 PALISADE_THROW( 2580 config_error, 2581 "EvalSum: Packed encoding parameters 'batch size' is not set; " 2582 "Please " 2583 "check the EncodingParams passed to the crypto context."); 2584 } else { 2585 if (IsPowerOfTwo(m)) { 2586 if (ciphertext->GetEncodingType() == CKKSPacked) 2587 newCiphertext = 2588 EvalSum2nComplex(batchSize, m, evalKeys, newCiphertext); 2589 else 2590 newCiphertext = EvalSum_2n(batchSize, m, evalKeys, newCiphertext); 2591 2592 } else { // Arbitrary cyclotomics 2593 if (encodingParams->GetPlaintextGenerator() == 0) { 2594 PALISADE_THROW(config_error, 2595 "EvalSum: Packed encoding parameters 'plaintext " 2596 "generator' is not set; Please check the " 2597 "EncodingParams passed to the crypto context."); 2598 } else { 2599 usint g = encodingParams->GetPlaintextGenerator(); 2600 for (int i = 0; i < floor(log2(batchSize)); i++) { 2601 auto ea = EvalAutomorphism(newCiphertext, g, evalKeys); 2602 newCiphertext = EvalAdd(newCiphertext, ea); 2603 g = (g * g) % m; 2604 } 2605 } 2606 } 2607 } 2608 2609 return newCiphertext; 2610 } 2611 2612 /** 2613 * Sums all elements over row-vectors in a matrix - works only with packed 2614 * encoding 2615 * 2616 * @param ciphertext the input ciphertext. 2617 * @param rowSize size of rows in the matrix 2618 * @param &evalKeys - reference to the map of evaluation keys generated by 2619 * @param subringDim the current cyclotomic order/subring dimension. If set to 2620 * 0, we use the full cyclotomic order. EvalAutomorphismKeyGen. 2621 * @return resulting ciphertext 2622 */ 2623 virtual Ciphertext<Element> EvalSumRows( 2624 ConstCiphertext<Element> ciphertext, usint rowSize, 2625 const std::map<usint, LPEvalKey<Element>> &evalKeys, 2626 usint subringDim = 0) const { 2627 if (!ciphertext) 2628 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 2629 if (!evalKeys.size()) 2630 PALISADE_THROW(config_error, "Input index map is empty"); 2631 const shared_ptr<LPCryptoParameters<Element>> cryptoParams = 2632 ciphertext->GetCryptoParameters(); 2633 Ciphertext<Element> newCiphertext( 2634 std::make_shared<CiphertextImpl<Element>>(*ciphertext)); 2635 2636 const auto encodingParams = cryptoParams->GetEncodingParams(); 2637 const auto elementParams = cryptoParams->GetElementParams(); 2638 2639 usint m = 2640 (subringDim == 0) ? elementParams->GetCyclotomicOrder() : subringDim; 2641 2642 if ((encodingParams->GetBatchSize() == 0)) { 2643 PALISADE_THROW( 2644 config_error, 2645 "EvalSum: Packed encoding parameters 'batch size' is not set; " 2646 "Please " 2647 "check the EncodingParams passed to the crypto context."); 2648 } else { 2649 if (IsPowerOfTwo(m)) { 2650 if (ciphertext->GetEncodingType() == CKKSPacked) 2651 newCiphertext = 2652 EvalSum2nComplexRows(rowSize, m, evalKeys, newCiphertext); 2653 else 2654 PALISADE_THROW(config_error, 2655 "Matrix summation of row-vectors is only supported " 2656 "for CKKS packed encoding."); 2657 2658 } else { // Arbitrary cyclotomics 2659 PALISADE_THROW(config_error, 2660 "Matrix summation of row-vectors is not supported for " 2661 "arbitrary cyclotomics."); 2662 } 2663 } 2664 2665 return newCiphertext; 2666 } 2667 2668 /** 2669 * Sums all elements over column-vectors in a matrix - works only with 2670 * packed encoding 2671 * 2672 * @param ciphertext the input ciphertext. 2673 * @param rowSize size of rows in the matrixs 2674 * @param &evalKeys - reference to the map of evaluation keys generated by 2675 * EvalAutomorphismKeyGen. 2676 * @return resulting ciphertext 2677 */ EvalSumCols(ConstCiphertext<Element> ciphertext,usint batchSize,const std::map<usint,LPEvalKey<Element>> & evalKeys,const std::map<usint,LPEvalKey<Element>> & rightEvalKeys)2678 virtual Ciphertext<Element> EvalSumCols( 2679 ConstCiphertext<Element> ciphertext, usint batchSize, 2680 const std::map<usint, LPEvalKey<Element>> &evalKeys, 2681 const std::map<usint, LPEvalKey<Element>> &rightEvalKeys) const { 2682 if (!ciphertext) 2683 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 2684 if (!evalKeys.size()) 2685 PALISADE_THROW(config_error, "Input evalKeys map is empty"); 2686 if (!rightEvalKeys.size()) 2687 PALISADE_THROW(config_error, "Input rightEvalKeys map is empty"); 2688 const shared_ptr<LPCryptoParameters<Element>> cryptoParams = 2689 ciphertext->GetCryptoParameters(); 2690 Ciphertext<Element> newCiphertext( 2691 std::make_shared<CiphertextImpl<Element>>(*ciphertext)); 2692 2693 const auto encodingParams = cryptoParams->GetEncodingParams(); 2694 const auto elementParams = cryptoParams->GetElementParams(); 2695 2696 usint m = elementParams->GetCyclotomicOrder(); 2697 2698 if ((encodingParams->GetBatchSize() == 0)) { 2699 PALISADE_THROW( 2700 config_error, 2701 "EvalSumCols: Packed encoding parameters 'batch size' is not set; " 2702 "Please check the EncodingParams passed to the crypto context."); 2703 } else { 2704 if (ciphertext->GetEncodingType() == CKKSPacked) { 2705 if (IsPowerOfTwo(m)) { 2706 newCiphertext = 2707 EvalSum2nComplex(batchSize, m, evalKeys, newCiphertext); 2708 2709 std::vector<std::complex<double>> mask(m / 4); 2710 for (size_t i = 0; i < mask.size(); i++) { 2711 if (i % batchSize == 0) 2712 mask[i] = 1; 2713 else 2714 mask[i] = 0; 2715 } 2716 2717 auto cc = ciphertext->GetCryptoContext(); 2718 2719 Plaintext plaintext = cc->MakeCKKSPackedPlaintext(mask, 1); 2720 2721 newCiphertext = EvalMult(newCiphertext, plaintext); 2722 2723 newCiphertext = 2724 EvalSum2nComplexCols(batchSize, m, rightEvalKeys, newCiphertext); 2725 2726 } else { // Arbitrary cyclotomics 2727 PALISADE_THROW(config_error, 2728 "Matrix summation of column-vectors is not supported " 2729 "for arbitrary cyclotomics."); 2730 } 2731 } else { 2732 PALISADE_THROW(config_error, 2733 "Matrix summation of column-vectors is only supported " 2734 "for CKKS packed encoding."); 2735 } 2736 } 2737 2738 return newCiphertext; 2739 } 2740 2741 /** 2742 * Evaluates inner product in batched encoding 2743 * 2744 * @param ciphertext1 first vector. 2745 * @param ciphertext2 second vector. 2746 * @param batchSize size of the batch to be summed up 2747 * @param &evalSumKeys - reference to the map of evaluation keys generated 2748 * by EvalAutomorphismKeyGen. 2749 * @param &evalMultKey - reference to the evaluation key generated by 2750 * EvalMultKeyGen. 2751 * @return resulting ciphertext 2752 */ EvalInnerProduct(ConstCiphertext<Element> ciphertext1,ConstCiphertext<Element> ciphertext2,usint batchSize,const std::map<usint,LPEvalKey<Element>> & evalSumKeys,const LPEvalKey<Element> evalMultKey)2753 virtual Ciphertext<Element> EvalInnerProduct( 2754 ConstCiphertext<Element> ciphertext1, 2755 ConstCiphertext<Element> ciphertext2, usint batchSize, 2756 const std::map<usint, LPEvalKey<Element>> &evalSumKeys, 2757 const LPEvalKey<Element> evalMultKey) const { 2758 Ciphertext<Element> result = 2759 EvalMult(ciphertext1, ciphertext2, evalMultKey); 2760 2761 result = EvalSum(result, batchSize, evalSumKeys); 2762 2763 // add a random number to all slots except for the first one so that no 2764 // information is leaked 2765 // if (ciphertext1->GetEncodingType() != CKKSPacked) 2766 // result = AddRandomNoise(result); 2767 return result; 2768 } 2769 2770 /** 2771 * Evaluates inner product in batched encoding 2772 * 2773 * @param ciphertext1 first vector. 2774 * @param plaintext plaintext. 2775 * @param batchSize size of the batch to be summed up 2776 * @param &evalSumKeys - reference to the map of evaluation keys generated 2777 * by EvalAutomorphismKeyGen. 2778 * @param &evalMultKey - reference to the evaluation key generated by 2779 * EvalMultKeyGen. 2780 * @return resulting ciphertext 2781 */ EvalInnerProduct(ConstCiphertext<Element> ciphertext1,ConstPlaintext plaintext,usint batchSize,const std::map<usint,LPEvalKey<Element>> & evalSumKeys)2782 virtual Ciphertext<Element> EvalInnerProduct( 2783 ConstCiphertext<Element> ciphertext1, ConstPlaintext plaintext, 2784 usint batchSize, 2785 const std::map<usint, LPEvalKey<Element>> &evalSumKeys) const { 2786 Ciphertext<Element> result = EvalMult(ciphertext1, plaintext); 2787 2788 result = EvalSum(result, batchSize, evalSumKeys); 2789 2790 // add a random number to all slots except for the first one so that no 2791 // information is leaked 2792 // if (ciphertext1->GetEncodingType() != CKKSPacked) 2793 // result = AddRandomNoise(result); 2794 return result; 2795 } 2796 2797 /** 2798 * Merges multiple ciphertexts with encrypted results in slot 0 into a 2799 * single ciphertext The slot assignment is done based on the order of 2800 * ciphertexts in the vector 2801 * 2802 * @param ciphertextVector vector of ciphertexts to be merged. 2803 * @param &evalKeys - reference to the map of evaluation keys generated by 2804 * EvalAutomorphismKeyGen. 2805 * @return resulting ciphertext 2806 */ EvalMerge(const vector<Ciphertext<Element>> & ciphertextVector,const std::map<usint,LPEvalKey<Element>> & evalKeys)2807 virtual Ciphertext<Element> EvalMerge( 2808 const vector<Ciphertext<Element>> &ciphertextVector, 2809 const std::map<usint, LPEvalKey<Element>> &evalKeys) const { 2810 if (ciphertextVector.size() == 0) 2811 PALISADE_THROW(math_error, 2812 "EvalMerge: the vector of ciphertexts to be merged " 2813 "cannot be empty"); 2814 2815 const shared_ptr<LPCryptoParameters<Element>> cryptoParams = 2816 ciphertextVector[0]->GetCryptoParameters(); 2817 Ciphertext<Element> newCiphertext( 2818 std::make_shared<CiphertextImpl<Element>>(*(ciphertextVector[0]))); 2819 2820 auto cc = ciphertextVector[0]->GetCryptoContext(); 2821 2822 Plaintext plaintext; 2823 if (ciphertextVector[0]->GetEncodingType() == CKKSPacked) { 2824 std::vector<std::complex<double>> plaintextVector({{1, 0}, {0, 0}}); 2825 plaintext = cc->MakeCKKSPackedPlaintext(plaintextVector); 2826 } else { 2827 std::vector<int64_t> plaintextVector = {1, 0}; 2828 plaintext = cc->MakePackedPlaintext(plaintextVector); 2829 } 2830 2831 newCiphertext = EvalMult(newCiphertext, plaintext); 2832 2833 for (size_t i = 1; i < ciphertextVector.size(); i++) { 2834 newCiphertext = EvalAdd( 2835 newCiphertext, EvalAtIndex(EvalMult(ciphertextVector[i], plaintext), 2836 -(int32_t)i, evalKeys)); 2837 } 2838 2839 return newCiphertext; 2840 } 2841 2842 /* Maintenance procedure used in the exact RNS variant of CKKS 2843 * @param c1 input ciphertext. 2844 * @param targetLevel The number of the level we want to take this 2845 * ciphertext to. Levels are numbered from 0 (all towers) to 2846 * GetNumberOfTowers()-1 (one remaining tower). 2847 * @return A ciphertext containing the same value as c1, but at level 2848 * targetLevel. 2849 */ AdjustLevelWithRescale(Ciphertext<Element> & c1,uint32_t targetLevel)2850 virtual Ciphertext<Element> AdjustLevelWithRescale( 2851 Ciphertext<Element> &c1, uint32_t targetLevel) const { 2852 std::string errMsg = 2853 "AdjustLevelWithoutRescale is not implemented for this scheme."; 2854 PALISADE_THROW(not_implemented_error, errMsg); 2855 } 2856 2857 private: GenerateIndices_2n(usint batchSize,usint m)2858 std::vector<usint> GenerateIndices_2n(usint batchSize, usint m) const { 2859 // stores automorphism indices needed for EvalSum 2860 std::vector<usint> indices; 2861 2862 if (batchSize > 1) { 2863 usint g = 5; 2864 for (int i = 0; i < ceil(log2(batchSize)) - 1; i++) { 2865 indices.push_back(g); 2866 g = (g * g) % m; 2867 } 2868 if (2 * batchSize < m) 2869 indices.push_back(g); 2870 else 2871 indices.push_back(m - 1); 2872 } 2873 2874 return indices; 2875 } 2876 GenerateIndices2nComplex(usint batchSize,usint m)2877 std::vector<usint> GenerateIndices2nComplex(usint batchSize, usint m) const { 2878 // stores automorphism indices needed for EvalSum 2879 std::vector<usint> indices; 2880 2881 // generator 2882 int32_t g = 5; 2883 usint gFinal = g; 2884 2885 for (size_t j = 0; j < ceil(log2(batchSize)); j++) { 2886 indices.push_back(gFinal); 2887 g = (g * g) % m; 2888 2889 gFinal = g; 2890 } 2891 2892 return indices; 2893 } 2894 GenerateIndices2nComplexRows(usint rowSize,usint m)2895 std::vector<usint> GenerateIndices2nComplexRows(usint rowSize, 2896 usint m) const { 2897 // stores automorphism indices needed for EvalSum 2898 std::vector<usint> indices; 2899 2900 usint colSize = m / (4 * rowSize); 2901 2902 // generator 2903 int32_t g0 = 5; 2904 usint g = 0; 2905 2906 int32_t f = (NativeInteger(g0).ModExp(rowSize, m)).ConvertToInt(); 2907 2908 for (size_t j = 0; j < ceil(log2(colSize)); j++) { 2909 g = f; 2910 2911 indices.push_back(g); 2912 2913 f = (f * f) % m; 2914 } 2915 2916 return indices; 2917 } 2918 GenerateIndices2nComplexCols(usint batchSize,usint m)2919 std::vector<usint> GenerateIndices2nComplexCols(usint batchSize, 2920 usint m) const { 2921 // stores automorphism indices needed for EvalSum 2922 std::vector<usint> indices; 2923 2924 // generator 2925 int32_t g = NativeInteger(5).ModInverse(m).ConvertToInt(); 2926 usint gFinal = g; 2927 2928 for (size_t j = 0; j < ceil(log2(batchSize)); j++) { 2929 indices.push_back(gFinal); 2930 g = (g * g) % m; 2931 2932 gFinal = g; 2933 } 2934 2935 return indices; 2936 } 2937 EvalSum_2n(usint batchSize,usint m,const std::map<usint,LPEvalKey<Element>> & evalKeys,ConstCiphertext<Element> ciphertext)2938 Ciphertext<Element> EvalSum_2n( 2939 usint batchSize, usint m, 2940 const std::map<usint, LPEvalKey<Element>> &evalKeys, 2941 ConstCiphertext<Element> ciphertext) const { 2942 Ciphertext<Element> newCiphertext( 2943 std::make_shared<CiphertextImpl<Element>>(*ciphertext)); 2944 2945 if (batchSize > 1) { 2946 usint g = 5; 2947 for (int i = 0; i < ceil(log2(batchSize)) - 1; i++) { 2948 newCiphertext = EvalAdd(newCiphertext, 2949 EvalAutomorphism(newCiphertext, g, evalKeys)); 2950 g = (g * g) % m; 2951 } 2952 if (2 * batchSize < m) 2953 newCiphertext = EvalAdd(newCiphertext, 2954 EvalAutomorphism(newCiphertext, g, evalKeys)); 2955 else 2956 newCiphertext = EvalAdd( 2957 newCiphertext, EvalAutomorphism(newCiphertext, m - 1, evalKeys)); 2958 } 2959 2960 return newCiphertext; 2961 } 2962 EvalSum2nComplex(usint batchSize,usint m,const std::map<usint,LPEvalKey<Element>> & evalKeys,ConstCiphertext<Element> ciphertext)2963 Ciphertext<Element> EvalSum2nComplex( 2964 usint batchSize, usint m, 2965 const std::map<usint, LPEvalKey<Element>> &evalKeys, 2966 ConstCiphertext<Element> ciphertext) const { 2967 Ciphertext<Element> newCiphertext( 2968 std::make_shared<CiphertextImpl<Element>>(*ciphertext)); 2969 2970 // generator 2971 int32_t g = 5; 2972 usint gFinal = g; 2973 2974 for (int i = 0; i < ceil(log2(batchSize)); i++) { 2975 newCiphertext = EvalAdd( 2976 newCiphertext, EvalAutomorphism(newCiphertext, gFinal, evalKeys)); 2977 g = (g * g) % m; 2978 2979 gFinal = g; 2980 } 2981 2982 return newCiphertext; 2983 } 2984 EvalSum2nComplexRows(usint rowSize,usint m,const std::map<usint,LPEvalKey<Element>> & evalKeys,ConstCiphertext<Element> ciphertext)2985 Ciphertext<Element> EvalSum2nComplexRows( 2986 usint rowSize, usint m, 2987 const std::map<usint, LPEvalKey<Element>> &evalKeys, 2988 ConstCiphertext<Element> ciphertext) const { 2989 Ciphertext<Element> newCiphertext( 2990 std::make_shared<CiphertextImpl<Element>>(*ciphertext)); 2991 2992 usint colSize = m / (4 * rowSize); 2993 2994 // generator 2995 int32_t g0 = 5; 2996 usint g = 0; 2997 int32_t f = (NativeInteger(g0).ModExp(rowSize, m)).ConvertToInt(); 2998 2999 for (size_t j = 0; j < ceil(log2(colSize)); j++) { 3000 g = f; 3001 3002 newCiphertext = 3003 EvalAdd(newCiphertext, EvalAutomorphism(newCiphertext, g, evalKeys)); 3004 3005 f = (f * f) % m; 3006 } 3007 3008 return newCiphertext; 3009 } 3010 EvalSum2nComplexCols(usint batchSize,usint m,const std::map<usint,LPEvalKey<Element>> & evalKeys,ConstCiphertext<Element> ciphertext)3011 Ciphertext<Element> EvalSum2nComplexCols( 3012 usint batchSize, usint m, 3013 const std::map<usint, LPEvalKey<Element>> &evalKeys, 3014 ConstCiphertext<Element> ciphertext) const { 3015 Ciphertext<Element> newCiphertext( 3016 std::make_shared<CiphertextImpl<Element>>(*ciphertext)); 3017 3018 // generator 3019 int32_t g = NativeInteger(5).ModInverse(m).ConvertToInt(); 3020 usint gFinal = g; 3021 3022 for (int i = 0; i < ceil(log2(batchSize)); i++) { 3023 newCiphertext = EvalAdd( 3024 newCiphertext, EvalAutomorphism(newCiphertext, gFinal, evalKeys)); 3025 g = (g * g) % m; 3026 3027 gFinal = g; 3028 } 3029 3030 return newCiphertext; 3031 } 3032 }; 3033 3034 /** 3035 * @brief main implementation class to capture essential cryptoparameters of 3036 * any LBC system 3037 * @tparam Element a ring element. 3038 */ 3039 template <typename Element> 3040 class LPCryptoParameters : public Serializable { 3041 public: LPCryptoParameters()3042 LPCryptoParameters() {} 3043 ~LPCryptoParameters()3044 virtual ~LPCryptoParameters() {} 3045 3046 /** 3047 * Returns the value of plaintext modulus p 3048 * 3049 * @return the plaintext modulus. 3050 */ GetPlaintextModulus()3051 virtual const PlaintextModulus &GetPlaintextModulus() const { 3052 return m_encodingParams->GetPlaintextModulus(); 3053 } 3054 3055 /** 3056 * Returns the reference to IL params 3057 * 3058 * @return the ring element parameters. 3059 */ GetElementParams()3060 virtual const shared_ptr<typename Element::Params> GetElementParams() const { 3061 return m_params; 3062 } 3063 3064 /** 3065 * Returns the reference to encoding params 3066 * 3067 * @return the encoding parameters. 3068 */ GetEncodingParams()3069 virtual const EncodingParams GetEncodingParams() const { 3070 return m_encodingParams; 3071 } 3072 3073 /** 3074 * Sets the value of plaintext modulus p 3075 */ SetPlaintextModulus(const PlaintextModulus & plaintextModulus)3076 virtual void SetPlaintextModulus(const PlaintextModulus &plaintextModulus) { 3077 m_encodingParams->SetPlaintextModulus(plaintextModulus); 3078 } 3079 3080 virtual bool operator==(const LPCryptoParameters<Element> &cmp) const = 0; 3081 virtual bool operator!=(const LPCryptoParameters<Element> &cmp) const { 3082 return !(*this == cmp); 3083 } 3084 3085 /** 3086 * Overload to allow printing of parameters to an iostream 3087 * NOTE that the implementation relies on calling the virtual 3088 * PrintParameters method 3089 * @param out - the stream to print to 3090 * @param item - reference to the item to print 3091 * @return the stream 3092 */ 3093 friend std::ostream &operator<<(std::ostream &out, 3094 const LPCryptoParameters &item) { 3095 item.PrintParameters(out); 3096 return out; 3097 } 3098 GetRelinWindow()3099 virtual usint GetRelinWindow() const { return 0; } 3100 GetDepth()3101 virtual int GetDepth() const { return 0; } GetMaxDepth()3102 virtual size_t GetMaxDepth() const { return 0; } 3103 GetDiscreteGaussianGenerator()3104 virtual const typename Element::DggType &GetDiscreteGaussianGenerator() 3105 const { 3106 PALISADE_THROW(config_error, "No DGG Available for this parameter set"); 3107 } 3108 3109 /** 3110 * Sets the reference to element params 3111 */ SetElementParams(shared_ptr<typename Element::Params> params)3112 virtual void SetElementParams(shared_ptr<typename Element::Params> params) { 3113 m_params = params; 3114 } 3115 3116 /** 3117 * Sets the reference to encoding params 3118 */ SetEncodingParams(EncodingParams encodingParams)3119 virtual void SetEncodingParams(EncodingParams encodingParams) { 3120 m_encodingParams = encodingParams; 3121 } 3122 3123 template <class Archive> save(Archive & ar,std::uint32_t const version)3124 void save(Archive &ar, std::uint32_t const version) const { 3125 ar(::cereal::make_nvp("elp", m_params)); 3126 ar(::cereal::make_nvp("enp", m_encodingParams)); 3127 } 3128 3129 template <class Archive> load(Archive & ar,std::uint32_t const version)3130 void load(Archive &ar, std::uint32_t const version) { 3131 if (version > SerializedVersion()) { 3132 PALISADE_THROW(deserialize_error, 3133 "serialized object version " + std::to_string(version) + 3134 " is from a later version of the library"); 3135 } 3136 ar(::cereal::make_nvp("elp", m_params)); 3137 ar(::cereal::make_nvp("enp", m_encodingParams)); 3138 } 3139 SerializedObjectName()3140 std::string SerializedObjectName() const { return "CryptoParameters"; } SerializedVersion()3141 static uint32_t SerializedVersion() { return 1; } 3142 3143 protected: LPCryptoParameters(const PlaintextModulus & plaintextModulus)3144 explicit LPCryptoParameters(const PlaintextModulus &plaintextModulus) { 3145 m_encodingParams = std::make_shared<EncodingParamsImpl>(plaintextModulus); 3146 } 3147 LPCryptoParameters(shared_ptr<typename Element::Params> params,const PlaintextModulus & plaintextModulus)3148 LPCryptoParameters(shared_ptr<typename Element::Params> params, 3149 const PlaintextModulus &plaintextModulus) { 3150 m_params = params; 3151 m_encodingParams = std::make_shared<EncodingParamsImpl>(plaintextModulus); 3152 } 3153 LPCryptoParameters(shared_ptr<typename Element::Params> params,EncodingParams encodingParams)3154 LPCryptoParameters(shared_ptr<typename Element::Params> params, 3155 EncodingParams encodingParams) { 3156 m_params = params; 3157 m_encodingParams = encodingParams; 3158 } 3159 LPCryptoParameters(LPCryptoParameters<Element> * from,shared_ptr<typename Element::Params> newElemParms)3160 LPCryptoParameters(LPCryptoParameters<Element> *from, 3161 shared_ptr<typename Element::Params> newElemParms) { 3162 *this = *from; 3163 m_params = newElemParms; 3164 } 3165 PrintParameters(std::ostream & out)3166 virtual void PrintParameters(std::ostream &out) const { 3167 out << "Element Parameters: " << *m_params << std::endl; 3168 out << "Encoding Parameters: " << *m_encodingParams << std::endl; 3169 } 3170 3171 private: 3172 // element-specific parameters 3173 shared_ptr<typename Element::Params> m_params; 3174 3175 // encoding-specific parameters 3176 EncodingParams m_encodingParams; 3177 }; 3178 3179 // forward decl so SchemeIdentifier works 3180 template <typename Element> 3181 class LPPublicKeyEncryptionScheme; 3182 3183 template <typename Element> 3184 class PalisadeSchemeIdentifier { 3185 string schemeName; 3186 LPPublicKeyEncryptionScheme<Element> *(*schemeMaker)(); 3187 3188 public: PalisadeSchemeIdentifier(string n,LPPublicKeyEncryptionScheme<Element> (* f)())3189 PalisadeSchemeIdentifier(string n, 3190 LPPublicKeyEncryptionScheme<Element> (*f)()) 3191 : schemeName(n), schemeMaker(f) {} 3192 GetName()3193 const string &GetName() const { return schemeName; } GetScheme()3194 LPPublicKeyEncryptionScheme<Element> *GetScheme() const { 3195 return (*schemeMaker)(); 3196 } 3197 }; 3198 3199 /** 3200 * @brief Abstract interface for public key encryption schemes 3201 * @tparam Element a ring element. 3202 */ 3203 template <typename Element> 3204 class LPPublicKeyEncryptionScheme { 3205 private: CheckMultipartyDecryptCompatibility(ConstCiphertext<Element> & ciphertext,CALLER_INFO_ARGS_HDR)3206 inline void CheckMultipartyDecryptCompatibility( 3207 ConstCiphertext<Element> &ciphertext, CALLER_INFO_ARGS_HDR) const { 3208 if (ciphertext->GetElements().size() > 2) { 3209 std::string errorMsg(std::string("ciphertext's number of elements is [") + 3210 std::to_string(ciphertext->GetElements().size()) + 3211 "]. Must be 2 or less for Multiparty Decryption." + 3212 CALLER_INFO); 3213 PALISADE_THROW(palisade_error, errorMsg); 3214 } 3215 } 3216 3217 public: LPPublicKeyEncryptionScheme()3218 LPPublicKeyEncryptionScheme() {} 3219 ~LPPublicKeyEncryptionScheme()3220 virtual ~LPPublicKeyEncryptionScheme() {} 3221 3222 virtual bool operator==(const LPPublicKeyEncryptionScheme &sch) const = 0; 3223 3224 virtual bool operator!=(const LPPublicKeyEncryptionScheme &sch) const { 3225 return !(*this == sch); 3226 } 3227 3228 /** 3229 * Enable features with a bit mast of PKESchemeFeature codes 3230 * @param mask 3231 */ Enable(usint mask)3232 virtual void Enable(usint mask) { 3233 if (mask & ENCRYPTION) Enable(ENCRYPTION); 3234 3235 if (mask & PRE) Enable(PRE); 3236 3237 if (mask & SHE) Enable(SHE); 3238 3239 if (mask & LEVELEDSHE) Enable(LEVELEDSHE); 3240 3241 if (mask & MULTIPARTY) Enable(MULTIPARTY); 3242 } 3243 GetEnabled()3244 virtual usint GetEnabled() const { 3245 usint flag = 0; 3246 3247 if (m_algorithmEncryption != nullptr) flag |= ENCRYPTION; 3248 if (m_algorithmPRE != nullptr) flag |= PRE; 3249 if (m_algorithmSHE != nullptr) flag |= SHE; 3250 if (m_algorithmLeveledSHE != nullptr) flag |= LEVELEDSHE; 3251 if (m_algorithmMultiparty != nullptr) flag |= MULTIPARTY; 3252 3253 return flag; 3254 } 3255 3256 // instantiated in the scheme implementation class 3257 virtual void Enable(PKESchemeFeature feature) = 0; 3258 3259 ///////////////////////////////////////// 3260 // wrapper for LPParameterSelectionAlgorithm 3261 // 3262 3263 virtual bool ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams, 3264 int32_t evalAddCount = 0, int32_t evalMultCount = 0, 3265 int32_t keySwitchCount = 0, size_t dcrtBits = 0, 3266 uint32_t n = 0) const { 3267 if (m_algorithmParamsGen) { 3268 return m_algorithmParamsGen->ParamsGen(cryptoParams, evalAddCount, 3269 evalMultCount, keySwitchCount, 3270 dcrtBits, n); 3271 } 3272 PALISADE_THROW(not_implemented_error, 3273 "Parameter generation operation has not been implemented"); 3274 } 3275 3276 ///////////////////////////////////////// 3277 // the three functions below are wrappers for things in 3278 // LPEncryptionAlgorithm (ENCRYPT) 3279 // 3280 Encrypt(const LPPublicKey<Element> publicKey,const Element & plaintext)3281 virtual Ciphertext<Element> Encrypt(const LPPublicKey<Element> publicKey, 3282 const Element &plaintext) const { 3283 if (m_algorithmEncryption) { 3284 return m_algorithmEncryption->Encrypt(publicKey, plaintext); 3285 } else { 3286 PALISADE_THROW(config_error, "Encrypt operation has not been enabled"); 3287 } 3288 } 3289 Encrypt(const LPPrivateKey<Element> privateKey,const Element & plaintext)3290 virtual Ciphertext<Element> Encrypt(const LPPrivateKey<Element> privateKey, 3291 const Element &plaintext) const { 3292 if (m_algorithmEncryption) { 3293 return m_algorithmEncryption->Encrypt(privateKey, plaintext); 3294 } 3295 PALISADE_THROW(config_error, "Encrypt operation has not been enabled"); 3296 } 3297 Decrypt(const LPPrivateKey<Element> privateKey,ConstCiphertext<Element> ciphertext,NativePoly * plaintext)3298 virtual DecryptResult Decrypt(const LPPrivateKey<Element> privateKey, 3299 ConstCiphertext<Element> ciphertext, 3300 NativePoly *plaintext) const { 3301 if (m_algorithmEncryption) { 3302 return m_algorithmEncryption->Decrypt(privateKey, ciphertext, plaintext); 3303 } 3304 PALISADE_THROW(config_error, "Decrypt operation has not been enabled"); 3305 } 3306 Decrypt(const LPPrivateKey<Element> privateKey,ConstCiphertext<Element> ciphertext,Poly * plaintext)3307 virtual DecryptResult Decrypt(const LPPrivateKey<Element> privateKey, 3308 ConstCiphertext<Element> ciphertext, 3309 Poly *plaintext) const { 3310 if (m_algorithmEncryption) { 3311 return m_algorithmEncryption->Decrypt(privateKey, ciphertext, plaintext); 3312 } 3313 PALISADE_THROW(config_error, "Decrypt operation has not been enabled"); 3314 } 3315 KeyGen(CryptoContext<Element> cc,bool makeSparse)3316 virtual LPKeyPair<Element> KeyGen(CryptoContext<Element> cc, 3317 bool makeSparse) { 3318 if (m_algorithmEncryption) { 3319 auto kp = m_algorithmEncryption->KeyGen(cc, makeSparse); 3320 kp.publicKey->SetKeyTag(kp.secretKey->GetKeyTag()); 3321 return kp; 3322 } 3323 PALISADE_THROW(config_error, "KeyGen operation has not been enabled"); 3324 } 3325 3326 ///////////////////////////////////////// 3327 // the three functions below are wrappers for things in LPPREAlgorithm (PRE) 3328 // 3329 ReKeyGen(const LPPublicKey<Element> newKey,const LPPrivateKey<Element> origPrivateKey)3330 virtual LPEvalKey<Element> ReKeyGen( 3331 const LPPublicKey<Element> newKey, 3332 const LPPrivateKey<Element> origPrivateKey) const { 3333 if (m_algorithmPRE) { 3334 auto rk = m_algorithmPRE->ReKeyGen(newKey, origPrivateKey); 3335 rk->SetKeyTag(newKey->GetKeyTag()); 3336 return rk; 3337 } 3338 PALISADE_THROW(config_error, "ReKeyGen operation has not been enabled"); 3339 } 3340 ReEncrypt(const LPEvalKey<Element> evalKey,ConstCiphertext<Element> ciphertext,const LPPublicKey<Element> publicKey)3341 virtual Ciphertext<Element> ReEncrypt( 3342 const LPEvalKey<Element> evalKey, ConstCiphertext<Element> ciphertext, 3343 const LPPublicKey<Element> publicKey) const { 3344 if (m_algorithmPRE) { 3345 auto ct = m_algorithmPRE->ReEncrypt(evalKey, ciphertext, publicKey); 3346 ct->SetKeyTag(evalKey->GetKeyTag()); 3347 return ct; 3348 } 3349 PALISADE_THROW(config_error, "ReEncrypt operation has not been enabled"); 3350 } 3351 3352 ///////////////////////////////////////// 3353 // the three functions below are wrappers for things in 3354 // LPMultipartyAlgorithm (Multiparty) 3355 // 3356 3357 // Wrapper for Multiparty Key Gen MultipartyKeyGen(CryptoContext<Element> cc,const LPPublicKey<Element> pk1,bool makeSparse,bool PRE)3358 virtual LPKeyPair<Element> MultipartyKeyGen(CryptoContext<Element> cc, 3359 const LPPublicKey<Element> pk1, 3360 bool makeSparse, bool PRE) { 3361 if (m_algorithmMultiparty) { 3362 if (!cc) PALISADE_THROW(config_error, "Input crypto context is nullptr"); 3363 if (!pk1) PALISADE_THROW(config_error, "Input public key is empty"); 3364 auto k = 3365 m_algorithmMultiparty->MultipartyKeyGen(cc, pk1, makeSparse, PRE); 3366 k.publicKey->SetKeyTag(k.secretKey->GetKeyTag()); 3367 return k; 3368 } 3369 PALISADE_THROW(config_error, 3370 "MultipartyKeyGen operation has not been enabled"); 3371 } 3372 3373 // Wrapper for Multiparty Key Gen MultipartyKeyGen(CryptoContext<Element> cc,const vector<LPPrivateKey<Element>> & secretKeys,bool makeSparse)3374 virtual LPKeyPair<Element> MultipartyKeyGen( 3375 CryptoContext<Element> cc, 3376 const vector<LPPrivateKey<Element>> &secretKeys, bool makeSparse) { 3377 if (m_algorithmMultiparty) { 3378 if (!cc) PALISADE_THROW(config_error, "Input crypto context is nullptr"); 3379 if (!secretKeys.size()) 3380 PALISADE_THROW(config_error, "Input private key vector is empty"); 3381 auto k = 3382 m_algorithmMultiparty->MultipartyKeyGen(cc, secretKeys, makeSparse); 3383 k.publicKey->SetKeyTag(k.secretKey->GetKeyTag()); 3384 return k; 3385 } 3386 PALISADE_THROW(config_error, 3387 "MultipartyKeyGen operation has not been enabled"); 3388 } 3389 MultipartyDecryptMain(const LPPrivateKey<Element> privateKey,ConstCiphertext<Element> ciphertext)3390 virtual Ciphertext<Element> MultipartyDecryptMain( 3391 const LPPrivateKey<Element> privateKey, 3392 ConstCiphertext<Element> ciphertext) const { 3393 if (m_algorithmMultiparty) { 3394 CheckMultipartyDecryptCompatibility(ciphertext); 3395 auto ct = 3396 m_algorithmMultiparty->MultipartyDecryptMain(privateKey, ciphertext); 3397 ct->SetKeyTag(privateKey->GetKeyTag()); 3398 return ct; 3399 } 3400 PALISADE_THROW(config_error, 3401 "MultipartyDecryptMain operation has not been enabled"); 3402 } 3403 MultipartyDecryptLead(const LPPrivateKey<Element> privateKey,ConstCiphertext<Element> ciphertext)3404 virtual Ciphertext<Element> MultipartyDecryptLead( 3405 const LPPrivateKey<Element> privateKey, 3406 ConstCiphertext<Element> ciphertext) const { 3407 if (m_algorithmMultiparty) { 3408 CheckMultipartyDecryptCompatibility(ciphertext); 3409 auto ct = 3410 m_algorithmMultiparty->MultipartyDecryptLead(privateKey, ciphertext); 3411 ct->SetKeyTag(privateKey->GetKeyTag()); 3412 return ct; 3413 } 3414 PALISADE_THROW(config_error, 3415 "MultipartyDecryptLead operation has not been enabled"); 3416 } 3417 MultipartyDecryptFusion(const vector<Ciphertext<Element>> & ciphertextVec,NativePoly * plaintext)3418 virtual DecryptResult MultipartyDecryptFusion( 3419 const vector<Ciphertext<Element>> &ciphertextVec, 3420 NativePoly *plaintext) const { 3421 if (m_algorithmMultiparty) { 3422 return m_algorithmMultiparty->MultipartyDecryptFusion(ciphertextVec, 3423 plaintext); 3424 } 3425 PALISADE_THROW(config_error, 3426 "MultipartyDecrypt operation has not been enabled"); 3427 } 3428 MultipartyDecryptFusion(const vector<Ciphertext<Element>> & ciphertextVec,Poly * plaintext)3429 virtual DecryptResult MultipartyDecryptFusion( 3430 const vector<Ciphertext<Element>> &ciphertextVec, Poly *plaintext) const { 3431 if (m_algorithmMultiparty) { 3432 return m_algorithmMultiparty->MultipartyDecryptFusion(ciphertextVec, 3433 plaintext); 3434 } 3435 PALISADE_THROW(config_error, 3436 "MultipartyDecrypt operation has not been enabled"); 3437 } 3438 MultiKeySwitchGen(const LPPrivateKey<Element> originalPrivateKey,const LPPrivateKey<Element> newPrivateKey,const LPEvalKey<Element> ek)3439 virtual LPEvalKey<Element> MultiKeySwitchGen( 3440 const LPPrivateKey<Element> originalPrivateKey, 3441 const LPPrivateKey<Element> newPrivateKey, 3442 const LPEvalKey<Element> ek) const { 3443 if (m_algorithmMultiparty) { 3444 if (!originalPrivateKey) 3445 PALISADE_THROW(config_error, "Input first private key is nullptr"); 3446 if (!newPrivateKey) 3447 PALISADE_THROW(config_error, "Input second private key is nullptr"); 3448 if (!ek) PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 3449 auto k = m_algorithmMultiparty->MultiKeySwitchGen(originalPrivateKey, 3450 newPrivateKey, ek); 3451 k->SetKeyTag(newPrivateKey->GetKeyTag()); 3452 return k; 3453 } 3454 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3455 } 3456 3457 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> 3458 MultiEvalAutomorphismKeyGen( 3459 const LPPrivateKey<Element> privateKey, 3460 const shared_ptr<std::map<usint, LPEvalKey<Element>>> eAuto, 3461 const std::vector<usint> &indexList, const std::string &keyId = "") { 3462 if (m_algorithmMultiparty) { 3463 if (!privateKey) 3464 PALISADE_THROW(config_error, "Input private key is nullptr"); 3465 if (!eAuto) 3466 PALISADE_THROW(config_error, "Input evaluation key map is nullptr"); 3467 if (!indexList.size()) 3468 PALISADE_THROW(config_error, "Input index vector is empty"); 3469 auto keys = m_algorithmMultiparty->MultiEvalAutomorphismKeyGen( 3470 privateKey, eAuto, indexList); 3471 for (auto it = keys->begin(); it != keys->end(); ++it) { 3472 if (it->second) { 3473 it->second->SetKeyTag(keyId); 3474 } 3475 } 3476 return keys; 3477 } 3478 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3479 } 3480 3481 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> 3482 MultiEvalAtIndexKeyGen( 3483 const LPPrivateKey<Element> privateKey, 3484 const shared_ptr<std::map<usint, LPEvalKey<Element>>> eAuto, 3485 const std::vector<int32_t> &indexList, const std::string &keyId = "") { 3486 if (m_algorithmMultiparty) { 3487 if (!privateKey) 3488 PALISADE_THROW(config_error, "Input private key is nullptr"); 3489 if (!eAuto) 3490 PALISADE_THROW(config_error, "Input evaluation key map is nullptr"); 3491 if (!indexList.size()) 3492 PALISADE_THROW(config_error, "Input index vector is empty"); 3493 auto keys = m_algorithmMultiparty->MultiEvalAtIndexKeyGen( 3494 privateKey, eAuto, indexList); 3495 for (auto it = keys->begin(); it != keys->end(); ++it) { 3496 if (it->second) { 3497 it->second->SetKeyTag(keyId); 3498 } 3499 } 3500 return keys; 3501 } 3502 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3503 } 3504 3505 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> MultiEvalSumKeyGen( 3506 const LPPrivateKey<Element> privateKey, 3507 const shared_ptr<std::map<usint, LPEvalKey<Element>>> eSum, 3508 const std::string &keyId = "") { 3509 if (m_algorithmMultiparty) { 3510 if (!privateKey) 3511 PALISADE_THROW(config_error, "Input private key is nullptr"); 3512 if (!eSum) 3513 PALISADE_THROW(config_error, "Input evaluation key map is nullptr"); 3514 auto keys = m_algorithmMultiparty->MultiEvalSumKeyGen(privateKey, eSum); 3515 for (auto it = keys->begin(); it != keys->end(); ++it) { 3516 if (it->second) { 3517 it->second->SetKeyTag(keyId); 3518 } 3519 } 3520 return keys; 3521 } 3522 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3523 } 3524 3525 virtual LPEvalKey<Element> MultiAddEvalKeys(LPEvalKey<Element> a, 3526 LPEvalKey<Element> b, 3527 const std::string &keyId = "") { 3528 if (m_algorithmMultiparty) { 3529 if (!a) 3530 PALISADE_THROW(config_error, "Input first evaluation key is nullptr"); 3531 if (!b) 3532 PALISADE_THROW(config_error, "Input second evaluation key is nullptr"); 3533 3534 auto key = m_algorithmMultiparty->MultiAddEvalKeys(a, b); 3535 key->SetKeyTag(keyId); 3536 return key; 3537 } 3538 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3539 } 3540 3541 virtual LPEvalKey<Element> MultiMultEvalKey(LPEvalKey<Element> evalKey, 3542 LPPrivateKey<Element> sk, 3543 const std::string &keyId = "") { 3544 if (m_algorithmMultiparty) { 3545 if (!evalKey) 3546 PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 3547 if (!sk) PALISADE_THROW(config_error, "Input private key is nullptr"); 3548 3549 auto key = m_algorithmMultiparty->MultiMultEvalKey(evalKey, sk); 3550 key->SetKeyTag(keyId); 3551 return key; 3552 } 3553 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3554 } 3555 3556 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> MultiAddEvalSumKeys( 3557 const shared_ptr<std::map<usint, LPEvalKey<Element>>> es1, 3558 const shared_ptr<std::map<usint, LPEvalKey<Element>>> es2, 3559 const std::string &keyId = "") { 3560 if (m_algorithmMultiparty) { 3561 if (!es1) 3562 PALISADE_THROW(config_error, 3563 "Input first evaluation key map is nullptr"); 3564 if (!es2) 3565 PALISADE_THROW(config_error, 3566 "Input second evaluation key map is nullptr"); 3567 auto keys = m_algorithmMultiparty->MultiAddEvalSumKeys(es1, es2); 3568 for (auto it = keys->begin(); it != keys->end(); ++it) { 3569 if (it->second) { 3570 it->second->SetKeyTag(keyId); 3571 } 3572 } 3573 return keys; 3574 } 3575 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3576 } 3577 3578 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> 3579 MultiAddEvalAutomorphismKeys( 3580 const shared_ptr<std::map<usint, LPEvalKey<Element>>> es1, 3581 const shared_ptr<std::map<usint, LPEvalKey<Element>>> es2, 3582 const std::string &keyId = "") { 3583 if (m_algorithmMultiparty) { 3584 if (!es1) 3585 PALISADE_THROW(config_error, 3586 "Input first evaluation key map is nullptr"); 3587 if (!es2) 3588 PALISADE_THROW(config_error, 3589 "Input second evaluation key map is nullptr"); 3590 3591 auto keys = m_algorithmMultiparty->MultiAddEvalAutomorphismKeys(es1, es2); 3592 for (auto it = keys->begin(); it != keys->end(); ++it) { 3593 if (it->second) { 3594 it->second->SetKeyTag(keyId); 3595 } 3596 } 3597 return keys; 3598 } 3599 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3600 } 3601 3602 virtual LPPublicKey<Element> MultiAddPubKeys(LPPublicKey<Element> pubKey1, 3603 LPPublicKey<Element> pubKey2, 3604 const std::string &keyId = "") { 3605 if (m_algorithmMultiparty) { 3606 if (!pubKey1) 3607 PALISADE_THROW(config_error, "Input first public key is nullptr"); 3608 if (!pubKey2) 3609 PALISADE_THROW(config_error, "Input second public key is nullptr"); 3610 3611 auto key = m_algorithmMultiparty->MultiAddPubKeys(pubKey1, pubKey2); 3612 key->SetKeyTag(keyId); 3613 return key; 3614 } 3615 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3616 } 3617 3618 virtual LPEvalKey<Element> MultiAddEvalMultKeys( 3619 LPEvalKey<Element> evalKey1, LPEvalKey<Element> evalKey2, 3620 const std::string &keyId = "") { 3621 if (m_algorithmMultiparty) { 3622 if (!evalKey1) 3623 PALISADE_THROW(config_error, "Input first evaluation key is nullptr"); 3624 if (!evalKey2) 3625 PALISADE_THROW(config_error, "Input second evaluation key is nullptr"); 3626 auto key = 3627 m_algorithmMultiparty->MultiAddEvalMultKeys(evalKey1, evalKey2); 3628 key->SetKeyTag(keyId); 3629 return key; 3630 } 3631 PALISADE_THROW(config_error, "Multiparty capability has not been enabled"); 3632 } 3633 3634 ///////////////////////////////////////// 3635 // the three functions below are wrappers for things in LPSHEAlgorithm (SHE) 3636 // 3637 AddRandomNoise(ConstCiphertext<Element> ciphertext)3638 virtual Ciphertext<Element> AddRandomNoise( 3639 ConstCiphertext<Element> ciphertext) const { 3640 if (m_algorithmSHE) { 3641 if (!ciphertext) 3642 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3643 return m_algorithmSHE->AddRandomNoise(ciphertext); 3644 } 3645 PALISADE_THROW(config_error, 3646 "AddRandomNoise operation has not been enabled"); 3647 } 3648 EvalAdd(ConstCiphertext<Element> ciphertext1,ConstCiphertext<Element> ciphertext2)3649 virtual Ciphertext<Element> EvalAdd( 3650 ConstCiphertext<Element> ciphertext1, 3651 ConstCiphertext<Element> ciphertext2) const { 3652 if (m_algorithmSHE) { 3653 if (!ciphertext1) 3654 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3655 if (!ciphertext2) 3656 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3657 return m_algorithmSHE->EvalAdd(ciphertext1, ciphertext2); 3658 } 3659 PALISADE_THROW(config_error, "EvalAdd operation has not been enabled"); 3660 } 3661 EvalAddInPlace(Ciphertext<Element> & ciphertext1,ConstCiphertext<Element> ciphertext2)3662 virtual void EvalAddInPlace(Ciphertext<Element> &ciphertext1, 3663 ConstCiphertext<Element> ciphertext2) const { 3664 if (m_algorithmSHE) { 3665 if (!ciphertext1) 3666 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3667 if (!ciphertext2) 3668 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3669 m_algorithmSHE->EvalAddInPlace(ciphertext1, ciphertext2); 3670 return; 3671 } 3672 PALISADE_THROW(config_error, 3673 "EvalAddInPlace operation has not been enabled"); 3674 } 3675 EvalAddMutable(Ciphertext<Element> & ciphertext1,Ciphertext<Element> & ciphertext2)3676 virtual Ciphertext<Element> EvalAddMutable( 3677 Ciphertext<Element> &ciphertext1, 3678 Ciphertext<Element> &ciphertext2) const { 3679 if (m_algorithmSHE) { 3680 if (!ciphertext1) 3681 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3682 if (!ciphertext2) 3683 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3684 return m_algorithmSHE->EvalAddMutable(ciphertext1, ciphertext2); 3685 } 3686 PALISADE_THROW(config_error, "EvalAdd operation has not been enabled"); 3687 } 3688 EvalAdd(ConstCiphertext<Element> ciphertext1,ConstPlaintext plaintext)3689 virtual Ciphertext<Element> EvalAdd(ConstCiphertext<Element> ciphertext1, 3690 ConstPlaintext plaintext) const { 3691 if (m_algorithmSHE) { 3692 if (!ciphertext1) 3693 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3694 if (!plaintext) 3695 PALISADE_THROW(config_error, "Input plaintext is nullptr"); 3696 return m_algorithmSHE->EvalAdd(ciphertext1, plaintext); 3697 } 3698 PALISADE_THROW(config_error, "EvalAdd operation has not been enabled"); 3699 } 3700 EvalAddMutable(Ciphertext<Element> & ciphertext1,Plaintext plaintext)3701 virtual Ciphertext<Element> EvalAddMutable(Ciphertext<Element> &ciphertext1, 3702 Plaintext plaintext) const { 3703 if (m_algorithmSHE) { 3704 if (!ciphertext1) 3705 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3706 if (!plaintext) 3707 PALISADE_THROW(config_error, "Input plaintext is nullptr"); 3708 return m_algorithmSHE->EvalAddMutable(ciphertext1, plaintext); 3709 } 3710 PALISADE_THROW(config_error, "EvalAdd operation has not been enabled"); 3711 } 3712 EvalAdd(ConstCiphertext<Element> ciphertext1,double constant)3713 virtual Ciphertext<Element> EvalAdd(ConstCiphertext<Element> ciphertext1, 3714 double constant) const { 3715 if (m_algorithmSHE) { 3716 if (!ciphertext1) 3717 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3718 return m_algorithmSHE->EvalAdd(ciphertext1, constant); 3719 } 3720 PALISADE_THROW(config_error, "EvalAdd operation has not been enabled"); 3721 } 3722 EvalLinearWSum(vector<Ciphertext<Element>> ciphertexts,vector<double> constants)3723 virtual Ciphertext<Element> EvalLinearWSum( 3724 vector<Ciphertext<Element>> ciphertexts, vector<double> constants) const { 3725 if (m_algorithmSHE) { 3726 if (!ciphertexts.size()) 3727 PALISADE_THROW(config_error, "Input ciphertext vector is empty"); 3728 return m_algorithmSHE->EvalLinearWSum(ciphertexts, constants); 3729 } 3730 PALISADE_THROW(config_error, 3731 "EvalLinearWSum operation has not been enabled"); 3732 } 3733 EvalLinearWSumMutable(vector<Ciphertext<Element>> ciphertexts,vector<double> constants)3734 virtual Ciphertext<Element> EvalLinearWSumMutable( 3735 vector<Ciphertext<Element>> ciphertexts, vector<double> constants) const { 3736 if (m_algorithmSHE) { 3737 if (!ciphertexts.size()) 3738 PALISADE_THROW(config_error, "Input ciphertext vector is empty"); 3739 return m_algorithmSHE->EvalLinearWSumMutable(ciphertexts, constants); 3740 } 3741 PALISADE_THROW(config_error, 3742 "EvalLinearWSum operation has not been enabled"); 3743 } 3744 EvalSub(ConstCiphertext<Element> ciphertext1,ConstCiphertext<Element> ciphertext2)3745 virtual Ciphertext<Element> EvalSub( 3746 ConstCiphertext<Element> ciphertext1, 3747 ConstCiphertext<Element> ciphertext2) const { 3748 if (m_algorithmSHE) { 3749 if (!ciphertext1) 3750 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3751 if (!ciphertext2) 3752 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3753 return m_algorithmSHE->EvalSub(ciphertext1, ciphertext2); 3754 } 3755 PALISADE_THROW(config_error, "EvalSub operation has not been enabled"); 3756 } 3757 EvalSubMutable(Ciphertext<Element> & ciphertext1,Ciphertext<Element> & ciphertext2)3758 virtual Ciphertext<Element> EvalSubMutable( 3759 Ciphertext<Element> &ciphertext1, 3760 Ciphertext<Element> &ciphertext2) const { 3761 if (m_algorithmSHE) { 3762 if (!ciphertext1) 3763 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3764 if (!ciphertext2) 3765 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3766 return m_algorithmSHE->EvalSubMutable(ciphertext1, ciphertext2); 3767 } 3768 PALISADE_THROW(config_error, "EvalSub operation has not been enabled"); 3769 } 3770 EvalSub(ConstCiphertext<Element> ciphertext1,ConstPlaintext plaintext)3771 virtual Ciphertext<Element> EvalSub(ConstCiphertext<Element> ciphertext1, 3772 ConstPlaintext plaintext) const { 3773 if (m_algorithmSHE) { 3774 if (!ciphertext1) 3775 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3776 if (!plaintext) 3777 PALISADE_THROW(config_error, "Input plaintext is nullptr"); 3778 return m_algorithmSHE->EvalSub(ciphertext1, plaintext); 3779 } 3780 PALISADE_THROW(config_error, "EvalSub operation has not been enabled"); 3781 } 3782 EvalSubMutable(Ciphertext<Element> & ciphertext1,Plaintext plaintext)3783 virtual Ciphertext<Element> EvalSubMutable(Ciphertext<Element> &ciphertext1, 3784 Plaintext plaintext) const { 3785 if (m_algorithmSHE) { 3786 if (!ciphertext1) 3787 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3788 if (!plaintext) 3789 PALISADE_THROW(config_error, "Input plaintext is nullptr"); 3790 return m_algorithmSHE->EvalSubMutable(ciphertext1, plaintext); 3791 } 3792 PALISADE_THROW(config_error, "EvalSub operation has not been enabled"); 3793 } 3794 EvalSub(ConstCiphertext<Element> ciphertext1,double constant)3795 virtual Ciphertext<Element> EvalSub(ConstCiphertext<Element> ciphertext1, 3796 double constant) const { 3797 if (m_algorithmSHE) { 3798 if (!ciphertext1) 3799 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3800 return m_algorithmSHE->EvalSub(ciphertext1, constant); 3801 } 3802 PALISADE_THROW(config_error, "EvalSub operation has not been enabled"); 3803 } 3804 EvalMult(ConstCiphertext<Element> ciphertext1,ConstCiphertext<Element> ciphertext2)3805 virtual Ciphertext<Element> EvalMult( 3806 ConstCiphertext<Element> ciphertext1, 3807 ConstCiphertext<Element> ciphertext2) const { 3808 if (m_algorithmSHE) { 3809 if (!ciphertext1) 3810 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3811 if (!ciphertext2) 3812 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3813 return m_algorithmSHE->EvalMult(ciphertext1, ciphertext2); 3814 } 3815 PALISADE_THROW(config_error, "EvalMult operation has not been enabled"); 3816 } 3817 EvalMultMutable(Ciphertext<Element> & ciphertext1,Ciphertext<Element> & ciphertext2)3818 virtual Ciphertext<Element> EvalMultMutable( 3819 Ciphertext<Element> &ciphertext1, 3820 Ciphertext<Element> &ciphertext2) const { 3821 if (m_algorithmSHE) { 3822 if (!ciphertext1) 3823 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3824 if (!ciphertext2) 3825 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3826 return m_algorithmSHE->EvalMultMutable(ciphertext1, ciphertext2); 3827 } 3828 PALISADE_THROW(config_error, "EvalMult operation has not been enabled"); 3829 } 3830 EvalMult(ConstCiphertext<Element> ciphertext,ConstPlaintext plaintext)3831 virtual Ciphertext<Element> EvalMult(ConstCiphertext<Element> ciphertext, 3832 ConstPlaintext plaintext) const { 3833 if (m_algorithmSHE) { 3834 if (!ciphertext) 3835 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3836 if (!plaintext) 3837 PALISADE_THROW(config_error, "Input plaintext is nullptr"); 3838 return m_algorithmSHE->EvalMult(ciphertext, plaintext); 3839 } 3840 PALISADE_THROW(config_error, "EvalMult operation has not been enabled"); 3841 } 3842 EvalMultMutable(Ciphertext<Element> & ciphertext,Plaintext plaintext)3843 virtual Ciphertext<Element> EvalMultMutable(Ciphertext<Element> &ciphertext, 3844 Plaintext plaintext) const { 3845 if (m_algorithmSHE) { 3846 if (!ciphertext) 3847 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3848 if (!plaintext) 3849 PALISADE_THROW(config_error, "Input plaintext is nullptr"); 3850 return m_algorithmSHE->EvalMultMutable(ciphertext, plaintext); 3851 } 3852 PALISADE_THROW(config_error, "EvalMult operation has not been enabled"); 3853 } 3854 EvalMult(ConstCiphertext<Element> ciphertext1,double constant)3855 virtual Ciphertext<Element> EvalMult(ConstCiphertext<Element> ciphertext1, 3856 double constant) const { 3857 if (m_algorithmSHE) { 3858 if (!ciphertext1) 3859 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3860 return m_algorithmSHE->EvalMult(ciphertext1, constant); 3861 } 3862 PALISADE_THROW(config_error, "EvalMult operation has not been enabled"); 3863 } 3864 EvalMultMutable(Ciphertext<Element> & ciphertext1,double constant)3865 virtual Ciphertext<Element> EvalMultMutable(Ciphertext<Element> &ciphertext1, 3866 double constant) const { 3867 if (m_algorithmSHE) { 3868 if (!ciphertext1) 3869 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3870 return m_algorithmSHE->EvalMultMutable(ciphertext1, constant); 3871 } 3872 PALISADE_THROW(config_error, "EvalMult operation has not been enabled"); 3873 } 3874 EvalMult(ConstCiphertext<Element> ciphertext1,ConstCiphertext<Element> ciphertext2,const LPEvalKey<Element> evalKey)3875 virtual Ciphertext<Element> EvalMult(ConstCiphertext<Element> ciphertext1, 3876 ConstCiphertext<Element> ciphertext2, 3877 const LPEvalKey<Element> evalKey) const { 3878 if (m_algorithmSHE) { 3879 if (!ciphertext1) 3880 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3881 if (!ciphertext2) 3882 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3883 if (!evalKey) 3884 PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 3885 return m_algorithmSHE->EvalMult(ciphertext1, ciphertext2, evalKey); 3886 } 3887 PALISADE_THROW(config_error, "EvalMult operation has not been enabled"); 3888 } 3889 EvalMultMutable(Ciphertext<Element> & ciphertext1,Ciphertext<Element> & ciphertext2,const LPEvalKey<Element> evalKey)3890 virtual Ciphertext<Element> EvalMultMutable( 3891 Ciphertext<Element> &ciphertext1, Ciphertext<Element> &ciphertext2, 3892 const LPEvalKey<Element> evalKey) const { 3893 if (m_algorithmSHE) { 3894 if (!ciphertext1) 3895 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 3896 if (!ciphertext2) 3897 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 3898 if (!evalKey) 3899 PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 3900 auto ct = 3901 m_algorithmSHE->EvalMultMutable(ciphertext1, ciphertext2, evalKey); 3902 return ct; 3903 } 3904 PALISADE_THROW(config_error, "EvalMult operation has not been enabled"); 3905 } 3906 EvalMultMany(const vector<Ciphertext<Element>> & ciphertext,const vector<LPEvalKey<Element>> & evalKeys)3907 virtual Ciphertext<Element> EvalMultMany( 3908 const vector<Ciphertext<Element>> &ciphertext, 3909 const vector<LPEvalKey<Element>> &evalKeys) const { 3910 if (m_algorithmSHE) { 3911 if (!ciphertext.size()) 3912 PALISADE_THROW(config_error, "Input ciphertext vector is empty"); 3913 if (!evalKeys.size()) 3914 PALISADE_THROW(config_error, "Input evaluation key vector is empty"); 3915 return m_algorithmSHE->EvalMultMany(ciphertext, evalKeys); 3916 } 3917 PALISADE_THROW(config_error, "EvalMultMany operation has not been enabled"); 3918 } 3919 EvalAddMany(const vector<Ciphertext<Element>> & ciphertexts)3920 virtual Ciphertext<Element> EvalAddMany( 3921 const vector<Ciphertext<Element>> &ciphertexts) const { 3922 if (m_algorithmSHE) { 3923 if (!ciphertexts.size()) 3924 PALISADE_THROW(config_error, "Input ciphertext vector is empty"); 3925 return m_algorithmSHE->EvalAddMany(ciphertexts); 3926 } 3927 PALISADE_THROW(config_error, "EvalAddMany operation has not been enabled"); 3928 } 3929 EvalAddManyInPlace(vector<Ciphertext<Element>> & ciphertexts)3930 virtual Ciphertext<Element> EvalAddManyInPlace( 3931 vector<Ciphertext<Element>> &ciphertexts) const { 3932 if (m_algorithmSHE) { 3933 if (!ciphertexts.size()) 3934 PALISADE_THROW(config_error, "Input ciphertext vector is empty"); 3935 return m_algorithmSHE->EvalAddManyInPlace(ciphertexts); 3936 } 3937 PALISADE_THROW(config_error, 3938 "EvalAddManyInPlace operation has not been enabled"); 3939 } 3940 EvalNegate(ConstCiphertext<Element> ciphertext)3941 virtual Ciphertext<Element> EvalNegate( 3942 ConstCiphertext<Element> ciphertext) const { 3943 if (m_algorithmSHE) { 3944 if (!ciphertext) 3945 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3946 auto ct = m_algorithmSHE->EvalNegate(ciphertext); 3947 return ct; 3948 } 3949 PALISADE_THROW(config_error, "EvalNegate operation has not been enabled"); 3950 } 3951 3952 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalAutomorphismKeyGen(const LPPublicKey<Element> publicKey,const LPPrivateKey<Element> origPrivateKey,const std::vector<usint> & indexList)3953 EvalAutomorphismKeyGen(const LPPublicKey<Element> publicKey, 3954 const LPPrivateKey<Element> origPrivateKey, 3955 const std::vector<usint> &indexList) const { 3956 if (m_algorithmSHE) { 3957 if (!publicKey) 3958 PALISADE_THROW(config_error, "Input public key is nullptr"); 3959 if (!origPrivateKey) 3960 PALISADE_THROW(config_error, "Input private key is nullptr"); 3961 auto km = m_algorithmSHE->EvalAutomorphismKeyGen( 3962 publicKey, origPrivateKey, indexList); 3963 for (auto &k : *km) k.second->SetKeyTag(origPrivateKey->GetKeyTag()); 3964 return km; 3965 } 3966 PALISADE_THROW(config_error, 3967 "EvalAutomorphismKeyGen operation has not been enabled"); 3968 } 3969 EvalAtIndexKeyGen(const LPPublicKey<Element> publicKey,const LPPrivateKey<Element> origPrivateKey,const std::vector<int32_t> & indexList)3970 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalAtIndexKeyGen( 3971 const LPPublicKey<Element> publicKey, 3972 const LPPrivateKey<Element> origPrivateKey, 3973 const std::vector<int32_t> &indexList) const { 3974 if (m_algorithmSHE) { 3975 if (!origPrivateKey) 3976 PALISADE_THROW(config_error, "Input private key is nullptr"); 3977 auto km = m_algorithmSHE->EvalAtIndexKeyGen(publicKey, origPrivateKey, 3978 indexList); 3979 for (auto &k : *km) k.second->SetKeyTag(origPrivateKey->GetKeyTag()); 3980 return km; 3981 } 3982 PALISADE_THROW(config_error, 3983 "EvalAtIndexKeyGen operation has not been enabled"); 3984 } 3985 EvalAutomorphism(ConstCiphertext<Element> ciphertext,usint i,const std::map<usint,LPEvalKey<Element>> & evalKeys,CALLER_INFO_ARGS_HDR)3986 virtual Ciphertext<Element> EvalAutomorphism( 3987 ConstCiphertext<Element> ciphertext, usint i, 3988 const std::map<usint, LPEvalKey<Element>> &evalKeys, 3989 CALLER_INFO_ARGS_HDR) const { 3990 if (m_algorithmSHE) { 3991 if (!ciphertext) 3992 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 3993 if (!evalKeys.size()) 3994 PALISADE_THROW(config_error, "Input evaluation key map is empty"); 3995 auto ct = m_algorithmSHE->EvalAutomorphism(ciphertext, i, evalKeys); 3996 return ct; 3997 } 3998 std::string errorMsg( 3999 std::string("EvalAutomorphism operation has not been enabled") + 4000 CALLER_INFO); 4001 PALISADE_THROW(config_error, errorMsg); 4002 } 4003 EvalAtIndex(ConstCiphertext<Element> ciphertext,usint i,const std::map<usint,LPEvalKey<Element>> & evalKeys)4004 virtual Ciphertext<Element> EvalAtIndex( 4005 ConstCiphertext<Element> ciphertext, usint i, 4006 const std::map<usint, LPEvalKey<Element>> &evalKeys) const { 4007 if (m_algorithmSHE) { 4008 if (!ciphertext) 4009 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4010 if (!evalKeys.size()) 4011 PALISADE_THROW(config_error, "Input evaluation key map is empty"); 4012 auto ct = m_algorithmSHE->EvalAtIndex(ciphertext, i, evalKeys); 4013 return ct; 4014 } 4015 PALISADE_THROW(config_error, "EvalAtIndex operation has not been enabled"); 4016 } 4017 EvalFastRotationPrecompute(ConstCiphertext<Element> ciphertext)4018 virtual shared_ptr<vector<Element>> EvalFastRotationPrecompute( 4019 ConstCiphertext<Element> ciphertext) const { 4020 if (m_algorithmSHE) { 4021 if (!ciphertext) 4022 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4023 auto ct = m_algorithmSHE->EvalFastRotationPrecompute(ciphertext); 4024 return ct; 4025 } 4026 PALISADE_THROW(config_error, 4027 "EvalFastRotationPrecompute operation has not been enabled"); 4028 } 4029 EvalFastRotation(ConstCiphertext<Element> ciphertext,const usint index,const usint m,const shared_ptr<vector<Element>> digits)4030 virtual Ciphertext<Element> EvalFastRotation( 4031 ConstCiphertext<Element> ciphertext, const usint index, const usint m, 4032 const shared_ptr<vector<Element>> digits) const { 4033 if (m_algorithmSHE) { 4034 if (!ciphertext) 4035 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4036 auto ct = m_algorithmSHE->EvalFastRotation(ciphertext, index, m, digits); 4037 return ct; 4038 } 4039 PALISADE_THROW(config_error, 4040 "EvalFastRotation operation has not been enabled"); 4041 } 4042 4043 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalAutomorphismKeyGen(const LPPrivateKey<Element> privateKey,const std::vector<usint> & indexList)4044 EvalAutomorphismKeyGen(const LPPrivateKey<Element> privateKey, 4045 const std::vector<usint> &indexList) const { 4046 if (m_algorithmSHE) { 4047 if (!privateKey) 4048 PALISADE_THROW(config_error, "Input private key is nullptr"); 4049 auto km = m_algorithmSHE->EvalAutomorphismKeyGen(privateKey, indexList); 4050 for (auto &k : *km) k.second->SetKeyTag(privateKey->GetKeyTag()); 4051 return km; 4052 } 4053 PALISADE_THROW(config_error, 4054 "EvalAutomorphismKeyGen operation has not been enabled"); 4055 } 4056 EvalSumKeyGen(const LPPrivateKey<Element> privateKey,const LPPublicKey<Element> publicKey)4057 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalSumKeyGen( 4058 const LPPrivateKey<Element> privateKey, 4059 const LPPublicKey<Element> publicKey) const { 4060 if (m_algorithmSHE) { 4061 if (!privateKey) 4062 PALISADE_THROW(config_error, "Input private key is nullptr"); 4063 auto km = m_algorithmSHE->EvalSumKeyGen(privateKey, publicKey); 4064 for (auto &k : *km) { 4065 k.second->SetKeyTag(privateKey->GetKeyTag()); 4066 } 4067 return km; 4068 } 4069 PALISADE_THROW(config_error, 4070 "EvalSumKeyGen operation has not been enabled"); 4071 } 4072 4073 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalSumRowsKeyGen( 4074 const LPPrivateKey<Element> privateKey, 4075 const LPPublicKey<Element> publicKey, usint rowSize, 4076 usint subringDim = 0) const { 4077 if (m_algorithmSHE) { 4078 if (!privateKey) 4079 PALISADE_THROW(config_error, "Input private key is nullptr"); 4080 auto km = m_algorithmSHE->EvalSumRowsKeyGen(privateKey, publicKey, 4081 rowSize, subringDim); 4082 for (auto &k : *km) { 4083 k.second->SetKeyTag(privateKey->GetKeyTag()); 4084 } 4085 return km; 4086 } 4087 PALISADE_THROW(config_error, 4088 "EvalSumRowsKeyGen operation has not been enabled"); 4089 } 4090 EvalSumColsKeyGen(const LPPrivateKey<Element> privateKey,const LPPublicKey<Element> publicKey)4091 virtual shared_ptr<std::map<usint, LPEvalKey<Element>>> EvalSumColsKeyGen( 4092 const LPPrivateKey<Element> privateKey, 4093 const LPPublicKey<Element> publicKey) const { 4094 if (m_algorithmSHE) { 4095 if (!privateKey) 4096 PALISADE_THROW(config_error, "Input private key is nullptr"); 4097 auto km = m_algorithmSHE->EvalSumColsKeyGen(privateKey, publicKey); 4098 for (auto &k : *km) { 4099 k.second->SetKeyTag(privateKey->GetKeyTag()); 4100 } 4101 return km; 4102 } 4103 PALISADE_THROW(config_error, 4104 "EvalSumColsKeyGen operation has not been enabled"); 4105 } 4106 EvalSum(ConstCiphertext<Element> ciphertext,usint batchSize,const std::map<usint,LPEvalKey<Element>> & evalKeys)4107 virtual Ciphertext<Element> EvalSum( 4108 ConstCiphertext<Element> ciphertext, usint batchSize, 4109 const std::map<usint, LPEvalKey<Element>> &evalKeys) const { 4110 if (m_algorithmSHE) { 4111 if (!ciphertext) 4112 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4113 if (!evalKeys.size()) 4114 PALISADE_THROW(config_error, "Input evaluation key map is empty"); 4115 auto ct = m_algorithmSHE->EvalSum(ciphertext, batchSize, evalKeys); 4116 return ct; 4117 } 4118 PALISADE_THROW(config_error, "EvalSum operation has not been enabled"); 4119 } 4120 4121 virtual Ciphertext<Element> EvalSumRows( 4122 ConstCiphertext<Element> ciphertext, usint rowSize, 4123 const std::map<usint, LPEvalKey<Element>> &evalKeys, 4124 usint subringDim = 0) const { 4125 if (m_algorithmSHE) { 4126 if (!ciphertext) 4127 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4128 if (!evalKeys.size()) 4129 PALISADE_THROW(config_error, "Input evaluation key map is empty"); 4130 auto ct = m_algorithmSHE->EvalSumRows(ciphertext, rowSize, evalKeys, 4131 subringDim); 4132 return ct; 4133 } 4134 PALISADE_THROW(config_error, "EvalSumRow operation has not been enabled"); 4135 } 4136 EvalSumCols(ConstCiphertext<Element> ciphertext,usint batchSize,const std::map<usint,LPEvalKey<Element>> & evalKeys,const std::map<usint,LPEvalKey<Element>> & rightEvalKeys)4137 virtual Ciphertext<Element> EvalSumCols( 4138 ConstCiphertext<Element> ciphertext, usint batchSize, 4139 const std::map<usint, LPEvalKey<Element>> &evalKeys, 4140 const std::map<usint, LPEvalKey<Element>> &rightEvalKeys) const { 4141 if (m_algorithmSHE) { 4142 if (!evalKeys.size()) 4143 PALISADE_THROW(config_error, "Input first evaluation key map is empty"); 4144 if (!rightEvalKeys.size()) 4145 PALISADE_THROW(config_error, 4146 "Input second evaluation key map is empty"); 4147 auto ct = m_algorithmSHE->EvalSumCols(ciphertext, batchSize, evalKeys, 4148 rightEvalKeys); 4149 return ct; 4150 } 4151 PALISADE_THROW(config_error, "EvalSumCols operation has not been enabled"); 4152 } 4153 EvalInnerProduct(ConstCiphertext<Element> ciphertext1,ConstCiphertext<Element> ciphertext2,usint batchSize,const std::map<usint,LPEvalKey<Element>> & evalSumKeys,const LPEvalKey<Element> evalMultKey)4154 virtual Ciphertext<Element> EvalInnerProduct( 4155 ConstCiphertext<Element> ciphertext1, 4156 ConstCiphertext<Element> ciphertext2, usint batchSize, 4157 const std::map<usint, LPEvalKey<Element>> &evalSumKeys, 4158 const LPEvalKey<Element> evalMultKey) const { 4159 if (m_algorithmSHE) { 4160 if (!ciphertext1) 4161 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 4162 if (!ciphertext2) 4163 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 4164 if (!evalSumKeys.size()) 4165 PALISADE_THROW(config_error, "Input evaluation key map is empty"); 4166 if (!evalMultKey) 4167 PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 4168 auto ct = m_algorithmSHE->EvalInnerProduct( 4169 ciphertext1, ciphertext2, batchSize, evalSumKeys, evalMultKey); 4170 ct->SetKeyTag(evalSumKeys.begin()->second->GetKeyTag()); 4171 return ct; 4172 } 4173 PALISADE_THROW(config_error, 4174 "EvalInnerProduct operation has not been enabled"); 4175 } 4176 EvalMerge(const vector<Ciphertext<Element>> & ciphertextVector,const std::map<usint,LPEvalKey<Element>> & evalKeys)4177 virtual Ciphertext<Element> EvalMerge( 4178 const vector<Ciphertext<Element>> &ciphertextVector, 4179 const std::map<usint, LPEvalKey<Element>> &evalKeys) const { 4180 if (m_algorithmSHE) { 4181 if (!ciphertextVector.size()) 4182 PALISADE_THROW(config_error, "Input ciphertext vector is empty"); 4183 if (!evalKeys.size()) 4184 PALISADE_THROW(config_error, "Input evaluation key map is empty"); 4185 return m_algorithmSHE->EvalMerge(ciphertextVector, evalKeys); 4186 } 4187 PALISADE_THROW(config_error, "EvalMerge operation has not been enabled"); 4188 } 4189 EvalInnerProduct(ConstCiphertext<Element> ciphertext1,ConstPlaintext plaintext,usint batchSize,const std::map<usint,LPEvalKey<Element>> & evalSumKeys)4190 virtual Ciphertext<Element> EvalInnerProduct( 4191 ConstCiphertext<Element> ciphertext1, ConstPlaintext plaintext, 4192 usint batchSize, 4193 const std::map<usint, LPEvalKey<Element>> &evalSumKeys) const { 4194 if (m_algorithmSHE) { 4195 if (!ciphertext1) 4196 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 4197 if (!plaintext) 4198 PALISADE_THROW(config_error, "Input plaintext is nullptr"); 4199 if (!evalSumKeys.size()) 4200 PALISADE_THROW(config_error, "Input evaluation key map is empty"); 4201 return m_algorithmSHE->EvalInnerProduct(ciphertext1, plaintext, batchSize, 4202 evalSumKeys); 4203 } 4204 PALISADE_THROW(config_error, 4205 "EvalInnerProduct operation has not been enabled"); 4206 } 4207 KeySwitchGen(const LPPrivateKey<Element> originalPrivateKey,const LPPrivateKey<Element> newPrivateKey)4208 virtual LPEvalKey<Element> KeySwitchGen( 4209 const LPPrivateKey<Element> originalPrivateKey, 4210 const LPPrivateKey<Element> newPrivateKey) const { 4211 if (m_algorithmSHE) { 4212 if (!originalPrivateKey) 4213 PALISADE_THROW(config_error, "Input first private key is nullptr"); 4214 if (!newPrivateKey) 4215 PALISADE_THROW(config_error, "Input second private key is nullptr"); 4216 auto kp = m_algorithmSHE->KeySwitchGen(originalPrivateKey, newPrivateKey); 4217 kp->SetKeyTag(newPrivateKey->GetKeyTag()); 4218 return kp; 4219 } 4220 PALISADE_THROW(config_error, "KeySwitchGen operation has not been enabled"); 4221 } 4222 KeySwitch(const LPEvalKey<Element> keySwitchHint,ConstCiphertext<Element> cipherText)4223 virtual Ciphertext<Element> KeySwitch( 4224 const LPEvalKey<Element> keySwitchHint, 4225 ConstCiphertext<Element> cipherText) const { 4226 if (m_algorithmSHE) { 4227 if (!keySwitchHint) 4228 PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 4229 if (!cipherText) 4230 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4231 auto ct = m_algorithmSHE->KeySwitch(keySwitchHint, cipherText); 4232 return ct; 4233 } 4234 PALISADE_THROW(config_error, "KeySwitch operation has not been enabled"); 4235 } 4236 KeySwitchInPlace(const LPEvalKey<Element> keySwitchHint,Ciphertext<Element> & cipherText)4237 virtual void KeySwitchInPlace(const LPEvalKey<Element> keySwitchHint, 4238 Ciphertext<Element> &cipherText) const { 4239 if (m_algorithmSHE) { 4240 if (!keySwitchHint) 4241 PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 4242 if (!cipherText) 4243 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4244 m_algorithmSHE->KeySwitchInPlace(keySwitchHint, cipherText); 4245 return; 4246 } 4247 PALISADE_THROW(config_error, 4248 "KeySwitchInPlace operation has not been enabled"); 4249 } 4250 EvalMultKeyGen(const LPPrivateKey<Element> originalPrivateKey)4251 virtual LPEvalKey<Element> EvalMultKeyGen( 4252 const LPPrivateKey<Element> originalPrivateKey) const { 4253 if (m_algorithmSHE) { 4254 if (!originalPrivateKey) 4255 PALISADE_THROW(config_error, "Input private key is nullptr"); 4256 auto ek = m_algorithmSHE->EvalMultKeyGen(originalPrivateKey); 4257 ek->SetKeyTag(originalPrivateKey->GetKeyTag()); 4258 return ek; 4259 } 4260 PALISADE_THROW(config_error, 4261 "EvalMultKeyGen operation has not been enabled"); 4262 } 4263 EvalMultKeysGen(const LPPrivateKey<Element> originalPrivateKey)4264 virtual vector<LPEvalKey<Element>> EvalMultKeysGen( 4265 const LPPrivateKey<Element> originalPrivateKey) const { 4266 if (m_algorithmSHE) { 4267 if (!originalPrivateKey) 4268 PALISADE_THROW(config_error, "Input private key is nullptr"); 4269 auto ek = m_algorithmSHE->EvalMultKeysGen(originalPrivateKey); 4270 for (size_t i = 0; i < ek.size(); i++) 4271 ek[i]->SetKeyTag(originalPrivateKey->GetKeyTag()); 4272 return ek; 4273 } 4274 PALISADE_THROW(config_error, 4275 "EvalMultKeysGen operation has not been enabled"); 4276 } 4277 EvalMultAndRelinearize(ConstCiphertext<Element> ct1,ConstCiphertext<Element> ct2,const vector<LPEvalKey<Element>> & ek)4278 virtual Ciphertext<Element> EvalMultAndRelinearize( 4279 ConstCiphertext<Element> ct1, ConstCiphertext<Element> ct2, 4280 const vector<LPEvalKey<Element>> &ek) const { 4281 if (m_algorithmSHE) { 4282 if (!ct1) 4283 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 4284 if (!ct2) 4285 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 4286 if (!ek.size()) 4287 PALISADE_THROW(config_error, "Input evaluation key vector is empty"); 4288 return m_algorithmSHE->EvalMultAndRelinearize(ct1, ct2, ek); 4289 } 4290 PALISADE_THROW(config_error, 4291 "EvalMultAndRelinearize operation has not been enabled"); 4292 } 4293 Relinearize(ConstCiphertext<Element> ciphertext,const vector<LPEvalKey<Element>> & ek)4294 virtual Ciphertext<Element> Relinearize( 4295 ConstCiphertext<Element> ciphertext, 4296 const vector<LPEvalKey<Element>> &ek) const { 4297 if (m_algorithmSHE) { 4298 if (!ciphertext) 4299 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4300 if (!ek.size()) 4301 PALISADE_THROW(config_error, "Input evaluation key vector is empty"); 4302 return m_algorithmSHE->Relinearize(ciphertext, ek); 4303 } 4304 PALISADE_THROW(config_error, "Relinearize operation has not been enabled"); 4305 } 4306 RelinearizeInPlace(Ciphertext<Element> & ciphertext,const vector<LPEvalKey<Element>> & ek)4307 virtual void RelinearizeInPlace( 4308 Ciphertext<Element> &ciphertext, 4309 const vector<LPEvalKey<Element>> &ek) const { 4310 if (m_algorithmSHE) { 4311 if (!ciphertext) 4312 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4313 if (!ek.size()) 4314 PALISADE_THROW(config_error, "Input evaluation key vector is empty"); 4315 return m_algorithmSHE->RelinearizeInPlace(ciphertext, ek); 4316 } 4317 PALISADE_THROW(config_error, "RelinearizeInPlace operation has not been enabled"); 4318 } 4319 4320 ///////////////////////////////////////// 4321 // the functions below are wrappers for things in LPFHEAlgorithm (FHE) 4322 // 4323 // TODO: Add Bootstrap and any other FHE methods 4324 4325 ///////////////////////////////////////// 4326 // the functions below are wrappers for things in LPSHEAlgorithm (SHE) 4327 // 4328 4329 virtual Ciphertext<Element> ModReduce(ConstCiphertext<Element> cipherText, 4330 size_t levels = 1) const { 4331 if (m_algorithmLeveledSHE) { 4332 if (!cipherText) 4333 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4334 auto ct = m_algorithmLeveledSHE->ModReduce(cipherText, levels); 4335 ct->SetKeyTag(cipherText->GetKeyTag()); 4336 return ct; 4337 } 4338 PALISADE_THROW(config_error, "ModReduce operation has not been enabled"); 4339 } 4340 4341 virtual void ModReduceInPlace(Ciphertext<Element> &cipherText, 4342 size_t levels = 1) const { 4343 if (m_algorithmLeveledSHE) { 4344 if (!cipherText) 4345 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4346 m_algorithmLeveledSHE->ModReduceInPlace(cipherText, levels); 4347 return; 4348 } 4349 PALISADE_THROW(config_error, "ModReduce operation has not been enabled"); 4350 } 4351 ComposedEvalMult(ConstCiphertext<Element> cipherText1,ConstCiphertext<Element> cipherText2,const LPEvalKey<Element> quadKeySwitchHint)4352 virtual Ciphertext<Element> ComposedEvalMult( 4353 ConstCiphertext<Element> cipherText1, 4354 ConstCiphertext<Element> cipherText2, 4355 const LPEvalKey<Element> quadKeySwitchHint) const { 4356 if (m_algorithmLeveledSHE) { 4357 if (!cipherText1) 4358 PALISADE_THROW(config_error, "Input first ciphertext is nullptr"); 4359 if (!cipherText2) 4360 PALISADE_THROW(config_error, "Input second ciphertext is nullptr"); 4361 if (!quadKeySwitchHint) 4362 PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 4363 auto ct = m_algorithmLeveledSHE->ComposedEvalMult( 4364 cipherText1, cipherText2, quadKeySwitchHint); 4365 ct->SetKeyTag(quadKeySwitchHint->GetKeyTag()); 4366 return ct; 4367 } 4368 PALISADE_THROW(config_error, 4369 "ComposedEvalMult operation has not been enabled"); 4370 } 4371 4372 virtual Ciphertext<Element> LevelReduce( 4373 ConstCiphertext<Element> cipherText1, 4374 const LPEvalKey<Element> linearKeySwitchHint, size_t levels = 1) const { 4375 if (m_algorithmLeveledSHE) { 4376 if (!cipherText1) 4377 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4378 // if (!linearKeySwitchHint) 4379 // PALISADE_THROW(config_error, "Input evaluation key is nullptr"); 4380 auto ct = m_algorithmLeveledSHE->LevelReduce(cipherText1, 4381 linearKeySwitchHint, levels); 4382 ct->SetKeyTag(cipherText1->GetKeyTag()); 4383 return ct; 4384 } 4385 PALISADE_THROW(config_error, "LevelReduce operation has not been enabled"); 4386 } 4387 4388 /** 4389 * Method for polynomial evaluation for polynomials represented as power 4390 * series. 4391 * 4392 * @param &cipherText input ciphertext 4393 * @param &coefficients is the vector of coefficients in the polynomial; the 4394 * size of the vector is the degree of the polynomial + 1 4395 * @return the result of polynomial evaluation. 4396 */ EvalPoly(ConstCiphertext<Element> ciphertext,const std::vector<double> & coefficients)4397 Ciphertext<Element> EvalPoly(ConstCiphertext<Element> ciphertext, 4398 const std::vector<double> &coefficients) const { 4399 if (this->m_algorithmLeveledSHE) { 4400 if (!ciphertext) 4401 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4402 auto ctm = 4403 this->m_algorithmLeveledSHE->EvalPoly(ciphertext, coefficients); 4404 return ctm; 4405 } else { 4406 PALISADE_THROW(config_error, "EvalPoly operation has not been enabled"); 4407 } 4408 } 4409 4410 /* 4411 * This exposes CKKS's own ParamsGen through the 4412 * LPPublicKeyEncryptionSchemeCKKS API. See 4413 * LPAlgorithmParamsGenCKKS::ParamsGen for a description of the arguments. 4414 * 4415 */ ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams,usint cyclOrder,usint numPrimes,usint scaleExp,usint relinWindow,MODE mode,enum KeySwitchTechnique ksTech,usint firstModSize,RescalingTechnique rsTech,uint32_t numLargeDigits)4416 virtual bool ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams, 4417 usint cyclOrder, usint numPrimes, usint scaleExp, 4418 usint relinWindow, MODE mode, 4419 enum KeySwitchTechnique ksTech, usint firstModSize, 4420 RescalingTechnique rsTech, 4421 uint32_t numLargeDigits) const { 4422 if (m_algorithmParamsGen) { 4423 return m_algorithmParamsGen->ParamsGen( 4424 cryptoParams, cyclOrder, numPrimes, scaleExp, relinWindow, mode, 4425 ksTech, firstModSize, rsTech, numLargeDigits); 4426 } 4427 PALISADE_THROW(not_implemented_error, 4428 "Parameter generation operation has not been implemented " 4429 "for this scheme."); 4430 } 4431 4432 /* 4433 * This exposes BGVrns own ParamsGen through the 4434 * LPPublicKeyEncryptionSchemeBGVrns API. See 4435 * LPAlgorithmParamsGenBGVrns::ParamsGen for a description of the arguments. 4436 * 4437 */ ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams,usint cyclOrder,usint ptm,usint numPrimes,usint relinWindow,MODE mode,enum KeySwitchTechnique ksTech,usint firstModSize,usint dcrtBits,uint32_t numLargeDigits)4438 virtual bool ParamsGen(shared_ptr<LPCryptoParameters<Element>> cryptoParams, 4439 usint cyclOrder, usint ptm, usint numPrimes, 4440 usint relinWindow, MODE mode, 4441 enum KeySwitchTechnique ksTech, usint firstModSize, 4442 usint dcrtBits, uint32_t numLargeDigits) const { 4443 if (m_algorithmParamsGen) { 4444 return m_algorithmParamsGen->ParamsGen( 4445 cryptoParams, cyclOrder, ptm, numPrimes, relinWindow, mode, ksTech, 4446 firstModSize, dcrtBits, numLargeDigits); 4447 } 4448 PALISADE_THROW( 4449 not_implemented_error, 4450 "Parameter generation operation has not been implemented for this " 4451 "scheme."); 4452 } 4453 4454 /* 4455 * Internal method performing level reduce (drop towers). 4456 * It's exposed here so methods in LPAlgorithmSHECKKS can access methods 4457 * from LPLeveledSHEAlgorithmCKKS (so that automatic rescaling can work 4458 * in EXACTRESCALE). 4459 * 4460 * @param cipherText1 input ciphertext 4461 * @param linearKeySwitchHint not used in the CKKS scheme. 4462 * @param levels the number of towers to drop from the input ciphertext 4463 * @return a ciphertext of the same plaintext value as that of the input, 4464 * but with fewer towers. 4465 * 4466 */ LevelReduceInternal(ConstCiphertext<Element> cipherText1,const LPEvalKey<Element> linearKeySwitchHint,size_t levels)4467 virtual Ciphertext<Element> LevelReduceInternal( 4468 ConstCiphertext<Element> cipherText1, 4469 const LPEvalKey<Element> linearKeySwitchHint, size_t levels) const { 4470 if (m_algorithmLeveledSHE) { 4471 if (!cipherText1) 4472 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4473 return m_algorithmLeveledSHE->LevelReduceInternal( 4474 cipherText1, linearKeySwitchHint, levels); 4475 } 4476 PALISADE_THROW(not_implemented_error, 4477 "LevelReduceInternal has not been enabled for this scheme."); 4478 } 4479 4480 /* 4481 * Internal method performing in-place level reduce (drop towers). 4482 * It's exposed here so methods in LPAlgorithmSHECKKS can access methods 4483 * from LPLeveledSHEAlgorithmCKKS (so that automatic rescaling can work 4484 * in EXACTRESCALE). 4485 * 4486 * @param cipherText1 input/output ciphertext 4487 * @param linearKeySwitchHint not used in the CKKS scheme. 4488 * @param levels the number of towers to drop from the input ciphertext 4489 * @return a ciphertext of the same plaintext value as that of the input, 4490 * but with fewer towers. 4491 * 4492 */ LevelReduceInternalInPlace(Ciphertext<Element> & cipherText1,const LPEvalKey<Element> linearKeySwitchHint,size_t levels)4493 virtual void LevelReduceInternalInPlace( 4494 Ciphertext<Element> &cipherText1, 4495 const LPEvalKey<Element> linearKeySwitchHint, size_t levels) const { 4496 if (m_algorithmLeveledSHE) { 4497 if (!cipherText1) 4498 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4499 m_algorithmLeveledSHE->LevelReduceInternalInPlace( 4500 cipherText1, linearKeySwitchHint, levels); 4501 return; 4502 } 4503 PALISADE_THROW( 4504 not_implemented_error, 4505 "LevelReduceInternalInPlace has not been enabled for this scheme."); 4506 } 4507 4508 /* 4509 * Internal method performing mod reduce (rescaling). 4510 * It's exposed here so methods in LPAlgorithmSHECKKS can access the method 4511 * from LPLeveledSHEAlgorithmCKKS (so that automatic rescaling can work 4512 * in EXACTRESCALE). 4513 * 4514 * @param cipherText1 input ciphertext 4515 * @return the rescaled ciphertext. 4516 * 4517 */ 4518 virtual Ciphertext<Element> ModReduceInternal( 4519 ConstCiphertext<Element> cipherText, size_t levels = 1) const { 4520 if (m_algorithmLeveledSHE) { 4521 if (!cipherText) 4522 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4523 return m_algorithmLeveledSHE->ModReduceInternal(cipherText, levels); 4524 } 4525 PALISADE_THROW(config_error, 4526 "ModReduceInternal has not been enabled for this scheme."); 4527 } 4528 4529 virtual void ModReduceInternalInPlace(Ciphertext<Element> &cipherText, 4530 size_t levels = 1) const { 4531 if (m_algorithmLeveledSHE) { 4532 if (!cipherText) 4533 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4534 m_algorithmLeveledSHE->ModReduceInternalInPlace(cipherText, levels); 4535 return; 4536 } 4537 PALISADE_THROW( 4538 config_error, 4539 "ModReduceInternalInPlace has not been enabled for this scheme."); 4540 } 4541 4542 virtual Ciphertext<Element> Compress(ConstCiphertext<Element> cipherText, 4543 size_t towersLeft = 1) const { 4544 if (m_algorithmLeveledSHE) { 4545 if (!cipherText) 4546 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4547 return m_algorithmLeveledSHE->Compress(cipherText, towersLeft); 4548 } 4549 PALISADE_THROW(config_error, 4550 "Compress has not been enabled for this scheme."); 4551 } 4552 AdjustLevelWithRescale(Ciphertext<Element> cipherText,uint32_t targetLevel)4553 virtual Ciphertext<Element> AdjustLevelWithRescale( 4554 Ciphertext<Element> cipherText, uint32_t targetLevel) const { 4555 if (m_algorithmSHE) { 4556 if (!cipherText) 4557 PALISADE_THROW(config_error, "Input ciphertext is nullptr"); 4558 return m_algorithmSHE->AdjustLevelWithRescale(cipherText, targetLevel); 4559 } 4560 PALISADE_THROW( 4561 config_error, 4562 "AdjustLevelWithRescale has not been enabled for this scheme."); 4563 } 4564 getAlgorithm()4565 const std::shared_ptr<LPEncryptionAlgorithm<Element>> getAlgorithm() const { 4566 return m_algorithmEncryption; 4567 } 4568 4569 template <class Archive> save(Archive & ar,std::uint32_t const version)4570 void save(Archive &ar, std::uint32_t const version) const { 4571 ar(::cereal::make_nvp("enabled", GetEnabled())); 4572 } 4573 4574 template <class Archive> load(Archive & ar,std::uint32_t const version)4575 void load(Archive &ar, std::uint32_t const version) { 4576 if (version > SerializedVersion()) { 4577 PALISADE_THROW(deserialize_error, 4578 "serialized object version " + std::to_string(version) + 4579 " is from a later version of the library"); 4580 } 4581 4582 usint enabled; 4583 ar(::cereal::make_nvp("enabled", enabled)); 4584 this->Enable(enabled); 4585 } 4586 SerializedObjectName()4587 virtual std::string SerializedObjectName() const { return "Scheme"; } SerializedVersion()4588 static uint32_t SerializedVersion() { return 1; } 4589 4590 friend std::ostream &operator<<( 4591 std::ostream &out, const LPPublicKeyEncryptionScheme<Element> &s) { 4592 out << typeid(s).name() << ":"; 4593 out << " ParameterGeneration " 4594 << (s.m_algorithmParamsGen == 0 4595 ? "none" 4596 : typeid(*s.m_algorithmParamsGen).name()); 4597 out << ", Encryption " 4598 << (s.m_algorithmEncryption == 0 4599 ? "none" 4600 : typeid(*s.m_algorithmEncryption).name()); 4601 out << ", PRE " 4602 << (s.m_algorithmPRE == 0 ? "none" : typeid(*s.m_algorithmPRE).name()); 4603 out << ", Multiparty " 4604 << (s.m_algorithmMultiparty == 0 4605 ? "none" 4606 : typeid(*s.m_algorithmMultiparty).name()); 4607 out << ", SHE " 4608 << (s.m_algorithmSHE == 0 ? "none" : typeid(*s.m_algorithmSHE).name()); 4609 out << ", LeveledSHE " 4610 << (s.m_algorithmLeveledSHE == 0 4611 ? "none" 4612 : typeid(*s.m_algorithmLeveledSHE).name()); 4613 return out; 4614 } 4615 4616 protected: 4617 std::shared_ptr<LPParameterGenerationAlgorithm<Element>> m_algorithmParamsGen; 4618 std::shared_ptr<LPEncryptionAlgorithm<Element>> m_algorithmEncryption; 4619 std::shared_ptr<LPPREAlgorithm<Element>> m_algorithmPRE; 4620 std::shared_ptr<LPMultipartyAlgorithm<Element>> m_algorithmMultiparty; 4621 std::shared_ptr<LPSHEAlgorithm<Element>> m_algorithmSHE; 4622 std::shared_ptr<LPLeveledSHEAlgorithm<Element>> m_algorithmLeveledSHE; 4623 }; 4624 4625 } // namespace lbcrypto 4626 4627 #endif 4628