1 /* Copyright (C) 2012-2019 IBM Corp.
2 * This program is Licensed under the Apache License, Version 2.0
3 * (the "License"); you may not use this file except in compliance
4 * with the License. You may obtain a copy of the License at
5 * http://www.apache.org/licenses/LICENSE-2.0
6 * Unless required by applicable law or agreed to in writing, software
7 * distributed under the License is distributed on an "AS IS" BASIS,
8 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 * See the License for the specific language governing permissions and
10 * limitations under the License. See accompanying LICENSE file.
11 */
12
13 /* Test_IO.cpp - Testing the I/O of the important classes of the library
14 * (context, keys, ciphertexts).
15 */
16 #include <cassert>
17 #include <fstream>
18 #include <unistd.h>
19
20 #include <NTL/ZZX.h>
21 #include <NTL/vector.h>
22
23 #include <helib/helib.h>
24 #include <helib/ArgMap.h>
25
26 NTL_CLIENT
27 using namespace helib;
28
29 #define N_TESTS 3
30 static long ms[N_TESTS][10] = {
31 //nSlots m phi(m) ord(2)
32 // { 2, 7, 6, 3, 0,0,0,0,0,0},
33 { 6, 31, 30, 5, 0,0,0,0,0,0},
34 { 6, 127, 126, 7, 127, 1, 108, 24, 6,-3}, // gens=108(6), 24(!3)
35 { 60, 1023, 600, 10, 11, 93, 838, 584, 10, 6}, // gens=838(10),584(6)
36 // { 378, 5461, 5292, 14}, // gens=3(126),509(3)
37 // { 630, 8191, 8190, 13}, // gens=39(630)
38 // { 600, 13981, 12000, 20}, // gens=10(30),23(10),3(!2)
39 // { 682, 15709, 15004, 22} // gens=5(682)
40 };
41
42 void checkCiphertext(const Ctxt& ctxt, const ZZX& ptxt, const SecKey& sk);
43
44 // Testing the I/O of the important classes of the library
45 // (context, keys, ciphertexts).
main(int argc,char * argv[])46 int main(int argc, char *argv[])
47 {
48 ArgMap amap;
49
50 long r=1;
51 long p=2;
52 long c = 2;
53 long w = 64;
54 long L = 100;
55 long mm=0;
56 bool noPrint = true;
57 amap.arg("p", p, "plaintext base");
58 amap.arg("r", r, "lifting");
59 amap.arg("c", c, "number of columns in the key-switching matrices");
60 amap.arg("m", mm, "cyclotomic index","{31,127,1023}");
61 amap.arg("noPrint", noPrint, "suppress printouts");
62 amap.parse(argc, argv);
63
64 bool useTable = (mm==0 && p==2);
65 long ptxtSpace = power_long(p,r);
66 long numTests = useTable? N_TESTS : 1;
67
68 std::unique_ptr<Context> contexts[numTests];
69 std::unique_ptr<SecKey> sKeys[numTests];
70 std::unique_ptr<Ctxt> ctxts[numTests];
71 std::unique_ptr<EncryptedArray> eas[numTests];
72 vector<ZZX> ptxts[numTests];
73
74 // first loop: generate stuff and write it to file
75
76 // open file for writing
77 {fstream keyFile("iotest.txt", fstream::out|fstream::trunc);
78 assert(keyFile.is_open());
79 for (long i=0; i<numTests; i++) {
80 long m = (mm==0)? ms[i][1] : mm;
81
82 if (!noPrint)
83 cout << "Testing IO: m="<<m<<", p^r="<<p<<"^"<<r<<endl;
84
85 Vec<long> mvec(INIT_SIZE,2);
86 mvec[0] = ms[i][4]; mvec[1] = ms[i][5];
87 vector<long> gens(2);
88 gens[0] = ms[i][6]; gens[1] = ms[i][7];
89 vector<long> ords(2);
90 ords[0] = ms[i][8]; ords[1] = ms[i][9];
91
92 if (useTable && gens[0]>0)
93 contexts[i].reset(new Context(m, p, r, gens, ords));
94 else
95 contexts[i].reset(new Context(m, p, r));
96 if (!noPrint)
97 contexts[i]->zMStar.printout();
98
99 buildModChain(*contexts[i], L, c); // Set the modulus chain
100 if (mm==0 && m==1023) contexts[i]->enableBootStrapping(mvec);
101
102 // Output the Context to file
103 writeContextBase(keyFile, *contexts[i]);
104 if (!noPrint)
105 writeContextBase(cout, *contexts[i]);
106 keyFile << *contexts[i] << endl;
107
108 sKeys[i].reset(new SecKey(*contexts[i]));
109 sKeys[i]->GenSecKey(); // A +-1/0 secret key
110 addSome1DMatrices(*sKeys[i]);// compute key-switching matrices that we need
111 const PubKey publicKey = *sKeys[i];
112 eas[i].reset(new EncryptedArray(*contexts[i]));
113
114 long nslots = eas[i]->size();
115
116 // Output the secret key to file, twice. Below we will have two copies
117 // of most things.
118 keyFile << *sKeys[i] << endl;;
119 keyFile << *sKeys[i] << endl;;
120
121 vector<ZZX> b;
122 long p2r = eas[i]->getContext().alMod.getPPowR();
123 ZZX poly = RandPoly(0,to_ZZ(p2r)); // choose a random constant polynomial
124 eas[i]->decode(ptxts[i], poly);
125
126 ctxts[i].reset(new Ctxt(publicKey));
127 eas[i]->encrypt(*ctxts[i], publicKey, ptxts[i]);
128 eas[i]->decrypt(*ctxts[i], *sKeys[i], b);
129 assert(ptxts[i].size() == b.size());
130 for (long j = 0; j < nslots; j++) assert (ptxts[i][j] == b[j]);
131
132 // output the plaintext
133 keyFile << "[ ";
134 for (long j = 0; j < nslots; j++) keyFile << ptxts[i][j] << " ";
135 keyFile << "]\n";
136
137 eas[i]->encode(poly,ptxts[i]);
138 keyFile << poly << endl;
139
140 // Output the ciphertext to file
141 keyFile << *ctxts[i] << endl;
142 keyFile << *ctxts[i] << endl;
143 // cerr << "okay " << i << endl<< endl;
144 }
145 keyFile.close();}
146 // cerr << "so far, so good\n\n";
147
148 // second loop: read from input and repeat the computation
149
150 // open file for read
151 {fstream keyFile("iotest.txt", fstream::in);
152 for (long i=0; i<numTests; i++) {
153
154 // Read context from file
155 unsigned long m1, p1, r1;
156 vector<long> gens, ords;
157 readContextBase(keyFile, m1, p1, r1, gens, ords);
158 Context tmpContext(m1, p1, r1, gens, ords);
159 keyFile >> tmpContext;
160 assert (*contexts[i] == tmpContext);
161 // cerr << i << ": context matches input\n";
162 cout << "GOOD\n";
163
164 // We define some things below wrt *contexts[i], not tmpContext.
165 // This is because the various operator== methods check equality of
166 // references, not equality of the referenced Context objects.
167 Context& context = *contexts[i];
168 SecKey secretKey(context);
169 SecKey secretKey2(tmpContext);
170 const PubKey& publicKey = secretKey;
171 const PubKey& publicKey2 = secretKey2;
172
173 keyFile >> secretKey;
174 keyFile >> secretKey2;
175 assert(secretKey == *sKeys[i]);
176 // cerr << " secret key matches input\n";
177 cout << "GOOD\n";
178
179 EncryptedArray ea(context);
180 EncryptedArray ea2(tmpContext);
181
182 long nslots = ea.size();
183
184 // Read the plaintext from file
185 vector<ZZX> a;
186 a.resize(nslots);
187 assert(nslots == (long)ptxts[i].size());
188 seekPastChar(keyFile, '['); // defined in NumbTh.cpp
189 for (long j = 0; j < nslots; j++) {
190 keyFile >> a[j];
191 assert(a[j] == ptxts[i][j]);
192 }
193 seekPastChar(keyFile, ']');
194 cout << "GOOD\n";
195 // cerr << " ptxt matches input\n";
196
197 // Read the encoded plaintext from file
198 ZZX poly1, poly2;
199 keyFile >> poly1;
200 eas[i]->encode(poly2,a);
201 assert(poly1 == poly2);
202 cout << "GOOD\n";
203 // cerr << " eas[i].encode(a)==poly1 okay\n";
204
205 ea.encode(poly2,a);
206 assert(poly1 == poly2);
207 cout << "GOOD\n";
208 // cerr << " ea.encode(a)==poly1 okay\n";
209
210 ea2.encode(poly2,a);
211 assert(poly1 == poly2);
212 cout << "GOOD\n";
213 // cerr << " ea2.encode(a)==poly1 okay\n";
214
215 eas[i]->decode(a,poly1);
216 assert(nslots == (long)a.size());
217 for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
218 cout << "GOOD\n";
219 // cerr << " eas[i].decode(poly1)==ptxts[i] okay\n";
220
221 ea.decode(a,poly1);
222 assert(nslots == (long)a.size());
223 for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
224 cout << "GOOD\n";
225 // cerr << " ea.decode(poly1)==ptxts[i] okay\n";
226
227 ea2.decode(a,poly1);
228 assert(nslots == (long)a.size());
229 for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
230 cout << "GOOD\n";
231 // cerr << " ea2.decode(poly1)==ptxts[i] okay\n";
232
233 // Read ciperhtext from file
234 Ctxt ctxt(publicKey);
235 Ctxt ctxt2(publicKey2);
236 keyFile >> ctxt;
237 keyFile >> ctxt2;
238 assert(ctxts[i]->equalsTo(ctxt,/*comparePkeys=*/false));
239 cout << "GOOD\n";
240 // cerr << " ctxt matches input\n";
241
242 sKeys[i]->Decrypt(poly2,*ctxts[i]);
243 assert(poly1 == poly2);
244 cout << "GOOD\n";
245 // cerr << " sKeys[i]->decrypt(*ctxts[i]) == poly1 okay\n";
246
247 secretKey.Decrypt(poly2,*ctxts[i]);
248 assert(poly1 == poly2);
249 cout << "GOOD\n";
250 // cerr << " secretKey.decrypt(*ctxts[i]) == poly1 okay\n";
251
252 secretKey.Decrypt(poly2,ctxt);
253 assert(poly1 == poly2);
254 cout << "GOOD\n";
255 // cerr << " secretKey.decrypt(ctxt) == poly1 okay\n";
256
257 secretKey2.Decrypt(poly2,ctxt2);
258 assert(poly1 == poly2);
259 cout << "GOOD\n";
260 // cerr << " secretKey2.decrypt(ctxt2) == poly1 okay\n";
261
262 eas[i]->decrypt(ctxt, *sKeys[i], a);
263 assert(nslots == (long)a.size());
264 for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
265 cout << "GOOD\n";
266 // cerr << " eas[i].decrypt(ctxt, *sKeys[i])==ptxts[i] okay\n";
267
268 ea.decrypt(ctxt, secretKey, a);
269 assert(nslots == (long)a.size());
270 for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
271 cout << "GOOD\n";
272 // cerr << " ea.decrypt(ctxt, secretKey)==ptxts[i] okay\n";
273
274 ea2.decrypt(ctxt2, secretKey2, a);
275 assert(nslots == (long)a.size());
276 for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]);
277 cout << "GOOD\n";
278 // cerr << " ea2.decrypt(ctxt2, secretKey2)==ptxts[i] okay\n";
279 }}
280 unlink("iotest.txt"); // clean up before exiting
281 }
282