1 /*
2 * Copyright 2019 Google LLC.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 // Unit Tests for CamenischShoup.
17
18 #include "private_join_and_compute/crypto/camenisch_shoup.h"
19
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22
23 #include <cmath>
24 #include <cstdint>
25 #include <memory>
26 #include <tuple>
27 #include <utility>
28 #include <vector>
29
30 #include "private_join_and_compute/crypto/big_num.h"
31 #include "private_join_and_compute/crypto/proto/camenisch_shoup.pb.h"
32 #include "private_join_and_compute/crypto/proto/proto_util.h"
33 #include "private_join_and_compute/util/status.inc"
34 #include "private_join_and_compute/util/status_testing.inc"
35
36 namespace private_join_and_compute {
37 namespace {
38 using ::testing::Eq;
39 using ::testing::HasSubstr;
40 using testing::IsOkAndHolds;
41 using testing::StatusIs;
42 using ::testing::TestWithParam;
43
PowInt(uint64_t base,int exponent)44 inline uint64_t PowInt(uint64_t base, int exponent) {
45 return static_cast<uint64_t>(std::pow(base, exponent));
46 }
47
48 const uint64_t P = 5;
49 const uint64_t Q = 7;
50 const uint64_t N = P * Q;
51 const uint64_t S = 1;
52 const uint64_t N_TO_S_PLUS_1 = PowInt(N, S + 1);
53 const uint64_t G = 607;
54 const uint64_t X = 2;
55 const uint64_t Y = PowInt(G, X) % N_TO_S_PLUS_1;
56
TEST(GenerateCamenischShoupKeyTest,GenerateKey)57 TEST(GenerateCamenischShoupKeyTest, GenerateKey) {
58 Context ctx;
59 int64_t n_length_bits = 32;
60 for (uint64_t s : {1, 2, 5}) {
61 for (uint64_t vector_commitment_length : {1, 2, 5}) {
62 CamenischShoupKey key = GenerateCamenischShoupKey(
63 &ctx, n_length_bits, s, vector_commitment_length);
64 // Check primes are the right length.
65 EXPECT_EQ(key.p.BitLength(), n_length_bits / 2);
66 EXPECT_EQ(key.q.BitLength(), n_length_bits / 2);
67 // Check n = p*q
68 EXPECT_EQ(key.n, key.p * key.q);
69 EXPECT_EQ(s, key.s);
70 BigNum n_to_s_plus_one = key.n.Exp(ctx.CreateBigNum(s + 1));
71 BigNum phi_n = (key.p - ctx.One()) * (key.q - ctx.One());
72 // Check that g has the right order.
73 EXPECT_EQ(ctx.One(), key.g.ModExp(phi_n, n_to_s_plus_one));
74 // Check that xs and ys have the right length and the right form.
75 EXPECT_EQ(key.ys.size(), vector_commitment_length);
76 EXPECT_EQ(key.xs.size(), vector_commitment_length);
77 for (uint64_t i = 0; i < vector_commitment_length; i++) {
78 EXPECT_EQ(key.ys[i], key.g.ModExp(key.xs[i], n_to_s_plus_one));
79 EXPECT_TRUE(key.xs[i].Gcd(key.n).IsOne());
80 EXPECT_LT(key.xs[i], key.n);
81 }
82 }
83 }
84 }
85
TEST(GenerateCamenischShoupKeyTest,GenerateKeyPair)86 TEST(GenerateCamenischShoupKeyTest, GenerateKeyPair) {
87 Context ctx;
88 BigNum n = ctx.CreateBigNum(N);
89 BigNum phi_n = ctx.CreateBigNum((P - 1) * (Q - 1));
90 uint64_t s = 2;
91 uint64_t vector_commitment_length = 2;
92 std::unique_ptr<CamenischShoupPublicKey> public_key;
93 std::unique_ptr<CamenischShoupPrivateKey> private_key;
94
95 std::tie(public_key, private_key) =
96 GenerateCamenischShoupKeyPair(&ctx, n, s, vector_commitment_length);
97 EXPECT_EQ(s, public_key->s);
98 BigNum n_to_s_plus_one = public_key->n.Exp(ctx.CreateBigNum(s + 1));
99
100 // Check that g has the right order.
101 EXPECT_EQ(ctx.One(), public_key->g.ModExp(phi_n, n_to_s_plus_one));
102 // Check that xs and ys have the right length and the right form.
103 EXPECT_EQ(public_key->ys.size(), vector_commitment_length);
104 EXPECT_EQ(private_key->xs.size(), vector_commitment_length);
105 for (uint64_t i = 0; i < vector_commitment_length; i++) {
106 EXPECT_EQ(public_key->ys[i],
107 public_key->g.ModExp(private_key->xs[i], n_to_s_plus_one));
108 EXPECT_TRUE(private_key->xs[i].Gcd(public_key->n).IsOne());
109 EXPECT_LT(private_key->xs[i], public_key->n);
110 }
111 }
112
113 // A test fixture for Serializing CamenischShoup Keys.
114 class SerializeCamenischShoupKeyTest : public ::testing::Test {
115 protected:
SetUp()116 void SetUp() override {
117 BigNum n = ctx_.CreateBigNum(N);
118 BigNum phi_n = ctx_.CreateBigNum((P - 1) * (Q - 1));
119 uint64_t s = 2;
120 int64_t vector_commitment_length = 2;
121
122 std::tie(public_key_, private_key_) =
123 GenerateCamenischShoupKeyPair(&ctx_, n, s, vector_commitment_length);
124 }
125
126 Context ctx_;
127 std::unique_ptr<CamenischShoupPublicKey> public_key_;
128 std::unique_ptr<CamenischShoupPrivateKey> private_key_;
129 };
130
TEST_F(SerializeCamenischShoupKeyTest,SerializeAndDeserializeKeyPair)131 TEST_F(SerializeCamenischShoupKeyTest, SerializeAndDeserializeKeyPair) {
132 // Serialize and deserialize public key
133 proto::CamenischShoupPublicKey public_key_proto =
134 CamenischShoupPublicKeyToProto(*public_key_);
135 ASSERT_OK_AND_ASSIGN(
136 CamenischShoupPublicKey public_key_deserialized,
137 ParseCamenischShoupPublicKeyProto(&ctx_, public_key_proto));
138
139 // Serialize and deserialize private key
140 proto::CamenischShoupPrivateKey private_key_proto =
141 CamenischShoupPrivateKeyToProto(*private_key_);
142 ASSERT_OK_AND_ASSIGN(
143 CamenischShoupPrivateKey private_key_deserialized,
144 ParseCamenischShoupPrivateKeyProto(&ctx_, private_key_proto));
145
146 // Check that fields all line up correctly.
147 EXPECT_EQ(public_key_->n, public_key_deserialized.n);
148 EXPECT_EQ(public_key_->s, public_key_deserialized.s);
149 EXPECT_EQ(public_key_->vector_encryption_length,
150 public_key_deserialized.vector_encryption_length);
151 EXPECT_EQ(public_key_->g, public_key_deserialized.g);
152 EXPECT_EQ(public_key_->ys, public_key_deserialized.ys);
153 EXPECT_EQ(private_key_->xs, private_key_deserialized.xs);
154 }
155
TEST_F(SerializeCamenischShoupKeyTest,DeserializingPublicKeyFailsWhenNIsMissing)156 TEST_F(SerializeCamenischShoupKeyTest,
157 DeserializingPublicKeyFailsWhenNIsMissing) {
158 // Serialize public key
159 proto::CamenischShoupPublicKey public_key_proto =
160 CamenischShoupPublicKeyToProto(*public_key_);
161
162 // Clear n.
163 proto::CamenischShoupPublicKey public_key_proto_no_n = public_key_proto;
164 public_key_proto_no_n.clear_n();
165 EXPECT_THAT(ParseCamenischShoupPublicKeyProto(&ctx_, public_key_proto_no_n),
166 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr(" n ")));
167 }
168
TEST_F(SerializeCamenischShoupKeyTest,DeserializingPublicKeyFailsWhenSIsMissing)169 TEST_F(SerializeCamenischShoupKeyTest,
170 DeserializingPublicKeyFailsWhenSIsMissing) {
171 // Serialize public key
172 proto::CamenischShoupPublicKey public_key_proto =
173 CamenischShoupPublicKeyToProto(*public_key_);
174
175 // Clear s.
176 proto::CamenischShoupPublicKey public_key_proto_no_s = public_key_proto;
177 public_key_proto_no_s.clear_s();
178 EXPECT_THAT(ParseCamenischShoupPublicKeyProto(&ctx_, public_key_proto_no_s),
179 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr(" s ")));
180 }
181
TEST_F(SerializeCamenischShoupKeyTest,DeserializingPublicKeyFailsWhenGIsMissing)182 TEST_F(SerializeCamenischShoupKeyTest,
183 DeserializingPublicKeyFailsWhenGIsMissing) {
184 // Serialize public key
185 proto::CamenischShoupPublicKey public_key_proto =
186 CamenischShoupPublicKeyToProto(*public_key_);
187 // Clear g.
188 proto::CamenischShoupPublicKey public_key_proto_no_g = public_key_proto;
189 public_key_proto_no_g.clear_g();
190 EXPECT_THAT(
191 ParseCamenischShoupPublicKeyProto(&ctx_, public_key_proto_no_g),
192 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("invalid g")));
193 }
194
TEST_F(SerializeCamenischShoupKeyTest,DeserializingPublicKeyFailsWhenYsIsMissing)195 TEST_F(SerializeCamenischShoupKeyTest,
196 DeserializingPublicKeyFailsWhenYsIsMissing) {
197 // Serialize public key
198 proto::CamenischShoupPublicKey public_key_proto =
199 CamenischShoupPublicKeyToProto(*public_key_);
200 // Clear ys.
201 proto::CamenischShoupPublicKey public_key_proto_no_ys = public_key_proto;
202 public_key_proto_no_ys.clear_ys();
203 EXPECT_THAT(
204 ParseCamenischShoupPublicKeyProto(&ctx_, public_key_proto_no_ys),
205 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("empty ys")));
206 }
207
TEST_F(SerializeCamenischShoupKeyTest,DeserializingPublicKeyFailsWhenGIsOutOfBounds)208 TEST_F(SerializeCamenischShoupKeyTest,
209 DeserializingPublicKeyFailsWhenGIsOutOfBounds) {
210 // Serialize public key
211 proto::CamenischShoupPublicKey public_key_proto =
212 CamenischShoupPublicKeyToProto(*public_key_);
213 BigNum out_of_bounds = ctx_.CreateBigNum(N).Exp(ctx_.CreateBigNum(2 * S));
214 // Set g out of bounds.
215 proto::CamenischShoupPublicKey public_key_proto_big_g = public_key_proto;
216 public_key_proto_big_g.set_g(out_of_bounds.ToBytes());
217 EXPECT_THAT(
218 ParseCamenischShoupPublicKeyProto(&ctx_, public_key_proto_big_g),
219 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("invalid g")));
220 }
221
TEST_F(SerializeCamenischShoupKeyTest,DeserializingPublicKeyFailsWhenYsIsOutOfBounds)222 TEST_F(SerializeCamenischShoupKeyTest,
223 DeserializingPublicKeyFailsWhenYsIsOutOfBounds) {
224 // Serialize public key
225 proto::CamenischShoupPublicKey public_key_proto =
226 CamenischShoupPublicKeyToProto(*public_key_);
227 // Set ys[0] out of bounds.
228 BigNum out_of_bounds = ctx_.CreateBigNum(N).Exp(ctx_.CreateBigNum(2 * S));
229 proto::CamenischShoupPublicKey public_key_proto_big_ys = public_key_proto;
230 std::vector<BigNum> big_ys = public_key_->ys;
231 big_ys[0] = out_of_bounds;
232 *public_key_proto_big_ys.mutable_ys() = BigNumVectorToProto(big_ys);
233 EXPECT_THAT(ParseCamenischShoupPublicKeyProto(&ctx_, public_key_proto_big_ys),
234 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("ys")));
235 }
236
237 // A test fixture for CamenischShoup.
238 class CamenischShoupTest : public ::testing::Test {
239 protected:
SetUp()240 void SetUp() override {
241 public_cam_shoup_ = std::make_unique<PublicCamenischShoup>(
242 &ctx_, ctx_.CreateBigNum(N), S, ctx_.CreateBigNum(G),
243 std::vector<BigNum>({ctx_.CreateBigNum(Y)}));
244 private_cam_shoup_ = std::make_unique<PrivateCamenischShoup>(
245 &ctx_, ctx_.CreateBigNum(N), S, ctx_.CreateBigNum(G),
246 std::vector<BigNum>({ctx_.CreateBigNum(Y)}),
247 std::vector<BigNum>({ctx_.CreateBigNum(X)}));
248 }
249
250 Context ctx_;
251 std::unique_ptr<PublicCamenischShoup> public_cam_shoup_;
252 std::unique_ptr<PrivateCamenischShoup> private_cam_shoup_;
253 };
254
TEST_F(CamenischShoupTest,TestEncryptWithRand)255 TEST_F(CamenischShoupTest, TestEncryptWithRand) {
256 BigNum r = ctx_.Three();
257 ASSERT_OK_AND_ASSIGN(
258 CamenischShoupCiphertext ct,
259 private_cam_shoup_->EncryptWithRand({ctx_.CreateBigNum(2)}, r));
260 EXPECT_EQ(ctx_.CreateBigNum(293), // (607)^(3) mod 35^2
261 ct.u);
262 EXPECT_EQ(ctx_.CreateBigNum(904), // (949)^(3) * (1 + 70) mod 35^2
263 ct.es[0]);
264 }
265
TEST_F(CamenischShoupTest,TestEncryptAndGetRand)266 TEST_F(CamenischShoupTest, TestEncryptAndGetRand) {
267 ASSERT_OK_AND_ASSIGN(
268 CamenischShoupCiphertextWithRand ct_with_rand,
269 private_cam_shoup_->EncryptAndGetRand({ctx_.CreateBigNum(2)}));
270 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
271 private_cam_shoup_->EncryptWithRand(
272 {ctx_.CreateBigNum(2)}, ct_with_rand.r));
273 EXPECT_EQ(ct.u, ct_with_rand.ct.u);
274 EXPECT_EQ(ct.es[0], ct_with_rand.ct.es[0]);
275 }
276
TEST_F(CamenischShoupTest,TestEncryptFailsForNegativeMessage)277 TEST_F(CamenischShoupTest, TestEncryptFailsForNegativeMessage) {
278 auto maybe_result = private_cam_shoup_->Encrypt({-ctx_.One()});
279 EXPECT_TRUE(IsInvalidArgument(maybe_result.status()));
280 EXPECT_THAT(maybe_result.status().message(),
281 HasSubstr("Cannot encrypt negative number"));
282 }
283
TEST_F(CamenischShoupTest,TestEncryptWithRandFailsForInvalidRandomness)284 TEST_F(CamenischShoupTest, TestEncryptWithRandFailsForInvalidRandomness) {
285 BigNum m = ctx_.CreateBigNum(2);
286
287 // Negative randomness
288 BigNum r = -ctx_.Three();
289 auto maybe_result_1 = private_cam_shoup_->EncryptWithRand({m}, r);
290 EXPECT_TRUE(IsInvalidArgument(maybe_result_1.status()));
291 EXPECT_THAT(maybe_result_1.status().message(), HasSubstr(">=0"));
292
293 // r not relatively prime to n.
294 r = ctx_.CreateBigNum(P);
295 auto maybe_result_2 = private_cam_shoup_->EncryptWithRand({m}, r);
296 EXPECT_TRUE(IsInvalidArgument(maybe_result_2.status()));
297 EXPECT_THAT(maybe_result_2.status().message(),
298 HasSubstr("not share prime factors"));
299 }
300
TEST_F(CamenischShoupTest,TestEncryptWithDifferentRandoms)301 TEST_F(CamenischShoupTest, TestEncryptWithDifferentRandoms) {
302 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct1,
303 private_cam_shoup_->Encrypt({ctx_.CreateBigNum(2)}));
304 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct2,
305 private_cam_shoup_->Encrypt({ctx_.CreateBigNum(2)}));
306 EXPECT_NE(ct1.u, ct2.u);
307 EXPECT_NE(ct1.es[0], ct2.es[0]);
308 }
309
TEST_F(CamenischShoupTest,TestDecryptFailsWithCorruptCiphertext)310 TEST_F(CamenischShoupTest, TestDecryptFailsWithCorruptCiphertext) {
311 CamenischShoupCiphertext ct =
312 CamenischShoupCiphertext{ctx_.Two(), {ctx_.Two()}};
313 auto maybe_result = private_cam_shoup_->Decrypt(ct);
314 EXPECT_TRUE(IsInvalidArgument(maybe_result.status()));
315 EXPECT_THAT(maybe_result.status().message(),
316 HasSubstr("Corrupt/invalid ciphertext"));
317 }
318
TEST_F(CamenischShoupTest,TestEncryptAndDecryptOneToTen)319 TEST_F(CamenischShoupTest, TestEncryptAndDecryptOneToTen) {
320 private_cam_shoup_ = std::make_unique<PrivateCamenischShoup>(
321 &ctx_, ctx_.CreateBigNum(N), S, ctx_.CreateBigNum(G),
322 std::vector<BigNum>({ctx_.CreateBigNum(Y)}),
323 std::vector<BigNum>({ctx_.CreateBigNum(X)}));
324 for (int i = 0; i < 10; i++) {
325 BigNum bn_i = ctx_.CreateBigNum(i);
326 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
327 private_cam_shoup_->Encrypt({bn_i}));
328 ASSERT_OK_AND_ASSIGN(auto decrypted_value, private_cam_shoup_->Decrypt(ct));
329 EXPECT_EQ(bn_i, decrypted_value[0]);
330 }
331 }
332
TEST_F(CamenischShoupTest,TestEncryptAndDecryptLargeMessage)333 TEST_F(CamenischShoupTest, TestEncryptAndDecryptLargeMessage) {
334 BigNum m = ctx_.CreateBigNum(N + 2);
335 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
336 private_cam_shoup_->Encrypt({m}));
337 ASSERT_OK_AND_ASSIGN(auto decrypted_value, private_cam_shoup_->Decrypt(ct));
338 EXPECT_EQ(m.Mod(ctx_.CreateBigNum(N)), decrypted_value[0]);
339 }
340
TEST_F(CamenischShoupTest,TestPublicEncryptOneAndDecrypt)341 TEST_F(CamenischShoupTest, TestPublicEncryptOneAndDecrypt) {
342 public_cam_shoup_ = std::make_unique<PublicCamenischShoup>(
343 &ctx_, ctx_.CreateBigNum(N), S, ctx_.CreateBigNum(G),
344 std::vector<BigNum>({ctx_.CreateBigNum(Y)}));
345 private_cam_shoup_ = std::make_unique<PrivateCamenischShoup>(
346 &ctx_, ctx_.CreateBigNum(N), S, ctx_.CreateBigNum(G),
347 std::vector<BigNum>({ctx_.CreateBigNum(Y)}),
348 std::vector<BigNum>({ctx_.CreateBigNum(X)}));
349 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
350 public_cam_shoup_->Encrypt({ctx_.One()}));
351 ASSERT_OK_AND_ASSIGN(auto decrypted_value, private_cam_shoup_->Decrypt(ct));
352 EXPECT_EQ(ctx_.CreateBigNum(1), decrypted_value[0]);
353 }
354
TEST_F(CamenischShoupTest,TestPublicEncryptWithRand)355 TEST_F(CamenischShoupTest, TestPublicEncryptWithRand) {
356 BigNum r = ctx_.Three();
357 ASSERT_OK_AND_ASSIGN(
358 CamenischShoupCiphertext ct,
359 public_cam_shoup_->EncryptWithRand({ctx_.CreateBigNum(2)}, r));
360 EXPECT_EQ(ctx_.CreateBigNum(293), // (607)^(3) mod 35^2
361 ct.u);
362 EXPECT_EQ(ctx_.CreateBigNum(904), // (949)^(3) * (1 + 70) mod 35^2
363 ct.es[0]);
364 }
365
366 // A test fixture for CamenischShoup with a large random modulus. The tests are
367 // parameterized by (s, vector_encryption_length), so that the modulus is
368 // n^(s+1)), and there are vector_encryption_length secret keys.
369 class CamenischShoupLargeModulusTest
370 : public TestWithParam<std::pair<uint64_t, uint64_t>> {
371 protected:
SetUp()372 void SetUp() override {
373 std::tie(s_, vector_encryption_length_) = GetParam();
374 key_ = std::make_unique<CamenischShoupKey>(GenerateCamenischShoupKey(
375 &ctx_, /*n_length_bits=*/32, s_, vector_encryption_length_));
376 public_cam_shoup_ = std::make_unique<PublicCamenischShoup>(
377 &ctx_, key_->n, key_->s, key_->g, key_->ys);
378 private_cam_shoup_ = std::make_unique<PrivateCamenischShoup>(
379 &ctx_, key_->n, key_->s, key_->g, key_->ys, key_->xs);
380 }
381
382 Context ctx_;
383 uint64_t s_;
384 uint64_t vector_encryption_length_;
385 std::unique_ptr<CamenischShoupKey> key_;
386 std::unique_ptr<PublicCamenischShoup> public_cam_shoup_;
387 std::unique_ptr<PrivateCamenischShoup> private_cam_shoup_;
388 };
389
TEST_P(CamenischShoupLargeModulusTest,TestEncryptAndDecryptOneItemWithLargeModulus)390 TEST_P(CamenischShoupLargeModulusTest,
391 TestEncryptAndDecryptOneItemWithLargeModulus) {
392 ASSERT_OK_AND_ASSIGN(
393 auto ct, private_cam_shoup_->Encrypt({ctx_.CreateBigNum(4234234)}));
394 ASSERT_OK_AND_ASSIGN(std::vector<BigNum> decrypted,
395 private_cam_shoup_->Decrypt(ct));
396
397 // The first decrypted value should be as expected.
398 EXPECT_EQ(ctx_.CreateBigNum(4234234), decrypted[0]);
399 EXPECT_EQ(vector_encryption_length_, decrypted.size());
400
401 // The rest should be padded with 0s.
402 for (uint64_t i = 1; i < vector_encryption_length_; i++) {
403 EXPECT_EQ(decrypted[i], ctx_.Zero());
404 }
405 }
406
TEST_P(CamenischShoupLargeModulusTest,TestEncryptAndDecryptRandomNumber)407 TEST_P(CamenischShoupLargeModulusTest, TestEncryptAndDecryptRandomNumber) {
408 std::vector<BigNum> random_messages;
409 random_messages.reserve(vector_encryption_length_);
410 for (uint64_t i = 0; i < vector_encryption_length_; i++) {
411 random_messages.push_back(
412 ctx_.GenerateRandLessThan(public_cam_shoup_->message_upper_bound()));
413 }
414 ASSERT_OK_AND_ASSIGN(auto ct, private_cam_shoup_->Encrypt(random_messages));
415 EXPECT_THAT(private_cam_shoup_->Decrypt(ct),
416 IsOkAndHolds(Eq(random_messages)));
417 }
418
TEST_P(CamenischShoupLargeModulusTest,TestAdd)419 TEST_P(CamenischShoupLargeModulusTest, TestAdd) {
420 std::vector<BigNum> random_messages_1;
421 std::vector<BigNum> random_messages_2;
422 std::vector<BigNum> sums;
423 random_messages_1.reserve(vector_encryption_length_);
424 random_messages_2.reserve(vector_encryption_length_);
425 sums.reserve(vector_encryption_length_);
426 for (uint64_t i = 0; i < vector_encryption_length_; i++) {
427 random_messages_1.push_back(
428 ctx_.GenerateRandLessThan(public_cam_shoup_->message_upper_bound()));
429 random_messages_2.push_back(
430 ctx_.GenerateRandLessThan(public_cam_shoup_->message_upper_bound()));
431 sums.push_back(random_messages_1[i].ModAdd(
432 random_messages_2[i], public_cam_shoup_->message_upper_bound()));
433 }
434
435 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct1,
436 public_cam_shoup_->Encrypt(random_messages_1));
437 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct2,
438 public_cam_shoup_->Encrypt(random_messages_2));
439
440 CamenischShoupCiphertext sum_ct = public_cam_shoup_->Add(ct1, ct2);
441
442 EXPECT_THAT(private_cam_shoup_->Decrypt(sum_ct), IsOkAndHolds(Eq(sums)));
443 }
444
TEST_P(CamenischShoupLargeModulusTest,TestMultiply)445 TEST_P(CamenischShoupLargeModulusTest, TestMultiply) {
446 std::vector<BigNum> random_messages;
447 BigNum scalar = ctx_.CreateBigNum(3);
448 std::vector<BigNum> products;
449 random_messages.reserve(vector_encryption_length_);
450 products.reserve(vector_encryption_length_);
451 for (uint64_t i = 0; i < vector_encryption_length_; i++) {
452 random_messages.push_back(
453 ctx_.GenerateRandLessThan(public_cam_shoup_->message_upper_bound()));
454 products.push_back(random_messages[i].ModMul(
455 scalar, public_cam_shoup_->message_upper_bound()));
456 }
457
458 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
459 public_cam_shoup_->Encrypt(random_messages));
460
461 CamenischShoupCiphertext prod_ct = public_cam_shoup_->Multiply(ct, scalar);
462
463 EXPECT_THAT(private_cam_shoup_->Decrypt(prod_ct), IsOkAndHolds(Eq(products)));
464 }
465
TEST_P(CamenischShoupLargeModulusTest,SerializeAndDeserializeCiphertext)466 TEST_P(CamenischShoupLargeModulusTest, SerializeAndDeserializeCiphertext) {
467 std::vector<BigNum> random_messages;
468 random_messages.reserve(vector_encryption_length_);
469 for (uint64_t i = 0; i < vector_encryption_length_; i++) {
470 random_messages.push_back(
471 ctx_.GenerateRandLessThan(public_cam_shoup_->message_upper_bound()));
472 }
473 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
474 private_cam_shoup_->Encrypt(random_messages));
475
476 proto::CamenischShoupCiphertext serialized_ciphertext =
477 CamenischShoupCiphertextToProto(ct);
478 ASSERT_OK_AND_ASSIGN(
479 CamenischShoupCiphertext deserialized_ciphertext,
480 private_cam_shoup_->ParseCiphertextProto(serialized_ciphertext));
481
482 EXPECT_EQ(ct.u, deserialized_ciphertext.u);
483 EXPECT_EQ(ct.es, deserialized_ciphertext.es);
484 }
485
TEST_P(CamenischShoupLargeModulusTest,DeserializingCiphertextFailsWhenUOutOfBounds)486 TEST_P(CamenischShoupLargeModulusTest,
487 DeserializingCiphertextFailsWhenUOutOfBounds) {
488 std::vector<BigNum> random_messages;
489 random_messages.reserve(vector_encryption_length_);
490 for (uint64_t i = 0; i < vector_encryption_length_; i++) {
491 random_messages.push_back(
492 ctx_.GenerateRandLessThan(public_cam_shoup_->message_upper_bound()));
493 }
494 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
495 private_cam_shoup_->Encrypt(random_messages));
496
497 proto::CamenischShoupCiphertext serialized_ciphertext =
498 CamenischShoupCiphertextToProto(ct);
499
500 BigNum out_of_bounds = public_cam_shoup_->modulus() + ctx_.One();
501 // Out of Bounds u.
502 proto::CamenischShoupCiphertext serialized_ciphertext_u_out_of_bounds =
503 serialized_ciphertext;
504 serialized_ciphertext_u_out_of_bounds.set_u(out_of_bounds.ToBytes());
505 EXPECT_THAT(private_cam_shoup_->ParseCiphertextProto(
506 serialized_ciphertext_u_out_of_bounds),
507 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr(" u")));
508 }
509
TEST_P(CamenischShoupLargeModulusTest,DeserializingCiphertextFailsWhenTooManyEs)510 TEST_P(CamenischShoupLargeModulusTest,
511 DeserializingCiphertextFailsWhenTooManyEs) {
512 std::vector<BigNum> random_messages;
513 random_messages.reserve(vector_encryption_length_);
514 for (uint64_t i = 0; i < vector_encryption_length_; i++) {
515 random_messages.push_back(
516 ctx_.GenerateRandLessThan(public_cam_shoup_->message_upper_bound()));
517 }
518 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
519 private_cam_shoup_->Encrypt(random_messages));
520
521 proto::CamenischShoupCiphertext serialized_ciphertext =
522 CamenischShoupCiphertextToProto(ct);
523
524 // Too many es.
525 proto::CamenischShoupCiphertext serialized_ciphertext_too_many_es =
526 serialized_ciphertext;
527 std::vector<BigNum> too_many_es = ct.es;
528 too_many_es.push_back(ctx_.Zero());
529 *serialized_ciphertext_too_many_es.mutable_es() =
530 BigNumVectorToProto(too_many_es);
531 EXPECT_THAT(private_cam_shoup_->ParseCiphertextProto(
532 serialized_ciphertext_too_many_es),
533 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr(" es")));
534 }
535
TEST_P(CamenischShoupLargeModulusTest,DeserializingCiphertextFailsWhenEsOutOfBounds)536 TEST_P(CamenischShoupLargeModulusTest,
537 DeserializingCiphertextFailsWhenEsOutOfBounds) {
538 std::vector<BigNum> random_messages;
539 random_messages.reserve(vector_encryption_length_);
540 for (uint64_t i = 0; i < vector_encryption_length_; i++) {
541 random_messages.push_back(
542 ctx_.GenerateRandLessThan(public_cam_shoup_->message_upper_bound()));
543 }
544 ASSERT_OK_AND_ASSIGN(CamenischShoupCiphertext ct,
545 private_cam_shoup_->Encrypt(random_messages));
546
547 proto::CamenischShoupCiphertext serialized_ciphertext =
548 CamenischShoupCiphertextToProto(ct);
549
550 BigNum out_of_bounds = public_cam_shoup_->modulus() + ctx_.One();
551
552 // es out of bounds.
553 proto::CamenischShoupCiphertext serialized_ciphertext_es_out_of_bounds =
554 serialized_ciphertext;
555 std::vector<BigNum> es_out_of_bounds = ct.es;
556 es_out_of_bounds[0] = out_of_bounds;
557 *serialized_ciphertext_es_out_of_bounds.mutable_es() =
558 BigNumVectorToProto(es_out_of_bounds);
559 EXPECT_THAT(private_cam_shoup_->ParseCiphertextProto(
560 serialized_ciphertext_es_out_of_bounds),
561 StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr(" es")));
562 }
563
TEST_P(CamenischShoupLargeModulusTest,DeserializingEmptyCiphertextGivesCiphertextWithEmptyEs)564 TEST_P(CamenischShoupLargeModulusTest,
565 DeserializingEmptyCiphertextGivesCiphertextWithEmptyEs) {
566 proto::CamenischShoupCiphertext serialized_ciphertext; // Default instance.
567
568 ASSERT_OK_AND_ASSIGN(
569 CamenischShoupCiphertext deserialized,
570 private_cam_shoup_->ParseCiphertextProto(serialized_ciphertext));
571
572 EXPECT_TRUE(deserialized.es.empty());
573 }
574
575 INSTANTIATE_TEST_SUITE_P(CamenischShoupLargeModulusTestWithDifferentS,
576 CamenischShoupLargeModulusTest,
577 ::testing::Values(std::make_pair(1, 1),
578 std::make_pair(5, 1),
579 std::make_pair(1, 5),
580 std::make_pair(5, 5)));
581
582 } // namespace
583 } // namespace private_join_and_compute
584