1 // @file ciphertext.h -- Operations for the reoresentation of ciphertext in
2 // PALISADE.
3 // @author TPOC: contact@palisade-crypto.org
4 //
5 // @copyright Copyright (c) 2019, New Jersey Institute of Technology (NJIT)
6 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 // 1. Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution. THIS SOFTWARE IS
14 // PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
15 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17 // EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 
25 #ifndef LBCRYPTO_CRYPTO_CIPHERTEXT_H
26 #define LBCRYPTO_CRYPTO_CIPHERTEXT_H
27 
28 #include <memory>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 
33 #include "palisade.h"
34 
35 namespace lbcrypto {
36 
main(int argc,char * argv[])37 template <typename Element>
38 class CiphertextImpl;
39 
40 /**
41  * @brief CiphertextImpl
42  *
43  * The CiphertextImpl object is used to contain encrypted text in the PALISADE
44  * library
45  *
46  * @tparam Element a ring element.
47  */
48 template <class Element>
49 class CiphertextImpl : public CryptoObject<Element> {
50  public:
51   /**
52    * Default constructor
53    */
54   CiphertextImpl()
55       : CryptoObject<Element>(),
56         m_depth(1),
57         encodingType(Unknown),
58         m_scalingFactor(1),
59         m_level(0) {
60     m_metadataMap = std::make_shared<std::map<string, shared_ptr<Metadata>>>();
61   }
62 
63   /**
64    * Construct a new ciphertext in the given context
65    *
66    * @param cc
67    */
68   explicit CiphertextImpl(CryptoContext<Element> cc, const string& id = "",
69                           PlaintextEncodings encType = Unknown)
70       : CryptoObject<Element>(cc, id),
71         m_depth(1),
72         encodingType(encType),
73         m_scalingFactor(1),
74         m_level(0) {
75     m_metadataMap = std::make_shared<std::map<string, shared_ptr<Metadata>>>();
76   }
77 
78   /**
79    * Construct a new ciphertext from the parameters of a given public key
80    *
81    * @param k key whose CryptoObject parameters will get cloned
82    */
83   explicit CiphertextImpl(const shared_ptr<LPKey<Element>> k)
84       : CryptoObject<Element>(k->GetCryptoContext(), k->GetKeyTag()),
85         m_depth(1),
86         encodingType(Unknown),
87         m_scalingFactor(1),
88         m_level(0) {
89     m_metadataMap = std::make_shared<std::map<string, shared_ptr<Metadata>>>();
90   }
91 
92   /**
93    * Copy constructor
94    */
95   CiphertextImpl(const CiphertextImpl<Element>& ciphertext)
96       : CryptoObject<Element>(ciphertext) {
97     m_elements = ciphertext.m_elements;
98     m_depth = ciphertext.m_depth;
99     m_level = ciphertext.m_level;
100     m_scalingFactor = ciphertext.m_scalingFactor;
101     encodingType = ciphertext.encodingType;
102     m_metadataMap = ciphertext.m_metadataMap;
103   }
104 
105   explicit CiphertextImpl(Ciphertext<Element> ciphertext)
106       : CryptoObject<Element>(*ciphertext) {
107     m_elements = ciphertext->m_elements;
108     m_depth = ciphertext->m_depth;
109     m_level = ciphertext->m_level;
110     m_scalingFactor = ciphertext->m_scalingFactor;
111     encodingType = ciphertext->encodingType;
112     m_metadataMap = ciphertext->m_metadataMap;
113   }
114 
115   /**
116    * Move constructor
117    */
118   CiphertextImpl(CiphertextImpl<Element>&& ciphertext)
119       : CryptoObject<Element>(ciphertext) {
120     m_elements = std::move(ciphertext.m_elements);
121     m_depth = std::move(ciphertext.m_depth);
122     m_level = std::move(ciphertext.m_level);
123     m_scalingFactor = std::move(ciphertext.m_scalingFactor);
124     encodingType = std::move(ciphertext.encodingType);
125     m_metadataMap = std::move(ciphertext.m_metadataMap);
126   }
127 
128   explicit CiphertextImpl(Ciphertext<Element>&& ciphertext)
129       : CryptoObject<Element>(*ciphertext) {
130     m_elements = std::move(ciphertext->m_elements);
131     m_depth = std::move(ciphertext->m_depth);
132     m_level = std::move(ciphertext->m_level);
133     m_scalingFactor = std::move(ciphertext->m_scalingFactor);
134     encodingType = std::move(ciphertext->encodingType);
135     m_metadataMap = std::move(ciphertext->m_metadataMap);
136   }
137 
138   /**
139    * This method creates a copy of this, skipping the actual encrypted
140    * elements. This means it copies parameters, key tags, encoding type,
141    * and metadata.
142    */
143   virtual Ciphertext<Element> CloneEmpty() const {
144     Ciphertext<Element> ct(std::make_shared<CiphertextImpl<Element>>(
145         this->GetCryptoContext(), this->GetKeyTag(), this->GetEncodingType()));
146 
147     ct->m_metadataMap =
148         std::make_shared<std::map<string, shared_ptr<Metadata>>>();
149     *(ct->m_metadataMap) = *(this->m_metadataMap);
150 
151     return ct;
152   }
153 
154   /**
155    * Destructor
156    */
157   virtual ~CiphertextImpl() {}
158 
159   /**
160    * GetEncodingType
161    * @return how the Plaintext that this CiphertextImpl was created from was
162    * encoded
163    */
164   PlaintextEncodings GetEncodingType() const { return encodingType; }
165 
166   /**
167    * SetEncodingType - after Encrypt, remember the CiphertextImpl's encoding
168    * type
169    * @param et
170    */
171   void SetEncodingType(PlaintextEncodings et) { encodingType = et; }
172 
173   /**
174    * Assignment Operator.
175    *
176    * @param &rhs the CiphertextImpl to assign from
177    * @return this CiphertextImpl
178    */
179   CiphertextImpl<Element>& operator=(const CiphertextImpl<Element>& rhs) {
180     if (this != &rhs) {
181       CryptoObject<Element>::operator=(rhs);
182       this->m_elements = rhs.m_elements;
183       this->m_depth = rhs.m_depth;
184       this->m_level = rhs.m_level;
185       this->m_scalingFactor = rhs.m_scalingFactor;
186       this->encodingType = rhs.encodingType;
187       this->m_metadataMap = rhs.m_metadataMap;
188     }
189 
190     return *this;
191   }
192 
193   /**
194    * Move Assignment Operator.
195    *
196    * @param &rhs the CiphertextImpl to move from
197    * @return this CiphertextImpl
198    */
199   CiphertextImpl<Element>& operator=(CiphertextImpl<Element>&& rhs) {
200     if (this != &rhs) {
201       CryptoObject<Element>::operator=(rhs);
202       this->m_elements = std::move(rhs.m_elements);
203       this->m_depth = std::move(rhs.m_depth);
204       this->m_level = std::move(rhs.m_level);
205       this->m_scalingFactor = std::move(rhs.m_scalingFactor);
206       this->encodingType = std::move(rhs.encodingType);
207       this->m_metadataMap = std::move(rhs.m_metadataMap);
208     }
209 
210     return *this;
211   }
212 
213   /**
214    * GetElement - get the ring element for the cases that use only one element
215    * in the vector this method will throw an exception if it's ever called in
216    * cases with other than 1 element
217    * @return the first (and only!) ring element
218    */
219   const Element& GetElement() const {
220     if (m_elements.size() == 1) return m_elements[0];
221 
222     PALISADE_THROW(config_error,
223                    "GetElement should only be used in cases with a "
224                    "Ciphertext with a single element");
225   }
226 
227     /**
228    * GetElement - get the ring element for the cases that use only one element
229    * in the vector this method will throw an exception if it's ever called in
230    * cases with other than 1 element
231    * @return the first (and only!) ring element
232    */
233   Element& GetElement() {
234     if (m_elements.size() == 1) return m_elements[0];
235 
236     PALISADE_THROW(config_error,
237                    "GetElement should only be used in cases with a "
238                    "Ciphertext with a single element");
239   }
240 
241   /**
242    * GetElements: get all of the ring elements in the CiphertextImpl
243    * @return vector of ring elements
244    */
245   const std::vector<Element>& GetElements() const { return m_elements; }
246 
247   /**
248    * GetElements: get all of the ring elements in the CiphertextImpl
249    * @return vector of ring elements
250    */
251   std::vector<Element>& GetElements() { return m_elements; }
252 
253   /**
254    * SetElement - sets the ring element for the cases that use only one element
255    * in the vector this method will throw an exception if it's ever called in
256    * cases with other than 1 element
257    * @param &element is a polynomial ring element.
258    */
259   void SetElement(const Element& element) {
260     if (m_elements.size() == 0)
261       m_elements.push_back(element);
262     else if (m_elements.size() == 1)
263       m_elements[0] = element;
264     else
265       PALISADE_THROW(config_error,
266                      "SetElement should only be used in cases with a "
267                      "Ciphertext with a single element");
268   }
269 
270   /**
271    * Sets the data elements.
272    *
273    * @param &element is a polynomial ring element.
274    */
275   void SetElements(const std::vector<Element>& elements) {
276     m_elements = elements;
277   }
278 
279   /**
280    * Sets the data elements by std::move.
281    *
282    * @param &&element is a polynomial ring element.
283    */
284   void SetElements(std::vector<Element>&& elements) {
285     m_elements = std::move(elements);
286   }
287 
288   /**
289    * Get the depth of the ciphertext.
290    * It will be used in multiplication/addition/subtraction to handle the
291    * keyswitching.
292    */
293   size_t GetDepth() const { return m_depth; }
294 
295   /**
296    * Set the depth of the ciphertext.
297    * It will be used in multiplication/addition/subtraction to handle the
298    * keyswitching.
299    */
300   void SetDepth(size_t depth) { m_depth = depth; }
301 
302   /**
303    * Get the level of the ciphertext.
304    */
305   size_t GetLevel() const { return m_level; }
306 
307   /**
308    * Set the level of the ciphertext.
309    */
310   void SetLevel(size_t level) { m_level = level; }
311 
312   /**
313    * Get the scaling factor of the ciphertext.
314    */
315   double GetScalingFactor() const { return m_scalingFactor; }
316 
317   /**
318    * Set the scaling factor of the ciphertext.
319    */
320   void SetScalingFactor(double sf) { m_scalingFactor = sf; }
321 
322   /**
323    * Get the Metadata map of the ciphertext.
324    */
325   MetadataMap GetMetadataMap() const { return this->m_metadataMap; }
326 
327   /**
328    * Set the Metadata map of the ciphertext.
329    */
330   void SetMetadataMap(MetadataMap mdata) { this->m_metadataMap = mdata; }
331 
332   /**
333    * This method searches the metadata map for metadata of a specific key.
334    *
335    * @param key the string value which serves as a key in the metadata map
336    * @return an iterator pointing at the position in the map where the key
337    *         was found (or the map.end() if not found).
338    */
339   std::map<string, shared_ptr<Metadata>>::iterator FindMetadataByKey(
340       string key) const {
341     return m_metadataMap->find(key);
342   }
343 
344   /**
345    * This method checks whether an iterator return from FindMetadataByKey
346    * corresponds to whether the key was found or not.
347    *
348    * @param it iterator pointing at the position in the map where the key
349    *         was found (or the map.end() if not found).
350    * @return a boolean value indicating whether the key was found or not.
351    */
352   bool MetadataFound(
353       std::map<string, shared_ptr<Metadata>>::iterator it) const {
354     return (it != m_metadataMap->end());
355   }
356 
357   /**
358    * This method returns the Metadata object stored in the iterator position
359    * returned by FindMetadataByKey.
360    *
361    * @param it iterator pointing at the position in the map where the key
362    *         was found (or the map.end() if not found).
363    * @return a shared pointer pointing to the Metadata object in the map.
364    */
365   shared_ptr<Metadata>& GetMetadata(
366       std::map<string, shared_ptr<Metadata>>::iterator it) const {
367     return it->second;
368   }
369 
370   /**
371    * Get a Metadata element from the Metadata map of the ciphertext.
372    */
373   shared_ptr<Metadata> GetMetadataByKey(string key) const {
374     auto it = m_metadataMap->find(key);
375     return std::make_shared<Metadata>(*(it->second));
376   }
377 
378   /**
379    * Set a Metadata element in the Metadata map of the ciphertext.
380    */
381   void SetMetadataByKey(string key, shared_ptr<Metadata> value) {
382     (*m_metadataMap)[key] = value;
383   }
384 
385   virtual Ciphertext<Element> Clone() const {
386     Ciphertext<Element> cRes = this->CloneEmpty();
387     cRes->SetElements(this->GetElements());
388     cRes->SetDepth(this->GetDepth());
389     cRes->SetLevel(this->GetLevel());
390     cRes->SetScalingFactor(this->GetScalingFactor());
391 
392     return cRes;
393   }
394 
395   bool operator==(const CiphertextImpl<Element>& rhs) const {
396     if (!CryptoObject<Element>::operator==(rhs)) return false;
397 
398     if (this->m_depth != rhs.m_depth) return false;
399 
400     if (this->m_level != rhs.m_level) return false;
401 
402     if (this->m_scalingFactor != rhs.m_scalingFactor) return false;
403 
404     const std::vector<Element>& lhsE = this->GetElements();
405     const std::vector<Element>& rhsE = rhs.GetElements();
406 
407     if (lhsE.size() != rhsE.size()) return false;
408 
409     for (size_t i = 0; i < lhsE.size(); i++) {
410       const Element& lE = lhsE[i];
411       const Element& rE = rhsE[i];
412 
413       if (lE != rE) return false;
414     }
415 
416     const shared_ptr<std::map<string, shared_ptr<Metadata>>> lhsMap =
417         this->m_metadataMap;
418     const shared_ptr<std::map<string, shared_ptr<Metadata>>> rhsMap =
419         rhs.m_metadataMap;
420 
421     if (lhsMap->size() != rhsMap->size()) return false;
422 
423     if (lhsMap->size() > 0) {
424       for (auto i = lhsMap->begin(), j = rhsMap->begin(); i != lhsMap->end();
425            ++i, ++j)
426         if (!(*(i->second) == *(j->second))) return false;
427     }
428 
429     return true;
430   }
431 
432   bool operator!=(const CiphertextImpl<Element>& rhs) const {
433     return !(*this == rhs);
434   }
435 
436   friend std::ostream& operator<<(std::ostream& out,
437                                   const CiphertextImpl<Element>& c) {
438     out << "enc=" << c.encodingType << " depth=" << c.m_depth << std::endl;
439     out << "metadata: [ ";
440     for (auto i = c.m_metadataMap->begin(); i != c.m_metadataMap->end(); ++i)
441       out << "(\"" << i->first << "\", " << *(i->second) << ") ";
442     out << "]" << std::endl;
443     for (size_t i = 0; i < c.m_elements.size(); i++) {
444       if (i != 0) out << std::endl;
445       out << "Element " << i << ": " << c.m_elements[i];
446     }
447     return out;
448   }
449 
450   friend std::ostream& operator<<(std::ostream& out, Ciphertext<Element> c) {
451     return out << *c;
452   }
453 
454   template <class Archive>
455   void save(Archive& ar, std::uint32_t const version) const {
456     ar(cereal::base_class<CryptoObject<Element>>(this));
457     ar(cereal::make_nvp("v", m_elements));
458     ar(cereal::make_nvp("d", m_depth));
459     ar(cereal::make_nvp("l", m_level));
460     ar(cereal::make_nvp("s", m_scalingFactor));
461     ar(cereal::make_nvp("e", encodingType));
462     ar(cereal::make_nvp("m", m_metadataMap));
463   }
464 
465   template <class Archive>
466   void load(Archive& ar, std::uint32_t const version) {
467     if (version > SerializedVersion()) {
468       PALISADE_THROW(deserialize_error,
469                      "serialized object version " + std::to_string(version) +
470                          " is from a later version of the library");
471     }
472     ar(cereal::base_class<CryptoObject<Element>>(this));
473     ar(cereal::make_nvp("v", m_elements));
474     ar(cereal::make_nvp("d", m_depth));
475     ar(cereal::make_nvp("l", m_level));
476     ar(cereal::make_nvp("s", m_scalingFactor));
477     ar(cereal::make_nvp("e", encodingType));
478     ar(cereal::make_nvp("m", m_metadataMap));
479   }
480 
481   std::string SerializedObjectName() const { return "Ciphertext"; }
482   static uint32_t SerializedVersion() { return 1; }
483 
484  private:
485   // FUTURE ENHANCEMENT: current value of error norm
486   // BigInteger m_norm;
487 
488   std::vector<Element>
489       m_elements;  /*!< vector of ring elements for this Ciphertext */
490   size_t m_depth;  // holds the multiplicative depth of the ciphertext.
491   PlaintextEncodings encodingType; /*!< how was this Ciphertext encoded? */
492 
493   double m_scalingFactor;
494   size_t m_level;  // holds the number of rescalings performed before getting
495                    // this ciphertext - initially 0
496 
497   // A map to hold different Metadata objects - used for flexible extensions of
498   // Ciphertext
499   MetadataMap m_metadataMap;
500 };
501 
502 // TODO the op= are not doing the work in-place, and should be updated
503 
504 /**
505  * operator+ overload for Ciphertexts.  Performs EvalAdd.
506  *
507  * @tparam Element a ring element.
508  * @param &a ciphertext operand
509  * @param &b ciphertext operand
510  *
511  * @return The result of addition.
512  */
513 template <class Element>
514 Ciphertext<Element> operator+(const Ciphertext<Element>& a,
515                               const Ciphertext<Element>& b) {
516   return a->GetCryptoContext()->EvalAdd(a, b);
517 }
518 
519 /**
520  * operator+= overload for Ciphertexts.  Performs EvalAdd.
521  *
522  * @tparam Element a ring element.
523  * @param &a ciphertext to be added to
524  * @param &b ciphertext to add to &a
525  *
526  * @return &a
527  */
528 template <class Element>
529 const Ciphertext<Element>& operator+=(Ciphertext<Element>& a,
530                                       const Ciphertext<Element>& b) {
531   return a = a->GetCryptoContext()->EvalAdd(a, b);
532 }
533 
534 /**
535  * Unary negation operator.
536  *
537  * @param &a ciphertext operand
538  * @return the result of the negation.
539  */
540 template <class Element>
541 Ciphertext<Element> operator-(const Ciphertext<Element>& a) {
542   return a->GetCryptoContext()->EvalNegate(a);
543 }
544 
545 /**
546  * operator- overload.  Performs EvalSub.
547  *
548  * @tparam Element a ring element.
549  * @param &a ciphertext operand
550  * @param &b ciphertext operand
551  *
552  * @return The result of subtraction.
553  */
554 template <class Element>
555 Ciphertext<Element> operator-(const Ciphertext<Element>& a,
556                               const Ciphertext<Element>& b) {
557   return a->GetCryptoContext()->EvalSub(a, b);
558 }
559 
560 /**
561  * operator-= overload for Ciphertexts.  Performs EvalAdd.
562  *
563  * @tparam Element a ring element.
564  * @param &a ciphertext to be subtracted from
565  * @param &b ciphertext to subtract from &a
566  *
567  * @return &a
568  */
569 template <class Element>
570 const Ciphertext<Element>& operator-=(Ciphertext<Element>& a,
571                                       const Ciphertext<Element>& b) {
572   return a = a->GetCryptoContext()->EvalSub(a, b);
573 }
574 
575 /**
576  * operator* overload.  Performs EvalMult.
577  *
578  * @tparam Element a ring element.
579  * @param &a ciphertext operand
580  * @param &b ciphertext operand
581  *
582  * @return The result of multiplication.
583  */
584 template <class Element>
585 Ciphertext<Element> operator*(const Ciphertext<Element>& a,
586                               const Ciphertext<Element>& b) {
587   return a->GetCryptoContext()->EvalMult(a, b);
588 }
589 
590 /**
591  * operator*= overload for Ciphertexts.  Performs EvalMult.
592  *
593  * @tparam Element a ring element.
594  * @param &a ciphertext to be multiplied
595  * @param &b ciphertext to multiply by &a
596  *
597  * @return &a
598  */
599 template <class Element>
600 const Ciphertext<Element>& operator*=(Ciphertext<Element>& a,
601                                       const Ciphertext<Element>& b) {
602   return a = a->GetCryptoContext()->EvalMult(a, b);
603 }
604 
605 }  // namespace lbcrypto
606 
607 #endif
608