1 // @file bfvrns.cpp - Example of basic SHE 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 // @section DESCRIPTION
25 // Demo software for BFV multiparty operations.
26 
27 #include <chrono>
28 #include <fstream>
29 #include <iostream>
30 #include <iterator>
31 
32 #include "palisade.h"
33 
34 using namespace std;
35 using namespace lbcrypto;
36 
37 int main(int argc, char *argv[]) {
38   ////////////////////////////////////////////////////////////
39   // Set-up of parameters
40   ////////////////////////////////////////////////////////////
41 
42   std::cout << "\nThis code demonstrates the use of the BFVrns scheme for "
43                "basic homomorphic encryption operations. "
44             << std::endl;
45   std::cout
46       << "This code shows how to auto-generate parameters during run-time "
47          "based on desired plaintext moduli and security levels. "
48       << std::endl;
49   std::cout << "In this demonstration we use three input plaintext and show "
50                "how to both add them together and multiply them together. "
51             << std::endl;
52 
53   // Generate parameters.
54   double diff, start, finish;
55 
56   int plaintextModulus = 256;
57   double sigma = 4;
58   double rootHermiteFactor = 1.006;
59 
60   // Set Crypto Parameters
61   CryptoContext<DCRTPoly> cryptoContext =
62       CryptoContextFactory<DCRTPoly>::genCryptoContextBFVrns(
63           plaintextModulus, rootHermiteFactor, sigma, 0, 5, 0, OPTIMIZED, 6);
64 
65   // enable features that you wish to use
66   cryptoContext->Enable(ENCRYPTION);
67   cryptoContext->Enable(SHE);
68 
69   std::cout << "p = "
70             << cryptoContext->GetCryptoParameters()->GetPlaintextModulus()
71             << std::endl;
72   std::cout << "n = "
73             << cryptoContext->GetCryptoParameters()
74                        ->GetElementParams()
75                        ->GetCyclotomicOrder() /
76                    2
77             << std::endl;
78   std::cout << "log2 q = "
79             << log2(cryptoContext->GetCryptoParameters()
80                         ->GetElementParams()
81                         ->GetModulus()
82                         .ConvertToDouble())
83             << std::endl;
84 
85   // Initialize Public Key Containers
86   LPKeyPair<DCRTPoly> keyPair;
87 
88   ////////////////////////////////////////////////////////////
89   // Perform Key Generation Operation
90   ////////////////////////////////////////////////////////////
91 
92   std::cout << "Running key generation (used for source data)..." << std::endl;
93 
94   start = currentDateTime();
95 
96   keyPair = cryptoContext->KeyGen();
97 
98   // Create evaluation key vector to be used in keyswitching
99   cryptoContext->EvalMultKeysGen(keyPair.secretKey);
100 
101   finish = currentDateTime();
102   diff = finish - start;
103   cout << "Key generation time: "
104        << "\t" << diff << " ms" << endl;
105 
106   if (!keyPair.good()) {
107     std::cout << "Key generation failed!" << std::endl;
108     exit(1);
109   }
110 
111   ////////////////////////////////////////////////////////////
112   // Encode source data
113   ////////////////////////////////////////////////////////////
114 
115   std::vector<int64_t> vectorOfInts1 = {5, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1, 0};
116   std::vector<int64_t> vectorOfInts2 = {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
117   std::vector<int64_t> vectorOfInts3 = {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
118   std::vector<int64_t> vectorOfInts4 = {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
119   std::vector<int64_t> vectorOfInts5 = {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
120   std::vector<int64_t> vectorOfInts6 = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
121 
122   Plaintext plaintext1 = cryptoContext->MakeCoefPackedPlaintext(vectorOfInts1);
123   Plaintext plaintext2 = cryptoContext->MakeCoefPackedPlaintext(vectorOfInts2);
124   Plaintext plaintext3 = cryptoContext->MakeCoefPackedPlaintext(vectorOfInts3);
125   Plaintext plaintext4 = cryptoContext->MakeCoefPackedPlaintext(vectorOfInts4);
126   Plaintext plaintext5 = cryptoContext->MakeCoefPackedPlaintext(vectorOfInts5);
127   Plaintext plaintext6 = cryptoContext->MakeCoefPackedPlaintext(vectorOfInts6);
128 
129   ////////////////////////////////////////////////////////////
130   // Encryption
131   ////////////////////////////////////////////////////////////
132 
133   Ciphertext<DCRTPoly> ciphertext1;
134   Ciphertext<DCRTPoly> ciphertext2;
135   Ciphertext<DCRTPoly> ciphertext3;
136   Ciphertext<DCRTPoly> ciphertext4;
137   Ciphertext<DCRTPoly> ciphertext5;
138   Ciphertext<DCRTPoly> ciphertext6;
139 
140   start = currentDateTime();
141 
142   ciphertext1 = cryptoContext->Encrypt(keyPair.publicKey, plaintext1);
143   ciphertext2 = cryptoContext->Encrypt(keyPair.publicKey, plaintext2);
144   ciphertext3 = cryptoContext->Encrypt(keyPair.publicKey, plaintext3);
145   ciphertext4 = cryptoContext->Encrypt(keyPair.publicKey, plaintext4);
146   ciphertext5 = cryptoContext->Encrypt(keyPair.publicKey, plaintext5);
147   ciphertext6 = cryptoContext->Encrypt(keyPair.publicKey, plaintext6);
148 
149   finish = currentDateTime();
150   diff = finish - start;
151   cout << "Encryption time: "
152        << "\t" << diff << " ms" << endl;
153 
154   ////////////////////////////////////////////////////////////
155   // Decryption of Ciphertext
156   ////////////////////////////////////////////////////////////
157 
158   Plaintext plaintext1Dec;
159   Plaintext plaintext2Dec;
160   Plaintext plaintext3Dec;
161   Plaintext plaintext4Dec;
162   Plaintext plaintext5Dec;
163   Plaintext plaintext6Dec;
164 
165   start = currentDateTime();
166 
167   cryptoContext->Decrypt(keyPair.secretKey, ciphertext1, &plaintext1Dec);
168   cryptoContext->Decrypt(keyPair.secretKey, ciphertext2, &plaintext2Dec);
169   cryptoContext->Decrypt(keyPair.secretKey, ciphertext3, &plaintext3Dec);
170   cryptoContext->Decrypt(keyPair.secretKey, ciphertext4, &plaintext4Dec);
171   cryptoContext->Decrypt(keyPair.secretKey, ciphertext5, &plaintext5Dec);
172   cryptoContext->Decrypt(keyPair.secretKey, ciphertext6, &plaintext6Dec);
173 
174   finish = currentDateTime();
175   diff = finish - start;
176   cout << "Decryption time: "
177        << "\t" << diff << " ms" << endl;
178 
179   cout << "\n Original Plaintext: \n";
180   cout << *plaintext1 << endl;
181   cout << *plaintext2 << endl;
182   cout << *plaintext3 << endl;
183   cout << *plaintext4 << endl;
184   cout << *plaintext5 << endl;
185   cout << *plaintext6 << endl;
186 
187   cout << "\n Resulting Decryption of Ciphertext: \n";
188   cout << *plaintext1Dec << endl;
189   cout << *plaintext2Dec << endl;
190   cout << *plaintext3Dec << endl;
191   cout << *plaintext4Dec << endl;
192   cout << *plaintext5Dec << endl;
193   cout << *plaintext6Dec << endl;
194 
195   cout << "\n";
196 
197   ////////////////////////////////////////////////////////////
198   // EvalMult Operation
199   ////////////////////////////////////////////////////////////
200 
201   Ciphertext<DCRTPoly> ciphertextMul12;
202   Ciphertext<DCRTPoly> ciphertextMul123;
203   Ciphertext<DCRTPoly> ciphertextMul1234;
204   Ciphertext<DCRTPoly> ciphertextMul12345;
205   Ciphertext<DCRTPoly> ciphertextMul123456;
206 
207   start = currentDateTime();
208   // Perform consecutive multiplications and do a keyswtiching at the end.
209   ciphertextMul12 = cryptoContext->EvalMultNoRelin(ciphertext1, ciphertext2);
210   ciphertextMul123 =
211       cryptoContext->EvalMultNoRelin(ciphertextMul12, ciphertext3);
212   ciphertextMul1234 =
213       cryptoContext->EvalMultNoRelin(ciphertextMul123, ciphertext4);
214   ciphertextMul12345 =
215       cryptoContext->EvalMultNoRelin(ciphertextMul1234, ciphertext5);
216   ciphertextMul123456 =
217       cryptoContext->EvalMultAndRelinearize(ciphertextMul12345, ciphertext6);
218 
219   finish = currentDateTime();
220   diff = finish - start;
221   cout << "EvalMult time: "
222        << "\t" << diff << " ms" << endl;
223 
224   ////////////////////////////////////////////////////////////
225   // Decryption after Accumulation Operation on Re-Encrypted Data
226   ////////////////////////////////////////////////////////////
227 
228   Plaintext plaintextMul1;
229   Plaintext plaintextMul2;
230   Plaintext plaintextMul3;
231   Plaintext plaintextMul4;
232   Plaintext plaintextMul5;
233 
234   start = currentDateTime();
235 
236   cryptoContext->Decrypt(keyPair.secretKey, ciphertextMul12, &plaintextMul1);
237   cryptoContext->Decrypt(keyPair.secretKey, ciphertextMul123, &plaintextMul2);
238   cryptoContext->Decrypt(keyPair.secretKey, ciphertextMul1234, &plaintextMul3);
239   cryptoContext->Decrypt(keyPair.secretKey, ciphertextMul12345, &plaintextMul4);
240   cryptoContext->Decrypt(keyPair.secretKey, ciphertextMul123456,
241                          &plaintextMul5);
242 
243   finish = currentDateTime();
244   diff = finish - start;
245 
246   // std::cin.get();
247 
248   cout << "\n Original Plaintext: \n";
249   cout << *plaintext1 << endl;
250   cout << *plaintext2 << endl;
251   cout << *plaintext3 << endl;
252   cout << *plaintext4 << endl;
253   cout << *plaintext5 << endl;
254   cout << *plaintext6 << endl;
255 
256   cout << "\n Resulting Plaintext (after polynomial multiplication): \n";
257   cout << *plaintextMul1 << endl;
258   cout << *plaintextMul2 << endl;
259   cout << *plaintextMul3 << endl;
260   cout << *plaintextMul4 << endl;
261   cout << *plaintextMul5 << endl;
262 
263   cout << "\n";
264 
265   ////////////////////////////////////////////////////////////
266   // EvalAdd Operation
267   ////////////////////////////////////////////////////////////
268 
269   Ciphertext<DCRTPoly> ciphertextAdd12;
270   Ciphertext<DCRTPoly> ciphertextAdd123;
271 
272   start = currentDateTime();
273 
274   ciphertextAdd12 = cryptoContext->EvalAdd(ciphertextMul12, ciphertextMul12345);
275   ciphertextAdd123 = cryptoContext->EvalAdd(ciphertextAdd12, ciphertextMul123);
276 
277   finish = currentDateTime();
278   diff = finish - start;
279   cout << "EvalAdd time: "
280        << "\t" << diff << " ms" << endl;
281 
282   ////////////////////////////////////////////////////////////
283   // Decryption after Accumulation Operation
284   ////////////////////////////////////////////////////////////
285 
286   Plaintext plaintextAdd1;
287   Plaintext plaintextAdd2;
288 
289   start = currentDateTime();
290 
291   cryptoContext->Decrypt(keyPair.secretKey, ciphertextAdd12, &plaintextAdd1);
292   cryptoContext->Decrypt(keyPair.secretKey, ciphertextAdd123, &plaintextAdd2);
293 
294   finish = currentDateTime();
295   diff = finish - start;
296 
297   cout << "\n Original Plaintext: \n";
298   cout << *plaintextMul1 << endl;
299   cout << *plaintextMul4 << endl;
300   cout << *plaintextMul5 << endl;
301 
302   cout << "\n Resulting Added Plaintext: \n";
303   cout << *plaintextAdd1 << endl;
304   cout << *plaintextAdd2 << endl;
305 
306   cout << "\n";
307 
308   ////////////////////////////////////////////////////////////
309   // Done
310   ////////////////////////////////////////////////////////////
311   Ciphertext<DCRTPoly> ciphertextMul1234567;
312   vector<Ciphertext<DCRTPoly>> cipherTextList;
313 
314   cipherTextList.push_back(ciphertext1);
315   cipherTextList.push_back(ciphertext2);
316   cipherTextList.push_back(ciphertext3);
317   cipherTextList.push_back(ciphertext4);
318   cipherTextList.push_back(ciphertext5);
319 
320   ciphertextMul1234567 = cryptoContext->EvalMultMany(cipherTextList);
321 
322   Plaintext plaintextMul7;
323   cryptoContext->Decrypt(keyPair.secretKey, ciphertextMul1234567,
324                          &plaintextMul7);
325 
326   cout << *plaintextMul7 << endl;
327 
328   std::cout << "Execution Completed." << std::endl;
329 
330   return 0;
331 }
332