Skip to content

Commit 55aef03

Browse files
authored
Ctxt Multiplication additional test and fixes
Ctxt Multiplication additional test and fixes * Fixed an error in TestCKKS rawMultiplication and added square test * Added extra checks for relinearization after multiplications. Added new tests for TestBGV which attempt to mimic TestCKKS
1 parent a6f02c5 commit 55aef03

File tree

3 files changed

+413
-4
lines changed

3 files changed

+413
-4
lines changed

tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ if (NOT ONLY_ADD_TEST)
2424
set(GTEST_SRC
2525
"test_common.cpp"
2626
"TestArgMap.cpp"
27+
"TestBGV.cpp"
2728
"TestBootstrappingWithMultiplications.cpp"
2829
"TestCKKS.cpp"
2930
"TestContext.cpp"
@@ -135,6 +136,7 @@ set(TEST_NAMES
135136
"GTestThinBootstrapping"
136137
"GTestThinEvalMap"
137138
"TestArgMap"
139+
"TestBGV"
138140
"TestCKKS"
139141
"TestContext"
140142
"TestCtxt"

tests/TestBGV.cpp

Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
/* Copyright (C) 2020 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+
#include <NTL/ZZ.h>
14+
#include <algorithm>
15+
16+
#include <helib/helib.h>
17+
#include <helib/debugging.h>
18+
19+
#include "gtest/gtest.h"
20+
#include "test_common.h"
21+
22+
namespace {
23+
struct Parameters
24+
{
25+
Parameters(unsigned m,
26+
unsigned p,
27+
unsigned r,
28+
unsigned bits,
29+
const std::vector<long>& gens = {},
30+
const std::vector<long>& ords = {}) :
31+
m(m), p(p), r(r), bits(bits), gens(gens), ords(ords){};
32+
33+
const unsigned m;
34+
const unsigned p;
35+
const unsigned r;
36+
const unsigned bits;
37+
const std::vector<long> gens;
38+
const std::vector<long> ords;
39+
40+
friend std::ostream& operator<<(std::ostream& os, const Parameters& params)
41+
{
42+
return os << "{"
43+
<< "m = " << params.m << ", "
44+
<< "p = " << params.p << ", "
45+
<< "r = " << params.r << ", "
46+
<< "gens = " << helib::vecToStr(params.gens) << ", "
47+
<< "ords = " << helib::vecToStr(params.ords) << ", "
48+
<< "bits = " << params.bits << "}";
49+
}
50+
};
51+
52+
class TestBGV : public ::testing::TestWithParam<Parameters>
53+
{
54+
protected:
55+
const unsigned long m;
56+
const unsigned long p;
57+
const unsigned long r;
58+
const unsigned long bits;
59+
helib::Context context;
60+
helib::SecKey secretKey;
61+
const helib::PubKey publicKey;
62+
const helib::EncryptedArray& ea;
63+
64+
TestBGV() :
65+
m(GetParam().m),
66+
p(GetParam().p),
67+
r(GetParam().r),
68+
bits(GetParam().bits),
69+
context(m, p, r),
70+
secretKey((buildModChain(context, bits), context)),
71+
publicKey((secretKey.GenSecKey(),
72+
helib::addSome1DMatrices(secretKey),
73+
secretKey)),
74+
ea(*(context.ea))
75+
{}
76+
77+
virtual void SetUp() override
78+
{
79+
if (helib_test::verbose) {
80+
ea.getPAlgebra().printout();
81+
std::cout << "r = " << context.alMod.getR() << std::endl;
82+
std::cout << "ctxtPrimes=" << context.ctxtPrimes
83+
<< ", specialPrimes=" << context.specialPrimes << std::endl
84+
<< std::endl;
85+
}
86+
87+
helib::setupDebugGlobals(&secretKey, context.ea);
88+
}
89+
90+
virtual void TearDown() override { helib::cleanupDebugGlobals(); }
91+
};
92+
93+
TEST_P(TestBGV, negatingCiphertextWorks)
94+
{
95+
helib::PtxtArray p1(ea), p2(ea);
96+
p1.random();
97+
98+
helib::Ctxt c1(publicKey);
99+
p1.encrypt(c1);
100+
101+
c1.negate();
102+
p1.negate();
103+
104+
p2.decrypt(c1, secretKey);
105+
106+
EXPECT_EQ(p1, p2);
107+
}
108+
109+
TEST_P(TestBGV, addingPolyConstantToCiphertextWorks)
110+
{
111+
helib::PtxtArray p1(ea), p2(ea), const1(ea);
112+
p1.random();
113+
const1.random();
114+
115+
helib::Ctxt c1(publicKey);
116+
p1.encrypt(c1);
117+
118+
c1.addConstant(const1);
119+
p1 += const1;
120+
121+
p2.decrypt(c1, secretKey);
122+
123+
EXPECT_EQ(p1, p2);
124+
}
125+
126+
TEST_P(TestBGV, addingNegatedPolyConstantToCiphertextWorks)
127+
{
128+
helib::PtxtArray p1(ea), p2(ea), const1(ea);
129+
p1.random();
130+
const1.random();
131+
132+
helib::Ctxt c1(publicKey);
133+
p1.encrypt(c1);
134+
135+
p1 -= const1;
136+
const1.negate();
137+
c1.addConstant(const1);
138+
139+
p2.decrypt(c1, secretKey);
140+
141+
EXPECT_EQ(p1, p2);
142+
}
143+
144+
TEST_P(TestBGV, multiplyingPolyConstantToCiphertextWorks)
145+
{
146+
helib::PtxtArray p1(ea), p2(ea), const1(ea);
147+
p1.random();
148+
const1.random();
149+
150+
helib::Ctxt c1(publicKey);
151+
p1.encrypt(c1);
152+
153+
c1.multByConstant(const1);
154+
p1 *= const1;
155+
156+
p2.decrypt(c1, secretKey);
157+
158+
EXPECT_EQ(p1, p2);
159+
}
160+
161+
TEST_P(TestBGV, addingLongToCiphertextWorks)
162+
{
163+
long const1 = 1;
164+
helib::PtxtArray p1(ea), p2(ea);
165+
p1.random();
166+
167+
helib::Ctxt c1(publicKey);
168+
p1.encrypt(c1);
169+
170+
c1.addConstant(const1);
171+
p1 += const1;
172+
173+
p2.decrypt(c1, secretKey);
174+
175+
EXPECT_EQ(p1, p2);
176+
}
177+
178+
TEST_P(TestBGV, multiplyingLongToCiphertextWorks)
179+
{
180+
long const1 = 2;
181+
helib::PtxtArray p1(ea), p2(ea);
182+
p1.random();
183+
184+
helib::Ctxt c1(publicKey);
185+
p1.encrypt(c1);
186+
187+
c1.multByConstant(const1);
188+
p1 *= const1;
189+
190+
p2.decrypt(c1, secretKey);
191+
192+
EXPECT_EQ(p1, p2);
193+
}
194+
195+
TEST_P(TestBGV, rotatingCiphertextWorks)
196+
{
197+
helib::PtxtArray p1(ea), p2(ea);
198+
p1.random();
199+
200+
helib::Ctxt c1(publicKey);
201+
p1.encrypt(c1);
202+
203+
ea.rotate(c1, 3);
204+
rotate(p1, 3);
205+
206+
p2.decrypt(c1, secretKey);
207+
208+
EXPECT_EQ(p1, p2);
209+
}
210+
211+
TEST_P(TestBGV, addingCiphertextsWorks)
212+
{
213+
helib::PtxtArray p1(ea), p2(ea), p3(ea);
214+
p1.random();
215+
p2.random();
216+
217+
helib::Ctxt c1(publicKey), c2(publicKey);
218+
p1.encrypt(c1);
219+
p2.encrypt(c2);
220+
221+
c1 += c2;
222+
p1 += p2;
223+
224+
p3.decrypt(c1, secretKey);
225+
226+
EXPECT_EQ(p1, p3);
227+
}
228+
229+
TEST_P(TestBGV, subtractingCiphertextsWorks)
230+
{
231+
helib::PtxtArray p1(ea), p2(ea), p3(ea);
232+
p1.random();
233+
p2.random();
234+
235+
helib::Ctxt c1(publicKey), c2(publicKey);
236+
p1.encrypt(c1);
237+
p2.encrypt(c2);
238+
239+
c1 -= c2;
240+
p1 -= p2;
241+
242+
p3.decrypt(c1, secretKey);
243+
244+
EXPECT_EQ(p1, p3);
245+
}
246+
247+
TEST_P(TestBGV, timesEqualsOfCiphertextsWorks)
248+
{
249+
helib::PtxtArray p1(ea), p2(ea), p3(ea);
250+
p1.random();
251+
p2.random();
252+
253+
helib::Ctxt c1(publicKey), c2(publicKey);
254+
p1.encrypt(c1);
255+
p2.encrypt(c2);
256+
257+
c1 *= c2;
258+
p1 *= p2;
259+
260+
p3.decrypt(c1, secretKey);
261+
262+
EXPECT_EQ(p1, p3);
263+
// Check that relinearization has occurred
264+
EXPECT_TRUE(c1.inCanonicalForm());
265+
}
266+
267+
TEST_P(TestBGV, rawMultiplicationOfCiphertextsWorks)
268+
{
269+
helib::PtxtArray p1(ea), p2(ea), p3(ea);
270+
p1.random();
271+
p2.random();
272+
273+
helib::Ctxt c1(publicKey), c2(publicKey);
274+
p1.encrypt(c1);
275+
p2.encrypt(c2);
276+
277+
c1.multLowLvl(c2);
278+
p1 *= p2;
279+
280+
p3.decrypt(c1, secretKey);
281+
282+
EXPECT_EQ(p1, p3);
283+
// Check that relinearization has not occurred
284+
EXPECT_FALSE(c1.inCanonicalForm());
285+
}
286+
287+
TEST_P(TestBGV, highLevelMultiplicationOfCiphertextsWorks)
288+
{
289+
helib::PtxtArray p1(ea), p2(ea), p3(ea);
290+
p1.random();
291+
p2.random();
292+
293+
helib::Ctxt c1(publicKey), c2(publicKey);
294+
p1.encrypt(c1);
295+
p2.encrypt(c2);
296+
297+
c1.multiplyBy(c2);
298+
p1 *= p2;
299+
300+
p3.decrypt(c1, secretKey);
301+
302+
EXPECT_EQ(p1, p3);
303+
// Check that relinearization has not occurred
304+
EXPECT_TRUE(c1.inCanonicalForm());
305+
}
306+
307+
TEST_P(TestBGV, squaringCiphertextWorks)
308+
{
309+
helib::PtxtArray p1(ea), p2(ea);
310+
p1.random();
311+
312+
helib::Ctxt c1(publicKey);
313+
p1.encrypt(c1);
314+
315+
c1.square();
316+
p1 *= p1;
317+
318+
p2.decrypt(c1, secretKey);
319+
320+
EXPECT_EQ(p1, p2);
321+
// Check that relinearization has not occurred
322+
EXPECT_TRUE(c1.inCanonicalForm());
323+
}
324+
325+
TEST_P(
326+
TestBGV,
327+
multiplyingCiphertextByNegativeConstantAndThenAddingToOtherCiphertextWorks)
328+
{
329+
helib::PtxtArray p1(ea), p2(ea), p3(ea), const1(ea, -1);
330+
p1.random();
331+
p2.random();
332+
333+
helib::Ctxt c1(publicKey), c2(publicKey);
334+
p1.encrypt(c1);
335+
p2.encrypt(c2);
336+
337+
c1.multByConstant(const1);
338+
c1 += c2;
339+
p1 *= const1;
340+
p1 += p2;
341+
342+
p3.decrypt(c1, secretKey);
343+
344+
EXPECT_EQ(p1, p3);
345+
}
346+
347+
INSTANTIATE_TEST_SUITE_P(typicalParameters,
348+
TestBGV,
349+
::testing::Values(
350+
// FAST
351+
Parameters(257, 2, 1, 150)
352+
// SLOW
353+
// Parameters(2049, 2, 1, 150)
354+
));
355+
356+
} // namespace

0 commit comments

Comments
 (0)