• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 Google LLC
2 //
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 //     http://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 
17 #include "tink/experimental/pqcrypto/signature/dilithium_verify_key_manager.h"
18 
19 #include <memory>
20 #include <string>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/container/flat_hash_set.h"
25 #include "absl/strings/str_cat.h"
26 #include "tink/experimental/pqcrypto/signature/dilithium_sign_key_manager.h"
27 #include "tink/experimental/pqcrypto/signature/subtle/dilithium_avx2_sign.h"
28 #include "tink/experimental/pqcrypto/signature/subtle/dilithium_avx2_verify.h"
29 #include "tink/experimental/pqcrypto/signature/subtle/dilithium_key.h"
30 #include "tink/experimental/pqcrypto/signature/util/enums.h"
31 #include "tink/public_key_verify.h"
32 #include "tink/util/secret_data.h"
33 #include "tink/util/status.h"
34 #include "tink/util/statusor.h"
35 #include "tink/util/test_matchers.h"
36 
37 extern "C" {
38 #include "third_party/pqclean/crypto_sign/dilithium2/api.h"
39 #include "third_party/pqclean/crypto_sign/dilithium2aes/api.h"
40 #include "third_party/pqclean/crypto_sign/dilithium3/api.h"
41 #include "third_party/pqclean/crypto_sign/dilithium3aes/api.h"
42 #include "third_party/pqclean/crypto_sign/dilithium5/api.h"
43 #include "third_party/pqclean/crypto_sign/dilithium5aes/api.h"
44 }
45 
46 namespace crypto {
47 namespace tink {
48 namespace {
49 
50 using ::crypto::tink::subtle::DilithiumPrivateKeyPqclean;
51 using ::crypto::tink::test::IsOk;
52 using ::crypto::tink::util::EnumsPqcrypto;
53 using ::crypto::tink::util::StatusOr;
54 using ::google::crypto::tink::DilithiumKeyFormat;
55 using ::google::crypto::tink::DilithiumParams;
56 using ::google::crypto::tink::DilithiumPrivateKey;
57 using ::google::crypto::tink::DilithiumPublicKey;
58 using ::google::crypto::tink::DilithiumSeedExpansion;
59 using ::google::crypto::tink::KeyData;
60 using ::testing::Eq;
61 using ::testing::Not;
62 
63 struct DilithiumTestCase {
64   std::string test_name;
65   int32_t private_key_size;
66   int32_t public_key_size;
67   DilithiumSeedExpansion seed_expansion;
68 };
69 
70 using DilithiumVerifyKeyManagerTest = testing::TestWithParam<DilithiumTestCase>;
71 
72 // Helper function that returns a valid dilithium private key.
CreateValidPrivateKey(int32_t private_key_size,DilithiumSeedExpansion seed_expansion)73 StatusOr<DilithiumPrivateKey> CreateValidPrivateKey(
74     int32_t private_key_size, DilithiumSeedExpansion seed_expansion) {
75   DilithiumKeyFormat key_format;
76   DilithiumParams* params = key_format.mutable_params();
77   params->set_key_size(private_key_size);
78   params->set_seed_expansion(seed_expansion);
79 
80   return DilithiumSignKeyManager().CreateKey(key_format);
81 }
82 
83 // Helper function that returns a valid dilithium public key.
CreateValidPublicKey(int32_t private_key_size,DilithiumSeedExpansion seed_expansion)84 StatusOr<DilithiumPublicKey> CreateValidPublicKey(
85     int32_t private_key_size, DilithiumSeedExpansion seed_expansion) {
86   StatusOr<DilithiumPrivateKey> private_key =
87       CreateValidPrivateKey(private_key_size, seed_expansion);
88 
89   if (!private_key.ok()) return private_key.status();
90   return DilithiumSignKeyManager().GetPublicKey(*private_key);
91 }
92 
TEST(DilithiumVerifyKeyManagerTest,Basics)93 TEST(DilithiumVerifyKeyManagerTest, Basics) {
94   EXPECT_THAT(DilithiumVerifyKeyManager().get_version(), Eq(0));
95   EXPECT_THAT(DilithiumVerifyKeyManager().key_material_type(),
96               Eq(KeyData::ASYMMETRIC_PUBLIC));
97   EXPECT_THAT(DilithiumVerifyKeyManager().get_key_type(),
98               Eq("type.googleapis.com/google.crypto.tink.DilithiumPublicKey"));
99 }
100 
TEST(DilithiumVerifyKeyManagerTest,ValidateEmptyKey)101 TEST(DilithiumVerifyKeyManagerTest, ValidateEmptyKey) {
102   EXPECT_THAT(DilithiumVerifyKeyManager().ValidateKey(DilithiumPublicKey()),
103               Not(IsOk()));
104 }
105 
TEST_P(DilithiumVerifyKeyManagerTest,InvalidParams)106 TEST_P(DilithiumVerifyKeyManagerTest, InvalidParams) {
107   const DilithiumTestCase& test_case = GetParam();
108 
109   DilithiumKeyFormat key_format;
110   DilithiumParams* params = key_format.mutable_params();
111   params->set_key_size(test_case.private_key_size);
112   params->set_seed_expansion(DilithiumSeedExpansion::SEED_EXPANSION_UNKNOWN);
113 
114   EXPECT_THAT(DilithiumVerifyKeyManager().ValidateParams(*params), Not(IsOk()));
115 }
116 
TEST_P(DilithiumVerifyKeyManagerTest,PublicKeyValid)117 TEST_P(DilithiumVerifyKeyManagerTest, PublicKeyValid) {
118   const DilithiumTestCase& test_case = GetParam();
119 
120   StatusOr<DilithiumPublicKey> public_key = CreateValidPublicKey(
121       test_case.private_key_size, test_case.seed_expansion);
122   ASSERT_THAT(public_key, IsOk());
123 
124   EXPECT_THAT(DilithiumVerifyKeyManager().ValidateKey(*public_key), IsOk());
125 }
126 
TEST_P(DilithiumVerifyKeyManagerTest,PublicKeyWrongVersion)127 TEST_P(DilithiumVerifyKeyManagerTest, PublicKeyWrongVersion) {
128   const DilithiumTestCase& test_case = GetParam();
129 
130   StatusOr<DilithiumPublicKey> public_key = CreateValidPublicKey(
131       test_case.private_key_size, test_case.seed_expansion);
132   ASSERT_THAT(public_key, IsOk());
133 
134   public_key->set_version(1);
135   EXPECT_THAT(DilithiumVerifyKeyManager().ValidateKey(*public_key),
136               Not(IsOk()));
137 }
138 
TEST_P(DilithiumVerifyKeyManagerTest,PublicKeyWrongKeyLength)139 TEST_P(DilithiumVerifyKeyManagerTest, PublicKeyWrongKeyLength) {
140   const DilithiumTestCase& test_case = GetParam();
141 
142   StatusOr<DilithiumPublicKey> public_key = CreateValidPublicKey(
143       test_case.private_key_size, test_case.seed_expansion);
144   ASSERT_THAT(public_key, IsOk());
145 
146   for (int keysize = 0; keysize < PQCLEAN_DILITHIUM2_CRYPTO_PUBLICKEYBYTES;
147        keysize++) {
148     public_key->set_key_value(std::string(keysize, '@'));
149     EXPECT_THAT(DilithiumVerifyKeyManager().ValidateKey(*public_key),
150                 Not(IsOk()));
151   }
152 }
153 
TEST_P(DilithiumVerifyKeyManagerTest,Create)154 TEST_P(DilithiumVerifyKeyManagerTest, Create) {
155   const DilithiumTestCase& test_case = GetParam();
156 
157   StatusOr<DilithiumPrivateKey> private_key = CreateValidPrivateKey(
158       test_case.private_key_size, test_case.seed_expansion);
159   ASSERT_THAT(private_key, IsOk());
160 
161   StatusOr<DilithiumPublicKey> public_key =
162       DilithiumSignKeyManager().GetPublicKey(*private_key);
163   ASSERT_THAT(public_key, IsOk());
164 
165   util::StatusOr<DilithiumPrivateKeyPqclean> dilithium_private_key =
166       DilithiumPrivateKeyPqclean::NewPrivateKey(
167           util::SecretDataFromStringView(private_key->key_value()),
168           EnumsPqcrypto::ProtoToSubtle(test_case.seed_expansion));
169   ASSERT_THAT(dilithium_private_key, IsOk());
170 
171   util::StatusOr<std::unique_ptr<PublicKeySign>> direct_signer =
172       subtle::DilithiumAvx2Sign::New(*dilithium_private_key);
173   ASSERT_THAT(direct_signer, IsOk());
174 
175   util::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier =
176       DilithiumVerifyKeyManager().GetPrimitive<PublicKeyVerify>(*public_key);
177   ASSERT_THAT(verifier, IsOk());
178 
179   std::string message = "Some message";
180   util::StatusOr<std::string> signature = (*direct_signer)->Sign(message);
181   ASSERT_THAT(signature, IsOk());
182   EXPECT_THAT((*verifier)->Verify(*signature, message), IsOk());
183 }
184 
TEST_P(DilithiumVerifyKeyManagerTest,CreateDifferentPublicKey)185 TEST_P(DilithiumVerifyKeyManagerTest, CreateDifferentPublicKey) {
186   const DilithiumTestCase& test_case = GetParam();
187 
188   StatusOr<DilithiumPrivateKey> private_key = CreateValidPrivateKey(
189       test_case.private_key_size, test_case.seed_expansion);
190   ASSERT_THAT(private_key, IsOk());
191 
192   // Create a new public key derived from a diffferent private key.
193   StatusOr<DilithiumPrivateKey> new_private_key = CreateValidPrivateKey(
194       test_case.private_key_size, test_case.seed_expansion);
195   ASSERT_THAT(new_private_key, IsOk());
196   StatusOr<DilithiumPublicKey> public_key =
197       DilithiumSignKeyManager().GetPublicKey(*new_private_key);
198   ASSERT_THAT(public_key, IsOk());
199 
200   util::StatusOr<DilithiumPrivateKeyPqclean> dilithium_private_key =
201       DilithiumPrivateKeyPqclean::NewPrivateKey(
202           util::SecretDataFromStringView(private_key->key_value()),
203           EnumsPqcrypto::ProtoToSubtle(test_case.seed_expansion));
204   ASSERT_THAT(dilithium_private_key, IsOk());
205 
206   util::StatusOr<std::unique_ptr<PublicKeySign>> direct_signer =
207       subtle::DilithiumAvx2Sign::New(*dilithium_private_key);
208   ASSERT_THAT(direct_signer, IsOk());
209 
210   util::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier =
211       DilithiumVerifyKeyManager().GetPrimitive<PublicKeyVerify>(*public_key);
212   ASSERT_THAT(verifier, IsOk());
213 
214   std::string message = "Some message";
215   util::StatusOr<std::string> signature = (*direct_signer)->Sign(message);
216   ASSERT_THAT(signature, IsOk());
217   EXPECT_THAT((*verifier)->Verify(*signature, message), Not(IsOk()));
218 }
219 
220 INSTANTIATE_TEST_SUITE_P(
221     DilithiumVerifyKeyManagerTests, DilithiumVerifyKeyManagerTest,
222     testing::ValuesIn<DilithiumTestCase>({
223         {"Dilithium2", PQCLEAN_DILITHIUM2_CRYPTO_SECRETKEYBYTES,
224          PQCLEAN_DILITHIUM2_CRYPTO_PUBLICKEYBYTES,
225          DilithiumSeedExpansion::SEED_EXPANSION_SHAKE},
226         {"Dilithium3", PQCLEAN_DILITHIUM3_CRYPTO_SECRETKEYBYTES,
227          PQCLEAN_DILITHIUM3_CRYPTO_PUBLICKEYBYTES,
228          DilithiumSeedExpansion::SEED_EXPANSION_SHAKE},
229         {"Dilithium5", PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES,
230          PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES,
231          DilithiumSeedExpansion::SEED_EXPANSION_SHAKE},
232         {"Dilithium2Aes", PQCLEAN_DILITHIUM2AES_CRYPTO_SECRETKEYBYTES,
233          PQCLEAN_DILITHIUM2AES_CRYPTO_PUBLICKEYBYTES,
234          DilithiumSeedExpansion::SEED_EXPANSION_AES},
235         {"Dilithium3Aes", PQCLEAN_DILITHIUM3AES_CRYPTO_SECRETKEYBYTES,
236          PQCLEAN_DILITHIUM3AES_CRYPTO_PUBLICKEYBYTES,
237          DilithiumSeedExpansion::SEED_EXPANSION_AES},
238         {"Dilithium5Aes", PQCLEAN_DILITHIUM5AES_CRYPTO_SECRETKEYBYTES,
239          PQCLEAN_DILITHIUM5AES_CRYPTO_PUBLICKEYBYTES,
240          DilithiumSeedExpansion::SEED_EXPANSION_AES},
241     }),
242     [](const testing::TestParamInfo<DilithiumVerifyKeyManagerTest::ParamType>&
__anon74641a020202(const testing::TestParamInfo<DilithiumVerifyKeyManagerTest::ParamType>& info) 243            info) { return info.param.test_name; });
244 
245 }  // namespace
246 
247 }  // namespace tink
248 }  // namespace crypto
249