Skip to content
This repository was archived by the owner on Apr 17, 2024. It is now read-only.

Commit 9325851

Browse files
ioannanedelcucopybara-github
authored andcommitted
Add proto parser and serializer for SLH-DSA public key.
PiperOrigin-RevId: 625367596
1 parent 3e4e908 commit 9325851

File tree

2 files changed

+263
-8
lines changed

2 files changed

+263
-8
lines changed

cc/experimental/pqcrypto/signature/slh_dsa_proto_serialization.cc

+106-8
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,20 @@
1818

1919
#include "absl/status/status.h"
2020
#include "absl/strings/string_view.h"
21+
#include "absl/types/optional.h"
2122
#include "tink/experimental/pqcrypto/signature/slh_dsa_parameters.h"
23+
#include "tink/experimental/pqcrypto/signature/slh_dsa_public_key.h"
24+
#include "tink/insecure_secret_key_access.h"
25+
#include "tink/internal/key_parser.h"
26+
#include "tink/internal/key_serializer.h"
2227
#include "tink/internal/mutable_serialization_registry.h"
2328
#include "tink/internal/parameters_parser.h"
2429
#include "tink/internal/parameters_serializer.h"
30+
#include "tink/internal/proto_key_serialization.h"
2531
#include "tink/internal/proto_parameters_serialization.h"
32+
#include "tink/partial_key_access.h"
33+
#include "tink/restricted_data.h"
34+
#include "tink/secret_key_access_token.h"
2635
#include "tink/util/status.h"
2736
#include "tink/util/statusor.h"
2837
#include "proto/experimental/pqcrypto/slh_dsa.pb.h"
@@ -32,6 +41,7 @@ namespace crypto {
3241
namespace tink {
3342
namespace {
3443

44+
using ::google::crypto::tink::KeyData;
3545
using ::google::crypto::tink::OutputPrefixType;
3646
using ::google::crypto::tink::SlhDsaHashType;
3747
using ::google::crypto::tink::SlhDsaKeyFormat;
@@ -44,9 +54,16 @@ using SlhDsaProtoParametersParserImpl =
4454
using SlhDsaProtoParametersSerializerImpl =
4555
internal::ParametersSerializerImpl<SlhDsaParameters,
4656
internal::ProtoParametersSerialization>;
57+
using SlhDsaProtoPublicKeyParserImpl =
58+
internal::KeyParserImpl<internal::ProtoKeySerialization, SlhDsaPublicKey>;
59+
using SlhDsaProtoPublicKeySerializerImpl =
60+
internal::KeySerializerImpl<SlhDsaPublicKey,
61+
internal::ProtoKeySerialization>;
4762

4863
const absl::string_view kPrivateTypeUrl =
4964
"type.googleapis.com/google.crypto.tink.SlhDsaPrivateKey";
65+
const absl::string_view kPublicTypeUrl =
66+
"type.googleapis.com/google.crypto.tink.SlhDsaPublicKey";
5067

5168
util::StatusOr<SlhDsaParameters::Variant> ToVariant(
5269
OutputPrefixType output_prefix_type) {
@@ -201,6 +218,37 @@ util::StatusOr<SlhDsaParameters> ParseParameters(
201218
proto_key_format.params());
202219
}
203220

221+
util::StatusOr<SlhDsaPublicKey> ParsePublicKey(
222+
const internal::ProtoKeySerialization& serialization,
223+
absl::optional<SecretKeyAccessToken> token) {
224+
if (serialization.TypeUrl() != kPublicTypeUrl) {
225+
return util::Status(absl::StatusCode::kInvalidArgument,
226+
"Wrong type URL when parsing SlhDsaPublicKey.");
227+
}
228+
229+
google::crypto::tink::SlhDsaPublicKey proto_key;
230+
const RestrictedData& restricted_data = serialization.SerializedKeyProto();
231+
if (!proto_key.ParseFromString(
232+
restricted_data.GetSecret(InsecureSecretKeyAccess::Get()))) {
233+
return util::Status(absl::StatusCode::kInvalidArgument,
234+
"Failed to parse SlhDsaPublicKey proto");
235+
}
236+
if (proto_key.version() != 0) {
237+
return util::Status(absl::StatusCode::kInvalidArgument,
238+
"Only version 0 keys are accepted.");
239+
}
240+
241+
util::StatusOr<SlhDsaParameters> parameters =
242+
ToParameters(serialization.GetOutputPrefixType(), proto_key.params());
243+
if (!parameters.ok()) {
244+
return parameters.status();
245+
}
246+
247+
return SlhDsaPublicKey::Create(*parameters, proto_key.key_value(),
248+
serialization.IdRequirement(),
249+
GetPartialKeyAccess());
250+
}
251+
204252
util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters(
205253
const SlhDsaParameters& parameters) {
206254
util::StatusOr<OutputPrefixType> output_prefix_type =
@@ -222,30 +270,80 @@ util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters(
222270
proto_key_format.SerializeAsString());
223271
}
224272

225-
SlhDsaProtoParametersParserImpl* SlhDsaProtoParametersParser() {
226-
static auto* parser =
273+
util::StatusOr<internal::ProtoKeySerialization> SerializePublicKey(
274+
const SlhDsaPublicKey& key, absl::optional<SecretKeyAccessToken> token) {
275+
util::StatusOr<SlhDsaParams> params = FromParameters(key.GetParameters());
276+
if (!params.ok()) {
277+
return params.status();
278+
}
279+
280+
google::crypto::tink::SlhDsaPublicKey proto_key;
281+
proto_key.set_version(0);
282+
*proto_key.mutable_params() = *params;
283+
proto_key.set_key_value(key.GetPublicKeyBytes(GetPartialKeyAccess()));
284+
285+
util::StatusOr<OutputPrefixType> output_prefix_type =
286+
ToOutputPrefixType(key.GetParameters().GetVariant());
287+
if (!output_prefix_type.ok()) {
288+
return output_prefix_type.status();
289+
}
290+
291+
RestrictedData restricted_output = RestrictedData(
292+
proto_key.SerializeAsString(), InsecureSecretKeyAccess::Get());
293+
return internal::ProtoKeySerialization::Create(
294+
kPublicTypeUrl, restricted_output, KeyData::ASYMMETRIC_PUBLIC,
295+
*output_prefix_type, key.GetIdRequirement());
296+
}
297+
298+
SlhDsaProtoParametersParserImpl& SlhDsaProtoParametersParser() {
299+
static auto parser =
227300
new SlhDsaProtoParametersParserImpl(kPrivateTypeUrl, ParseParameters);
228-
return parser;
301+
return *parser;
229302
}
230303

231-
SlhDsaProtoParametersSerializerImpl* SlhDsaProtoParametersSerializer() {
232-
static auto* serializer = new SlhDsaProtoParametersSerializerImpl(
304+
SlhDsaProtoParametersSerializerImpl& SlhDsaProtoParametersSerializer() {
305+
static auto serializer = new SlhDsaProtoParametersSerializerImpl(
233306
kPrivateTypeUrl, SerializeParameters);
234-
return serializer;
307+
return *serializer;
308+
}
309+
310+
SlhDsaProtoPublicKeyParserImpl& SlhDsaProtoPublicKeyParser() {
311+
static auto* parser =
312+
new SlhDsaProtoPublicKeyParserImpl(kPublicTypeUrl, ParsePublicKey);
313+
return *parser;
314+
}
315+
316+
SlhDsaProtoPublicKeySerializerImpl& SlhDsaProtoPublicKeySerializer() {
317+
static auto* serializer =
318+
new SlhDsaProtoPublicKeySerializerImpl(SerializePublicKey);
319+
return *serializer;
235320
}
236321

237322
} // namespace
238323

239324
util::Status RegisterSlhDsaProtoSerialization() {
240325
util::Status status =
241326
internal::MutableSerializationRegistry::GlobalInstance()
242-
.RegisterParametersParser(SlhDsaProtoParametersParser());
327+
.RegisterParametersParser(&SlhDsaProtoParametersParser());
328+
if (!status.ok()) {
329+
return status;
330+
}
331+
332+
status =
333+
internal::MutableSerializationRegistry::GlobalInstance()
334+
.RegisterParametersSerializer(&SlhDsaProtoParametersSerializer());
335+
if (!status.ok()) {
336+
return status;
337+
}
338+
339+
status = internal::MutableSerializationRegistry::GlobalInstance()
340+
.RegisterKeyParser(&SlhDsaProtoPublicKeyParser());
243341
if (!status.ok()) {
244342
return status;
245343
}
246344

247345
return internal::MutableSerializationRegistry::GlobalInstance()
248-
.RegisterParametersSerializer(SlhDsaProtoParametersSerializer());
346+
.RegisterKeySerializer(&SlhDsaProtoPublicKeySerializer());
249347
}
250348

251349
} // namespace tink

cc/experimental/pqcrypto/signature/slh_dsa_proto_serialization_test.cc

+157
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,17 @@
2525
#include "absl/strings/string_view.h"
2626
#include "absl/types/optional.h"
2727
#include "tink/experimental/pqcrypto/signature/slh_dsa_parameters.h"
28+
#include "tink/experimental/pqcrypto/signature/slh_dsa_public_key.h"
29+
#include "tink/insecure_secret_key_access.h"
2830
#include "tink/internal/mutable_serialization_registry.h"
31+
#include "tink/internal/proto_key_serialization.h"
2932
#include "tink/internal/proto_parameters_serialization.h"
3033
#include "tink/internal/serialization.h"
34+
#include "tink/key.h"
3135
#include "tink/parameters.h"
36+
#include "tink/partial_key_access.h"
37+
#include "tink/restricted_data.h"
38+
#include "tink/subtle/random.h"
3239
#include "tink/util/statusor.h"
3340
#include "tink/util/test_matchers.h"
3441
#include "proto/experimental/pqcrypto/slh_dsa.pb.h"
@@ -38,8 +45,10 @@ namespace crypto {
3845
namespace tink {
3946
namespace {
4047

48+
using ::crypto::tink::subtle::Random;
4149
using ::crypto::tink::test::IsOk;
4250
using ::crypto::tink::test::StatusIs;
51+
using ::google::crypto::tink::KeyData;
4352
using ::google::crypto::tink::OutputPrefixType;
4453
using ::google::crypto::tink::SlhDsaHashType;
4554
using ::google::crypto::tink::SlhDsaKeyFormat;
@@ -54,6 +63,8 @@ using ::testing::Values;
5463

5564
const absl::string_view kPrivateTypeUrl =
5665
"type.googleapis.com/google.crypto.tink.SlhDsaPrivateKey";
66+
const absl::string_view kPublicTypeUrl =
67+
"type.googleapis.com/google.crypto.tink.SlhDsaPublicKey";
5768

5869
struct TestCase {
5970
SlhDsaParameters::Variant variant;
@@ -289,6 +300,152 @@ TEST_P(SlhDsaProtoSerializationTest,
289300
EXPECT_THAT(key_format.params().key_size(), Eq(64));
290301
}
291302

303+
TEST_P(SlhDsaProtoSerializationTest, ParsePublicKeyWorks) {
304+
TestCase test_case = GetParam();
305+
ASSERT_THAT(RegisterSlhDsaProtoSerialization(), IsOk());
306+
307+
SlhDsaParams params;
308+
params.set_sig_type(SlhDsaSignatureType::SMALL_SIGNATURE);
309+
params.set_hash_type(SlhDsaHashType::SHA2);
310+
params.set_key_size(64);
311+
312+
std::string raw_key_bytes = Random::GetRandomBytes(32);
313+
google::crypto::tink::SlhDsaPublicKey key_proto;
314+
key_proto.set_version(0);
315+
key_proto.set_key_value(raw_key_bytes);
316+
*key_proto.mutable_params() = params;
317+
RestrictedData serialized_key = RestrictedData(
318+
key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
319+
320+
util::StatusOr<internal::ProtoKeySerialization> serialization =
321+
internal::ProtoKeySerialization::Create(
322+
kPublicTypeUrl, serialized_key, KeyData::ASYMMETRIC_PUBLIC,
323+
test_case.output_prefix_type, test_case.id_requirement);
324+
ASSERT_THAT(serialization, IsOk());
325+
326+
util::StatusOr<std::unique_ptr<Key>> key =
327+
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
328+
*serialization, /*token=*/absl::nullopt);
329+
ASSERT_THAT(key, IsOk());
330+
EXPECT_THAT((*key)->GetIdRequirement(), Eq(test_case.id_requirement));
331+
EXPECT_THAT((*key)->GetParameters().HasIdRequirement(),
332+
test_case.id_requirement.has_value());
333+
334+
util::StatusOr<SlhDsaParameters> expected_parameters =
335+
SlhDsaParameters::Create(
336+
SlhDsaParameters::HashType::kSha2, /*private_key_size_in_bytes=*/64,
337+
SlhDsaParameters::SignatureType::kSmallSignature, test_case.variant);
338+
ASSERT_THAT(expected_parameters, IsOk());
339+
340+
util::StatusOr<SlhDsaPublicKey> expected_key =
341+
SlhDsaPublicKey::Create(*expected_parameters, raw_key_bytes,
342+
test_case.id_requirement, GetPartialKeyAccess());
343+
ASSERT_THAT(expected_key, IsOk());
344+
345+
EXPECT_THAT(**key, Eq(*expected_key));
346+
}
347+
348+
TEST_F(SlhDsaProtoSerializationTest,
349+
ParsePublicKeyWithInvalidSerializationFails) {
350+
ASSERT_THAT(RegisterSlhDsaProtoSerialization(), IsOk());
351+
352+
RestrictedData serialized_key =
353+
RestrictedData("invalid_serialization", InsecureSecretKeyAccess::Get());
354+
355+
util::StatusOr<internal::ProtoKeySerialization> serialization =
356+
internal::ProtoKeySerialization::Create(kPublicTypeUrl, serialized_key,
357+
KeyData::ASYMMETRIC_PUBLIC,
358+
OutputPrefixType::TINK,
359+
/*id_requirement=*/0x23456789);
360+
ASSERT_THAT(serialization, IsOk());
361+
362+
util::StatusOr<std::unique_ptr<Key>> key =
363+
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
364+
*serialization, InsecureSecretKeyAccess::Get());
365+
EXPECT_THAT(key.status(),
366+
StatusIs(absl::StatusCode::kInvalidArgument,
367+
HasSubstr("Failed to parse SlhDsaPublicKey proto")));
368+
}
369+
370+
TEST_F(SlhDsaProtoSerializationTest, ParsePublicKeyWithInvalidVersionFails) {
371+
ASSERT_THAT(RegisterSlhDsaProtoSerialization(), IsOk());
372+
373+
SlhDsaParams params;
374+
params.set_sig_type(SlhDsaSignatureType::SMALL_SIGNATURE);
375+
params.set_hash_type(SlhDsaHashType::SHA2);
376+
params.set_key_size(64);
377+
378+
std::string raw_key_bytes = Random::GetRandomBytes(32);
379+
google::crypto::tink::SlhDsaPublicKey key_proto;
380+
key_proto.set_version(1);
381+
key_proto.set_key_value(raw_key_bytes);
382+
*key_proto.mutable_params() = params;
383+
RestrictedData serialized_key = RestrictedData(
384+
key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
385+
386+
util::StatusOr<internal::ProtoKeySerialization> serialization =
387+
internal::ProtoKeySerialization::Create(kPublicTypeUrl, serialized_key,
388+
KeyData::ASYMMETRIC_PUBLIC,
389+
OutputPrefixType::TINK,
390+
/*id_requirement=*/0x23456789);
391+
ASSERT_THAT(serialization, IsOk());
392+
393+
util::StatusOr<std::unique_ptr<Key>> key =
394+
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
395+
*serialization, /*token=*/absl::nullopt);
396+
EXPECT_THAT(key.status(),
397+
StatusIs(absl::StatusCode::kInvalidArgument,
398+
HasSubstr("Only version 0 keys are accepted")));
399+
}
400+
401+
TEST_P(SlhDsaProtoSerializationTest, SerializePublicKeyWorks) {
402+
TestCase test_case = GetParam();
403+
ASSERT_THAT(RegisterSlhDsaProtoSerialization(), IsOk());
404+
405+
util::StatusOr<SlhDsaParameters> parameters = SlhDsaParameters::Create(
406+
SlhDsaParameters::HashType::kSha2, /*private_key_size_in_bytes=*/64,
407+
SlhDsaParameters::SignatureType::kSmallSignature, test_case.variant);
408+
ASSERT_THAT(parameters, IsOk());
409+
410+
std::string raw_key_bytes = Random::GetRandomBytes(32);
411+
util::StatusOr<SlhDsaPublicKey> key =
412+
SlhDsaPublicKey::Create(*parameters, raw_key_bytes,
413+
test_case.id_requirement, GetPartialKeyAccess());
414+
ASSERT_THAT(key, IsOk());
415+
416+
util::StatusOr<std::unique_ptr<Serialization>> serialization =
417+
internal::MutableSerializationRegistry::GlobalInstance()
418+
.SerializeKey<internal::ProtoKeySerialization>(
419+
*key, /*token=*/absl::nullopt);
420+
ASSERT_THAT(serialization, IsOk());
421+
EXPECT_THAT((*serialization)->ObjectIdentifier(), Eq(kPublicTypeUrl));
422+
423+
const internal::ProtoKeySerialization* proto_serialization =
424+
dynamic_cast<const internal::ProtoKeySerialization*>(
425+
serialization->get());
426+
ASSERT_THAT(proto_serialization, NotNull());
427+
EXPECT_THAT(proto_serialization->TypeUrl(), Eq(kPublicTypeUrl));
428+
EXPECT_THAT(proto_serialization->KeyMaterialType(),
429+
Eq(KeyData::ASYMMETRIC_PUBLIC));
430+
EXPECT_THAT(proto_serialization->GetOutputPrefixType(),
431+
Eq(test_case.output_prefix_type));
432+
EXPECT_THAT(proto_serialization->IdRequirement(),
433+
Eq(test_case.id_requirement));
434+
435+
google::crypto::tink::SlhDsaPublicKey proto_key;
436+
ASSERT_THAT(proto_key.ParseFromString(
437+
proto_serialization->SerializedKeyProto().GetSecret(
438+
InsecureSecretKeyAccess::Get())),
439+
IsTrue());
440+
EXPECT_THAT(proto_key.version(), Eq(0));
441+
EXPECT_THAT(proto_key.key_value(), Eq(raw_key_bytes));
442+
EXPECT_THAT(proto_key.has_params(), IsTrue());
443+
EXPECT_THAT(proto_key.params().key_size(), Eq(64));
444+
EXPECT_THAT(proto_key.params().hash_type(), Eq(SlhDsaHashType::SHA2));
445+
EXPECT_THAT(proto_key.params().sig_type(),
446+
Eq(SlhDsaSignatureType::SMALL_SIGNATURE));
447+
}
448+
292449
} // namespace
293450
} // namespace tink
294451
} // namespace crypto

0 commit comments

Comments
 (0)