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