aboutsummaryrefslogtreecommitdiff
path: root/private_join_and_compute/util/elgamal_key_util_test.cc
blob: d1d00d80bc2a625fe05d9d54bea95f20c59b6652 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * Copyright 2019 Google LLC.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "private_join_and_compute/util/elgamal_key_util.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <filesystem>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "private_join_and_compute/crypto/context.h"
#include "private_join_and_compute/crypto/ec_group.h"
#include "private_join_and_compute/crypto/elgamal.h"
#include "private_join_and_compute/crypto/elgamal.pb.h"
#include "private_join_and_compute/crypto/openssl.inc"
#include "private_join_and_compute/util/elgamal_proto_util.h"
#include "private_join_and_compute/util/proto_util.h"
#include "private_join_and_compute/util/status_testing.inc"

namespace private_join_and_compute::elgamal_key_util {
namespace {

using elgamal::PublicKey;
using elgamal_proto_util::DeserializePrivateKey;
using elgamal_proto_util::DeserializePublicKey;
using private_join_and_compute::ElGamalPublicKey;
using private_join_and_compute::ElGamalSecretKey;
using private_join_and_compute::ProtoUtils;
using ::testing::HasSubstr;
using ::testing::Test;

const int kTestCurveId = NID_X9_62_prime256v1;

TEST(ElGamalKeyUtilTest, GenerateKeyPair) {
  std::filesystem::path temp_dir(::testing::TempDir());
  std::string pub_key_filename = (temp_dir / "elgamal_pub.key").string();
  std::string prv_key_filename = (temp_dir / "elgamal_prv.key").string();
  ASSERT_OK(
      GenerateElGamalKeyPair(kTestCurveId, pub_key_filename, prv_key_filename));
  ASSERT_TRUE(std::filesystem::exists(pub_key_filename));
  ASSERT_TRUE(std::filesystem::exists(prv_key_filename));

  // Verify the keys written to files are correct.
  Context context;
  ASSERT_OK_AND_ASSIGN(auto ec_group, ECGroup::Create(kTestCurveId, &context));
  ASSERT_OK_AND_ASSIGN(
      auto public_key_proto,
      ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(pub_key_filename));
  ASSERT_OK_AND_ASSIGN(
      auto private_key_proto,
      ProtoUtils::ReadProtoFromFile<ElGamalSecretKey>(prv_key_filename));
  ASSERT_OK_AND_ASSIGN(auto public_key,
                       DeserializePublicKey(&ec_group, public_key_proto));
  ASSERT_OK_AND_ASSIGN(auto private_key,
                       DeserializePrivateKey(&context, private_key_proto));
  ASSERT_OK_AND_ASSIGN(auto product, public_key->g.Mul(private_key->x));
  EXPECT_EQ(product, public_key->y);
}

TEST(ElGamalKeyUtilTest, ComputeJointElGamalPublicKey) {
  std::filesystem::path temp_dir(::testing::TempDir());
  std::string pub_key_filename_1 = (temp_dir / "elgamal_pub1.key").string();
  std::string prv_key_filename_1 = (temp_dir / "elgamal_prv1.key").string();
  ASSERT_OK(GenerateElGamalKeyPair(kTestCurveId, pub_key_filename_1,
                                   prv_key_filename_1));
  std::string pub_key_filename_2 = (temp_dir / "elgamal_pub2.key").string();
  std::string prv_key_filename_2 = (temp_dir / "elgamal_prv2.key").string();
  ASSERT_OK(GenerateElGamalKeyPair(kTestCurveId, pub_key_filename_2,
                                   prv_key_filename_2));
  std::string joint_pub_key_filename =
      (temp_dir / "joint_elgamal_pub.key").string();
  std::vector<std::string> pub_key_shares{pub_key_filename_1,
                                          pub_key_filename_2};
  ASSERT_OK(ComputeJointElGamalPublicKey(kTestCurveId, pub_key_shares,
                                         joint_pub_key_filename));
  ASSERT_TRUE(std::filesystem::exists(joint_pub_key_filename));

  // Verify the joint key written to file is correct.
  Context context;
  ASSERT_OK_AND_ASSIGN(auto ec_group, ECGroup::Create(kTestCurveId, &context));
  ASSERT_OK_AND_ASSIGN(
      auto joint_public_key_proto,
      ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(joint_pub_key_filename));
  ASSERT_OK_AND_ASSIGN(auto joint_public_key,
                       DeserializePublicKey(&ec_group, joint_public_key_proto));
  ASSERT_OK_AND_ASSIGN(
      auto share_1_proto,
      ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(pub_key_filename_1));
  ASSERT_OK_AND_ASSIGN(auto share_1,
                       DeserializePublicKey(&ec_group, share_1_proto));
  ASSERT_OK_AND_ASSIGN(
      auto share_2_proto,
      ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(pub_key_filename_2));
  ASSERT_OK_AND_ASSIGN(auto share_2,
                       DeserializePublicKey(&ec_group, share_2_proto));
  std::vector<std::unique_ptr<elgamal::PublicKey>> key_shares;
  key_shares.reserve(2);
  key_shares.push_back(std::move(share_1));
  key_shares.push_back(std::move(share_2));
  ASSERT_OK_AND_ASSIGN(auto expected_joint_public_key,
                       elgamal::GeneratePublicKeyFromShares(key_shares));
  EXPECT_EQ(joint_public_key->g, expected_joint_public_key->g);
  EXPECT_EQ(joint_public_key->y, expected_joint_public_key->y);
}

TEST(ElGamalKeyUtilTest, TestEmptyKeyShares) {
  std::vector<std::string> empty_key_shares;
  std::filesystem::path temp_dir(::testing::TempDir());
  std::string joint_pub_key_filename =
      (temp_dir / "joint_elgamal_pub.key").string();
  auto outcome = ComputeJointElGamalPublicKey(kTestCurveId, empty_key_shares,
                                              joint_pub_key_filename);
  EXPECT_TRUE(IsInvalidArgument(outcome));
}

TEST(ElGamalKeyUtilTest, TestKeyReadWrite) {
  std::unique_ptr<Context> context(new Context);
  ASSERT_OK_AND_ASSIGN(ECGroup group,
                       ECGroup::Create(kTestCurveId, context.get()));
  ASSERT_OK_AND_ASSIGN(
      auto key_pair, private_join_and_compute::elgamal::GenerateKeyPair(group));
  ASSERT_OK_AND_ASSIGN(
      auto public_key_proto,
      elgamal_proto_util::SerializePublicKey(*key_pair.first.get()));
  ASSERT_OK_AND_ASSIGN(
      auto private_key_proto,
      elgamal_proto_util::SerializePrivateKey(*key_pair.second.get()));

  std::filesystem::path temp_dir(::testing::TempDir());
  std::string pub_key_filename = (temp_dir / "elgamal_pub.key").string();
  std::string prv_key_filename = (temp_dir / "elgamal_prv.key").string();

  // Verify write and read public key to file returns the expected key.
  ASSERT_OK(ProtoUtils::WriteProtoToFile(public_key_proto, pub_key_filename));
  ASSERT_OK_AND_ASSIGN(
      auto public_key_proto_2,
      ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(pub_key_filename));
  EXPECT_EQ(public_key_proto.g(), public_key_proto_2.g());
  EXPECT_EQ(public_key_proto.y(), public_key_proto_2.y());

  // Verify write and read private key to file returns the expected key.
  ASSERT_OK(ProtoUtils::WriteProtoToFile(private_key_proto, prv_key_filename));
  ASSERT_OK_AND_ASSIGN(
      auto private_key_proto_2,
      ProtoUtils::ReadProtoFromFile<ElGamalSecretKey>(prv_key_filename));
  EXPECT_EQ(private_key_proto.x(), private_key_proto_2.x());
}

}  // namespace
}  // namespace private_join_and_compute::elgamal_key_util