1 // @file  simple-integers-serial-bgvrns.cpp - Simple example for BGVrns (integer
2 // arithmetic) with serialization.
3 // Refer to the simple-real-numbers-serial file for an example of how to use
4 // this in a "client-server" setup
5 // @author TPOC: contact@palisade-crypto.org
6 //
7 // @copyright Copyright (c) 2019, New Jersey Institute of Technology (NJIT))
8 // All rights reserved.
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 // 1. Redistributions of source code must retain the above copyright notice,
12 // this list of conditions and the following disclaimer.
13 // 2. Redistributions in binary form must reproduce the above copyright notice,
14 // this list of conditions and the following disclaimer in the documentation
15 // and/or other materials provided with the distribution. THIS SOFTWARE IS
16 // PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
17 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 // EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #include "palisade.h"
28 
29 // header files needed for serialization
30 #include "ciphertext-ser.h"
31 #include "cryptocontext-ser.h"
32 #include "pubkeylp-ser.h"
33 #include "scheme/bgvrns/bgvrns-ser.h"
34 
35 using namespace lbcrypto;
36 
37 const std::string DATAFOLDER = "demoData";
38 
main()39 int main() {
40   std::cout << "This program requres the subdirectory `" << DATAFOLDER
41             << "' to exist, otherwise you will get "
42             << "an error writing serializations." << std::endl;
43 
44   // Sample Program: Step 1 - Set CryptoContext
45 
46   // Set the main parameters
47   int plaintextModulus = 65537;
48   double sigma = 3.2;
49   SecurityLevel securityLevel = HEStd_128_classic;
50   uint32_t depth = 2;
51 
52   // Instantiate the crypto context
53   CryptoContext<DCRTPoly> cryptoContext =
54       CryptoContextFactory<DCRTPoly>::genCryptoContextBGVrns(
55           depth, plaintextModulus, securityLevel, sigma, depth, OPTIMIZED, BV);
56 
57   // Enable features that you wish to use
58   cryptoContext->Enable(ENCRYPTION);
59   cryptoContext->Enable(SHE);
60   cryptoContext->Enable(LEVELEDSHE);
61 
62   std::cout << "\nThe cryptocontext has been generated." << std::endl;
63 
64   // Serialize cryptocontext
65   if (!Serial::SerializeToFile(DATAFOLDER + "/cryptocontext.txt", cryptoContext,
66                                SerType::BINARY)) {
67     std::cerr << "Error writing serialization of the crypto context to "
68                  "cryptocontext.txt"
69               << std::endl;
70     return 1;
71   }
72   std::cout << "The cryptocontext has been serialized." << std::endl;
73 
74   // Sample Program: Step 2 - Key Generation
75 
76   // Initialize Public Key Containers
77   LPKeyPair<DCRTPoly> keyPair;
78 
79   // Generate a public/private key pair
80   keyPair = cryptoContext->KeyGen();
81 
82   std::cout << "The key pair has been generated." << std::endl;
83 
84   // Serialize the public key
85   if (!Serial::SerializeToFile(DATAFOLDER + "/key-public.txt",
86                                keyPair.publicKey, SerType::BINARY)) {
87     std::cerr << "Error writing serialization of public key to key-public.txt"
88               << std::endl;
89     return 1;
90   }
91   std::cout << "The public key has been serialized." << std::endl;
92 
93   // Serialize the secret key
94   if (!Serial::SerializeToFile(DATAFOLDER + "/key-private.txt",
95                                keyPair.secretKey, SerType::BINARY)) {
96     std::cerr << "Error writing serialization of private key to key-private.txt"
97               << std::endl;
98     return 1;
99   }
100   std::cout << "The secret key has been serialized." << std::endl;
101 
102   // Generate the relinearization key
103   cryptoContext->EvalMultKeyGen(keyPair.secretKey);
104 
105   std::cout << "The eval mult keys have been generated." << std::endl;
106 
107   // Serialize the relinearization (evaluation) key for homomorphic
108   // multiplication
109   std::ofstream emkeyfile(DATAFOLDER + "/" + "key-eval-mult.txt",
110                           std::ios::out | std::ios::binary);
111   if (emkeyfile.is_open()) {
112     if (cryptoContext->SerializeEvalMultKey(emkeyfile, SerType::BINARY) == false) {
113       std::cerr << "Error writing serialization of the eval mult keys to "
114                    "key-eval-mult.txt"
115                 << std::endl;
116       return 1;
117     }
118     std::cout << "The eval mult keys have been serialized." << std::endl;
119 
120     emkeyfile.close();
121   } else {
122     std::cerr << "Error serializing eval mult keys" << std::endl;
123     return 1;
124   }
125 
126   // Generate the rotation evaluation keys
127   cryptoContext->EvalAtIndexKeyGen(keyPair.secretKey, {1, 2, -1, -2});
128 
129   std::cout << "The rotation keys have been generated." << std::endl;
130 
131   // Serialize the rotation keyhs
132   std::ofstream erkeyfile(DATAFOLDER + "/" + "key-eval-rot.txt",
133                           std::ios::out | std::ios::binary);
134   if (erkeyfile.is_open()) {
135     if (cryptoContext->SerializeEvalAutomorphismKey(erkeyfile, SerType::BINARY) == false) {
136       std::cerr << "Error writing serialization of the eval rotation keys to "
137                    "key-eval-rot.txt"
138                 << std::endl;
139       return 1;
140     }
141     std::cout << "The eval rotation keys have been serialized." << std::endl;
142 
143     erkeyfile.close();
144   } else {
145     std::cerr << "Error serializing eval rotation keys" << std::endl;
146     return 1;
147   }
148 
149   // Sample Program: Step 3: Encryption
150 
151   // First plaintext vector is encoded
152   std::vector<int64_t> vectorOfInts1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
153   Plaintext plaintext1 = cryptoContext->MakePackedPlaintext(vectorOfInts1);
154   // Second plaintext vector is encoded
155   std::vector<int64_t> vectorOfInts2 = {3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12};
156   Plaintext plaintext2 = cryptoContext->MakePackedPlaintext(vectorOfInts2);
157   // Third plaintext vector is encoded
158   std::vector<int64_t> vectorOfInts3 = {1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12};
159   Plaintext plaintext3 = cryptoContext->MakePackedPlaintext(vectorOfInts3);
160 
161   std::cout << "Plaintext #1: " << plaintext1 << std::endl;
162   std::cout << "Plaintext #2: " << plaintext2 << std::endl;
163   std::cout << "Plaintext #3: " << plaintext3 << std::endl;
164 
165   // The encoded vectors are encrypted
166   auto ciphertext1 = cryptoContext->Encrypt(keyPair.publicKey, plaintext1);
167   auto ciphertext2 = cryptoContext->Encrypt(keyPair.publicKey, plaintext2);
168   auto ciphertext3 = cryptoContext->Encrypt(keyPair.publicKey, plaintext3);
169 
170   std::cout << "The plaintexts have been encrypted." << std::endl;
171 
172   if (!Serial::SerializeToFile(DATAFOLDER + "/" + "ciphertext1.txt",
173                                ciphertext1, SerType::BINARY)) {
174     std::cerr
175         << "Error writing serialization of ciphertext 1 to ciphertext1.txt"
176         << std::endl;
177     return 1;
178   }
179   std::cout << "The first ciphertext has been serialized." << std::endl;
180 
181   if (!Serial::SerializeToFile(DATAFOLDER + "/" + "ciphertext2.txt",
182                                ciphertext2, SerType::BINARY)) {
183     std::cerr
184         << "Error writing serialization of ciphertext 2 to ciphertext2.txt"
185         << std::endl;
186     return 1;
187   }
188   std::cout << "The second ciphertext has been serialized." << std::endl;
189 
190   if (!Serial::SerializeToFile(DATAFOLDER + "/" + "ciphertext3.txt",
191                                ciphertext1, SerType::BINARY)) {
192     std::cerr
193         << "Error writing serialization of ciphertext 3 to ciphertext3.txt"
194         << std::endl;
195     return 1;
196   }
197   std::cout << "The third ciphertext has been serialized." << std::endl;
198 
199 
200   // Sample Program: Step 4 - Evaluation
201 
202   // PALISADE maintains an internal map of CryptoContext objects which are
203   // indexed by a tag and the tag is applied to both the CryptoContext and some
204   // of the keys. When deserializing a context, PALISADE checks for the tag and
205   // if it finds it in the CryptoContext map, it will return the stored version.
206   // Hence, we need to clear the context and clear the keys.
207   cryptoContext->ClearEvalMultKeys();
208   cryptoContext->ClearEvalAutomorphismKeys();
209   lbcrypto::CryptoContextFactory<lbcrypto::DCRTPoly>::ReleaseAllContexts();
210 
211   // Deserialize the crypto context
212   CryptoContext<DCRTPoly> cc;
213   if (!Serial::DeserializeFromFile(DATAFOLDER + "/cryptocontext.txt", cc,
214                                    SerType::BINARY)) {
215     std::cerr << "I cannot read serialization from "
216               << DATAFOLDER + "/cryptocontext.txt" << std::endl;
217     return 1;
218   }
219   std::cout << "The cryptocontext has been deserialized." << std::endl;
220 
221   LPPublicKey<DCRTPoly> pk;
222   if (Serial::DeserializeFromFile(DATAFOLDER + "/key-public.txt", pk,
223                                   SerType::BINARY) == false) {
224     std::cerr << "Could not read public key" << std::endl;
225     return 1;
226   }
227   std::cout << "The public key has been deserialized." << std::endl;
228 
229   std::ifstream emkeys(DATAFOLDER + "/key-eval-mult.txt",
230                        std::ios::in | std::ios::binary);
231   if (!emkeys.is_open()) {
232     std::cerr << "I cannot read serialization from "
233               << DATAFOLDER + "/key-eval-mult.txt" << std::endl;
234     return 1;
235   }
236   if (cc->DeserializeEvalMultKey(emkeys, SerType::BINARY) == false) {
237     std::cerr << "Could not deserialize the eval mult key file" << std::endl;
238     return 1;
239   }
240   std::cout << "Deserialized the eval mult keys." << std::endl;
241 
242   std::ifstream erkeys(DATAFOLDER + "/key-eval-rot.txt",
243                        std::ios::in | std::ios::binary);
244   if (!erkeys.is_open()) {
245     std::cerr << "I cannot read serialization from "
246               << DATAFOLDER + "/key-eval-rot.txt" << std::endl;
247     return 1;
248   }
249   if (cc->DeserializeEvalAutomorphismKey(erkeys, SerType::BINARY) == false) {
250     std::cerr << "Could not deserialize the eval rotation key file"
251               << std::endl;
252     return 1;
253   }
254   std::cout << "Deserialized the eval rotation keys." << std::endl;
255 
256   //deserializing ciphertexts
257   Ciphertext<DCRTPoly> ct1;
258   if (Serial::DeserializeFromFile(DATAFOLDER + "/ciphertext1.txt", ct1,
259                                   SerType::BINARY) == false) {
260     std::cerr << "Could not read the ciphertext" << std::endl;
261     return 1;
262   }
263   std::cout << "The first ciphertext has been deserialized." << std::endl;
264 
265   Ciphertext<DCRTPoly> ct2;
266   if (Serial::DeserializeFromFile(DATAFOLDER + "/ciphertext1.txt", ct2,
267                                   SerType::BINARY) == false) {
268     std::cerr << "Could not read the ciphertext" << std::endl;
269     return 1;
270   }
271   std::cout << "The second ciphertext has been deserialized." << std::endl;
272 
273   Ciphertext<DCRTPoly> ct3;
274   if (Serial::DeserializeFromFile(DATAFOLDER + "/ciphertext1.txt", ct3,
275                                   SerType::BINARY) == false) {
276     std::cerr << "Could not read the ciphertext" << std::endl;
277     return 1;
278   }
279   std::cout << "The third ciphertext has been deserialized." << std::endl;
280 
281   // Homomorphic additions
282   auto ciphertextAdd12 = cc->EvalAdd(ct1, ct2);//iphertext2);
283   auto ciphertextAddResult = cc->EvalAdd(ciphertextAdd12, ct3);//iphertext3);
284 
285   // Homomorphic multiplications
286   auto ciphertextMul12 = cc->EvalMult(ct1, ct2);//iphertext2);
287   auto ciphertextMultResult = cc->EvalMult(ciphertextMul12, ct3);//iphertext3);
288 
289   // Homomorphic rotations
290   auto ciphertextRot1 = cc->EvalAtIndex(ct1, 1);
291   auto ciphertextRot2 = cc->EvalAtIndex(ct1, 2);
292   auto ciphertextRot3 = cc->EvalAtIndex(ct1, -1);
293   auto ciphertextRot4 = cc->EvalAtIndex(ct1, -2);
294 
295   // Sample Program: Step 5 - Decryption
296 
297   LPPrivateKey<DCRTPoly> sk;
298   if (Serial::DeserializeFromFile(DATAFOLDER + "/key-private.txt", sk,
299                                   SerType::BINARY) == false) {
300     std::cerr << "Could not read secret key" << std::endl;
301     return 1;
302   }
303   std::cout << "The secret key has been deserialized." << std::endl;
304 
305   // Decrypt the result of additions
306   Plaintext plaintextAddResult;
307   cc->Decrypt(sk, ciphertextAddResult, &plaintextAddResult);
308 
309   // Decrypt the result of multiplications
310   Plaintext plaintextMultResult;
311   cc->Decrypt(sk, ciphertextMultResult, &plaintextMultResult);
312 
313   // Decrypt the result of rotations
314   Plaintext plaintextRot1;
315   cc->Decrypt(sk, ciphertextRot1, &plaintextRot1);
316   Plaintext plaintextRot2;
317   cc->Decrypt(sk, ciphertextRot2, &plaintextRot2);
318   Plaintext plaintextRot3;
319   cc->Decrypt(sk, ciphertextRot3, &plaintextRot3);
320   Plaintext plaintextRot4;
321   cc->Decrypt(sk, ciphertextRot4, &plaintextRot4);
322 
323   // Shows only the same number of elements as in the original plaintext vector
324   // By default it will show all coefficients in the BFV-encoded polynomial
325   plaintextRot1->SetLength(vectorOfInts1.size());
326   plaintextRot2->SetLength(vectorOfInts1.size());
327   plaintextRot3->SetLength(vectorOfInts1.size());
328   plaintextRot4->SetLength(vectorOfInts1.size());
329 
330   // Output results
331   std::cout << "\nResults of homomorphic computations" << std::endl;
332   std::cout << "#1 + #2 + #3: " << plaintextAddResult << std::endl;
333   std::cout << "#1 * #2 * #3: " << plaintextMultResult << std::endl;
334   std::cout << "Left rotation of #1 by 1: " << plaintextRot1 << std::endl;
335   std::cout << "Left rotation of #1 by 2: " << plaintextRot2 << std::endl;
336   std::cout << "Right rotation of #1 by 1: " << plaintextRot3 << std::endl;
337   std::cout << "Right rotation of #1 by 2: " << plaintextRot4 << std::endl;
338 
339   return 0;
340 }
341