From 5a5ae2b3fa00c614e700eed2f36a114c5996450c Mon Sep 17 00:00:00 2001 From: wconner Date: Thu, 27 Jul 2023 09:38:52 -0700 Subject: Add Ed25519 parameters type. PiperOrigin-RevId: 551556793 --- cc/signature/BUILD.bazel | 22 ++++++ cc/signature/CMakeLists.txt | 21 ++++++ cc/signature/ed25519_parameters.cc | 48 ++++++++++++ cc/signature/ed25519_parameters.h | 69 ++++++++++++++++++ cc/signature/ed25519_parameters_test.cc | 125 ++++++++++++++++++++++++++++++++ 5 files changed, 285 insertions(+) create mode 100644 cc/signature/ed25519_parameters.cc create mode 100644 cc/signature/ed25519_parameters.h create mode 100644 cc/signature/ed25519_parameters_test.cc diff --git a/cc/signature/BUILD.bazel b/cc/signature/BUILD.bazel index 8be1801eb..7f31b48a8 100644 --- a/cc/signature/BUILD.bazel +++ b/cc/signature/BUILD.bazel @@ -432,6 +432,17 @@ cc_library( ], ) +cc_library( + name = "ed25519_parameters", + srcs = ["ed25519_parameters.cc"], + hdrs = ["ed25519_parameters.h"], + include_prefix = "tink/signature", + deps = [ + ":signature_parameters", + "//util:statusor", + ], +) + # tests cc_test( @@ -803,3 +814,14 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "ed25519_parameters_test", + srcs = ["ed25519_parameters_test.cc"], + deps = [ + ":ed25519_parameters", + "//util:statusor", + "//util:test_matchers", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/cc/signature/CMakeLists.txt b/cc/signature/CMakeLists.txt index b72a0427d..68a8fc6aa 100644 --- a/cc/signature/CMakeLists.txt +++ b/cc/signature/CMakeLists.txt @@ -412,6 +412,16 @@ tink_cc_library( tink::core::private_key ) +tink_cc_library( + NAME ed25519_parameters + SRCS + ed25519_parameters.cc + ed25519_parameters.h + DEPS + tink::signature::signature_parameters + tink::util::statusor +) + # tests tink_cc_test( @@ -767,3 +777,14 @@ tink_cc_test( absl::status tink::util::test_matchers ) + +tink_cc_test( + NAME ed25519_parameters_test + SRCS + ed25519_parameters_test.cc + DEPS + tink::signature::ed25519_parameters + gmock + tink::util::statusor + tink::util::test_matchers +) diff --git a/cc/signature/ed25519_parameters.cc b/cc/signature/ed25519_parameters.cc new file mode 100644 index 000000000..4f448ac3e --- /dev/null +++ b/cc/signature/ed25519_parameters.cc @@ -0,0 +1,48 @@ +// Copyright 2023 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 +// +// http://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 "tink/signature/ed25519_parameters.h" + +#include + +#include "tink/util/statusor.h" + +namespace crypto { +namespace tink { + +util::StatusOr Ed25519Parameters::Create(Variant variant) { + static const std::set* supported_variants = + new std::set({Variant::kTink, Variant::kCrunchy, + Variant::kLegacy, Variant::kNoPrefix}); + if (supported_variants->find(variant) == supported_variants->end()) { + return util::Status( + absl::StatusCode::kInvalidArgument, + "Cannot create Ed25519 parameters with unknown variant."); + } + return Ed25519Parameters(variant); +} + +bool Ed25519Parameters::operator==(const Parameters& other) const { + const Ed25519Parameters* that = + dynamic_cast(&other); + if (that == nullptr) { + return false; + } + return variant_ == that->variant_; +} + +} // namespace tink +} // namespace crypto diff --git a/cc/signature/ed25519_parameters.h b/cc/signature/ed25519_parameters.h new file mode 100644 index 000000000..959693e90 --- /dev/null +++ b/cc/signature/ed25519_parameters.h @@ -0,0 +1,69 @@ +// Copyright 2023 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 +// +// http://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. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TINK_SIGNATURE_ED25519_PARAMETERS_H_ +#define TINK_SIGNATURE_ED25519_PARAMETERS_H_ + +#include "tink/signature/signature_parameters.h" +#include "tink/util/statusor.h" + +namespace crypto { +namespace tink { + +class Ed25519Parameters : public SignatureParameters { + public: + // Description of the output prefix prepended to the signature. + enum class Variant : int { + // Prepends '0x01' to signature. + kTink = 1, + // Prepends '0x00' to signature. + kCrunchy = 2, + // Appends a 0-byte to input message BEFORE computing the signature, then + // prepends '0x00' to signature. + kLegacy = 3, + // Does not prepend any prefix (i.e., keys must have no ID requirement). + kNoPrefix = 4, + // Added to guard from failures that may be caused by future expansions. + kDoNotUseInsteadUseDefaultWhenWritingSwitchStatements = 20, + }; + + // Copyable and movable. + Ed25519Parameters(const Ed25519Parameters& other) = default; + Ed25519Parameters& operator=(const Ed25519Parameters& other) = default; + Ed25519Parameters(Ed25519Parameters&& other) = default; + Ed25519Parameters& operator=(Ed25519Parameters&& other) = default; + + // Creates a new Ed25519 parameters object unless `variant` is invalid. + static util::StatusOr Create(Variant variant); + + Variant GetVariant() const { return variant_; } + + bool HasIdRequirement() const override { + return variant_ != Variant::kNoPrefix; + } + + bool operator==(const Parameters& other) const override; + + private: + explicit Ed25519Parameters(Variant variant) : variant_(variant) {} + + Variant variant_; +}; + +} // namespace tink +} // namespace crypto + +#endif // TINK_SIGNATURE_ED25519_PARAMETERS_H_ diff --git a/cc/signature/ed25519_parameters_test.cc b/cc/signature/ed25519_parameters_test.cc new file mode 100644 index 000000000..f79be9620 --- /dev/null +++ b/cc/signature/ed25519_parameters_test.cc @@ -0,0 +1,125 @@ +// Copyright 2023 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 +// +// http://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 "tink/signature/ed25519_parameters.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "tink/util/statusor.h" +#include "tink/util/test_matchers.h" + +namespace crypto { +namespace tink { +namespace { + +using ::crypto::tink::test::IsOk; +using ::crypto::tink::test::StatusIs; +using ::testing::Eq; +using ::testing::IsTrue; +using ::testing::TestWithParam; +using ::testing::Values; + +struct TestCase { + Ed25519Parameters::Variant variant; + bool has_id_requirement; +}; + +using Ed25519ParametersTest = TestWithParam; + +INSTANTIATE_TEST_SUITE_P(Ed25519ParametersTestSuite, Ed25519ParametersTest, + Values(TestCase{Ed25519Parameters::Variant::kTink, + /*has_id_requirement=*/true}, + TestCase{Ed25519Parameters::Variant::kCrunchy, + /*has_id_requirement=*/true}, + TestCase{Ed25519Parameters::Variant::kLegacy, + /*has_id_requirement=*/true}, + TestCase{Ed25519Parameters::Variant::kNoPrefix, + /*has_id_requirement=*/false})); + +TEST_P(Ed25519ParametersTest, Create) { + TestCase test_case = GetParam(); + + util::StatusOr parameters = + Ed25519Parameters::Create(test_case.variant); + ASSERT_THAT(parameters, IsOk()); + + EXPECT_THAT(parameters->GetVariant(), Eq(test_case.variant)); + EXPECT_THAT(parameters->HasIdRequirement(), Eq(test_case.has_id_requirement)); +} + +TEST(Ed25519ParametersTest, CreateWithInvalidVariantFails) { + EXPECT_THAT(Ed25519Parameters::Create( + Ed25519Parameters::Variant:: + kDoNotUseInsteadUseDefaultWhenWritingSwitchStatements) + .status(), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST(Ed25519ParametersTest, CopyConstructor) { + util::StatusOr parameters = + Ed25519Parameters::Create(Ed25519Parameters::Variant::kTink); + ASSERT_THAT(parameters, IsOk()); + + Ed25519Parameters copy(*parameters); + + EXPECT_THAT(copy.GetVariant(), Eq(Ed25519Parameters::Variant::kTink)); + EXPECT_THAT(copy.HasIdRequirement(), IsTrue()); +} + +TEST(Ed25519ParametersTest, CopyAssignment) { + util::StatusOr parameters = + Ed25519Parameters::Create(Ed25519Parameters::Variant::kTink); + ASSERT_THAT(parameters, IsOk()); + + Ed25519Parameters copy = *parameters; + + EXPECT_THAT(copy.GetVariant(), Eq(Ed25519Parameters::Variant::kTink)); + EXPECT_THAT(copy.HasIdRequirement(), IsTrue()); +} + +TEST_P(Ed25519ParametersTest, ParametersEquals) { + TestCase test_case = GetParam(); + + util::StatusOr parameters = + Ed25519Parameters::Create(test_case.variant); + ASSERT_THAT(parameters, IsOk()); + + util::StatusOr other_parameters = + Ed25519Parameters::Create(test_case.variant); + ASSERT_THAT(other_parameters, IsOk()); + + EXPECT_TRUE(*parameters == *other_parameters); + EXPECT_TRUE(*other_parameters == *parameters); + EXPECT_FALSE(*parameters != *other_parameters); + EXPECT_FALSE(*other_parameters != *parameters); +} + +TEST(Ed25519ParametersTest, VariantNotEqual) { + util::StatusOr parameters = + Ed25519Parameters::Create(Ed25519Parameters::Variant::kTink); + ASSERT_THAT(parameters, IsOk()); + + util::StatusOr other_parameters = + Ed25519Parameters::Create(Ed25519Parameters::Variant::kNoPrefix); + ASSERT_THAT(other_parameters, IsOk()); + + EXPECT_TRUE(*parameters != *other_parameters); + EXPECT_FALSE(*parameters == *other_parameters); +} + +} // namespace +} // namespace tink +} // namespace crypto -- cgit v1.2.3