blob: b6f1b79ef61d142880d6297cff0cd11bc0420c9b [file] [log] [blame]
/*
* 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