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 #include "private_join_and_compute/util/elgamal_key_util.h"
17
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20
21 #include <filesystem>
22 #include <memory>
23 #include <string>
24 #include <utility>
25 #include <vector>
26
27 #include "private_join_and_compute/crypto/context.h"
28 #include "private_join_and_compute/crypto/ec_group.h"
29 #include "private_join_and_compute/crypto/elgamal.h"
30 #include "private_join_and_compute/crypto/elgamal.pb.h"
31 #include "private_join_and_compute/crypto/openssl.inc"
32 #include "private_join_and_compute/util/elgamal_proto_util.h"
33 #include "private_join_and_compute/util/proto_util.h"
34 #include "private_join_and_compute/util/status_testing.inc"
35
36 namespace private_join_and_compute::elgamal_key_util {
37 namespace {
38
39 using elgamal::PublicKey;
40 using elgamal_proto_util::DeserializePrivateKey;
41 using elgamal_proto_util::DeserializePublicKey;
42 using private_join_and_compute::ElGamalPublicKey;
43 using private_join_and_compute::ElGamalSecretKey;
44 using private_join_and_compute::ProtoUtils;
45 using ::testing::HasSubstr;
46 using ::testing::Test;
47
48 const int kTestCurveId = NID_X9_62_prime256v1;
49
TEST(ElGamalKeyUtilTest,GenerateKeyPair)50 TEST(ElGamalKeyUtilTest, GenerateKeyPair) {
51 std::filesystem::path temp_dir(::testing::TempDir());
52 std::string pub_key_filename = (temp_dir / "elgamal_pub.key").string();
53 std::string prv_key_filename = (temp_dir / "elgamal_prv.key").string();
54 ASSERT_OK(
55 GenerateElGamalKeyPair(kTestCurveId, pub_key_filename, prv_key_filename));
56 ASSERT_TRUE(std::filesystem::exists(pub_key_filename));
57 ASSERT_TRUE(std::filesystem::exists(prv_key_filename));
58
59 // Verify the keys written to files are correct.
60 Context context;
61 ASSERT_OK_AND_ASSIGN(auto ec_group, ECGroup::Create(kTestCurveId, &context));
62 ASSERT_OK_AND_ASSIGN(
63 auto public_key_proto,
64 ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(pub_key_filename));
65 ASSERT_OK_AND_ASSIGN(
66 auto private_key_proto,
67 ProtoUtils::ReadProtoFromFile<ElGamalSecretKey>(prv_key_filename));
68 ASSERT_OK_AND_ASSIGN(auto public_key,
69 DeserializePublicKey(&ec_group, public_key_proto));
70 ASSERT_OK_AND_ASSIGN(auto private_key,
71 DeserializePrivateKey(&context, private_key_proto));
72 ASSERT_OK_AND_ASSIGN(auto product, public_key->g.Mul(private_key->x));
73 EXPECT_EQ(product, public_key->y);
74 }
75
TEST(ElGamalKeyUtilTest,ComputeJointElGamalPublicKey)76 TEST(ElGamalKeyUtilTest, ComputeJointElGamalPublicKey) {
77 std::filesystem::path temp_dir(::testing::TempDir());
78 std::string pub_key_filename_1 = (temp_dir / "elgamal_pub1.key").string();
79 std::string prv_key_filename_1 = (temp_dir / "elgamal_prv1.key").string();
80 ASSERT_OK(GenerateElGamalKeyPair(kTestCurveId, pub_key_filename_1,
81 prv_key_filename_1));
82 std::string pub_key_filename_2 = (temp_dir / "elgamal_pub2.key").string();
83 std::string prv_key_filename_2 = (temp_dir / "elgamal_prv2.key").string();
84 ASSERT_OK(GenerateElGamalKeyPair(kTestCurveId, pub_key_filename_2,
85 prv_key_filename_2));
86 std::string joint_pub_key_filename =
87 (temp_dir / "joint_elgamal_pub.key").string();
88 std::vector<std::string> pub_key_shares{pub_key_filename_1,
89 pub_key_filename_2};
90 ASSERT_OK(ComputeJointElGamalPublicKey(kTestCurveId, pub_key_shares,
91 joint_pub_key_filename));
92 ASSERT_TRUE(std::filesystem::exists(joint_pub_key_filename));
93
94 // Verify the joint key written to file is correct.
95 Context context;
96 ASSERT_OK_AND_ASSIGN(auto ec_group, ECGroup::Create(kTestCurveId, &context));
97 ASSERT_OK_AND_ASSIGN(
98 auto joint_public_key_proto,
99 ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(joint_pub_key_filename));
100 ASSERT_OK_AND_ASSIGN(auto joint_public_key,
101 DeserializePublicKey(&ec_group, joint_public_key_proto));
102 ASSERT_OK_AND_ASSIGN(
103 auto share_1_proto,
104 ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(pub_key_filename_1));
105 ASSERT_OK_AND_ASSIGN(auto share_1,
106 DeserializePublicKey(&ec_group, share_1_proto));
107 ASSERT_OK_AND_ASSIGN(
108 auto share_2_proto,
109 ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(pub_key_filename_2));
110 ASSERT_OK_AND_ASSIGN(auto share_2,
111 DeserializePublicKey(&ec_group, share_2_proto));
112 std::vector<std::unique_ptr<elgamal::PublicKey>> key_shares;
113 key_shares.reserve(2);
114 key_shares.push_back(std::move(share_1));
115 key_shares.push_back(std::move(share_2));
116 ASSERT_OK_AND_ASSIGN(auto expected_joint_public_key,
117 elgamal::GeneratePublicKeyFromShares(key_shares));
118 EXPECT_EQ(joint_public_key->g, expected_joint_public_key->g);
119 EXPECT_EQ(joint_public_key->y, expected_joint_public_key->y);
120 }
121
TEST(ElGamalKeyUtilTest,TestEmptyKeyShares)122 TEST(ElGamalKeyUtilTest, TestEmptyKeyShares) {
123 std::vector<std::string> empty_key_shares;
124 std::filesystem::path temp_dir(::testing::TempDir());
125 std::string joint_pub_key_filename =
126 (temp_dir / "joint_elgamal_pub.key").string();
127 auto outcome = ComputeJointElGamalPublicKey(kTestCurveId, empty_key_shares,
128 joint_pub_key_filename);
129 EXPECT_TRUE(IsInvalidArgument(outcome));
130 }
131
TEST(ElGamalKeyUtilTest,TestKeyReadWrite)132 TEST(ElGamalKeyUtilTest, TestKeyReadWrite) {
133 std::unique_ptr<Context> context(new Context);
134 ASSERT_OK_AND_ASSIGN(ECGroup group,
135 ECGroup::Create(kTestCurveId, context.get()));
136 ASSERT_OK_AND_ASSIGN(
137 auto key_pair, private_join_and_compute::elgamal::GenerateKeyPair(group));
138 ASSERT_OK_AND_ASSIGN(
139 auto public_key_proto,
140 elgamal_proto_util::SerializePublicKey(*key_pair.first.get()));
141 ASSERT_OK_AND_ASSIGN(
142 auto private_key_proto,
143 elgamal_proto_util::SerializePrivateKey(*key_pair.second.get()));
144
145 std::filesystem::path temp_dir(::testing::TempDir());
146 std::string pub_key_filename = (temp_dir / "elgamal_pub.key").string();
147 std::string prv_key_filename = (temp_dir / "elgamal_prv.key").string();
148
149 // Verify write and read public key to file returns the expected key.
150 ASSERT_OK(ProtoUtils::WriteProtoToFile(public_key_proto, pub_key_filename));
151 ASSERT_OK_AND_ASSIGN(
152 auto public_key_proto_2,
153 ProtoUtils::ReadProtoFromFile<ElGamalPublicKey>(pub_key_filename));
154 EXPECT_EQ(public_key_proto.g(), public_key_proto_2.g());
155 EXPECT_EQ(public_key_proto.y(), public_key_proto_2.y());
156
157 // Verify write and read private key to file returns the expected key.
158 ASSERT_OK(ProtoUtils::WriteProtoToFile(private_key_proto, prv_key_filename));
159 ASSERT_OK_AND_ASSIGN(
160 auto private_key_proto_2,
161 ProtoUtils::ReadProtoFromFile<ElGamalSecretKey>(prv_key_filename));
162 EXPECT_EQ(private_key_proto.x(), private_key_proto_2.x());
163 }
164
165 } // namespace
166 } // namespace private_join_and_compute::elgamal_key_util
167