1 /***
2  * © 2020 Duality Technologies, Inc. All rights reserved.
3  * This is a proprietary software product of Duality Technologies, Inc.
4  *protected under copyright laws and international copyright treaties, patent
5  *law, trade secret law and other intellectual property rights of general
6  *applicability. Any use of this software is strictly prohibited absent a
7  *written agreement executed by Duality Technologies, Inc., which provides
8  *certain limited rights to use this software. You may not copy, distribute,
9  *make publicly available, publicly perform, disassemble, de-compile or reverse
10  *engineer any part of this software, breach its security, or circumvent,
11  *manipulate, impair or disrupt its operation.
12  ***/
13 
14 #ifndef LBCRYPTO_CRYPTO_METADATA_H
15 #define LBCRYPTO_CRYPTO_METADATA_H
16 
17 namespace lbcrypto {
18 
19 /**
20  * @brief Empty metadata container
21  */
22 class Metadata {
23  public:
24   /**
25    * Default constructor
26    */
Metadata()27   Metadata() {}
28 
29   /**
30    * Copy constructor
31    */
Metadata(const Metadata & mdata)32   Metadata(const Metadata& mdata) { Metadata(); }
33 
34   /**
35    * Destructor
36    */
~Metadata()37   virtual ~Metadata() {}
38 
39   /**
40    * This method creates a copy of the Metadata object
41    * wrapped in a shared_ptr
42    */
Clone()43   virtual std::shared_ptr<Metadata> Clone() const {
44     return std::make_shared<Metadata>();
45   }
46 
47   /**
48    * Equality operator for Metadata.
49    * Unless overriden by subclasses, Metadata does not carry any
50    * metadata, so all Metadata objects are equal.
51    */
52   virtual bool operator==(const Metadata& mdata) const { return true; }
53 
54   /**
55    * Inequality operator, implemented by a call to the
56    * equality operator.
57    */
58   virtual bool operator!=(const Metadata& mdata) const {
59     return !(*this == mdata);
60   }
61 
62   /**
63    * A method that prints the contents of metadata objects.
64    * Please override in subclasses to print all members.
65    */
print(std::ostream & out)66   virtual std::ostream& print(std::ostream& out) const {
67     out << "[ ]" << std::endl;
68     return out;
69   }
70 
71   /**
72    * << operator implements by calling member method print.
73    * This is a friend method and cannot be overriden by subclasses.
74    */
75   friend std::ostream& operator<<(std::ostream& out, const Metadata& m) {
76     m.print(out);
77     return out;
78   }
79 
80   /**
81    * save method for serialization
82    */
83   template <class Archive>
save(Archive & ar,std::uint32_t const version)84   void save(Archive& ar, std::uint32_t const version) const {}
85 
86   /**
87    * load method for serialization
88    */
89   template <class Archive>
load(Archive & ar,std::uint32_t const version)90   void load(Archive& ar, std::uint32_t const version) {
91     if (version > SerializedVersion()) {
92       PALISADE_THROW(deserialize_error,
93                      "serialized object version " + std::to_string(version) +
94                          " is from a later version of the library");
95     }
96   }
97 
98   /**
99    * SerializedObjectName method for serialization
100    */
SerializedObjectName()101   virtual std::string SerializedObjectName() const { return "Metadata"; }
102 
103   /**
104    * SerializedVersion method for serialization
105    */
SerializedVersion()106   static uint32_t SerializedVersion() { return 1; }
107 };
108 
109 /**
110  * @brief Example class inheriting from Metadata and adding a member.
111  * This is used in unit tests.
112  */
113 class MetadataTest : public Metadata {
114  public:
115   /**
116    * Default constructor
117    */
MetadataTest()118   MetadataTest() : Metadata(), m_s("") {}
119   /**
120    * Destructor
121    */
~MetadataTest()122   virtual ~MetadataTest() {}
123 
124   /**
125    * Copy constructor
126    */
MetadataTest(const MetadataTest & mdata)127   MetadataTest(const MetadataTest& mdata) : Metadata() { m_s = mdata.m_s; }
128 
129   /**
130    * This method creates a new MetadataTest object.
131    *
132    * Since Ciphertexts have a map of shared_ptr<Metadata>,
133    * whenever we retrieve the contents of the map, we actually
134    * get the shared pointer and we do not create a new object.
135    *
136    * If we do want to create a new object (e.g., because we
137    * want to modify it only for a new Ciphertext), we can use
138    * the Clone method.
139    *
140    */
Clone()141   std::shared_ptr<Metadata> Clone() const {
142     auto mdata = std::make_shared<MetadataTest>();
143     mdata->m_s = this->m_s;
144     return mdata;
145   }
146 
147   /**
148    * Setter method for the only value stored in this Metadata container.
149    */
SetMetadata(string str)150   void SetMetadata(string str) { m_s = string(str); }
151 
152   /**
153    * This method returns the (only) value stored in this Metadata container
154    */
GetMetadata()155   string GetMetadata() const { return m_s; }
156 
157   /**
158    * Defines how to check equality between objects of this class.
159    */
160   bool operator==(const Metadata& mdata) const {
161     try {
162       const MetadataTest& mdataTest = dynamic_cast<const MetadataTest&>(mdata);
163       return m_s == mdataTest.GetMetadata();  // All Metadata objects without
164                                               // any members are equal
catch(const std::bad_cast & e)165     } catch (const std::bad_cast& e) {
166       PALISADE_THROW(
167           palisade_error,
168           "Tried to downcast an object of different class to MetadataTest");
169     }
170   }
171 
172   /**
173    * Defines how to print the contents of objects of this class.
174    */
print(std::ostream & out)175   std::ostream& print(std::ostream& out) const {
176     out << "[ " << m_s << " ]";
177     return out;
178   }
179 
180   /**
181    * save method for serialization
182    */
183   template <class Archive>
save(Archive & ar,std::uint32_t const version)184   void save(Archive& ar, std::uint32_t const version) const {
185     ar(cereal::base_class<Metadata>(this));
186     ar(cereal::make_nvp("str", m_s));
187   }
188 
189   /**
190    * load method for serialization
191    */
192   template <class Archive>
load(Archive & ar,std::uint32_t const version)193   void load(Archive& ar, std::uint32_t const version) {
194     if (version > SerializedVersion()) {
195       PALISADE_THROW(deserialize_error,
196                      "serialized object version " + std::to_string(version) +
197                          " is from a later version of the library");
198     }
199     ar(cereal::base_class<Metadata>(this));
200     ar(cereal::make_nvp("str", m_s));
201   }
202 
203   /**
204    * This static method retrieves a MetadataTest object
205    * from a Ciphertext, and clones it so we can further
206    * modify it.
207    *
208    * @param ciphertext the ciphertext whose metadata to retrieve.
209    */
210   template <class Element>
CloneMetadata(ConstCiphertext<Element> ciphertext)211   static const shared_ptr<MetadataTest> CloneMetadata(
212       ConstCiphertext<Element> ciphertext) {
213     auto it = ciphertext->FindMetadataByKey("test");
214 
215     if (ciphertext->MetadataFound(it)) {
216       return std::dynamic_pointer_cast<MetadataTest>(
217           ciphertext->GetMetadata(it)->Clone());
218     } else {
219       PALISADE_THROW(
220           palisade_error,
221           "Attempt to access metadata (MetadataTest) that has not been set.");
222     }
223   }
224 
225   /**
226    * This static method retrieves a MetadataTest object
227    * from a Ciphertext, without cloning it. This means that any
228    * modifications on the MetadataTest object will affect the
229    * original Ciphertext we retrieved the metadata from.
230    *
231    * @param ciphertext the ciphertext whose metadata to retrieve.
232    */
233   template <class Element>
GetMetadata(ConstCiphertext<Element> ciphertext)234   static const shared_ptr<MetadataTest> GetMetadata(
235       ConstCiphertext<Element> ciphertext) {
236     auto it = ciphertext->FindMetadataByKey("test");
237 
238     if (ciphertext->MetadataFound(it)) {
239       return std::dynamic_pointer_cast<MetadataTest>(
240           ciphertext->GetMetadata(it));
241     } else {
242       PALISADE_THROW(
243           palisade_error,
244           "Attempt to access metadata (MetadataTest) that has not been set.");
245     }
246   }
247 
248   /**
249    * This static method stores a MetadataTest object
250    * to a Ciphertext. If the Ciphertext already has another MetadataTest
251    * object stored in its map, it will get overwritten by this MetadataTest
252    * object.
253    *
254    * Whenever we want to modify the metadata of a ciphertext, it is
255    * recommended to (1) clone the MetadataTest object from another
256    * ciphertext or create a new MetadataTest object with
257    * make_shared<MetadataTest>(), (2) modify it using the Setter methods
258    * of MetadataTest, and (3) store it to the ciphertext we want using
259    * this method.
260    *
261    * @param ciphertext the ciphertext whose metadata to retrieve.
262    */
263   template <class Element>
StoreMetadata(Ciphertext<Element> ciphertext,shared_ptr<MetadataTest> mdata)264   static void StoreMetadata(Ciphertext<Element> ciphertext,
265                             shared_ptr<MetadataTest> mdata) {
266     ciphertext->SetMetadataByKey("test", mdata);
267   }
268 
269  protected:
270   string m_s;
271 };
272 
273 }  // end namespace lbcrypto
274 
275 #endif
276