| /* |
| * Copyright 2019 Google Inc. |
| * 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 "privacy/blinders/cpp/util/elgamal_key_util.h" |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include <filesystem> |
| #include <memory> |
| |
| #include "crypto/context.h" |
| #include "crypto/ec_group.h" |
| #include "crypto/elgamal.h" |
| #include "crypto/elgamal.pb.h" |
| #include "crypto/openssl.inc" |
| #include "privacy/blinders/cpp/util/elgamal_proto_util.h" |
| #include "util/proto_util.h" |
| #include "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 |